initial implementation of the darwin_objc unstable feature
This commit is contained in:
@@ -109,18 +109,36 @@ pub(crate) fn compile_codegen_unit(
|
||||
attributes::apply_to_llfn(entry, llvm::AttributePlace::Function, &attrs);
|
||||
}
|
||||
|
||||
// Define Objective-C module info and module flags. Note, the module info will
|
||||
// also be added to the `llvm.compiler.used` variable, created later.
|
||||
//
|
||||
// These are only necessary when we need the linker to do its Objective-C-specific
|
||||
// magic. We could theoretically do it unconditionally, but at a slight cost to linker
|
||||
// performance in the common case where it's unnecessary.
|
||||
if !cx.objc_classrefs.borrow().is_empty() || !cx.objc_selrefs.borrow().is_empty() {
|
||||
if cx.objc_abi_version() == 1 {
|
||||
cx.define_objc_module_info();
|
||||
}
|
||||
cx.add_objc_module_flags();
|
||||
}
|
||||
|
||||
// Finalize code coverage by injecting the coverage map. Note, the coverage map will
|
||||
// also be added to the `llvm.compiler.used` variable, created next.
|
||||
if cx.sess().instrument_coverage() {
|
||||
cx.coverageinfo_finalize();
|
||||
}
|
||||
|
||||
// Create the llvm.used and llvm.compiler.used variables.
|
||||
// Create the llvm.used variable.
|
||||
if !cx.used_statics.is_empty() {
|
||||
cx.create_used_variable_impl(c"llvm.used", &cx.used_statics);
|
||||
}
|
||||
if !cx.compiler_used_statics.is_empty() {
|
||||
cx.create_used_variable_impl(c"llvm.compiler.used", &cx.compiler_used_statics);
|
||||
|
||||
// Create the llvm.compiler.used variable.
|
||||
{
|
||||
let compiler_used_statics = cx.compiler_used_statics.borrow();
|
||||
if !compiler_used_statics.is_empty() {
|
||||
cx.create_used_variable_impl(c"llvm.compiler.used", &compiler_used_statics);
|
||||
}
|
||||
}
|
||||
|
||||
// Run replace-all-uses-with for statics that need it. This must
|
||||
|
||||
@@ -108,6 +108,10 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
|
||||
bytes_in_context(self.llcx(), bytes)
|
||||
}
|
||||
|
||||
pub(crate) fn null_terminate_const_bytes(&self, bytes: &[u8]) -> &'ll Value {
|
||||
null_terminate_bytes_in_context(self.llcx(), bytes)
|
||||
}
|
||||
|
||||
pub(crate) fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value {
|
||||
unsafe {
|
||||
let idx = c_uint::try_from(idx).expect("LLVMGetAggregateElement index overflow");
|
||||
@@ -381,6 +385,16 @@ pub(crate) fn bytes_in_context<'ll>(llcx: &'ll llvm::Context, bytes: &[u8]) -> &
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn null_terminate_bytes_in_context<'ll>(
|
||||
llcx: &'ll llvm::Context,
|
||||
bytes: &[u8],
|
||||
) -> &'ll Value {
|
||||
unsafe {
|
||||
let ptr = bytes.as_ptr() as *const c_char;
|
||||
llvm::LLVMConstStringInContext2(llcx, ptr, bytes.len(), FALSE)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn named_struct<'ll>(ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value {
|
||||
let len = c_uint::try_from(elts.len()).expect("LLVMConstStructInContext elements len overflow");
|
||||
unsafe { llvm::LLVMConstNamedStruct(ty, elts.as_ptr(), len) }
|
||||
|
||||
@@ -16,6 +16,7 @@ use rustc_middle::mir::mono::MonoItem;
|
||||
use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
|
||||
use rustc_middle::ty::{self, Instance};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::Symbol;
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use crate::common::CodegenCx;
|
||||
@@ -331,6 +332,10 @@ impl<'ll> CodegenCx<'ll, '_> {
|
||||
}
|
||||
|
||||
g
|
||||
} else if let Some(classname) = fn_attrs.objc_class {
|
||||
self.get_objc_classref(classname)
|
||||
} else if let Some(methname) = fn_attrs.objc_selector {
|
||||
self.get_objc_selref(methname)
|
||||
} else {
|
||||
check_and_apply_linkage(self, fn_attrs, llty, sym, def_id)
|
||||
};
|
||||
@@ -543,8 +548,225 @@ impl<'ll> CodegenCx<'ll, '_> {
|
||||
|
||||
/// Add a global value to a list to be stored in the `llvm.compiler.used` variable,
|
||||
/// an array of ptr.
|
||||
pub(crate) fn add_compiler_used_global(&mut self, global: &'ll Value) {
|
||||
self.compiler_used_statics.push(global);
|
||||
pub(crate) fn add_compiler_used_global(&self, global: &'ll Value) {
|
||||
self.compiler_used_statics.borrow_mut().push(global);
|
||||
}
|
||||
|
||||
// We do our best here to match what Clang does when compiling Objective-C natively.
|
||||
// See Clang's `CGObjCCommonMac::CreateCStringLiteral`:
|
||||
// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L4134
|
||||
fn define_objc_classname(&self, classname: &str) -> &'ll Value {
|
||||
assert_eq!(self.objc_abi_version(), 1);
|
||||
|
||||
let llval = self.null_terminate_const_bytes(classname.as_bytes());
|
||||
let llty = self.val_ty(llval);
|
||||
let sym = self.generate_local_symbol_name("OBJC_CLASS_NAME_");
|
||||
let g = self.define_global(&sym, llty).unwrap_or_else(|| {
|
||||
bug!("symbol `{}` is already defined", sym);
|
||||
});
|
||||
set_global_alignment(self, g, self.tcx.data_layout.i8_align.abi);
|
||||
llvm::set_initializer(g, llval);
|
||||
llvm::set_linkage(g, llvm::Linkage::PrivateLinkage);
|
||||
llvm::set_section(g, c"__TEXT,__cstring,cstring_literals");
|
||||
llvm::LLVMSetGlobalConstant(g, llvm::TRUE);
|
||||
llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global);
|
||||
self.add_compiler_used_global(g);
|
||||
|
||||
g
|
||||
}
|
||||
|
||||
// We do our best here to match what Clang does when compiling Objective-C natively.
|
||||
// See Clang's `ObjCNonFragileABITypesHelper`:
|
||||
// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L6052
|
||||
fn get_objc_class_t(&self) -> &'ll Type {
|
||||
if let Some(class_t) = self.objc_class_t.get() {
|
||||
return class_t;
|
||||
}
|
||||
|
||||
assert_eq!(self.objc_abi_version(), 2);
|
||||
|
||||
// struct _class_t {
|
||||
// struct _class_t* isa;
|
||||
// struct _class_t* const superclass;
|
||||
// void* cache;
|
||||
// IMP* vtable;
|
||||
// struct class_ro_t* ro;
|
||||
// }
|
||||
|
||||
let class_t = self.type_named_struct("struct._class_t");
|
||||
let els = [self.type_ptr(); 5];
|
||||
let packed = false;
|
||||
self.set_struct_body(class_t, &els, packed);
|
||||
|
||||
self.objc_class_t.set(Some(class_t));
|
||||
class_t
|
||||
}
|
||||
|
||||
// We do our best here to match what Clang does when compiling Objective-C natively. We
|
||||
// deduplicate references within a CGU, but we need a reference definition in each referencing
|
||||
// CGU. All attempts at using external references to a single reference definition result in
|
||||
// linker errors.
|
||||
fn get_objc_classref(&self, classname: Symbol) -> &'ll Value {
|
||||
let mut classrefs = self.objc_classrefs.borrow_mut();
|
||||
if let Some(classref) = classrefs.get(&classname).copied() {
|
||||
return classref;
|
||||
}
|
||||
|
||||
let g = match self.objc_abi_version() {
|
||||
1 => {
|
||||
// See Clang's `CGObjCMac::EmitClassRefFromId`:
|
||||
// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L5205
|
||||
let llval = self.define_objc_classname(classname.as_str());
|
||||
let llty = self.type_ptr();
|
||||
let sym = self.generate_local_symbol_name("OBJC_CLASS_REFERENCES_");
|
||||
let g = self.define_global(&sym, llty).unwrap_or_else(|| {
|
||||
bug!("symbol `{}` is already defined", sym);
|
||||
});
|
||||
set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi);
|
||||
llvm::set_initializer(g, llval);
|
||||
llvm::set_linkage(g, llvm::Linkage::PrivateLinkage);
|
||||
llvm::set_section(g, c"__OBJC,__cls_refs,literal_pointers,no_dead_strip");
|
||||
self.add_compiler_used_global(g);
|
||||
g
|
||||
}
|
||||
2 => {
|
||||
// See Clang's `CGObjCNonFragileABIMac::EmitClassRefFromId`:
|
||||
// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L7423
|
||||
let llval = {
|
||||
let extern_sym = format!("OBJC_CLASS_$_{}", classname.as_str());
|
||||
let extern_llty = self.get_objc_class_t();
|
||||
self.declare_global(&extern_sym, extern_llty)
|
||||
};
|
||||
let llty = self.type_ptr();
|
||||
let sym = self.generate_local_symbol_name("OBJC_CLASSLIST_REFERENCES_$_");
|
||||
let g = self.define_global(&sym, llty).unwrap_or_else(|| {
|
||||
bug!("symbol `{}` is already defined", sym);
|
||||
});
|
||||
set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi);
|
||||
llvm::set_initializer(g, llval);
|
||||
llvm::set_linkage(g, llvm::Linkage::InternalLinkage);
|
||||
llvm::set_section(g, c"__DATA,__objc_classrefs,regular,no_dead_strip");
|
||||
self.add_compiler_used_global(g);
|
||||
g
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
classrefs.insert(classname, g);
|
||||
g
|
||||
}
|
||||
|
||||
// We do our best here to match what Clang does when compiling Objective-C natively. We
|
||||
// deduplicate references within a CGU, but we need a reference definition in each referencing
|
||||
// CGU. All attempts at using external references to a single reference definition result in
|
||||
// linker errors.
|
||||
//
|
||||
// Newer versions of Apple Clang generate calls to `@"objc_msgSend$methname"` selector stub
|
||||
// functions. We don't currently do that. The code we generate is closer to what Apple Clang
|
||||
// generates with the `-fno-objc-msgsend-selector-stubs` option.
|
||||
fn get_objc_selref(&self, methname: Symbol) -> &'ll Value {
|
||||
let mut selrefs = self.objc_selrefs.borrow_mut();
|
||||
if let Some(selref) = selrefs.get(&methname).copied() {
|
||||
return selref;
|
||||
}
|
||||
|
||||
let abi_version = self.objc_abi_version();
|
||||
|
||||
// See Clang's `CGObjCCommonMac::CreateCStringLiteral`:
|
||||
// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L4134
|
||||
let methname_llval = self.null_terminate_const_bytes(methname.as_str().as_bytes());
|
||||
let methname_llty = self.val_ty(methname_llval);
|
||||
let methname_sym = self.generate_local_symbol_name("OBJC_METH_VAR_NAME_");
|
||||
let methname_g = self.define_global(&methname_sym, methname_llty).unwrap_or_else(|| {
|
||||
bug!("symbol `{}` is already defined", methname_sym);
|
||||
});
|
||||
set_global_alignment(self, methname_g, self.tcx.data_layout.i8_align.abi);
|
||||
llvm::set_initializer(methname_g, methname_llval);
|
||||
llvm::set_linkage(methname_g, llvm::Linkage::PrivateLinkage);
|
||||
llvm::set_section(
|
||||
methname_g,
|
||||
match abi_version {
|
||||
1 => c"__TEXT,__cstring,cstring_literals",
|
||||
2 => c"__TEXT,__objc_methname,cstring_literals",
|
||||
_ => unreachable!(),
|
||||
},
|
||||
);
|
||||
llvm::LLVMSetGlobalConstant(methname_g, llvm::TRUE);
|
||||
llvm::LLVMSetUnnamedAddress(methname_g, llvm::UnnamedAddr::Global);
|
||||
self.add_compiler_used_global(methname_g);
|
||||
|
||||
// See Clang's `CGObjCMac::EmitSelectorAddr`:
|
||||
// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L5243
|
||||
// And Clang's `CGObjCNonFragileABIMac::EmitSelectorAddr`:
|
||||
// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L7586
|
||||
let selref_llval = methname_g;
|
||||
let selref_llty = self.type_ptr();
|
||||
let selref_sym = self.generate_local_symbol_name("OBJC_SELECTOR_REFERENCES_");
|
||||
let selref_g = self.define_global(&selref_sym, selref_llty).unwrap_or_else(|| {
|
||||
bug!("symbol `{}` is already defined", selref_sym);
|
||||
});
|
||||
set_global_alignment(self, selref_g, self.tcx.data_layout.pointer_align().abi);
|
||||
llvm::set_initializer(selref_g, selref_llval);
|
||||
llvm::set_externally_initialized(selref_g, true);
|
||||
llvm::set_linkage(
|
||||
selref_g,
|
||||
match abi_version {
|
||||
1 => llvm::Linkage::PrivateLinkage,
|
||||
2 => llvm::Linkage::InternalLinkage,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
);
|
||||
llvm::set_section(
|
||||
selref_g,
|
||||
match abi_version {
|
||||
1 => c"__OBJC,__message_refs,literal_pointers,no_dead_strip",
|
||||
2 => c"__DATA,__objc_selrefs,literal_pointers,no_dead_strip",
|
||||
_ => unreachable!(),
|
||||
},
|
||||
);
|
||||
self.add_compiler_used_global(selref_g);
|
||||
|
||||
selrefs.insert(methname, selref_g);
|
||||
selref_g
|
||||
}
|
||||
|
||||
// We do our best here to match what Clang does when compiling Objective-C natively.
|
||||
// See Clang's `ObjCTypesHelper`:
|
||||
// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L5936
|
||||
// And Clang's `CGObjCMac::EmitModuleInfo`:
|
||||
// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L5151
|
||||
pub(crate) fn define_objc_module_info(&mut self) {
|
||||
assert_eq!(self.objc_abi_version(), 1);
|
||||
|
||||
// struct _objc_module {
|
||||
// long version; // Hardcoded to 7 in Clang.
|
||||
// long size; // sizeof(struct _objc_module)
|
||||
// char* name; // Hardcoded to classname "" in Clang.
|
||||
// struct _objc_symtab* symtab; // Null without class or category definitions.
|
||||
// }
|
||||
|
||||
let llty = self.type_named_struct("struct._objc_module");
|
||||
let i32_llty = self.type_i32();
|
||||
let ptr_llty = self.type_ptr();
|
||||
let packed = false;
|
||||
self.set_struct_body(llty, &[i32_llty, i32_llty, ptr_llty, ptr_llty], packed);
|
||||
|
||||
let version = self.const_uint(i32_llty, 7);
|
||||
let size = self.const_uint(i32_llty, 16);
|
||||
let name = self.define_objc_classname("");
|
||||
let symtab = self.const_null(ptr_llty);
|
||||
let llval = crate::common::named_struct(llty, &[version, size, name, symtab]);
|
||||
|
||||
let sym = "OBJC_MODULES";
|
||||
let g = self.define_global(&sym, llty).unwrap_or_else(|| {
|
||||
bug!("symbol `{}` is already defined", sym);
|
||||
});
|
||||
set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi);
|
||||
llvm::set_initializer(g, llval);
|
||||
llvm::set_linkage(g, llvm::Linkage::PrivateLinkage);
|
||||
llvm::set_section(g, c"__OBJC,__module_info,regular,no_dead_strip");
|
||||
|
||||
self.add_compiler_used_global(g);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ use rustc_session::config::{
|
||||
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, FunctionReturn, PAuthKey, PacRet,
|
||||
};
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol};
|
||||
use rustc_symbol_mangling::mangle_internal_symbol;
|
||||
use rustc_target::spec::{HasTargetSpec, RelocModel, SmallDataThresholdSupport, Target, TlsModel};
|
||||
use smallvec::SmallVec;
|
||||
@@ -119,7 +119,7 @@ pub(crate) struct FullCx<'ll, 'tcx> {
|
||||
|
||||
/// Statics that will be placed in the llvm.compiler.used variable
|
||||
/// See <https://llvm.org/docs/LangRef.html#the-llvm-compiler-used-global-variable> for details
|
||||
pub compiler_used_statics: Vec<&'ll Value>,
|
||||
pub compiler_used_statics: RefCell<Vec<&'ll Value>>,
|
||||
|
||||
/// Mapping of non-scalar types to llvm types.
|
||||
pub type_lowering: RefCell<FxHashMap<(Ty<'tcx>, Option<VariantIdx>), &'ll Type>>,
|
||||
@@ -146,6 +146,15 @@ pub(crate) struct FullCx<'ll, 'tcx> {
|
||||
/// `global_asm!` needs to be able to find this new global so that it can
|
||||
/// compute the correct mangled symbol name to insert into the asm.
|
||||
pub renamed_statics: RefCell<FxHashMap<DefId, &'ll Value>>,
|
||||
|
||||
/// Cached Objective-C class type
|
||||
pub objc_class_t: Cell<Option<&'ll Type>>,
|
||||
|
||||
/// Cache of Objective-C class references
|
||||
pub objc_classrefs: RefCell<FxHashMap<Symbol, &'ll Value>>,
|
||||
|
||||
/// Cache of Objective-C selector references
|
||||
pub objc_selrefs: RefCell<FxHashMap<Symbol, &'ll Value>>,
|
||||
}
|
||||
|
||||
fn to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode {
|
||||
@@ -644,7 +653,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
||||
const_globals: Default::default(),
|
||||
statics_to_rauw: RefCell::new(Vec::new()),
|
||||
used_statics: Vec::new(),
|
||||
compiler_used_statics: Vec::new(),
|
||||
compiler_used_statics: Default::default(),
|
||||
type_lowering: Default::default(),
|
||||
scalar_lltypes: Default::default(),
|
||||
coverage_cx,
|
||||
@@ -655,6 +664,9 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
||||
intrinsics: Default::default(),
|
||||
local_gen_sym_counter: Cell::new(0),
|
||||
renamed_statics: Default::default(),
|
||||
objc_class_t: Cell::new(None),
|
||||
objc_classrefs: Default::default(),
|
||||
objc_selrefs: Default::default(),
|
||||
},
|
||||
PhantomData,
|
||||
)
|
||||
@@ -679,6 +691,69 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
||||
llvm::set_linkage(g, llvm::Linkage::AppendingLinkage);
|
||||
llvm::set_section(g, c"llvm.metadata");
|
||||
}
|
||||
|
||||
/// The Objective-C ABI that is used.
|
||||
///
|
||||
/// This corresponds to the `-fobjc-abi-version=` flag in Clang / GCC.
|
||||
pub(crate) fn objc_abi_version(&self) -> u32 {
|
||||
assert!(self.tcx.sess.target.is_like_darwin);
|
||||
if self.tcx.sess.target.arch == "x86" && self.tcx.sess.target.os == "macos" {
|
||||
// 32-bit x86 macOS uses ABI version 1 (a.k.a. the "fragile ABI").
|
||||
1
|
||||
} else {
|
||||
// All other Darwin-like targets we support use ABI version 2
|
||||
// (a.k.a the "non-fragile ABI").
|
||||
2
|
||||
}
|
||||
}
|
||||
|
||||
// We do our best here to match what Clang does when compiling Objective-C natively.
|
||||
// See Clang's `CGObjCCommonMac::EmitImageInfo`:
|
||||
// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L5085
|
||||
pub(crate) fn add_objc_module_flags(&self) {
|
||||
let abi_version = self.objc_abi_version();
|
||||
|
||||
llvm::add_module_flag_u32(
|
||||
self.llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Error,
|
||||
"Objective-C Version",
|
||||
abi_version,
|
||||
);
|
||||
|
||||
llvm::add_module_flag_u32(
|
||||
self.llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Error,
|
||||
"Objective-C Image Info Version",
|
||||
0,
|
||||
);
|
||||
|
||||
llvm::add_module_flag_str(
|
||||
self.llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Error,
|
||||
"Objective-C Image Info Section",
|
||||
match abi_version {
|
||||
1 => "__OBJC,__image_info,regular",
|
||||
2 => "__DATA,__objc_imageinfo,regular,no_dead_strip",
|
||||
_ => unreachable!(),
|
||||
},
|
||||
);
|
||||
|
||||
if self.tcx.sess.target.env == "sim" {
|
||||
llvm::add_module_flag_u32(
|
||||
self.llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Error,
|
||||
"Objective-C Is Simulated",
|
||||
1 << 5,
|
||||
);
|
||||
}
|
||||
|
||||
llvm::add_module_flag_u32(
|
||||
self.llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Error,
|
||||
"Objective-C Class Properties",
|
||||
1 << 6,
|
||||
);
|
||||
}
|
||||
}
|
||||
impl<'ll> SimpleCx<'ll> {
|
||||
pub(crate) fn get_type_of_global(&self, val: &'ll Value) -> &'ll Type {
|
||||
|
||||
@@ -1237,6 +1237,7 @@ unsafe extern "C" {
|
||||
pub(crate) safe fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool);
|
||||
pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool);
|
||||
pub(crate) safe fn LLVMSetTailCallKind(CallInst: &Value, kind: TailCallKind);
|
||||
pub(crate) safe fn LLVMSetExternallyInitialized(GlobalVar: &Value, IsExtInit: Bool);
|
||||
|
||||
// Operations on attributes
|
||||
pub(crate) fn LLVMCreateStringAttribute(
|
||||
|
||||
@@ -258,6 +258,10 @@ pub(crate) fn set_alignment(llglobal: &Value, align: Align) {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_externally_initialized(llglobal: &Value, is_ext_init: bool) {
|
||||
LLVMSetExternallyInitialized(llglobal, is_ext_init.to_llvm_bool());
|
||||
}
|
||||
|
||||
/// Get the `name`d comdat from `llmod` and assign it to `llglobal`.
|
||||
///
|
||||
/// Inserts the comdat into `llmod` if it does not exist.
|
||||
|
||||
Reference in New Issue
Block a user