Skip to content

Commit 89f8abe

Browse files
authored
Rollup merge of #135026 - Flakebi:global-addrspace, r=saethlin
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. Tracking issue: #135024
2 parents a6434ef + b06e840 commit 89f8abe

File tree

5 files changed

+155
-21
lines changed

5 files changed

+155
-21
lines changed

compiler/rustc_codegen_llvm/src/builder.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1325,7 +1325,9 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
13251325
impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> {
13261326
fn get_static(&mut self, def_id: DefId) -> &'ll Value {
13271327
// Forward to the `get_static` method of `CodegenCx`
1328-
self.cx().get_static(def_id)
1328+
let s = self.cx().get_static(def_id);
1329+
// Cast to default address space if globals are in a different addrspace
1330+
self.cx().const_pointercast(s, self.type_ptr())
13291331
}
13301332
}
13311333

compiler/rustc_codegen_llvm/src/common.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,8 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
225225
llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global);
226226
}
227227
llvm::set_linkage(g, llvm::Linkage::InternalLinkage);
228+
// Cast to default address space if globals are in a different addrspace
229+
let g = self.const_pointercast(g, self.type_ptr());
228230
(s.to_owned(), g)
229231
})
230232
.1;
@@ -289,7 +291,7 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
289291
let alloc = alloc.inner();
290292
let value = match alloc.mutability {
291293
Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
292-
_ => self.static_addr_of(init, alloc.align, None),
294+
_ => self.static_addr_of_impl(init, alloc.align, None),
293295
};
294296
if !self.sess().fewer_names() && llvm::get_value_name(value).is_empty()
295297
{
@@ -315,7 +317,7 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
315317
.global_alloc(self.tcx.vtable_allocation((ty, dyn_ty.principal())))
316318
.unwrap_memory();
317319
let init = const_alloc_to_llvm(self, alloc, /*static*/ false);
318-
let value = self.static_addr_of(init, alloc.inner().align, None);
320+
let value = self.static_addr_of_impl(init, alloc.inner().align, None);
319321
(value, AddressSpace::DATA)
320322
}
321323
GlobalAlloc::Static(def_id) => {
@@ -327,7 +329,8 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
327329
let llval = unsafe {
328330
llvm::LLVMConstInBoundsGEP2(
329331
self.type_i8(),
330-
self.const_bitcast(base_addr, self.type_ptr_ext(base_addr_space)),
332+
// Cast to the required address space if necessary
333+
self.const_pointercast(base_addr, self.type_ptr_ext(base_addr_space)),
331334
&self.const_usize(offset.bytes()),
332335
1,
333336
)

compiler/rustc_codegen_llvm/src/consts.rs

+44-17
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,14 @@ 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+
217+
/// Create a global variable.
218+
///
219+
/// The returned global variable is a pointer in the default address space for globals.
220+
/// Fails if a symbol with the given name already exists.
213221
pub(crate) fn static_addr_of_mut(
214222
&self,
215223
cv: &'ll Value,
@@ -233,6 +241,34 @@ impl<'ll> CodegenCx<'ll, '_> {
233241
gv
234242
}
235243

244+
/// Create a global constant.
245+
///
246+
/// The returned global variable is a pointer in the default address space for globals.
247+
pub(crate) fn static_addr_of_impl(
248+
&self,
249+
cv: &'ll Value,
250+
align: Align,
251+
kind: Option<&str>,
252+
) -> &'ll Value {
253+
if let Some(&gv) = self.const_globals.borrow().get(&cv) {
254+
unsafe {
255+
// Upgrade the alignment in cases where the same constant is used with different
256+
// alignment requirements
257+
let llalign = align.bytes() as u32;
258+
if llalign > llvm::LLVMGetAlignment(gv) {
259+
llvm::LLVMSetAlignment(gv, llalign);
260+
}
261+
}
262+
return gv;
263+
}
264+
let gv = self.static_addr_of_mut(cv, align, kind);
265+
unsafe {
266+
llvm::LLVMSetGlobalConstant(gv, True);
267+
}
268+
self.const_globals.borrow_mut().insert(cv, gv);
269+
gv
270+
}
271+
236272
#[instrument(level = "debug", skip(self))]
237273
pub(crate) fn get_static(&self, def_id: DefId) -> &'ll Value {
238274
let instance = Instance::mono(self.tcx, def_id);
@@ -505,24 +541,15 @@ impl<'ll> CodegenCx<'ll, '_> {
505541
}
506542

507543
impl<'ll> StaticCodegenMethods for CodegenCx<'ll, '_> {
544+
/// Get a pointer to a global variable.
545+
///
546+
/// The pointer will always be in the default address space. If global variables default to a
547+
/// different address space, an addrspacecast is inserted.
508548
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
549+
let gv = self.static_addr_of_impl(cv, align, kind);
550+
// static_addr_of_impl returns the bare global variable, which might not be in the default
551+
// address space. Cast to the default address space if necessary.
552+
self.const_pointercast(gv, self.type_ptr())
526553
}
527554

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

compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs

+25
Original file line numberDiff line numberDiff line change
@@ -1488,6 +1488,26 @@ fn build_vtable_type_di_node<'ll, 'tcx>(
14881488
.di_node
14891489
}
14901490

1491+
/// Get the global variable for the vtable.
1492+
///
1493+
/// When using global variables, we may have created an addrspacecast to get a pointer to the
1494+
/// default address space if global variables are created in a different address space.
1495+
/// For modifying the vtable, we need the real global variable. This function accepts either a
1496+
/// global variable (which is simply returned), or an addrspacecast constant expression.
1497+
/// If the given value is an addrspacecast, the cast is removed and the global variable behind
1498+
/// the cast is returned.
1499+
fn find_vtable_behind_cast<'ll>(vtable: &'ll Value) -> &'ll Value {
1500+
// The vtable is a global variable, which may be behind an addrspacecast.
1501+
unsafe {
1502+
if let Some(c) = llvm::LLVMIsAConstantExpr(vtable) {
1503+
if llvm::LLVMGetConstOpcode(c) == llvm::Opcode::AddrSpaceCast {
1504+
return llvm::LLVMGetOperand(c, 0).unwrap();
1505+
}
1506+
}
1507+
}
1508+
vtable
1509+
}
1510+
14911511
pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
14921512
cx: &CodegenCx<'ll, 'tcx>,
14931513
ty: Ty<'tcx>,
@@ -1508,6 +1528,8 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
15081528

15091529
let Some(trait_ref) = trait_ref else { return };
15101530

1531+
// Unwrap potential addrspacecast
1532+
let vtable = find_vtable_behind_cast(vtable);
15111533
let trait_ref_self = trait_ref.with_self_ty(cx.tcx, ty);
15121534
let trait_ref_self = cx.tcx.erase_regions(trait_ref_self);
15131535
let trait_def_id = trait_ref_self.def_id();
@@ -1581,6 +1603,9 @@ pub(crate) fn create_vtable_di_node<'ll, 'tcx>(
15811603
return;
15821604
}
15831605

1606+
// Unwrap potential addrspacecast
1607+
let vtable = find_vtable_behind_cast(vtable);
1608+
15841609
// When full debuginfo is enabled, we want to try and prevent vtables from being
15851610
// merged. Otherwise debuggers will have a hard time mapping from dyn pointer
15861611
// to concrete type.

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

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

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

9961072
// Operations on global variables, functions, and aliases (globals)
9971073
pub fn LLVMIsDeclaration(Global: &Value) -> Bool;
@@ -1048,6 +1124,7 @@ unsafe extern "C" {
10481124
// Operations on instructions
10491125
pub fn LLVMIsAInstruction(Val: &Value) -> Option<&Value>;
10501126
pub fn LLVMGetFirstBasicBlock(Fn: &Value) -> &BasicBlock;
1127+
pub fn LLVMGetOperand(Val: &Value, Index: c_uint) -> Option<&Value>;
10511128

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

0 commit comments

Comments
 (0)