Skip to content

Commit 4ffff8f

Browse files
Make librustc_codegen_llvm aware of LLVM address spaces.
In order to not require overloading functions based on their argument's address space (among other things), we require the presence of a "flat" (ie an address space which is shared with every other address space) address space. This isn't exposed in any way to Rust code. This just makes Rust compatible with LLVM target machines which, for example, place allocas in a different address space. `amdgcn-amd-amdhsa-amdgiz` is a specific example, which places allocas in address space 5 or the private (at the work item level) address space.
1 parent 7164a9f commit 4ffff8f

File tree

24 files changed

+897
-91
lines changed

24 files changed

+897
-91
lines changed

src/librustc_codegen_llvm/abi.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -649,10 +649,11 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
649649
PassMode::Ignore => cx.type_void(),
650650
PassMode::Direct(_) | PassMode::Pair(..) => {
651651
self.ret.layout.immediate_llvm_type(cx)
652+
.copy_addr_space(cx.flat_addr_space())
652653
}
653654
PassMode::Cast(cast) => cast.llvm_type(cx),
654655
PassMode::Indirect(..) => {
655-
llargument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx)));
656+
llargument_tys.push(cx.type_ptr_to_flat(self.ret.memory_ty(cx)));
656657
cx.type_void()
657658
}
658659
};
@@ -665,8 +666,11 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
665666

666667
let llarg_ty = match arg.mode {
667668
PassMode::Ignore => continue,
668-
PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx),
669+
PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx)
670+
.copy_addr_space(cx.flat_addr_space()),
669671
PassMode::Pair(..) => {
672+
// Keep the argument type address space given by
673+
// `scalar_pair_element_llvm_type`.
670674
llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0, true));
671675
llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true));
672676
continue;
@@ -679,7 +683,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
679683
continue;
680684
}
681685
PassMode::Cast(cast) => cast.llvm_type(cx),
682-
PassMode::Indirect(_, None) => cx.type_ptr_to(arg.memory_ty(cx)),
686+
PassMode::Indirect(_, None) => cx.type_ptr_to_flat(arg.memory_ty(cx)),
683687
};
684688
llargument_tys.push(llarg_ty);
685689
}

src/librustc_codegen_llvm/builder.rs

+73-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope, AsmDialect};
22
use llvm::{self, False, BasicBlock};
33
use rustc_codegen_ssa::common::{IntPredicate, TypeKind, RealPredicate};
44
use rustc_codegen_ssa::{self, MemFlags};
5-
use common::Funclet;
5+
use common::{Funclet, val_addr_space, val_addr_space_opt};
66
use context::CodegenCx;
77
use type_::Type;
88
use type_of::LayoutLlvmExt;
@@ -18,6 +18,7 @@ use syntax;
1818
use rustc_codegen_ssa::base::to_immediate;
1919
use rustc_codegen_ssa::mir::operand::{OperandValue, OperandRef};
2020
use rustc_codegen_ssa::mir::place::PlaceRef;
21+
use rustc_target::spec::AddrSpaceIdx;
2122
use std::borrow::Cow;
2223
use std::ffi::CStr;
2324
use std::ops::{Deref, Range};
@@ -846,26 +847,59 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
846847

847848
fn ptrtoint(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
848849
self.count_insn("ptrtoint");
850+
let val = self.flat_addr_cast(val);
849851
unsafe {
850852
llvm::LLVMBuildPtrToInt(self.llbuilder, val, dest_ty, noname())
851853
}
852854
}
853855

854856
fn inttoptr(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
855857
self.count_insn("inttoptr");
858+
let dest_ty = dest_ty.copy_addr_space(self.cx().flat_addr_space());
856859
unsafe {
857860
llvm::LLVMBuildIntToPtr(self.llbuilder, val, dest_ty, noname())
858861
}
859862
}
860863

861864
fn bitcast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
862865
self.count_insn("bitcast");
866+
let dest_ty = dest_ty.copy_addr_space(val_addr_space(val));
863867
unsafe {
864868
llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty, noname())
865869
}
866870
}
867871

872+
/// address space casts, then bitcasts to dest_ty without changing address spaces.
873+
fn as_ptr_cast(&mut self, val: &'ll Value,
874+
addr_space: AddrSpaceIdx,
875+
dest_ty: &'ll Type) -> &'ll Value
876+
{
877+
let val = self.addrspace_cast(val, addr_space);
878+
self.pointercast(val, dest_ty.copy_addr_space(addr_space))
879+
}
880+
fn flat_as_ptr_cast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
881+
self.as_ptr_cast(val, self.cx().flat_addr_space(), dest_ty)
882+
}
868883

884+
fn addrspace_cast(&mut self, val: &'ll Value, dest: AddrSpaceIdx) -> &'ll Value {
885+
// LLVM considers no-op address space casts to be invalid.
886+
let src_ty = self.cx.val_ty(val);
887+
if src_ty.is_ptr() && src_ty.address_space() != dest {
888+
let dest_ty = src_ty.copy_addr_space(dest);
889+
self.cx().check_addr_space_cast(val, dest_ty);
890+
self.count_insn("addrspacecast");
891+
unsafe {
892+
llvm::LLVMBuildAddrSpaceCast(self.llbuilder, val,
893+
dest_ty, noname())
894+
}
895+
} else {
896+
val
897+
}
898+
}
899+
900+
fn flat_addr_cast(&mut self, val: &'ll Value) -> &'ll Value {
901+
self.addrspace_cast(val, self.cx().flat_addr_space())
902+
}
869903
fn intcast(&mut self, val: &'ll Value, dest_ty: &'ll Type, is_signed: bool) -> &'ll Value {
870904
self.count_insn("intcast");
871905
unsafe {
@@ -875,6 +909,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
875909

876910
fn pointercast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
877911
self.count_insn("pointercast");
912+
let dest_ty = dest_ty.copy_addr_space(val_addr_space(val));
878913
unsafe {
879914
llvm::LLVMBuildPointerCast(self.llbuilder, val, dest_ty, noname())
880915
}
@@ -883,7 +918,18 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
883918
/* Comparisons */
884919
fn icmp(&mut self, op: IntPredicate, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
885920
self.count_insn("icmp");
921+
886922
let op = llvm::IntPredicate::from_generic(op);
923+
924+
match (val_addr_space_opt(lhs), val_addr_space_opt(rhs)) {
925+
(Some(l), Some(r)) if l == r => {},
926+
(Some(l), Some(r)) if l != r => {
927+
bug!("tried to cmp ptrs of different addr spaces: lhs {:?} rhs {:?}",
928+
lhs, rhs);
929+
},
930+
_ => {},
931+
}
932+
887933
unsafe {
888934
llvm::LLVMBuildICmp(self.llbuilder, op as c_uint, lhs, rhs, noname())
889935
}
@@ -1004,7 +1050,8 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
10041050
flags: MemFlags,
10051051
) {
10061052
let ptr_width = &self.sess().target.target.target_pointer_width;
1007-
let intrinsic_key = format!("llvm.memset.p0i8.i{}", ptr_width);
1053+
let addr_space = self.val_ty(ptr).address_space();
1054+
let intrinsic_key = format!("llvm.memset.p{}i8.i{}", addr_space, ptr_width);
10081055
let llintrinsicfn = self.get_intrinsic(&intrinsic_key);
10091056
let ptr = self.pointercast(ptr, self.type_i8p());
10101057
let align = self.const_u32(align.bytes() as u32);
@@ -1352,7 +1399,8 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
13521399
ptr: &'ll Value) -> &'ll Value {
13531400
let dest_ptr_ty = self.cx.val_ty(ptr);
13541401
let stored_ty = self.cx.val_ty(val);
1355-
let stored_ptr_ty = self.cx.type_ptr_to(stored_ty);
1402+
let stored_ptr_ty = self.cx.type_as_ptr_to(stored_ty,
1403+
dest_ptr_ty.address_space());
13561404

13571405
assert_eq!(self.cx.type_kind(dest_ptr_ty), TypeKind::Pointer);
13581406

@@ -1398,7 +1446,18 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
13981446
debug!("Type mismatch in function call of {:?}. \
13991447
Expected {:?} for param {}, got {:?}; injecting bitcast",
14001448
llfn, expected_ty, i, actual_ty);
1401-
self.bitcast(actual_val, expected_ty)
1449+
if expected_ty.is_ptr() && actual_ty.is_ptr() {
1450+
let actual_val = self.addrspace_cast(actual_val,
1451+
expected_ty.address_space());
1452+
self.pointercast(actual_val, expected_ty)
1453+
} else {
1454+
let actual_val = if actual_ty.is_ptr() {
1455+
self.flat_addr_cast(actual_val)
1456+
} else {
1457+
actual_val
1458+
};
1459+
self.bitcast(actual_val, expected_ty)
1460+
}
14021461
} else {
14031462
actual_val
14041463
}
@@ -1488,7 +1547,16 @@ impl Builder<'a, 'll, 'tcx> {
14881547
return;
14891548
}
14901549

1491-
let lifetime_intrinsic = self.cx.get_intrinsic(intrinsic);
1550+
let addr_space = self.cx.val_ty(ptr).address_space();
1551+
// Old LLVMs don't have the address space specific intrinsics.
1552+
// So as a semi-crude workaround, don't specialize if in the
1553+
// default address space.
1554+
let lifetime_intrinsic = if let AddrSpaceIdx(0) = addr_space {
1555+
self.cx.get_intrinsic(intrinsic)
1556+
} else {
1557+
let intrinsic = format!("{}.p{}i8", intrinsic, addr_space);
1558+
self.cx.get_intrinsic(&intrinsic)
1559+
};
14921560

14931561
let ptr = self.pointercast(ptr, self.cx.type_i8p());
14941562
self.call(lifetime_intrinsic, &[self.cx.const_u64(size), ptr], None);

src/librustc_codegen_llvm/common.rs

+32-7
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ use rustc_codegen_ssa::traits::*;
1313
use rustc::ty::layout::{HasDataLayout, LayoutOf, self, TyLayout, Size};
1414
use rustc::mir::interpret::{Scalar, AllocKind, Allocation};
1515
use consts::const_alloc_to_llvm;
16+
use rustc_codegen_ssa::common::TypeKind;
1617
use rustc_codegen_ssa::mir::place::PlaceRef;
18+
use rustc_target::spec::AddrSpaceIdx;
1719

1820
use libc::{c_uint, c_char};
1921

@@ -170,9 +172,9 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
170172
s.len() as c_uint,
171173
!null_terminated as Bool);
172174
let sym = self.generate_local_symbol_name("str");
173-
let g = self.define_global(&sym[..], self.val_ty(sc)).unwrap_or_else(||{
174-
bug!("symbol `{}` is already defined", sym);
175-
});
175+
let addr_space = self.const_addr_space();
176+
let g = self.define_global(&sym[..], self.val_ty(sc), addr_space)
177+
.unwrap_or_else(|| bug!("symbol `{}` is already defined", sym) );
176178
llvm::LLVMSetInitializer(g, sc);
177179
llvm::LLVMSetGlobalConstant(g, True);
178180
llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage);
@@ -284,6 +286,10 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
284286
}
285287
}
286288

289+
fn const_as_cast(&self, val: &'ll Value, addr_space: AddrSpaceIdx) -> &'ll Value {
290+
self.const_addrcast(val, addr_space)
291+
}
292+
287293
fn scalar_to_backend(
288294
&self,
289295
cv: Scalar,
@@ -299,10 +305,16 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
299305
Scalar::Bits { bits, size } => {
300306
assert_eq!(size as u64, layout.value.size(self).bytes());
301307
let llval = self.const_uint_big(self.type_ix(bitsize), bits);
302-
if layout.value == layout::Pointer {
303-
unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
308+
let flat_llty = llty.copy_addr_space(self.flat_addr_space());
309+
let llval = if layout.value == layout::Pointer {
310+
unsafe { llvm::LLVMConstIntToPtr(llval, flat_llty) }
304311
} else {
305-
self.const_bitcast(llval, llty)
312+
self.const_bitcast(llval, flat_llty)
313+
};
314+
if llty.is_ptr() {
315+
self.const_as_cast(llval, llty.address_space())
316+
} else {
317+
llval
306318
}
307319
},
308320
Scalar::Ptr(ptr) => {
@@ -311,7 +323,8 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
311323
Some(AllocKind::Memory(alloc)) => {
312324
let init = const_alloc_to_llvm(self, alloc);
313325
if alloc.mutability == Mutability::Mutable {
314-
self.static_addr_of_mut(init, alloc.align, None)
326+
self.static_addr_of_mut(init, alloc.align, None,
327+
self.mutable_addr_space())
315328
} else {
316329
self.static_addr_of(init, alloc.align, None)
317330
}
@@ -330,6 +343,7 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
330343
&self.const_usize(ptr.offset.bytes()),
331344
1,
332345
) };
346+
let llval = self.const_flat_as_cast(llval);
333347
if layout.value != layout::Pointer {
334348
unsafe { llvm::LLVMConstPtrToInt(llval, llty) }
335349
} else {
@@ -367,6 +381,17 @@ pub fn val_ty(v: &'ll Value) -> &'ll Type {
367381
llvm::LLVMTypeOf(v)
368382
}
369383
}
384+
pub fn val_addr_space_opt(v: &'ll Value) -> Option<AddrSpaceIdx> {
385+
let ty = val_ty(v);
386+
if ty.kind() == TypeKind::Pointer {
387+
Some(ty.address_space())
388+
} else {
389+
None
390+
}
391+
}
392+
pub fn val_addr_space(v: &'ll Value) -> AddrSpaceIdx {
393+
val_addr_space_opt(v).unwrap_or_default()
394+
}
370395

371396
pub fn bytes_in_context(llcx: &'ll llvm::Context, bytes: &[u8]) -> &'ll Value {
372397
unsafe {

0 commit comments

Comments
 (0)