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_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 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()); + // 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 linkage = llvm::LLVMRustGetLinkage(g); - let visibility = llvm::LLVMRustGetVisibility(g); + let attrs = &self.tcx.codegen_fn_attrs(def_id); + let g = check_and_apply_linkage(&self, &attrs, ty, sym, None); - let new_g = llvm::LLVMRustGetOrInsertGlobal( - cx.llmod, name_string.as_ptr(), val_llty); + // 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); + } - llvm::LLVMRustSetLinkage(new_g, linkage); - llvm::LLVMRustSetVisibility(new_g, visibility); + 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(); - // 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 + // 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); + &self.instances.borrow_mut().insert(instance, g); + g + } - if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { - llvm::set_thread_local_mode(g, cx.tls_model); + fn codegen_static( + &self, + def_id: DefId, + is_mutable: bool, + ) { + unsafe { + let attrs = &self.tcx.codegen_fn_attrs(def_id); - // 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()); + 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); - // 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, - ); + 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()); + } } - } 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); + + // 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); + } + + 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 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 or the MIT license +// , 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 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 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 callee; use builder::{Builder, MemFlags}; use common::{self, IntPredicate}; -use consts; use meth; use monomorphize; use type_of::LayoutLlvmExt; @@ -28,6 +27,7 @@ use interfaces::{ BuilderMethods, ConstMethods, BaseTypeMethods, DerivedTypeMethods, DerivedIntrinsicMethods, + StaticMethods, }; use syntax::symbol::Symbol; @@ -380,10 +380,11 @@ fn codegen_terminator(&mut self, 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 @@ fn codegen_terminator(&mut self, &[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 @@ fn codegen_terminator(&mut self, &[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::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 base; use builder::Builder; use common::{CodegenCx, IntPredicate}; -use consts; use type_of::LayoutLlvmExt; use value::Value; use glue; @@ -24,6 +23,7 @@ use interfaces::{ BuilderMethods, ConstMethods, BaseTypeMethods, DerivedTypeMethods, DerivedIntrinsicMethods, + StaticMethods, }; use super::{FunctionCx, LocalRef}; @@ -66,14 +66,14 @@ pub fn from_const_alloc( 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 @@ pub fn codegen_place(&mut self, } 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 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::ty::TypeFoldable; use rustc::ty::layout::LayoutOf; use std::fmt; +use interfaces::StaticMethods; pub use rustc::mir::mono::MonoItem; @@ -54,7 +54,7 @@ fn define(&self, cx: &CodegenCx<'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);