aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/CodeGen/CodeGenPrepare.cpp
diff options
context:
space:
mode:
authorTim Besard <tim@juliacomputing.com>2022-07-16 10:34:42 -0400
committerMatt Arsenault <Matthew.Arsenault@amd.com>2022-07-16 10:56:42 -0400
commita323dfc0152a11c6934695b1ae67920dae9fad9b (patch)
treea51572db654f99736361887148f29d0501f6c63e /llvm/lib/CodeGen/CodeGenPrepare.cpp
parentdc681bc2e039679cd430b3247883c21cc5699cb3 (diff)
downloadllvm-a323dfc0152a11c6934695b1ae67920dae9fad9b.zip
llvm-a323dfc0152a11c6934695b1ae67920dae9fad9b.tar.gz
llvm-a323dfc0152a11c6934695b1ae67920dae9fad9b.tar.bz2
Don't sink ptrtoint/inttoptr sequences into non-noop addrspacecasts.
In https://reviews.llvm.org/D30114, support for mismatching address spaces was introduced to CodeGenPrepare's optimizeMemoryInst, using addrspacecast as it was argued that only no-op addrspacecasts would be considered when constructing the address mode. However, by doing inttoptr/ptrtoint, it's possible to get CGP to emit an addrspace that's not actually no-op, introducing a miscompilation: define void @kernel(i8* %julia_ptr) { %intptr = ptrtoint i8* %julia_ptr to i64 %ptr = inttoptr i64 %intptr to i32 addrspace(3)* br label %end end: store atomic i32 1, i32 addrspace(3)* %ptr unordered, align 4 ret void } Gets compiled to: define void @kernel(i8* %julia_ptr) { end: %0 = addrspacecast i8* %julia_ptr to i32 addrspace(3)* store atomic i32 1, i32 addrspace(3)* %0 unordered, align 4 ret void } In the case of NVPTX, this introduces a cvta.to.shared, whereas leaving out the %end block and branch doesn't trigger this optimization. This results in illegal memory accesses as seen in https://github.com/JuliaGPU/CUDA.jl/issues/558 In this change, I introduced a check before doing the pointer cast that verifies address spaces are the same. If not, it emits a ptrtoint/inttoptr combination to get a no-op cast between address spaces. I decided against disallowing ptrtoint/inttoptr with non-default AS in matchOperationAddr, because now its still possible to look through multiple sequences of them that ultimately do not result in a address space mismatch (i.e. the second lit test).
Diffstat (limited to 'llvm/lib/CodeGen/CodeGenPrepare.cpp')
-rw-r--r--llvm/lib/CodeGen/CodeGenPrepare.cpp36
1 files changed, 31 insertions, 5 deletions
diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp
index 6778af2..d80123c 100644
--- a/llvm/lib/CodeGen/CodeGenPrepare.cpp
+++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp
@@ -5227,18 +5227,31 @@ bool CodeGenPrepare::optimizeMemoryInst(Instruction *MemoryInst, Value *Addr,
WeakTrackingVH SunkAddrVH = SunkAddrs[Addr];
Value * SunkAddr = SunkAddrVH.pointsToAliveValue() ? SunkAddrVH : nullptr;
+ Type *IntPtrTy = DL->getIntPtrType(Addr->getType());
if (SunkAddr) {
LLVM_DEBUG(dbgs() << "CGP: Reusing nonlocal addrmode: " << AddrMode
<< " for " << *MemoryInst << "\n");
- if (SunkAddr->getType() != Addr->getType())
- SunkAddr = Builder.CreatePointerCast(SunkAddr, Addr->getType());
+ if (SunkAddr->getType() != Addr->getType()) {
+ if (SunkAddr->getType()->getPointerAddressSpace() !=
+ Addr->getType()->getPointerAddressSpace() &&
+ !DL->isNonIntegralPointerType(Addr->getType())) {
+ // There are two reasons the address spaces might not match: a no-op
+ // addrspacecast, or a ptrtoint/inttoptr pair. Either way, we emit a
+ // ptrtoint/inttoptr pair to ensure we match the original semantics.
+ // TODO: allow bitcast between different address space pointers with the
+ // same size.
+ SunkAddr = Builder.CreatePtrToInt(SunkAddr, IntPtrTy, "sunkaddr");
+ SunkAddr =
+ Builder.CreateIntToPtr(SunkAddr, Addr->getType(), "sunkaddr");
+ } else
+ SunkAddr = Builder.CreatePointerCast(SunkAddr, Addr->getType());
+ }
} else if (AddrSinkUsingGEPs || (!AddrSinkUsingGEPs.getNumOccurrences() &&
SubtargetInfo->addrSinkUsingGEPs())) {
// By default, we use the GEP-based method when AA is used later. This
// prevents new inttoptr/ptrtoint pairs from degrading AA capabilities.
LLVM_DEBUG(dbgs() << "CGP: SINKING nonlocal addrmode: " << AddrMode
<< " for " << *MemoryInst << "\n");
- Type *IntPtrTy = DL->getIntPtrType(Addr->getType());
Value *ResultPtr = nullptr, *ResultIndex = nullptr;
// First, find the pointer.
@@ -5361,8 +5374,21 @@ bool CodeGenPrepare::optimizeMemoryInst(Instruction *MemoryInst, Value *Addr,
AddrMode.InBounds);
}
- if (SunkAddr->getType() != Addr->getType())
- SunkAddr = Builder.CreatePointerCast(SunkAddr, Addr->getType());
+ if (SunkAddr->getType() != Addr->getType()) {
+ if (SunkAddr->getType()->getPointerAddressSpace() !=
+ Addr->getType()->getPointerAddressSpace() &&
+ !DL->isNonIntegralPointerType(Addr->getType())) {
+ // There are two reasons the address spaces might not match: a no-op
+ // addrspacecast, or a ptrtoint/inttoptr pair. Either way, we emit a
+ // ptrtoint/inttoptr pair to ensure we match the original semantics.
+ // TODO: allow bitcast between different address space pointers with
+ // the same size.
+ SunkAddr = Builder.CreatePtrToInt(SunkAddr, IntPtrTy, "sunkaddr");
+ SunkAddr =
+ Builder.CreateIntToPtr(SunkAddr, Addr->getType(), "sunkaddr");
+ } else
+ SunkAddr = Builder.CreatePointerCast(SunkAddr, Addr->getType());
+ }
}
} else {
// We'd require a ptrtoint/inttoptr down the line, which we can't do for