about summary refs log tree commit diff
diff options
context:
space:
mode:
-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