Skip to content

Commit 436e4fb

Browse files
committed
Cast global variables to default address space
Pointers for variables all need to be in the same address space for correct compilation. Therefore ensure that even if a global variable is created in a different address space, it is casted to the default address space before its value is used. This is necessary for the amdgpu target and others where the default address space for global variables is not 0. For example `core` does not compile in debug mode when not casting the address space to the default one because it tries to emit the following (simplified) LLVM IR, containing a type mismatch: ```llvm @alloc_0 = addrspace(1) constant <{ [6 x i8] }> <{ [6 x i8] c"bit.rs" }>, align 1 @alloc_1 = addrspace(1) constant <{ ptr }> <{ ptr addrspace(1) @alloc_0 }>, align 8 ; ^ here a struct containing a `ptr` is needed, but it is created using a `ptr addrspace(1)` ``` For this to compile, we need to insert a constant `addrspacecast` before we use a global variable: ```llvm @alloc_0 = addrspace(1) constant <{ [6 x i8] }> <{ [6 x i8] c"bit.rs" }>, align 1 @alloc_1 = addrspace(1) constant <{ ptr }> <{ ptr addrspacecast (ptr addrspace(1) @alloc_0 to ptr) }>, align 8 ``` As vtables are global variables as well, they are also created with an `addrspacecast`. In the SSA backend, after a vtable global is created, metadata is added to it. To add metadata, we need the non-casted global variable. Therefore we strip away an addrspacecast if there is one, to get the underlying global.
1 parent bf6f8a4 commit 436e4fb

File tree

5 files changed

+130
-21
lines changed

5 files changed

+130
-21
lines changed

compiler/rustc_codegen_llvm/src/builder.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1225,7 +1225,9 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
12251225
impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> {
12261226
fn get_static(&mut self, def_id: DefId) -> &'ll Value {
12271227
// Forward to the `get_static` method of `CodegenCx`
1228-
self.cx().get_static(def_id)
1228+
let s = self.cx().get_static(def_id);
1229+
// Cast to default address space if statics are in a different addrspace
1230+
self.cx().const_pointercast(s, self.type_ptr())
12291231
}
12301232
}
12311233

compiler/rustc_codegen_llvm/src/common.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
221221
llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global);
222222
}
223223
llvm::set_linkage(g, llvm::Linkage::InternalLinkage);
224+
let g = self.const_pointercast(g, self.type_ptr());
224225
(s.to_owned(), g)
225226
})
226227
.1;
@@ -285,7 +286,7 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
285286
let alloc = alloc.inner();
286287
let value = match alloc.mutability {
287288
Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
288-
_ => self.static_addr_of(init, alloc.align, None),
289+
_ => self.static_addr_of_impl(init, alloc.align, None),
289290
};
290291
if !self.sess().fewer_names() && llvm::get_value_name(value).is_empty()
291292
{
@@ -311,7 +312,7 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
311312
.global_alloc(self.tcx.vtable_allocation((ty, dyn_ty.principal())))
312313
.unwrap_memory();
313314
let init = const_alloc_to_llvm(self, alloc, /*static*/ false);
314-
let value = self.static_addr_of(init, alloc.inner().align, None);
315+
let value = self.static_addr_of_impl(init, alloc.inner().align, None);
315316
(value, AddressSpace::DATA)
316317
}
317318
GlobalAlloc::Static(def_id) => {
@@ -323,7 +324,7 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
323324
let llval = unsafe {
324325
llvm::LLVMConstInBoundsGEP2(
325326
self.type_i8(),
326-
self.const_bitcast(base_addr, self.type_ptr_ext(base_addr_space)),
327+
self.const_pointercast(base_addr, self.type_ptr_ext(base_addr_space)),
327328
&self.const_usize(offset.bytes()),
328329
1,
329330
)

compiler/rustc_codegen_llvm/src/consts.rs

+31-17
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,10 @@ impl<'ll> CodegenCx<'ll, '_> {
210210
unsafe { llvm::LLVMConstBitCast(val, ty) }
211211
}
212212

213+
pub(crate) fn const_pointercast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value {
214+
unsafe { llvm::LLVMConstPointerCast(val, ty) }
215+
}
216+
213217
pub(crate) fn static_addr_of_mut(
214218
&self,
215219
cv: &'ll Value,
@@ -233,6 +237,31 @@ impl<'ll> CodegenCx<'ll, '_> {
233237
gv
234238
}
235239

240+
pub(crate) fn static_addr_of_impl(
241+
&self,
242+
cv: &'ll Value,
243+
align: Align,
244+
kind: Option<&str>,
245+
) -> &'ll Value {
246+
if let Some(&gv) = self.const_globals.borrow().get(&cv) {
247+
unsafe {
248+
// Upgrade the alignment in cases where the same constant is used with different
249+
// alignment requirements
250+
let llalign = align.bytes() as u32;
251+
if llalign > llvm::LLVMGetAlignment(gv) {
252+
llvm::LLVMSetAlignment(gv, llalign);
253+
}
254+
}
255+
return gv;
256+
}
257+
let gv = self.static_addr_of_mut(cv, align, kind);
258+
unsafe {
259+
llvm::LLVMSetGlobalConstant(gv, True);
260+
}
261+
self.const_globals.borrow_mut().insert(cv, gv);
262+
gv
263+
}
264+
236265
#[instrument(level = "debug", skip(self))]
237266
pub(crate) fn get_static(&self, def_id: DefId) -> &'ll Value {
238267
let instance = Instance::mono(self.tcx, def_id);
@@ -506,23 +535,8 @@ impl<'ll> CodegenCx<'ll, '_> {
506535

507536
impl<'ll> StaticCodegenMethods for CodegenCx<'ll, '_> {
508537
fn static_addr_of(&self, cv: &'ll Value, align: Align, kind: Option<&str>) -> &'ll Value {
509-
if let Some(&gv) = self.const_globals.borrow().get(&cv) {
510-
unsafe {
511-
// Upgrade the alignment in cases where the same constant is used with different
512-
// alignment requirements
513-
let llalign = align.bytes() as u32;
514-
if llalign > llvm::LLVMGetAlignment(gv) {
515-
llvm::LLVMSetAlignment(gv, llalign);
516-
}
517-
}
518-
return gv;
519-
}
520-
let gv = self.static_addr_of_mut(cv, align, kind);
521-
unsafe {
522-
llvm::LLVMSetGlobalConstant(gv, True);
523-
}
524-
self.const_globals.borrow_mut().insert(cv, gv);
525-
gv
538+
let gv = self.static_addr_of_impl(cv, align, kind);
539+
self.const_pointercast(gv, self.type_ptr())
526540
}
527541

528542
fn codegen_static(&self, def_id: DefId) {

compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs

+15
Original file line numberDiff line numberDiff line change
@@ -1500,6 +1500,18 @@ fn build_vtable_type_di_node<'ll, 'tcx>(
15001500
.di_node
15011501
}
15021502

1503+
fn find_vtable_behind_cast<'ll>(vtable: &'ll Value) -> &'ll Value {
1504+
// The vtable is a global variable, which may be behind an addrspacecast.
1505+
unsafe {
1506+
if let Some(c) = llvm::LLVMIsAConstantExpr(vtable) {
1507+
if llvm::LLVMGetConstOpcode(c) == llvm::Opcode::AddrSpaceCast {
1508+
return llvm::LLVMGetOperand(c, 0).unwrap();
1509+
}
1510+
}
1511+
}
1512+
vtable
1513+
}
1514+
15031515
pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
15041516
cx: &CodegenCx<'ll, 'tcx>,
15051517
ty: Ty<'tcx>,
@@ -1520,6 +1532,7 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
15201532

15211533
let Some(trait_ref) = trait_ref else { return };
15221534

1535+
let vtable = find_vtable_behind_cast(vtable);
15231536
let trait_ref_self = trait_ref.with_self_ty(cx.tcx, ty);
15241537
let trait_ref_self = cx.tcx.erase_regions(trait_ref_self);
15251538
let trait_def_id = trait_ref_self.def_id();
@@ -1593,6 +1606,8 @@ pub(crate) fn create_vtable_di_node<'ll, 'tcx>(
15931606
return;
15941607
}
15951608

1609+
let vtable = find_vtable_behind_cast(vtable);
1610+
15961611
// When full debuginfo is enabled, we want to try and prevent vtables from being
15971612
// merged. Otherwise debuggers will have a hard time mapping from dyn pointer
15981613
// to concrete type.

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+77
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,79 @@ pub enum MemoryEffects {
660660
InaccessibleMemOnly,
661661
}
662662

663+
/// LLVMOpcode
664+
#[derive(Copy, Clone, PartialEq, Eq)]
665+
#[repr(C)]
666+
pub enum Opcode {
667+
Ret = 1,
668+
Br = 2,
669+
Switch = 3,
670+
IndirectBr = 4,
671+
Invoke = 5,
672+
Unreachable = 7,
673+
CallBr = 67,
674+
FNeg = 66,
675+
Add = 8,
676+
FAdd = 9,
677+
Sub = 10,
678+
FSub = 11,
679+
Mul = 12,
680+
FMul = 13,
681+
UDiv = 14,
682+
SDiv = 15,
683+
FDiv = 16,
684+
URem = 17,
685+
SRem = 18,
686+
FRem = 19,
687+
Shl = 20,
688+
LShr = 21,
689+
AShr = 22,
690+
And = 23,
691+
Or = 24,
692+
Xor = 25,
693+
Alloca = 26,
694+
Load = 27,
695+
Store = 28,
696+
GetElementPtr = 29,
697+
Trunc = 30,
698+
ZExt = 31,
699+
SExt = 32,
700+
FPToUI = 33,
701+
FPToSI = 34,
702+
UIToFP = 35,
703+
SIToFP = 36,
704+
FPTrunc = 37,
705+
FPExt = 38,
706+
PtrToInt = 39,
707+
IntToPtr = 40,
708+
BitCast = 41,
709+
AddrSpaceCast = 60,
710+
ICmp = 42,
711+
FCmp = 43,
712+
PHI = 44,
713+
Call = 45,
714+
Select = 46,
715+
UserOp1 = 47,
716+
UserOp2 = 48,
717+
VAArg = 49,
718+
ExtractElement = 50,
719+
InsertElement = 51,
720+
ShuffleVector = 52,
721+
ExtractValue = 53,
722+
InsertValue = 54,
723+
Freeze = 68,
724+
Fence = 55,
725+
AtomicCmpXchg = 56,
726+
AtomicRMW = 57,
727+
Resume = 58,
728+
LandingPad = 59,
729+
CleanupRet = 61,
730+
CatchRet = 62,
731+
CatchPad = 63,
732+
CleanupPad = 64,
733+
CatchSwitch = 65,
734+
}
735+
663736
unsafe extern "C" {
664737
type Opaque;
665738
}
@@ -975,7 +1048,10 @@ unsafe extern "C" {
9751048
pub fn LLVMConstPtrToInt<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
9761049
pub fn LLVMConstIntToPtr<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
9771050
pub fn LLVMConstBitCast<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
1051+
pub fn LLVMConstPointerCast<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
9781052
pub fn LLVMGetAggregateElement(ConstantVal: &Value, Idx: c_uint) -> Option<&Value>;
1053+
pub fn LLVMGetConstOpcode(ConstantVal: &Value) -> Opcode;
1054+
pub fn LLVMIsAConstantExpr(Val: &Value) -> Option<&Value>;
9791055

9801056
// Operations on global variables, functions, and aliases (globals)
9811057
pub fn LLVMIsDeclaration(Global: &Value) -> Bool;
@@ -1032,6 +1108,7 @@ unsafe extern "C" {
10321108
// Operations on instructions
10331109
pub fn LLVMIsAInstruction(Val: &Value) -> Option<&Value>;
10341110
pub fn LLVMGetFirstBasicBlock(Fn: &Value) -> &BasicBlock;
1111+
pub fn LLVMGetOperand(Val: &Value, Index: c_uint) -> Option<&Value>;
10351112

10361113
// Operations on call sites
10371114
pub fn LLVMSetInstructionCallConv(Instr: &Value, CC: c_uint);

0 commit comments

Comments
 (0)