about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorJosh Stone <jistone@redhat.com>2017-09-08 14:49:51 -0700
committerJosh Stone <jistone@redhat.com>2017-09-08 14:49:51 -0700
commit95a5a0ed16171cfab039c3b59f45a6e4a93075fa (patch)
treef860f3df7ee187b0d9ab738c7b0f3c128c1712dd /src
parentdead08cb331343b84564628b139b657f93548320 (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_back/target/mod.rs6
-rw-r--r--src/librustc_back/target/s390x_unknown_linux_gnu.rs1
-rw-r--r--src/librustc_trans/consts.rs24
3 files changed, 29 insertions, 2 deletions
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index 130e1b695db..301cf3f8c82 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -425,6 +425,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 {
@@ -486,6 +489,7 @@ impl Default for TargetOptions {
             crt_static_default: false,
             crt_static_respected: false,
             stack_probes: false,
+            min_global_align: None,
         }
     }
 }
@@ -724,6 +728,7 @@ impl Target {
         key!(crt_static_default, bool);
         key!(crt_static_respected, 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()) {
@@ -914,6 +919,7 @@ impl ToJson for Target {
         target_option_val!(crt_static_default);
         target_option_val!(crt_static_respected);
         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 78a6bb7933d..aad9effacd4 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 a30a15f75b3..bad8a8655d0 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;
@@ -42,6 +43,25 @@ pub fn bitcast(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,
@@ -53,7 +73,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
@@ -276,7 +296,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