Skip to content

Commit eed781a

Browse files
committed
Fully working atomics with opaque pointers
1 parent 48bb9e6 commit eed781a

File tree

1 file changed

+28
-23
lines changed

1 file changed

+28
-23
lines changed

crates/rustc_codegen_nvvm/src/builder.rs

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,6 @@ impl<'ll, 'tcx, 'a> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
232232
// Get the return type.
233233
let sig = llvm::LLVMGetElementType(self.val_ty(self.llfn()));
234234
let return_ty = llvm::LLVMGetReturnType(sig);
235-
;
236235
// Check if new_ty & return_ty are different pointers.
237236
// FIXME: get rid of this nonsense once we are past LLVM 7 and don't have
238237
// to suffer from typed pointers.
@@ -1195,13 +1194,15 @@ impl<'ll, 'tcx, 'a> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
11951194
);
11961195
}
11971196
};
1198-
let tuple = self.type_struct(&[self.val_ty(src),self.type_i1()], false);
1197+
let tuple = self.type_struct(&[self.val_ty(src), self.type_i1()], false);
11991198
let res = self.atomic_op(
12001199
dst,
12011200
tuple,
1202-
|builder, dst,ty| {
1203-
builder.abort();
1204-
return builder.const_undef(ty);
1201+
|builder, dst, ty| {
1202+
let address_space =
1203+
unsafe { llvm::LLVMGetPointerAddressSpace(builder.val_ty(dst)) };
1204+
let dst_ty = unsafe { llvm::LLVMPointerType(builder.val_ty(cmp), address_space) };
1205+
let dst = builder.pointercast(dst, dst_ty);
12051206
// We are in a supported address space - just use ordinary atomics
12061207
unsafe {
12071208
llvm::LLVMRustBuildAtomicCmpXchg(
@@ -1215,7 +1216,13 @@ impl<'ll, 'tcx, 'a> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
12151216
)
12161217
}
12171218
},
1218-
|builder, dst,ty| {
1219+
|builder, dst, ty| {
1220+
let dst = builder.pointercast(dst, unsafe {
1221+
llvm::LLVMPointerType(
1222+
builder.val_ty(cmp),
1223+
llvm::LLVMGetPointerAddressSpace(builder.val_ty(dst)),
1224+
)
1225+
});
12191226
// Local space is only accessible to the current thread.
12201227
// So, there are no synchronization issues, and we can emulate it using a simple load / compare / store.
12211228
let load: &'ll Value =
@@ -1253,12 +1260,12 @@ impl<'ll, 'tcx, 'a> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
12531260
self.atomic_op(
12541261
dst,
12551262
self.val_ty(src),
1256-
|builder, dst,ty| {
1263+
|builder, dst, ty| {
12571264
// We are in a supported address space - just use ordinary atomics
1258-
let address_space = unsafe { llvm::LLVMGetPointerAddressSpace(builder.val_ty(dst)) };
1265+
let address_space =
1266+
unsafe { llvm::LLVMGetPointerAddressSpace(builder.val_ty(dst)) };
12591267
let dst_ty = unsafe { llvm::LLVMPointerType(ty, address_space) };
1260-
let dst = builder.pointercast(dst,dst_ty);
1261-
let src = if matches!(op, AtomicRmwBinOp::AtomicXchg) {builder.pointercast(src,dst_ty)} else {src};
1268+
let dst = builder.pointercast(dst, dst_ty);
12621269
unsafe {
12631270
llvm::LLVMBuildAtomicRMW(
12641271
builder.llbuilder,
@@ -1270,9 +1277,13 @@ impl<'ll, 'tcx, 'a> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
12701277
)
12711278
}
12721279
},
1273-
|builder, dst,ty| {
1280+
|builder, dst, ty| {
12741281
// Local space is only accessible to the current thread.
12751282
// So, there are no synchronization issues, and we can emulate it using a simple load / compare / store.
1283+
let dst = builder.pointercast(dst, unsafe {
1284+
llvm::LLVMPointerType(ty, llvm::LLVMGetPointerAddressSpace(builder.val_ty(dst)))
1285+
});
1286+
12761287
let load: &'ll Value =
12771288
unsafe { llvm::LLVMBuildLoad(builder.llbuilder, dst, UNNAMED) };
12781289
let next_val = match op {
@@ -1352,13 +1363,13 @@ impl<'ll, 'tcx, 'a> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
13521363
let mut call = unsafe {
13531364
let llfn = if self.cx.type_kind(llty) == TypeKind::Pointer {
13541365
self.pointercast(llfn, llty)
1355-
} else if self.cx.type_kind(self.val_ty(llfn)) == TypeKind::Pointer {
1366+
} else if self.cx.type_kind(self.val_ty(llfn)) == TypeKind::Pointer {
13561367
let target_fnptr = llvm::LLVMPointerType(llty, 0);
13571368
self.pointercast(llfn, target_fnptr)
13581369
} else {
13591370
llfn
13601371
};
1361-
1372+
13621373
llvm::LLVMRustBuildCall(
13631374
self.llbuilder,
13641375
llfn,
@@ -1794,16 +1805,10 @@ impl<'ll, 'tcx, 'a> Builder<'a, 'll, 'tcx> {
17941805
fn atomic_op(
17951806
&mut self,
17961807
dst: &'ll Value,
1797-
ty:&'ll Type,
1798-
atomic_supported: impl FnOnce(&mut Builder<'a, 'll, 'tcx>, &'ll Value,&'ll Type) -> &'ll Value,
1799-
emulate_local: impl FnOnce(&mut Builder<'a, 'll, 'tcx>, &'ll Value,&'ll Type) -> &'ll Value,
1808+
ty: &'ll Type,
1809+
atomic_supported: impl FnOnce(&mut Builder<'a, 'll, 'tcx>, &'ll Value, &'ll Type) -> &'ll Value,
1810+
emulate_local: impl FnOnce(&mut Builder<'a, 'll, 'tcx>, &'ll Value, &'ll Type) -> &'ll Value,
18001811
) -> &'ll Value {
1801-
1802-
let emulate_local = |builder:&mut Self,_,_|{
1803-
// ATOMICS don't work with untyped pointers *YET*.
1804-
builder.abort();
1805-
builder.const_undef(ty)
1806-
};
18071812
// (FractalFir) Atomics in CUDA have some limitations, and we have to work around them.
18081813
// For example, they are restricted in what address space they operate on.
18091814
// CUDA has 4 address spaces(and a generic one, which is an union of all of those).
@@ -1873,7 +1878,7 @@ impl<'ll, 'tcx, 'a> Builder<'a, 'll, 'tcx> {
18731878
self.cond_br(isspacep_local, local_bb, atomic_ub_bb);
18741879
// The pointer is in the thread(local) space.
18751880
self.switch_to_block(local_bb);
1876-
let local_res = emulate_local(self, dst,ty);
1881+
let local_res = emulate_local(self, dst, ty);
18771882
self.br(merge_bb);
18781883
// The pointer is neither in the supported address space, nor the local space.
18791884
// This is very likely UB. So, we trap here.

0 commit comments

Comments
 (0)