about summary refs log tree commit diff
path: root/src/librustc_codegen_llvm
diff options
context:
space:
mode:
authorDenis Merigoux <denis.merigoux@gmail.com>2018-09-10 16:28:47 +0200
committerEduard-Mihai Burtescu <edy.burt@gmail.com>2018-11-16 14:11:59 +0200
commit3c082a23e838a4a852eefdaa9da61fd3dfe1e2d0 (patch)
treec56c08b3f0c17d474d39882a3cdac849af087dbf /src/librustc_codegen_llvm
parentd77e34f35ba276b514459b1669818605c9fbf416 (diff)
downloadrust-3c082a23e838a4a852eefdaa9da61fd3dfe1e2d0.tar.gz
rust-3c082a23e838a4a852eefdaa9da61fd3dfe1e2d0.zip
Added StaticMethods trait
Diffstat (limited to 'src/librustc_codegen_llvm')
-rw-r--r--src/librustc_codegen_llvm/consts.rs624
-rw-r--r--src/librustc_codegen_llvm/interfaces/mod.rs2
-rw-r--r--src/librustc_codegen_llvm/interfaces/statics.rs36
-rw-r--r--src/librustc_codegen_llvm/intrinsic.rs3
-rw-r--r--src/librustc_codegen_llvm/meth.rs5
-rw-r--r--src/librustc_codegen_llvm/mir/block.rs29
-rw-r--r--src/librustc_codegen_llvm/mir/constant.rs15
-rw-r--r--src/librustc_codegen_llvm/mir/place.rs10
-rw-r--r--src/librustc_codegen_llvm/mir/rvalue.rs5
-rw-r--r--src/librustc_codegen_llvm/mono_item.rs4
10 files changed, 390 insertions, 343 deletions
diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs
index d36b790761c..83036e65ba3 100644
--- a/src/librustc_codegen_llvm/consts.rs
+++ b/src/librustc_codegen_llvm/consts.rs
@@ -24,7 +24,7 @@ use type_::Type;
 use type_of::LayoutLlvmExt;
 use value::Value;
 use rustc::ty::{self, Ty};
-use interfaces::{BaseTypeMethods, DerivedTypeMethods};
+use interfaces::{BaseTypeMethods, DerivedTypeMethods, StaticMethods};
 
 use rustc::ty::layout::{Align, LayoutOf};
 
@@ -32,17 +32,6 @@ use rustc::hir::{self, CodegenFnAttrs, CodegenFnAttrFlags};
 
 use std::ffi::{CStr, CString};
 
-pub fn ptrcast(val: &'ll Value, ty: &'ll Type) -> &'ll Value {
-    unsafe {
-        llvm::LLVMConstPointerCast(val, ty)
-    }
-}
-
-pub fn bitcast(val: &'ll Value, ty: &'ll Type) -> &'ll Value {
-    unsafe {
-        llvm::LLVMConstBitCast(val, ty)
-    }
-}
 
 fn set_global_alignment(cx: &CodegenCx<'ll, '_>,
                         gv: &'ll Value,
@@ -63,178 +52,6 @@ fn set_global_alignment(cx: &CodegenCx<'ll, '_>,
     }
 }
 
-pub fn addr_of_mut(
-    cx: &CodegenCx<'ll, '_>,
-    cv: &'ll Value,
-    align: Align,
-    kind: Option<&str>,
-) -> &'ll Value {
-    unsafe {
-        let gv = match kind {
-            Some(kind) if !cx.tcx.sess.fewer_names() => {
-                let name = cx.generate_local_symbol_name(kind);
-                let gv = declare::define_global(cx, &name[..],
-                    cx.val_ty(cv)).unwrap_or_else(||{
-                        bug!("symbol `{}` is already defined", name);
-                });
-                llvm::LLVMRustSetLinkage(gv, llvm::Linkage::PrivateLinkage);
-                gv
-            },
-            _ => declare::define_private_global(cx, cx.val_ty(cv)),
-        };
-        llvm::LLVMSetInitializer(gv, cv);
-        set_global_alignment(cx, gv, align);
-        SetUnnamedAddr(gv, true);
-        gv
-    }
-}
-
-pub fn addr_of(
-    cx: &CodegenCx<'ll, '_>,
-    cv: &'ll Value,
-    align: Align,
-    kind: Option<&str>,
-) -> &'ll Value {
-    if let Some(&gv) = cx.const_globals.borrow().get(&cv) {
-        unsafe {
-            // Upgrade the alignment in cases where the same constant is used with different
-            // alignment requirements
-            let llalign = align.abi() as u32;
-            if llalign > llvm::LLVMGetAlignment(gv) {
-                llvm::LLVMSetAlignment(gv, llalign);
-            }
-        }
-        return gv;
-    }
-    let gv = addr_of_mut(cx, cv, align, kind);
-    unsafe {
-        llvm::LLVMSetGlobalConstant(gv, True);
-    }
-    cx.const_globals.borrow_mut().insert(cv, gv);
-    gv
-}
-
-pub fn get_static(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll Value {
-    let instance = Instance::mono(cx.tcx, def_id);
-    if let Some(&g) = cx.instances.borrow().get(&instance) {
-        return g;
-    }
-
-    let defined_in_current_codegen_unit = cx.codegen_unit
-                                            .items()
-                                            .contains_key(&MonoItem::Static(def_id));
-    assert!(!defined_in_current_codegen_unit,
-            "consts::get_static() should always hit the cache for \
-             statics defined in the same CGU, but did not for `{:?}`",
-            def_id);
-
-    let ty = instance.ty(cx.tcx);
-    let sym = cx.tcx.symbol_name(instance).as_str();
-
-    debug!("get_static: sym={} instance={:?}", sym, instance);
-
-    let g = if let Some(id) = cx.tcx.hir.as_local_node_id(def_id) {
-
-        let llty = cx.layout_of(ty).llvm_type(cx);
-        let (g, attrs) = match cx.tcx.hir.get(id) {
-            Node::Item(&hir::Item {
-                ref attrs, span, node: hir::ItemKind::Static(..), ..
-            }) => {
-                if declare::get_declared_value(cx, &sym[..]).is_some() {
-                    span_bug!(span, "Conflicting symbol names for static?");
-                }
-
-                let g = declare::define_global(cx, &sym[..], llty).unwrap();
-
-                if !cx.tcx.is_reachable_non_generic(def_id) {
-                    unsafe {
-                        llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden);
-                    }
-                }
-
-                (g, attrs)
-            }
-
-            Node::ForeignItem(&hir::ForeignItem {
-                ref attrs, span, node: hir::ForeignItemKind::Static(..), ..
-            }) => {
-                let fn_attrs = cx.tcx.codegen_fn_attrs(def_id);
-                (check_and_apply_linkage(cx, &fn_attrs, ty, sym, Some(span)), attrs)
-            }
-
-            item => bug!("get_static: expected static, found {:?}", item)
-        };
-
-        debug!("get_static: sym={} attrs={:?}", sym, attrs);
-
-        for attr in attrs {
-            if attr.check_name("thread_local") {
-                llvm::set_thread_local_mode(g, cx.tls_model);
-            }
-        }
-
-        g
-    } else {
-        // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
-        debug!("get_static: sym={} item_attr={:?}", sym, cx.tcx.item_attrs(def_id));
-
-        let attrs = cx.tcx.codegen_fn_attrs(def_id);
-        let g = check_and_apply_linkage(cx, &attrs, ty, sym, None);
-
-        // Thread-local statics in some other crate need to *always* be linked
-        // against in a thread-local fashion, so we need to be sure to apply the
-        // thread-local attribute locally if it was present remotely. If we
-        // don't do this then linker errors can be generated where the linker
-        // complains that one object files has a thread local version of the
-        // symbol and another one doesn't.
-        if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
-            llvm::set_thread_local_mode(g, cx.tls_model);
-        }
-
-        let needs_dll_storage_attr =
-            cx.use_dll_storage_attrs && !cx.tcx.is_foreign_item(def_id) &&
-            // ThinLTO can't handle this workaround in all cases, so we don't
-            // emit the attrs. Instead we make them unnecessary by disallowing
-            // dynamic linking when cross-language LTO is enabled.
-            !cx.tcx.sess.opts.debugging_opts.cross_lang_lto.enabled();
-
-        // If this assertion triggers, there's something wrong with commandline
-        // argument validation.
-        debug_assert!(!(cx.tcx.sess.opts.debugging_opts.cross_lang_lto.enabled() &&
-                        cx.tcx.sess.target.target.options.is_like_msvc &&
-                        cx.tcx.sess.opts.cg.prefer_dynamic));
-
-        if needs_dll_storage_attr {
-            // This item is external but not foreign, i.e. it originates from an external Rust
-            // crate. Since we don't know whether this crate will be linked dynamically or
-            // statically in the final application, we always mark such symbols as 'dllimport'.
-            // If final linkage happens to be static, we rely on compiler-emitted __imp_ stubs to
-            // make things work.
-            //
-            // However, in some scenarios we defer emission of statics to downstream
-            // crates, so there are cases where a static with an upstream DefId
-            // is actually present in the current crate. We can find out via the
-            // is_codegened_item query.
-            if !cx.tcx.is_codegened_item(def_id) {
-                unsafe {
-                    llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport);
-                }
-            }
-        }
-        g
-    };
-
-    if cx.use_dll_storage_attrs && cx.tcx.is_dllimport_foreign_item(def_id) {
-        // For foreign (native) libs we know the exact storage type to use.
-        unsafe {
-            llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport);
-        }
-    }
-
-    cx.instances.borrow_mut().insert(instance, g);
-    g
-}
-
 fn check_and_apply_linkage(
     cx: &CodegenCx<'ll, 'tcx>,
     attrs: &CodegenFnAttrs,
@@ -294,146 +111,337 @@ fn check_and_apply_linkage(
     }
 }
 
-pub fn codegen_static<'a, 'tcx>(
-    cx: &CodegenCx<'a, 'tcx>,
-    def_id: DefId,
-    is_mutable: bool,
-) {
+pub fn ptrcast(val: &'ll Value, ty: &'ll Type) -> &'ll Value {
     unsafe {
-        let attrs = cx.tcx.codegen_fn_attrs(def_id);
+        llvm::LLVMConstPointerCast(val, ty)
+    }
+}
 
-        let (v, alloc) = match ::mir::codegen_static_initializer(cx, def_id) {
-            Ok(v) => v,
-            // Error has already been reported
-            Err(_) => return,
-        };
+impl StaticMethods<'tcx> for CodegenCx<'ll, 'tcx> {
 
-        let g = get_static(cx, def_id);
+    fn static_ptrcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value {
+        ptrcast(val, ty)
+    }
 
-        // boolean SSA values are i1, but they have to be stored in i8 slots,
-        // otherwise some LLVM optimization passes don't work as expected
-        let mut val_llty = cx.val_ty(v);
-        let v = if val_llty == cx.type_i1() {
-            val_llty = cx.type_i8();
-            llvm::LLVMConstZExt(v, val_llty)
-        } else {
-            v
-        };
+    fn static_bitcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value {
+        unsafe {
+            llvm::LLVMConstBitCast(val, ty)
+        }
+    }
+
+    fn static_addr_of_mut(
+        &self,
+        cv: &'ll Value,
+        align: Align,
+        kind: Option<&str>,
+    ) -> &'ll Value {
+        unsafe {
+            let gv = match kind {
+                Some(kind) if !&self.tcx.sess.fewer_names() => {
+                    let name = &self.generate_local_symbol_name(kind);
+                    let gv = declare::define_global(&self, &name[..],
+                        &self.val_ty(cv)).unwrap_or_else(||{
+                            bug!("symbol `{}` is already defined", name);
+                    });
+                    llvm::LLVMRustSetLinkage(gv, llvm::Linkage::PrivateLinkage);
+                    gv
+                },
+                _ => declare::define_private_global(&self, &self.val_ty(cv)),
+            };
+            llvm::LLVMSetInitializer(gv, cv);
+            set_global_alignment(&self, gv, align);
+            SetUnnamedAddr(gv, true);
+            gv
+        }
+    }
+
+    fn static_addr_of(
+        &self,
+        cv: &'ll Value,
+        align: Align,
+        kind: Option<&str>,
+    ) -> &'ll Value {
+        if let Some(&gv) = &self.const_globals.borrow().get(&cv) {
+            unsafe {
+                // Upgrade the alignment in cases where the same constant is used with different
+                // alignment requirements
+                let llalign = align.abi() as u32;
+                if llalign > llvm::LLVMGetAlignment(gv) {
+                    llvm::LLVMSetAlignment(gv, llalign);
+                }
+            }
+            return gv;
+        }
+        let gv = &self.static_addr_of_mut(cv, align, kind);
+        unsafe {
+            llvm::LLVMSetGlobalConstant(gv, True);
+        }
+        &self.const_globals.borrow_mut().insert(cv, gv);
+        gv
+    }
+
+    fn get_static(&self, def_id: DefId) -> &'ll Value {
+        let instance = Instance::mono(self.tcx, def_id);
+        if let Some(&g) = &self.instances.borrow().get(&instance) {
+            return g;
+        }
+
+        let defined_in_current_codegen_unit = &self.codegen_unit
+                                                .items()
+                                                .contains_key(&MonoItem::Static(def_id));
+        assert!(!defined_in_current_codegen_unit,
+                "consts::get_static() should always hit the cache for \
+                 statics defined in the same CGU, but did not for `{:?}`",
+                 def_id);
+
+        let ty = instance.ty(self.tcx);
+        let sym = self.tcx.symbol_name(instance).as_str();
+
+        debug!("get_static: sym={} instance={:?}", sym, instance);
+
+        let g = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
+
+            let llty = &self.layout_of(ty).llvm_type(&self);
+            let (g, attrs) = match &self.tcx.hir.get(id) {
+                Node::Item(&hir::Item {
+                    ref attrs, span, node: hir::ItemKind::Static(..), ..
+                }) => {
+                    if declare::get_declared_value(&self, &sym[..]).is_some() {
+                        span_bug!(span, "Conflicting symbol names for static?");
+                    }
+
+                    let g = declare::define_global(&self, &sym[..], llty).unwrap();
+
+                    if !&self.tcx.is_reachable_non_generic(def_id) {
+                        unsafe {
+                            llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden);
+                        }
+                    }
+
+                    (g, attrs)
+                }
+
+                Node::ForeignItem(&hir::ForeignItem {
+                    ref attrs, span, node: hir::ForeignItemKind::Static(..), ..
+                }) => {
+                    let fn_attrs = &self.tcx.codegen_fn_attrs(def_id);
+                    (check_and_apply_linkage(&self, &fn_attrs, ty, sym, Some(span)), attrs)
+                }
+
+                item => bug!("get_static: expected static, found {:?}", item)
+            };
+
+            debug!("get_static: sym={} attrs={:?}", sym, attrs);
+
+            for attr in attrs {
+                if attr.check_name("thread_local") {
+                    llvm::set_thread_local_mode(g, self.tls_model);
+                }
+            }
 
-        let instance = Instance::mono(cx.tcx, def_id);
-        let ty = instance.ty(cx.tcx);
-        let llty = cx.layout_of(ty).llvm_type(cx);
-        let g = if val_llty == llty {
             g
         } else {
-            // If we created the global with the wrong type,
-            // correct the type.
-            let empty_string = const_cstr!("");
-            let name_str_ref = CStr::from_ptr(llvm::LLVMGetValueName(g));
-            let name_string = CString::new(name_str_ref.to_bytes()).unwrap();
-            llvm::LLVMSetValueName(g, empty_string.as_ptr());
-
-            let linkage = llvm::LLVMRustGetLinkage(g);
-            let visibility = llvm::LLVMRustGetVisibility(g);
-
-            let new_g = llvm::LLVMRustGetOrInsertGlobal(
-                cx.llmod, name_string.as_ptr(), val_llty);
-
-            llvm::LLVMRustSetLinkage(new_g, linkage);
-            llvm::LLVMRustSetVisibility(new_g, visibility);
-
-            // To avoid breaking any invariants, we leave around the old
-            // global for the moment; we'll replace all references to it
-            // with the new global later. (See base::codegen_backend.)
-            cx.statics_to_rauw.borrow_mut().push((g, new_g));
-            new_g
+            // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
+            debug!("get_static: sym={} item_attr={:?}", sym, &self.tcx.item_attrs(def_id));
+
+            let attrs = &self.tcx.codegen_fn_attrs(def_id);
+            let g = check_and_apply_linkage(&self, &attrs, ty, sym, None);
+
+            // Thread-local statics in some other crate need to *always* be linked
+            // against in a thread-local fashion, so we need to be sure to apply the
+            // thread-local attribute locally if it was present remotely. If we
+            // don't do this then linker errors can be generated where the linker
+            // complains that one object files has a thread local version of the
+            // symbol and another one doesn't.
+            if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
+                llvm::set_thread_local_mode(g, self.tls_model);
+            }
+
+            let needs_dll_storage_attr =
+                self.use_dll_storage_attrs && !&self.tcx.is_foreign_item(def_id) &&
+                // ThinLTO can't handle this workaround in all cases, so we don't
+                // emit the attrs. Instead we make them unnecessary by disallowing
+                // dynamic linking when cross-language LTO is enabled.
+                !&self.tcx.sess.opts.debugging_opts.cross_lang_lto.enabled();
+
+            // If this assertion triggers, there's something wrong with commandline
+            // argument validation.
+            debug_assert!(!(self.tcx.sess.opts.debugging_opts.cross_lang_lto.enabled() &&
+                            self.tcx.sess.target.target.options.is_like_msvc &&
+                            self.tcx.sess.opts.cg.prefer_dynamic));
+
+            if needs_dll_storage_attr {
+                // This item is external but not foreign, i.e. it originates from an external Rust
+                // crate. Since we don't know whether this crate will be linked dynamically or
+                // statically in the final application, we always mark such symbols as 'dllimport'.
+                // If final linkage happens to be static, we rely on compiler-emitted __imp_ stubs
+                // to make things work.
+                //
+                // However, in some scenarios we defer emission of statics to downstream
+                // crates, so there are cases where a static with an upstream DefId
+                // is actually present in the current crate. We can find out via the
+                // is_codegened_item query.
+                if !&self.tcx.is_codegened_item(def_id) {
+                    unsafe {
+                        llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport);
+                    }
+                }
+            }
+            g
         };
-        set_global_alignment(cx, g, cx.align_of(ty));
-        llvm::LLVMSetInitializer(g, v);
-
-        // As an optimization, all shared statics which do not have interior
-        // mutability are placed into read-only memory.
-        if !is_mutable {
-            if cx.type_is_freeze(ty) {
-                llvm::LLVMSetGlobalConstant(g, llvm::True);
+
+        if self.use_dll_storage_attrs && self.tcx.is_dllimport_foreign_item(def_id) {
+            // For foreign (native) libs we know the exact storage type to use.
+            unsafe {
+                llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport);
             }
         }
 
-        debuginfo::create_global_var_metadata(cx, def_id, g);
-
-        if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
-            llvm::set_thread_local_mode(g, cx.tls_model);
-
-            // Do not allow LLVM to change the alignment of a TLS on macOS.
-            //
-            // By default a global's alignment can be freely increased.
-            // This allows LLVM to generate more performant instructions
-            // e.g. using load-aligned into a SIMD register.
-            //
-            // However, on macOS 10.10 or below, the dynamic linker does not
-            // respect any alignment given on the TLS (radar 24221680).
-            // This will violate the alignment assumption, and causing segfault at runtime.
-            //
-            // This bug is very easy to trigger. In `println!` and `panic!`,
-            // the `LOCAL_STDOUT`/`LOCAL_STDERR` handles are stored in a TLS,
-            // which the values would be `mem::replace`d on initialization.
-            // The implementation of `mem::replace` will use SIMD
-            // whenever the size is 32 bytes or higher. LLVM notices SIMD is used
-            // and tries to align `LOCAL_STDOUT`/`LOCAL_STDERR` to a 32-byte boundary,
-            // which macOS's dyld disregarded and causing crashes
-            // (see issues #51794, #51758, #50867, #48866 and #44056).
-            //
-            // To workaround the bug, we trick LLVM into not increasing
-            // the global's alignment by explicitly assigning a section to it
-            // (equivalent to automatically generating a `#[link_section]` attribute).
-            // See the comment in the `GlobalValue::canIncreaseAlignment()` function
-            // of `lib/IR/Globals.cpp` for why this works.
-            //
-            // When the alignment is not increased, the optimized `mem::replace`
-            // will use load-unaligned instructions instead, and thus avoiding the crash.
-            //
-            // We could remove this hack whenever we decide to drop macOS 10.10 support.
-            if cx.tcx.sess.target.target.options.is_like_osx {
-                let sect_name = if alloc.bytes.iter().all(|b| *b == 0) {
-                    CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_bss\0")
-                } else {
-                    CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_data\0")
-                };
-                llvm::LLVMSetSection(g, sect_name.as_ptr());
+        &self.instances.borrow_mut().insert(instance, g);
+        g
+    }
+
+    fn codegen_static(
+        &self,
+        def_id: DefId,
+        is_mutable: bool,
+    ) {
+        unsafe {
+            let attrs = &self.tcx.codegen_fn_attrs(def_id);
+
+            let (v, alloc) = match ::mir::codegen_static_initializer(&self, def_id) {
+                Ok(v) => v,
+                // Error has already been reported
+                Err(_) => return,
+            };
+
+            let g = &self.get_static(def_id);
+
+            // boolean SSA values are i1, but they have to be stored in i8 slots,
+            // otherwise some LLVM optimization passes don't work as expected
+            let mut val_llty = self.val_ty(v);
+            let v = if val_llty == self.type_i1() {
+                val_llty = self.type_i8();
+                llvm::LLVMConstZExt(v, val_llty)
+            } else {
+                v
+            };
+
+            let instance = Instance::mono(self.tcx, def_id);
+            let ty = instance.ty(self.tcx);
+            let llty = self.layout_of(ty).llvm_type(&self);
+            let g = if val_llty == llty {
+                g
+            } else {
+                // If we created the global with the wrong type,
+                // correct the type.
+                let empty_string = const_cstr!("");
+                let name_str_ref = CStr::from_ptr(llvm::LLVMGetValueName(g));
+                let name_string = CString::new(name_str_ref.to_bytes()).unwrap();
+                llvm::LLVMSetValueName(g, empty_string.as_ptr());
+
+                let linkage = llvm::LLVMRustGetLinkage(g);
+                let visibility = llvm::LLVMRustGetVisibility(g);
+
+                let new_g = llvm::LLVMRustGetOrInsertGlobal(
+                    &self.llmod, name_string.as_ptr(), val_llty);
+
+                llvm::LLVMRustSetLinkage(new_g, linkage);
+                llvm::LLVMRustSetVisibility(new_g, visibility);
+
+                // To avoid breaking any invariants, we leave around the old
+                // global for the moment; we'll replace all references to it
+                // with the new global later. (See base::codegen_backend.)
+                &self.statics_to_rauw.borrow_mut().push((g, new_g));
+                new_g
+            };
+            set_global_alignment(&self, g, self.align_of(ty));
+            llvm::LLVMSetInitializer(g, v);
+
+            // As an optimization, all shared statics which do not have interior
+            // mutability are placed into read-only memory.
+            if !is_mutable {
+                if self.type_is_freeze(ty) {
+                    llvm::LLVMSetGlobalConstant(g, llvm::True);
+                }
             }
-        }
 
+            debuginfo::create_global_var_metadata(&self, def_id, g);
+
+            if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
+                llvm::set_thread_local_mode(g, self.tls_model);
+
+                // Do not allow LLVM to change the alignment of a TLS on macOS.
+                //
+                // By default a global's alignment can be freely increased.
+                // This allows LLVM to generate more performant instructions
+                // e.g. using load-aligned into a SIMD register.
+                //
+                // However, on macOS 10.10 or below, the dynamic linker does not
+                // respect any alignment given on the TLS (radar 24221680).
+                // This will violate the alignment assumption, and causing segfault at runtime.
+                //
+                // This bug is very easy to trigger. In `println!` and `panic!`,
+                // the `LOCAL_STDOUT`/`LOCAL_STDERR` handles are stored in a TLS,
+                // which the values would be `mem::replace`d on initialization.
+                // The implementation of `mem::replace` will use SIMD
+                // whenever the size is 32 bytes or higher. LLVM notices SIMD is used
+                // and tries to align `LOCAL_STDOUT`/`LOCAL_STDERR` to a 32-byte boundary,
+                // which macOS's dyld disregarded and causing crashes
+                // (see issues #51794, #51758, #50867, #48866 and #44056).
+                //
+                // To workaround the bug, we trick LLVM into not increasing
+                // the global's alignment by explicitly assigning a section to it
+                // (equivalent to automatically generating a `#[link_section]` attribute).
+                // See the comment in the `GlobalValue::canIncreaseAlignment()` function
+                // of `lib/IR/Globals.cpp` for why this works.
+                //
+                // When the alignment is not increased, the optimized `mem::replace`
+                // will use load-unaligned instructions instead, and thus avoiding the crash.
+                //
+                // We could remove this hack whenever we decide to drop macOS 10.10 support.
+                if self.tcx.sess.target.target.options.is_like_osx {
+                    let sect_name = if alloc.bytes.iter().all(|b| *b == 0) {
+                        CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_bss\0")
+                    } else {
+                        CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_data\0")
+                    };
+                    llvm::LLVMSetSection(g, sect_name.as_ptr());
+                }
+            }
 
-        // Wasm statics with custom link sections get special treatment as they
-        // go into custom sections of the wasm executable.
-        if cx.tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
-            if let Some(section) = attrs.link_section {
-                let section = llvm::LLVMMDStringInContext(
-                    cx.llcx,
-                    section.as_str().as_ptr() as *const _,
-                    section.as_str().len() as c_uint,
-                );
-                let alloc = llvm::LLVMMDStringInContext(
-                    cx.llcx,
-                    alloc.bytes.as_ptr() as *const _,
-                    alloc.bytes.len() as c_uint,
-                );
-                let data = [section, alloc];
-                let meta = llvm::LLVMMDNodeInContext(cx.llcx, data.as_ptr(), 2);
-                llvm::LLVMAddNamedMetadataOperand(
-                    cx.llmod,
-                    "wasm.custom_sections\0".as_ptr() as *const _,
-                    meta,
-                );
+
+            // Wasm statics with custom link sections get special treatment as they
+            // go into custom sections of the wasm executable.
+            if self.tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
+                if let Some(section) = attrs.link_section {
+                    let section = llvm::LLVMMDStringInContext(
+                        &self.llcx,
+                        section.as_str().as_ptr() as *const _,
+                        section.as_str().len() as c_uint,
+                    );
+                    let alloc = llvm::LLVMMDStringInContext(
+                        &self.llcx,
+                        alloc.bytes.as_ptr() as *const _,
+                        alloc.bytes.len() as c_uint,
+                    );
+                    let data = [section, alloc];
+                    let meta = llvm::LLVMMDNodeInContext(&self.llcx, data.as_ptr(), 2);
+                    llvm::LLVMAddNamedMetadataOperand(
+                        &self.llmod,
+                        "wasm.custom_sections\0".as_ptr() as *const _,
+                        meta,
+                    );
+                }
+            } else {
+                base::set_link_section(g, &attrs);
             }
-        } else {
-            base::set_link_section(g, &attrs);
-        }
 
-        if attrs.flags.contains(CodegenFnAttrFlags::USED) {
-            // This static will be stored in the llvm.used variable which is an array of i8*
-            let cast = llvm::LLVMConstPointerCast(g, cx.type_i8p());
-            cx.used_statics.borrow_mut().push(cast);
+            if attrs.flags.contains(CodegenFnAttrFlags::USED) {
+                // This static will be stored in the llvm.used variable which is an array of i8*
+                let cast = llvm::LLVMConstPointerCast(g, &self.type_i8p());
+                &self.used_statics.borrow_mut().push(cast);
+            }
         }
     }
 }
diff --git a/src/librustc_codegen_llvm/interfaces/mod.rs b/src/librustc_codegen_llvm/interfaces/mod.rs
index def4b49f27d..24cae1e941e 100644
--- a/src/librustc_codegen_llvm/interfaces/mod.rs
+++ b/src/librustc_codegen_llvm/interfaces/mod.rs
@@ -13,9 +13,11 @@ mod backend;
 mod consts;
 mod type_;
 mod intrinsic;
+mod statics;
 
 pub use self::builder::BuilderMethods;
 pub use self::backend::Backend;
 pub use self::consts::ConstMethods;
 pub use self::type_::{TypeMethods, BaseTypeMethods, DerivedTypeMethods};
 pub use self::intrinsic::{IntrinsicMethods, BaseIntrinsicMethods, DerivedIntrinsicMethods};
+pub use self::statics::StaticMethods;
diff --git a/src/librustc_codegen_llvm/interfaces/statics.rs b/src/librustc_codegen_llvm/interfaces/statics.rs
new file mode 100644
index 00000000000..109ef91dcfa
--- /dev/null
+++ b/src/librustc_codegen_llvm/interfaces/statics.rs
@@ -0,0 +1,36 @@
+// Copyright 2018 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.
+
+use rustc::ty::layout::Align;
+use rustc::hir::def_id::DefId;
+use super::backend::Backend;
+
+pub trait StaticMethods<'tcx>: Backend {
+    fn static_ptrcast(&self, val: Self::Value, ty: Self::Type) -> Self::Value;
+    fn static_bitcast(&self, val: Self::Value, ty: Self::Type) -> Self::Value;
+    fn static_addr_of_mut(
+        &self,
+        cv: Self::Value,
+        align: Align,
+        kind: Option<&str>,
+    ) -> Self::Value;
+    fn static_addr_of(
+        &self,
+        cv: Self::Value,
+        align: Align,
+        kind: Option<&str>,
+    ) -> Self::Value;
+    fn get_static(&self, def_id: DefId) -> Self::Value;
+    fn codegen_static(
+        &self,
+        def_id: DefId,
+        is_mutable: bool,
+    );
+}
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index b1709f96d10..af433d2ba78 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -34,6 +34,7 @@ use value::Value;
 
 use interfaces::{
     BuilderMethods, ConstMethods, BaseTypeMethods, DerivedTypeMethods, DerivedIntrinsicMethods,
+    StaticMethods,
 };
 
 use rustc::session::Session;
@@ -853,7 +854,7 @@ fn codegen_msvc_try(
 
         let tcx = cx.tcx;
         let tydesc = match tcx.lang_items().msvc_try_filter() {
-            Some(did) => ::consts::get_static(cx, did),
+            Some(did) => cx.get_static(did),
             None => bug!("msvc_try_filter not defined"),
         };
         let tok = catchpad.catch_pad(cs, &[tydesc, cx.const_i32(0), slot]);
diff --git a/src/librustc_codegen_llvm/meth.rs b/src/librustc_codegen_llvm/meth.rs
index 466f8b8ac52..2eed9273cad 100644
--- a/src/librustc_codegen_llvm/meth.rs
+++ b/src/librustc_codegen_llvm/meth.rs
@@ -12,11 +12,10 @@ use abi::{FnType, FnTypeExt};
 use callee;
 use context::CodegenCx;
 use builder::Builder;
-use consts;
 use monomorphize;
 use value::Value;
 
-use interfaces::{BuilderMethods, ConstMethods, BaseTypeMethods, DerivedTypeMethods};
+use interfaces::{BuilderMethods, ConstMethods, BaseTypeMethods, DerivedTypeMethods, StaticMethods};
 
 use rustc::ty::{self, Ty};
 use rustc::ty::layout::HasDataLayout;
@@ -120,7 +119,7 @@ pub fn get_vtable(
 
     let vtable_const = cx.const_struct(&components, false);
     let align = cx.data_layout().pointer_align;
-    let vtable = consts::addr_of(cx, vtable_const, align, Some("vtable"));
+    let vtable = cx.static_addr_of(vtable_const, align, Some("vtable"));
 
     debuginfo::create_vtable_metadata(cx, ty, vtable);
 
diff --git a/src/librustc_codegen_llvm/mir/block.rs b/src/librustc_codegen_llvm/mir/block.rs
index 0fd1e28d5a6..c5e3ad54ef3 100644
--- a/src/librustc_codegen_llvm/mir/block.rs
+++ b/src/librustc_codegen_llvm/mir/block.rs
@@ -19,7 +19,6 @@ use base;
 use callee;
 use builder::{Builder, MemFlags};
 use common::{self, IntPredicate};
-use consts;
 use meth;
 use monomorphize;
 use type_of::LayoutLlvmExt;
@@ -28,6 +27,7 @@ use value::Value;
 
 use interfaces::{
     BuilderMethods, ConstMethods, BaseTypeMethods, DerivedTypeMethods, DerivedIntrinsicMethods,
+    StaticMethods,
 };
 
 use syntax::symbol::Symbol;
@@ -380,10 +380,11 @@ impl FunctionCx<'a, 'll, 'tcx, &'ll Value> {
                         let index = self.codegen_operand(&mut bx, index).immediate();
 
                         let file_line_col = bx.cx().const_struct(&[filename, line, col], false);
-                        let file_line_col = consts::addr_of(bx.cx(),
-                                                            file_line_col,
-                                                            align,
-                                                            Some("panic_bounds_check_loc"));
+                        let file_line_col = bx.cx().static_addr_of(
+                            file_line_col,
+                            align,
+                            Some("panic_bounds_check_loc")
+                        );
                         (lang_items::PanicBoundsCheckFnLangItem,
                          vec![file_line_col, index, len])
                     }
@@ -395,10 +396,11 @@ impl FunctionCx<'a, 'll, 'tcx, &'ll Value> {
                             &[msg_str, filename, line, col],
                             false
                         );
-                        let msg_file_line_col = consts::addr_of(bx.cx(),
-                                                                msg_file_line_col,
-                                                                align,
-                                                                Some("panic_loc"));
+                        let msg_file_line_col = bx.cx().static_addr_of(
+                            msg_file_line_col,
+                            align,
+                            Some("panic_loc")
+                        );
                         (lang_items::PanicFnLangItem,
                          vec![msg_file_line_col])
                     }
@@ -518,10 +520,11 @@ impl FunctionCx<'a, 'll, 'tcx, &'ll Value> {
                         &[msg_str, filename, line, col],
                         false,
                     );
-                    let msg_file_line_col = consts::addr_of(bx.cx,
-                                                            msg_file_line_col,
-                                                            align,
-                                                            Some("panic_loc"));
+                    let msg_file_line_col = bx.cx.static_addr_of(
+                        msg_file_line_col,
+                        align,
+                        Some("panic_loc"),
+                    );
 
                     // Obtain the panic entry point.
                     let def_id =
diff --git a/src/librustc_codegen_llvm/mir/constant.rs b/src/librustc_codegen_llvm/mir/constant.rs
index d9be3fbfb2a..d448ca1735b 100644
--- a/src/librustc_codegen_llvm/mir/constant.rs
+++ b/src/librustc_codegen_llvm/mir/constant.rs
@@ -19,13 +19,12 @@ use rustc::ty::{self, Ty};
 use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Size};
 use builder::Builder;
 use common::{CodegenCx};
-use consts;
 use type_of::LayoutLlvmExt;
 use type_::Type;
 use syntax::ast::Mutability;
 use syntax::source_map::Span;
 use value::Value;
-use interfaces::{BuilderMethods, ConstMethods, BaseTypeMethods, DerivedTypeMethods};
+use interfaces::{BuilderMethods, ConstMethods, BaseTypeMethods, DerivedTypeMethods, StaticMethods};
 
 use super::super::callee;
 use super::FunctionCx;
@@ -48,7 +47,7 @@ pub fn scalar_to_llvm(
             if layout.value == layout::Pointer {
                 unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
             } else {
-                consts::bitcast(llval, llty)
+                cx.static_bitcast(llval, llty)
             }
         },
         Scalar::Ptr(ptr) => {
@@ -57,9 +56,9 @@ pub fn scalar_to_llvm(
                 Some(AllocType::Memory(alloc)) => {
                     let init = const_alloc_to_llvm(cx, alloc);
                     if alloc.mutability == Mutability::Mutable {
-                        consts::addr_of_mut(cx, init, alloc.align, None)
+                        cx.static_addr_of_mut(init, alloc.align, None)
                     } else {
-                        consts::addr_of(cx, init, alloc.align, None)
+                        cx.static_addr_of(init, alloc.align, None)
                     }
                 }
                 Some(AllocType::Function(fn_instance)) => {
@@ -67,19 +66,19 @@ pub fn scalar_to_llvm(
                 }
                 Some(AllocType::Static(def_id)) => {
                     assert!(cx.tcx.is_static(def_id).is_some());
-                    consts::get_static(cx, def_id)
+                    cx.get_static(def_id)
                 }
                 None => bug!("missing allocation {:?}", ptr.alloc_id),
             };
             let llval = unsafe { llvm::LLVMConstInBoundsGEP(
-                consts::bitcast(base_addr, cx.type_i8p()),
+                cx.static_bitcast(base_addr, cx.type_i8p()),
                 &cx.const_usize(ptr.offset.bytes()),
                 1,
             ) };
             if layout.value != layout::Pointer {
                 unsafe { llvm::LLVMConstPtrToInt(llval, llty) }
             } else {
-                consts::bitcast(llval, llty)
+                cx.static_bitcast(llval, llty)
             }
         }
     }
diff --git a/src/librustc_codegen_llvm/mir/place.rs b/src/librustc_codegen_llvm/mir/place.rs
index 1c119f6a0a3..f419be8fe3e 100644
--- a/src/librustc_codegen_llvm/mir/place.rs
+++ b/src/librustc_codegen_llvm/mir/place.rs
@@ -16,7 +16,6 @@ use rustc::mir::tcx::PlaceTy;
 use base;
 use builder::Builder;
 use common::{CodegenCx, IntPredicate};
-use consts;
 use type_of::LayoutLlvmExt;
 use value::Value;
 use glue;
@@ -24,6 +23,7 @@ use mir::constant::const_alloc_to_llvm;
 
 use interfaces::{
     BuilderMethods, ConstMethods, BaseTypeMethods, DerivedTypeMethods, DerivedIntrinsicMethods,
+    StaticMethods,
 };
 
 use super::{FunctionCx, LocalRef};
@@ -66,14 +66,14 @@ impl PlaceRef<'tcx, &'ll Value> {
         offset: Size,
     ) -> PlaceRef<'tcx, &'ll Value> {
         let init = const_alloc_to_llvm(bx.cx(), alloc);
-        let base_addr = consts::addr_of(bx.cx(), init, layout.align, None);
+        let base_addr = bx.cx().static_addr_of(init, layout.align, None);
 
         let llval = unsafe { LLVMConstInBoundsGEP(
-            consts::bitcast(base_addr, bx.cx().type_i8p()),
+            bx.cx().static_bitcast(base_addr, bx.cx().type_i8p()),
             &bx.cx().const_usize(offset.bytes()),
             1,
         )};
-        let llval = consts::bitcast(llval, bx.cx().type_ptr_to(layout.llvm_type(bx.cx())));
+        let llval = bx.cx().static_bitcast(llval, bx.cx().type_ptr_to(layout.llvm_type(bx.cx())));
         PlaceRef::new_sized(llval, layout, alloc.align)
     }
 
@@ -497,7 +497,7 @@ impl FunctionCx<'a, 'll, 'tcx, &'ll Value> {
             }
             mir::Place::Static(box mir::Static { def_id, ty }) => {
                 let layout = cx.layout_of(self.monomorphize(&ty));
-                PlaceRef::new_sized(consts::get_static(cx, def_id), layout, layout.align)
+                PlaceRef::new_sized(cx.get_static(def_id), layout, layout.align)
             },
             mir::Place::Projection(box mir::Projection {
                 ref base,
diff --git a/src/librustc_codegen_llvm/mir/rvalue.rs b/src/librustc_codegen_llvm/mir/rvalue.rs
index 56e3aa56e60..08d528ba921 100644
--- a/src/librustc_codegen_llvm/mir/rvalue.rs
+++ b/src/librustc_codegen_llvm/mir/rvalue.rs
@@ -20,7 +20,6 @@ use base;
 use builder::Builder;
 use callee;
 use common::{self, IntPredicate, RealPredicate};
-use consts;
 use monomorphize;
 use type_::Type;
 use type_of::LayoutLlvmExt;
@@ -841,7 +840,7 @@ fn cast_int_to_float(bx: &Builder<'_, 'll, '_>,
         let max = bx.cx().const_uint_big(int_ty, MAX_F32_PLUS_HALF_ULP);
         let overflow = bx.icmp(IntPredicate::IntUGE, x, max);
         let infinity_bits = bx.cx().const_u32(ieee::Single::INFINITY.to_bits() as u32);
-        let infinity = consts::bitcast(infinity_bits, float_ty);
+        let infinity = bx.bitcast(infinity_bits, float_ty);
         bx.select(overflow, infinity, bx.uitofp(x, float_ty))
     } else {
         if signed {
@@ -922,7 +921,7 @@ fn cast_float_to_int(bx: &Builder<'_, 'll, '_>,
             64 => bx.cx().const_u64(bits as u64),
             n => bug!("unsupported float width {}", n),
         };
-        consts::bitcast(bits_llval, float_ty)
+        bx.bitcast(bits_llval, float_ty)
     };
     let (f_min, f_max) = match bx.cx().float_width(float_ty) {
         32 => compute_clamp_bounds_single(signed, int_ty),
diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs
index 91c1ccbe002..c26cc4efd2c 100644
--- a/src/librustc_codegen_llvm/mono_item.rs
+++ b/src/librustc_codegen_llvm/mono_item.rs
@@ -17,7 +17,6 @@
 use asm;
 use attributes;
 use base;
-use consts;
 use context::CodegenCx;
 use declare;
 use llvm;
@@ -30,6 +29,7 @@ use rustc::mir::mono::{Linkage, Visibility};
 use rustc::ty::TypeFoldable;
 use rustc::ty::layout::LayoutOf;
 use std::fmt;
+use interfaces::StaticMethods;
 
 pub use rustc::mir::mono::MonoItem;
 
@@ -54,7 +54,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> {
                         bug!("Expected Def::Static for {:?}, found nothing", def_id)
                     }
                 };
-                consts::codegen_static(&cx, def_id, is_mutable);
+                cx.codegen_static(def_id, is_mutable);
             }
             MonoItem::GlobalAsm(node_id) => {
                 let item = cx.tcx.hir.expect_item(node_id);