ABI fixes for ppc64 and s390x.
This commit is contained in:
parent
6eec89a42b
commit
99c271af8c
405
rust-1.20.0-44066-ppc64-struct-abi.patch
Normal file
405
rust-1.20.0-44066-ppc64-struct-abi.patch
Normal file
@ -0,0 +1,405 @@
|
|||||||
|
From 6f680d06544edae491d2281d89b0b93efcdd6143 Mon Sep 17 00:00:00 2001
|
||||||
|
From: bors <bors@rust-lang.org>
|
||||||
|
Date: Sat, 2 Sep 2017 19:46:51 +0000
|
||||||
|
Subject: [PATCH] Auto merge of #44066 - cuviper:powerpc64-extern-abi,
|
||||||
|
r=alexcrichton
|
||||||
|
|
||||||
|
powerpc64: improve extern struct ABI
|
||||||
|
|
||||||
|
These fixes all have to do with the 64-bit PowerPC ELF ABI for big-endian
|
||||||
|
targets. The ELF v2 ABI for powerpc64le already worked well.
|
||||||
|
|
||||||
|
- Return after marking return aggregates indirect. Fixes #42757.
|
||||||
|
- Pass one-member float aggregates as direct argument values.
|
||||||
|
- Aggregate arguments less than 64-bit must be written in the least-
|
||||||
|
significant bits of the parameter space.
|
||||||
|
- Larger aggregates are instead padded at the tail.
|
||||||
|
(i.e. filling MSBs, padding the remaining LSBs.)
|
||||||
|
|
||||||
|
New tests were also added for the single-float aggregate, and a 3-byte
|
||||||
|
aggregate to check that it's filled into LSBs. Overall, at least these
|
||||||
|
formerly-failing tests now pass on powerpc64:
|
||||||
|
|
||||||
|
- run-make/extern-fn-struct-passing-abi
|
||||||
|
- run-make/extern-fn-with-packed-struct
|
||||||
|
- run-pass/extern-pass-TwoU16s.rs
|
||||||
|
- run-pass/extern-pass-TwoU8s.rs
|
||||||
|
- run-pass/struct-return.rs
|
||||||
|
---
|
||||||
|
src/librustc_trans/cabi_powerpc64.rs | 64 +++++++++++++++++-----
|
||||||
|
src/librustc_trans/cabi_x86.rs | 41 ++++++++++++--
|
||||||
|
.../run-make/extern-fn-struct-passing-abi/test.c | 32 ++++++++++-
|
||||||
|
.../run-make/extern-fn-struct-passing-abi/test.rs | 27 +++++++++
|
||||||
|
.../run-make/extern-fn-with-packed-struct/test.c | 5 ++
|
||||||
|
.../run-make/extern-fn-with-packed-struct/test.rs | 26 +--------
|
||||||
|
6 files changed, 151 insertions(+), 44 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/librustc_trans/cabi_powerpc64.rs b/src/librustc_trans/cabi_powerpc64.rs
|
||||||
|
index c4f8d0b4b963..a3780c8cfa92 100644
|
||||||
|
--- a/src/librustc_trans/cabi_powerpc64.rs
|
||||||
|
+++ b/src/librustc_trans/cabi_powerpc64.rs
|
||||||
|
@@ -14,14 +14,26 @@
|
||||||
|
|
||||||
|
use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform};
|
||||||
|
use context::CrateContext;
|
||||||
|
+use rustc::ty::layout;
|
||||||
|
|
||||||
|
-fn is_homogenous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>)
|
||||||
|
+#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
+enum ABI {
|
||||||
|
+ ELFv1, // original ABI used for powerpc64 (big-endian)
|
||||||
|
+ ELFv2, // newer ABI used for powerpc64le
|
||||||
|
+}
|
||||||
|
+use self::ABI::*;
|
||||||
|
+
|
||||||
|
+fn is_homogenous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||||
|
+ arg: &mut ArgType<'tcx>,
|
||||||
|
+ abi: ABI)
|
||||||
|
-> Option<Uniform> {
|
||||||
|
arg.layout.homogenous_aggregate(ccx).and_then(|unit| {
|
||||||
|
let size = arg.layout.size(ccx);
|
||||||
|
|
||||||
|
- // Ensure we have at most eight uniquely addressable members.
|
||||||
|
- if size > unit.size.checked_mul(8, ccx).unwrap() {
|
||||||
|
+ // ELFv1 only passes one-member aggregates transparently.
|
||||||
|
+ // ELFv2 passes up to eight uniquely addressable members.
|
||||||
|
+ if (abi == ELFv1 && size > unit.size)
|
||||||
|
+ || size > unit.size.checked_mul(8, ccx).unwrap() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -42,21 +54,23 @@ fn is_homogenous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut Arg
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
-fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
|
||||||
|
+fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>, abi: ABI) {
|
||||||
|
if !ret.layout.is_aggregate() {
|
||||||
|
ret.extend_integer_width_to(64);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
- // The PowerPC64 big endian ABI doesn't return aggregates in registers
|
||||||
|
- if ccx.sess().target.target.target_endian == "big" {
|
||||||
|
+ // The ELFv1 ABI doesn't return aggregates in registers
|
||||||
|
+ if abi == ELFv1 {
|
||||||
|
ret.make_indirect(ccx);
|
||||||
|
+ return;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if let Some(uniform) = is_homogenous_aggregate(ccx, ret) {
|
||||||
|
+ if let Some(uniform) = is_homogenous_aggregate(ccx, ret, abi) {
|
||||||
|
ret.cast_to(ccx, uniform);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
let size = ret.layout.size(ccx);
|
||||||
|
let bits = size.bits();
|
||||||
|
if bits <= 128 {
|
||||||
|
@@ -80,31 +94,55 @@ fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tc
|
||||||
|
ret.make_indirect(ccx);
|
||||||
|
}
|
||||||
|
|
||||||
|
-fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
|
||||||
|
+fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>, abi: ABI) {
|
||||||
|
if !arg.layout.is_aggregate() {
|
||||||
|
arg.extend_integer_width_to(64);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if let Some(uniform) = is_homogenous_aggregate(ccx, arg) {
|
||||||
|
+ if let Some(uniform) = is_homogenous_aggregate(ccx, arg, abi) {
|
||||||
|
arg.cast_to(ccx, uniform);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
- let total = arg.layout.size(ccx);
|
||||||
|
+ let size = arg.layout.size(ccx);
|
||||||
|
+ let (unit, total) = match abi {
|
||||||
|
+ ELFv1 => {
|
||||||
|
+ // In ELFv1, aggregates smaller than a doubleword should appear in
|
||||||
|
+ // the least-significant bits of the parameter doubleword. The rest
|
||||||
|
+ // should be padded at their tail to fill out multiple doublewords.
|
||||||
|
+ if size.bits() <= 64 {
|
||||||
|
+ (Reg { kind: RegKind::Integer, size }, size)
|
||||||
|
+ } else {
|
||||||
|
+ let align = layout::Align::from_bits(64, 64).unwrap();
|
||||||
|
+ (Reg::i64(), size.abi_align(align))
|
||||||
|
+ }
|
||||||
|
+ },
|
||||||
|
+ ELFv2 => {
|
||||||
|
+ // In ELFv2, we can just cast directly.
|
||||||
|
+ (Reg::i64(), size)
|
||||||
|
+ },
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
arg.cast_to(ccx, Uniform {
|
||||||
|
- unit: Reg::i64(),
|
||||||
|
+ unit,
|
||||||
|
total
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
|
||||||
|
+ let abi = match ccx.sess().target.target.target_endian.as_str() {
|
||||||
|
+ "big" => ELFv1,
|
||||||
|
+ "little" => ELFv2,
|
||||||
|
+ _ => unimplemented!(),
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
if !fty.ret.is_ignore() {
|
||||||
|
- classify_ret_ty(ccx, &mut fty.ret);
|
||||||
|
+ classify_ret_ty(ccx, &mut fty.ret, abi);
|
||||||
|
}
|
||||||
|
|
||||||
|
for arg in &mut fty.args {
|
||||||
|
if arg.is_ignore() { continue; }
|
||||||
|
- classify_arg_ty(ccx, arg);
|
||||||
|
+ classify_arg_ty(ccx, arg, abi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/src/librustc_trans/cabi_x86.rs b/src/librustc_trans/cabi_x86.rs
|
||||||
|
index 9f5520dabe33..05932ef2de80 100644
|
||||||
|
--- a/src/librustc_trans/cabi_x86.rs
|
||||||
|
+++ b/src/librustc_trans/cabi_x86.rs
|
||||||
|
@@ -11,12 +11,30 @@
|
||||||
|
use abi::{ArgAttribute, FnType, LayoutExt, Reg, RegKind};
|
||||||
|
use common::CrateContext;
|
||||||
|
|
||||||
|
+use rustc::ty::layout::{self, Layout, TyLayout};
|
||||||
|
+
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
pub enum Flavor {
|
||||||
|
General,
|
||||||
|
Fastcall
|
||||||
|
}
|
||||||
|
|
||||||
|
+fn is_single_fp_element<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||||
|
+ layout: TyLayout<'tcx>) -> bool {
|
||||||
|
+ match *layout {
|
||||||
|
+ Layout::Scalar { value: layout::F32, .. } |
|
||||||
|
+ Layout::Scalar { value: layout::F64, .. } => true,
|
||||||
|
+ Layout::Univariant { .. } => {
|
||||||
|
+ if layout.field_count() == 1 {
|
||||||
|
+ is_single_fp_element(ccx, layout.field(ccx, 0))
|
||||||
|
+ } else {
|
||||||
|
+ false
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ _ => false
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||||
|
fty: &mut FnType<'tcx>,
|
||||||
|
flavor: Flavor) {
|
||||||
|
@@ -33,12 +51,23 @@ pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||||
|
if t.options.is_like_osx || t.options.is_like_windows
|
||||||
|
|| t.options.is_like_openbsd {
|
||||||
|
let size = fty.ret.layout.size(ccx);
|
||||||
|
- match size.bytes() {
|
||||||
|
- 1 => fty.ret.cast_to(ccx, Reg::i8()),
|
||||||
|
- 2 => fty.ret.cast_to(ccx, Reg::i16()),
|
||||||
|
- 4 => fty.ret.cast_to(ccx, Reg::i32()),
|
||||||
|
- 8 => fty.ret.cast_to(ccx, Reg::i64()),
|
||||||
|
- _ => fty.ret.make_indirect(ccx)
|
||||||
|
+
|
||||||
|
+ // According to Clang, everyone but MSVC returns single-element
|
||||||
|
+ // float aggregates directly in a floating-point register.
|
||||||
|
+ if !t.options.is_like_msvc && is_single_fp_element(ccx, fty.ret.layout) {
|
||||||
|
+ match size.bytes() {
|
||||||
|
+ 4 => fty.ret.cast_to(ccx, Reg::f32()),
|
||||||
|
+ 8 => fty.ret.cast_to(ccx, Reg::f64()),
|
||||||
|
+ _ => fty.ret.make_indirect(ccx)
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ match size.bytes() {
|
||||||
|
+ 1 => fty.ret.cast_to(ccx, Reg::i8()),
|
||||||
|
+ 2 => fty.ret.cast_to(ccx, Reg::i16()),
|
||||||
|
+ 4 => fty.ret.cast_to(ccx, Reg::i32()),
|
||||||
|
+ 8 => fty.ret.cast_to(ccx, Reg::i64()),
|
||||||
|
+ _ => fty.ret.make_indirect(ccx)
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fty.ret.make_indirect(ccx);
|
||||||
|
diff --git a/src/test/run-make/extern-fn-struct-passing-abi/test.c b/src/test/run-make/extern-fn-struct-passing-abi/test.c
|
||||||
|
index 44a940a17a98..25cd6da10b8f 100644
|
||||||
|
--- a/src/test/run-make/extern-fn-struct-passing-abi/test.c
|
||||||
|
+++ b/src/test/run-make/extern-fn-struct-passing-abi/test.c
|
||||||
|
@@ -43,6 +43,16 @@ struct FloatPoint {
|
||||||
|
double y;
|
||||||
|
};
|
||||||
|
|
||||||
|
+struct FloatOne {
|
||||||
|
+ double x;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+struct IntOdd {
|
||||||
|
+ int8_t a;
|
||||||
|
+ int8_t b;
|
||||||
|
+ int8_t c;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
// System V x86_64 ABI:
|
||||||
|
// a, b, c, d, e should be in registers
|
||||||
|
// s should be byval pointer
|
||||||
|
@@ -283,7 +293,7 @@ struct Huge huge_struct(struct Huge s) {
|
||||||
|
// p should be in registers
|
||||||
|
// return should be in registers
|
||||||
|
//
|
||||||
|
-// Win64 ABI:
|
||||||
|
+// Win64 ABI and 64-bit PowerPC ELFv1 ABI:
|
||||||
|
// p should be a byval pointer
|
||||||
|
// return should be in a hidden sret pointer
|
||||||
|
struct FloatPoint float_point(struct FloatPoint p) {
|
||||||
|
@@ -292,3 +302,23 @@ struct FloatPoint float_point(struct FloatPoint p) {
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+// 64-bit PowerPC ELFv1 ABI:
|
||||||
|
+// f1 should be in a register
|
||||||
|
+// return should be in a hidden sret pointer
|
||||||
|
+struct FloatOne float_one(struct FloatOne f1) {
|
||||||
|
+ assert(f1.x == 7.);
|
||||||
|
+
|
||||||
|
+ return f1;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+// 64-bit PowerPC ELFv1 ABI:
|
||||||
|
+// i should be in the least-significant bits of a register
|
||||||
|
+// return should be in a hidden sret pointer
|
||||||
|
+struct IntOdd int_odd(struct IntOdd i) {
|
||||||
|
+ assert(i.a == 1);
|
||||||
|
+ assert(i.b == 2);
|
||||||
|
+ assert(i.c == 3);
|
||||||
|
+
|
||||||
|
+ return i;
|
||||||
|
+}
|
||||||
|
diff --git a/src/test/run-make/extern-fn-struct-passing-abi/test.rs b/src/test/run-make/extern-fn-struct-passing-abi/test.rs
|
||||||
|
index aaae7ae4fb49..54a4f868eb4e 100644
|
||||||
|
--- a/src/test/run-make/extern-fn-struct-passing-abi/test.rs
|
||||||
|
+++ b/src/test/run-make/extern-fn-struct-passing-abi/test.rs
|
||||||
|
@@ -53,6 +53,20 @@ struct FloatPoint {
|
||||||
|
y: f64
|
||||||
|
}
|
||||||
|
|
||||||
|
+#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
+#[repr(C)]
|
||||||
|
+struct FloatOne {
|
||||||
|
+ x: f64,
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
+#[repr(C)]
|
||||||
|
+struct IntOdd {
|
||||||
|
+ a: i8,
|
||||||
|
+ b: i8,
|
||||||
|
+ c: i8,
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
#[link(name = "test", kind = "static")]
|
||||||
|
extern {
|
||||||
|
fn byval_rect(a: i32, b: i32, c: i32, d: i32, e: i32, s: Rect);
|
||||||
|
@@ -83,6 +97,10 @@ extern {
|
||||||
|
fn huge_struct(s: Huge) -> Huge;
|
||||||
|
|
||||||
|
fn float_point(p: FloatPoint) -> FloatPoint;
|
||||||
|
+
|
||||||
|
+ fn float_one(f: FloatOne) -> FloatOne;
|
||||||
|
+
|
||||||
|
+ fn int_odd(i: IntOdd) -> IntOdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
@@ -91,6 +109,8 @@ fn main() {
|
||||||
|
let u = FloatRect { a: 3489, b: 3490, c: 8. };
|
||||||
|
let v = Huge { a: 5647, b: 5648, c: 5649, d: 5650, e: 5651 };
|
||||||
|
let p = FloatPoint { x: 5., y: -3. };
|
||||||
|
+ let f1 = FloatOne { x: 7. };
|
||||||
|
+ let i = IntOdd { a: 1, b: 2, c: 3 };
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
byval_rect(1, 2, 3, 4, 5, s);
|
||||||
|
@@ -113,5 +133,12 @@ fn main() {
|
||||||
|
assert_eq!(sret_byval_struct(1, 2, 3, 4, s), t);
|
||||||
|
assert_eq!(sret_split_struct(1, 2, s), t);
|
||||||
|
assert_eq!(float_point(p), p);
|
||||||
|
+ assert_eq!(int_odd(i), i);
|
||||||
|
+
|
||||||
|
+ // MSVC/GCC/Clang are not consistent in the ABI of single-float aggregates.
|
||||||
|
+ // x86_64: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82028
|
||||||
|
+ // i686: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82041
|
||||||
|
+ #[cfg(not(all(windows, target_env = "gnu")))]
|
||||||
|
+ assert_eq!(float_one(f1), f1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/src/test/run-make/extern-fn-with-packed-struct/test.c b/src/test/run-make/extern-fn-with-packed-struct/test.c
|
||||||
|
index 506954fca461..4124e202c1dd 100644
|
||||||
|
--- a/src/test/run-make/extern-fn-with-packed-struct/test.c
|
||||||
|
+++ b/src/test/run-make/extern-fn-with-packed-struct/test.c
|
||||||
|
@@ -1,6 +1,8 @@
|
||||||
|
// ignore-license
|
||||||
|
// Pragma needed cause of gcc bug on windows: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52991
|
||||||
|
|
||||||
|
+#include <assert.h>
|
||||||
|
+
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma pack(push,1)
|
||||||
|
struct Foo {
|
||||||
|
@@ -18,5 +20,8 @@ struct __attribute__((packed)) Foo {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Foo foo(struct Foo foo) {
|
||||||
|
+ assert(foo.a == 1);
|
||||||
|
+ assert(foo.b == 2);
|
||||||
|
+ assert(foo.c == 3);
|
||||||
|
return foo;
|
||||||
|
}
|
||||||
|
diff --git a/src/test/run-make/extern-fn-with-packed-struct/test.rs b/src/test/run-make/extern-fn-with-packed-struct/test.rs
|
||||||
|
index 9e81636e3670..d2540ad61542 100644
|
||||||
|
--- a/src/test/run-make/extern-fn-with-packed-struct/test.rs
|
||||||
|
+++ b/src/test/run-make/extern-fn-with-packed-struct/test.rs
|
||||||
|
@@ -8,36 +8,14 @@
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
-use std::fmt;
|
||||||
|
-
|
||||||
|
-#[repr(packed)]
|
||||||
|
-#[derive(Copy, Clone)]
|
||||||
|
+#[repr(C, packed)]
|
||||||
|
+#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
|
struct Foo {
|
||||||
|
a: i8,
|
||||||
|
b: i16,
|
||||||
|
c: i8
|
||||||
|
}
|
||||||
|
|
||||||
|
-impl PartialEq for Foo {
|
||||||
|
- fn eq(&self, other: &Foo) -> bool {
|
||||||
|
- self.a == other.a && self.b == other.b && self.c == other.c
|
||||||
|
- }
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-impl fmt::Debug for Foo {
|
||||||
|
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
- let a = self.a;
|
||||||
|
- let b = self.b;
|
||||||
|
- let c = self.c;
|
||||||
|
-
|
||||||
|
- f.debug_struct("Foo")
|
||||||
|
- .field("a", &a)
|
||||||
|
- .field("b", &b)
|
||||||
|
- .field("c", &c)
|
||||||
|
- .finish()
|
||||||
|
- }
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
#[link(name = "test", kind = "static")]
|
||||||
|
extern {
|
||||||
|
fn foo(f: Foo) -> Foo;
|
||||||
|
--
|
||||||
|
2.13.5
|
||||||
|
|
209
rust-1.20.0-44440-s390x-global-align.patch
Normal file
209
rust-1.20.0-44440-s390x-global-align.patch
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
From 3ca86983df58daf0242b0618d3beb9ea917193e2 Mon Sep 17 00:00:00 2001
|
||||||
|
From: bors <bors@rust-lang.org>
|
||||||
|
Date: Mon, 11 Sep 2017 12:53:21 +0000
|
||||||
|
Subject: [PATCH] Auto merge of #44440 - cuviper:min_global_align, r=japaric
|
||||||
|
|
||||||
|
Add `TargetOptions::min_global_align`, with s390x at 16-bit
|
||||||
|
|
||||||
|
The SystemZ `LALR` instruction provides PC-relative addressing for globals,
|
||||||
|
but only to *even* addresses, so other compilers make sure that such
|
||||||
|
globals are always 2-byte aligned. In Clang, this is modeled with
|
||||||
|
`TargetInfo::MinGlobalAlign`, and `TargetOptions::min_global_align` now
|
||||||
|
serves the same purpose for rustc.
|
||||||
|
|
||||||
|
In Clang, the only targets that set this are SystemZ, Lanai, and NVPTX, and
|
||||||
|
the latter two don't have targets in rust master.
|
||||||
|
|
||||||
|
Fixes #44411.
|
||||||
|
r? @eddyb
|
||||||
|
---
|
||||||
|
src/librustc_back/target/mod.rs | 6 ++++
|
||||||
|
.../target/s390x_unknown_linux_gnu.rs | 1 +
|
||||||
|
src/librustc_trans/consts.rs | 24 ++++++++++++--
|
||||||
|
src/test/run-make/min-global-align/Makefile | 22 +++++++++++++
|
||||||
|
.../run-make/min-global-align/min_global_align.rs | 38 ++++++++++++++++++++++
|
||||||
|
5 files changed, 89 insertions(+), 2 deletions(-)
|
||||||
|
create mode 100644 src/test/run-make/min-global-align/Makefile
|
||||||
|
create mode 100644 src/test/run-make/min-global-align/min_global_align.rs
|
||||||
|
|
||||||
|
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
|
||||||
|
index edbbcf6f0b64..f88a3879d6c0 100644
|
||||||
|
--- a/src/librustc_back/target/mod.rs
|
||||||
|
+++ b/src/librustc_back/target/mod.rs
|
||||||
|
@@ -414,6 +414,9 @@ pub struct TargetOptions {
|
||||||
|
|
||||||
|
/// Whether or not stack probes (__rust_probestack) are enabled
|
||||||
|
pub stack_probes: bool,
|
||||||
|
+
|
||||||
|
+ /// The minimum alignment for global symbols.
|
||||||
|
+ pub min_global_align: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TargetOptions {
|
||||||
|
@@ -472,6 +475,7 @@ impl Default for TargetOptions {
|
||||||
|
abi_blacklist: vec![],
|
||||||
|
crt_static_default: false,
|
||||||
|
stack_probes: false,
|
||||||
|
+ min_global_align: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -695,6 +699,7 @@ impl Target {
|
||||||
|
try!(key!(panic_strategy, PanicStrategy));
|
||||||
|
key!(crt_static_default, bool);
|
||||||
|
key!(stack_probes, bool);
|
||||||
|
+ key!(min_global_align, Option<u64>);
|
||||||
|
|
||||||
|
if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) {
|
||||||
|
for name in array.iter().filter_map(|abi| abi.as_string()) {
|
||||||
|
@@ -882,6 +887,7 @@ impl ToJson for Target {
|
||||||
|
target_option_val!(panic_strategy);
|
||||||
|
target_option_val!(crt_static_default);
|
||||||
|
target_option_val!(stack_probes);
|
||||||
|
+ target_option_val!(min_global_align);
|
||||||
|
|
||||||
|
if default.abi_blacklist != self.options.abi_blacklist {
|
||||||
|
d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter()
|
||||||
|
diff --git a/src/librustc_back/target/s390x_unknown_linux_gnu.rs b/src/librustc_back/target/s390x_unknown_linux_gnu.rs
|
||||||
|
index 78a6bb7933d9..aad9effacd44 100644
|
||||||
|
--- a/src/librustc_back/target/s390x_unknown_linux_gnu.rs
|
||||||
|
+++ b/src/librustc_back/target/s390x_unknown_linux_gnu.rs
|
||||||
|
@@ -22,6 +22,7 @@ pub fn target() -> TargetResult {
|
||||||
|
base.max_atomic_width = Some(64);
|
||||||
|
// see #36994
|
||||||
|
base.exe_allocation_crate = None;
|
||||||
|
+ base.min_global_align = Some(16);
|
||||||
|
|
||||||
|
Ok(Target {
|
||||||
|
llvm_target: "s390x-unknown-linux-gnu".to_string(),
|
||||||
|
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
|
||||||
|
index eac0a0625671..cfb29d848d0f 100644
|
||||||
|
--- a/src/librustc_trans/consts.rs
|
||||||
|
+++ b/src/librustc_trans/consts.rs
|
||||||
|
@@ -26,6 +26,7 @@ use rustc::ty;
|
||||||
|
|
||||||
|
use rustc::hir;
|
||||||
|
|
||||||
|
+use std::cmp;
|
||||||
|
use std::ffi::{CStr, CString};
|
||||||
|
use syntax::ast;
|
||||||
|
use syntax::attr;
|
||||||
|
@@ -36,6 +37,25 @@ pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+fn set_global_alignment(ccx: &CrateContext,
|
||||||
|
+ gv: ValueRef,
|
||||||
|
+ mut align: machine::llalign) {
|
||||||
|
+ // The target may require greater alignment for globals than the type does.
|
||||||
|
+ // Note: GCC and Clang also allow `__attribute__((aligned))` on variables,
|
||||||
|
+ // which can force it to be smaller. Rust doesn't support this yet.
|
||||||
|
+ if let Some(min) = ccx.sess().target.target.options.min_global_align {
|
||||||
|
+ match ty::layout::Align::from_bits(min, min) {
|
||||||
|
+ Ok(min) => align = cmp::max(align, min.abi() as machine::llalign),
|
||||||
|
+ Err(err) => {
|
||||||
|
+ ccx.sess().err(&format!("invalid minimum global alignment: {}", err));
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ unsafe {
|
||||||
|
+ llvm::LLVMSetAlignment(gv, align);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
pub fn addr_of_mut(ccx: &CrateContext,
|
||||||
|
cv: ValueRef,
|
||||||
|
align: machine::llalign,
|
||||||
|
@@ -47,7 +67,7 @@ pub fn addr_of_mut(ccx: &CrateContext,
|
||||||
|
bug!("symbol `{}` is already defined", name);
|
||||||
|
});
|
||||||
|
llvm::LLVMSetInitializer(gv, cv);
|
||||||
|
- llvm::LLVMSetAlignment(gv, align);
|
||||||
|
+ set_global_alignment(ccx, gv, align);
|
||||||
|
llvm::LLVMRustSetLinkage(gv, llvm::Linkage::InternalLinkage);
|
||||||
|
SetUnnamedAddr(gv, true);
|
||||||
|
gv
|
||||||
|
@@ -251,7 +271,7 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||||
|
ccx.statics_to_rauw().borrow_mut().push((g, new_g));
|
||||||
|
new_g
|
||||||
|
};
|
||||||
|
- llvm::LLVMSetAlignment(g, ccx.align_of(ty));
|
||||||
|
+ set_global_alignment(ccx, g, ccx.align_of(ty));
|
||||||
|
llvm::LLVMSetInitializer(g, v);
|
||||||
|
|
||||||
|
// As an optimization, all shared statics which do not have interior
|
||||||
|
diff --git a/src/test/run-make/min-global-align/Makefile b/src/test/run-make/min-global-align/Makefile
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000000..2eacc36f380d
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/test/run-make/min-global-align/Makefile
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+-include ../tools.mk
|
||||||
|
+
|
||||||
|
+# This tests ensure that global variables respect the target minimum alignment.
|
||||||
|
+# The three bools `STATIC_BOOL`, `STATIC_MUT_BOOL`, and `CONST_BOOL` all have
|
||||||
|
+# type-alignment of 1, but some targets require greater global alignment.
|
||||||
|
+
|
||||||
|
+SRC = min_global_align.rs
|
||||||
|
+LL = $(TMPDIR)/min_global_align.ll
|
||||||
|
+
|
||||||
|
+all:
|
||||||
|
+ifeq ($(UNAME),Linux)
|
||||||
|
+# Most targets are happy with default alignment -- take i686 for example.
|
||||||
|
+ifeq ($(filter x86,$(LLVM_COMPONENTS)),x86)
|
||||||
|
+ $(RUSTC) --target=i686-unknown-linux-gnu --emit=llvm-ir $(SRC)
|
||||||
|
+ [ "$$(grep -c 'align 1' "$(LL)")" -eq "3" ]
|
||||||
|
+endif
|
||||||
|
+# SystemZ requires even alignment for PC-relative addressing.
|
||||||
|
+ifeq ($(filter systemz,$(LLVM_COMPONENTS)),systemz)
|
||||||
|
+ $(RUSTC) --target=s390x-unknown-linux-gnu --emit=llvm-ir $(SRC)
|
||||||
|
+ [ "$$(grep -c 'align 2' "$(LL)")" -eq "3" ]
|
||||||
|
+endif
|
||||||
|
+endif
|
||||||
|
diff --git a/src/test/run-make/min-global-align/min_global_align.rs b/src/test/run-make/min-global-align/min_global_align.rs
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000000..3d4f9001a747
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/test/run-make/min-global-align/min_global_align.rs
|
||||||
|
@@ -0,0 +1,38 @@
|
||||||
|
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
+// file at the top-level directory of this distribution and at
|
||||||
|
+// http://rust-lang.org/COPYRIGHT.
|
||||||
|
+//
|
||||||
|
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
+// option. This file may not be copied, modified, or distributed
|
||||||
|
+// except according to those terms.
|
||||||
|
+
|
||||||
|
+#![feature(no_core, lang_items)]
|
||||||
|
+#![crate_type="rlib"]
|
||||||
|
+#![no_core]
|
||||||
|
+
|
||||||
|
+pub static STATIC_BOOL: bool = true;
|
||||||
|
+
|
||||||
|
+pub static mut STATIC_MUT_BOOL: bool = true;
|
||||||
|
+
|
||||||
|
+const CONST_BOOL: bool = true;
|
||||||
|
+pub static CONST_BOOL_REF: &'static bool = &CONST_BOOL;
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+#[lang = "sized"]
|
||||||
|
+trait Sized {}
|
||||||
|
+
|
||||||
|
+#[lang = "copy"]
|
||||||
|
+trait Copy {}
|
||||||
|
+
|
||||||
|
+#[lang = "freeze"]
|
||||||
|
+trait Freeze {}
|
||||||
|
+
|
||||||
|
+#[lang = "sync"]
|
||||||
|
+trait Sync {}
|
||||||
|
+impl Sync for bool {}
|
||||||
|
+impl Sync for &'static bool {}
|
||||||
|
+
|
||||||
|
+#[lang="drop_in_place"]
|
||||||
|
+pub unsafe fn drop_in_place<T: ?Sized>(_: *mut T) { }
|
||||||
|
--
|
||||||
|
2.13.5
|
||||||
|
|
@ -48,7 +48,7 @@
|
|||||||
|
|
||||||
Name: rust
|
Name: rust
|
||||||
Version: 1.20.0
|
Version: 1.20.0
|
||||||
Release: 1%{?dist}
|
Release: 2%{?dist}
|
||||||
Summary: The Rust Programming Language
|
Summary: The Rust Programming Language
|
||||||
License: (ASL 2.0 or MIT) and (BSD and ISC and MIT)
|
License: (ASL 2.0 or MIT) and (BSD and ISC and MIT)
|
||||||
# ^ written as: (rust itself) and (bundled libraries)
|
# ^ written as: (rust itself) and (bundled libraries)
|
||||||
@ -64,6 +64,8 @@ Source0: https://static.rust-lang.org/dist/%{rustc_package}.tar.xz
|
|||||||
|
|
||||||
Patch1: rust-1.19.0-43297-configure-debuginfo.patch
|
Patch1: rust-1.19.0-43297-configure-debuginfo.patch
|
||||||
Patch2: rust-1.20.0-44203-exclude-compiler-rt-test.patch
|
Patch2: rust-1.20.0-44203-exclude-compiler-rt-test.patch
|
||||||
|
Patch3: rust-1.20.0-44066-ppc64-struct-abi.patch
|
||||||
|
Patch4: rust-1.20.0-44440-s390x-global-align.patch
|
||||||
|
|
||||||
# Get the Rust triple for any arch.
|
# Get the Rust triple for any arch.
|
||||||
%{lua: function rust_triple(arch)
|
%{lua: function rust_triple(arch)
|
||||||
@ -311,6 +313,8 @@ sed -i.ffi -e '$a #[link(name = "ffi")] extern {}' \
|
|||||||
|
|
||||||
%patch1 -p1 -b .debuginfo
|
%patch1 -p1 -b .debuginfo
|
||||||
%patch2 -p1 -b .compiler-rt
|
%patch2 -p1 -b .compiler-rt
|
||||||
|
%patch3 -p1 -b .ppc64-struct-abi
|
||||||
|
%patch4 -p1 -b .s390x-global-align
|
||||||
|
|
||||||
# The configure macro will modify some autoconf-related files, which upsets
|
# The configure macro will modify some autoconf-related files, which upsets
|
||||||
# cargo when it tries to verify checksums in those files. If we just truncate
|
# cargo when it tries to verify checksums in those files. If we just truncate
|
||||||
@ -469,6 +473,9 @@ rm -f %{buildroot}%{rustlibdir}/etc/lldb_*.py*
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Mon Sep 11 2017 Josh Stone <jistone@redhat.com> - 1.20.0-2
|
||||||
|
- ABI fixes for ppc64 and s390x.
|
||||||
|
|
||||||
* Thu Aug 31 2017 Josh Stone <jistone@redhat.com> - 1.20.0-1
|
* Thu Aug 31 2017 Josh Stone <jistone@redhat.com> - 1.20.0-1
|
||||||
- Update to 1.20.0.
|
- Update to 1.20.0.
|
||||||
- Add a rust-src subpackage.
|
- Add a rust-src subpackage.
|
||||||
|
Loading…
Reference in New Issue
Block a user