diff --git a/llvm/include/llvm/Support/AMDGPUAddrSpace.h b/llvm/include/llvm/Support/AMDGPUAddrSpace.h index 4a278d0acc23b8..a7533b99a84414 100644 --- a/llvm/include/llvm/Support/AMDGPUAddrSpace.h +++ b/llvm/include/llvm/Support/AMDGPUAddrSpace.h @@ -93,6 +93,33 @@ inline bool isExtendedGlobalAddrSpace(unsigned AS) { AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT || AS > AMDGPUAS::MAX_AMDGPU_ADDRESS; } + +inline bool isConstantAddressSpace(unsigned AS) { + switch (AS) { + using namespace AMDGPUAS; + case CONSTANT_ADDRESS: + case CONSTANT_ADDRESS_32BIT: + case CONSTANT_BUFFER_0: + case CONSTANT_BUFFER_1: + case CONSTANT_BUFFER_2: + case CONSTANT_BUFFER_3: + case CONSTANT_BUFFER_4: + case CONSTANT_BUFFER_5: + case CONSTANT_BUFFER_6: + case CONSTANT_BUFFER_7: + case CONSTANT_BUFFER_8: + case CONSTANT_BUFFER_9: + case CONSTANT_BUFFER_10: + case CONSTANT_BUFFER_11: + case CONSTANT_BUFFER_12: + case CONSTANT_BUFFER_13: + case CONSTANT_BUFFER_14: + case CONSTANT_BUFFER_15: + return true; + default: + return false; + } +} } // end namespace AMDGPU } // end namespace llvm diff --git a/llvm/lib/Analysis/Lint.cpp b/llvm/lib/Analysis/Lint.cpp index e0a029802bbd9a..4689451243cd96 100644 --- a/llvm/lib/Analysis/Lint.cpp +++ b/llvm/lib/Analysis/Lint.cpp @@ -67,6 +67,7 @@ #include "llvm/IR/PassManager.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" +#include "llvm/Support/AMDGPUAddrSpace.h" #include "llvm/Support/Casting.h" #include "llvm/Support/KnownBits.h" #include "llvm/Support/raw_ostream.h" @@ -102,6 +103,8 @@ class Lint : public InstVisitor { void visitReturnInst(ReturnInst &I); void visitLoadInst(LoadInst &I); void visitStoreInst(StoreInst &I); + void visitAtomicCmpXchgInst(AtomicCmpXchgInst &I); + void visitAtomicRMWInst(AtomicRMWInst &I); void visitXor(BinaryOperator &I); void visitSub(BinaryOperator &I); void visitLShr(BinaryOperator &I); @@ -124,6 +127,7 @@ class Lint : public InstVisitor { public: Module *Mod; + Triple TT; const DataLayout *DL; AliasAnalysis *AA; AssumptionCache *AC; @@ -135,8 +139,8 @@ class Lint : public InstVisitor { Lint(Module *Mod, const DataLayout *DL, AliasAnalysis *AA, AssumptionCache *AC, DominatorTree *DT, TargetLibraryInfo *TLI) - : Mod(Mod), DL(DL), AA(AA), AC(AC), DT(DT), TLI(TLI), - MessagesStr(Messages) {} + : Mod(Mod), TT(Triple::normalize(Mod->getTargetTriple())), DL(DL), AA(AA), + AC(AC), DT(DT), TLI(TLI), MessagesStr(Messages) {} void WriteValues(ArrayRef Vs) { for (const Value *V : Vs) { @@ -401,6 +405,11 @@ void Lint::visitMemoryReference(Instruction &I, const MemoryLocation &Loc, "Unusual: Address one pointer dereference", &I); if (Flags & MemRef::Write) { + if (TT.isAMDGPU()) + Check(!AMDGPU::isConstantAddressSpace( + UnderlyingObject->getType()->getPointerAddressSpace()), + "Undefined behavior: Write to memory in const addrspace", &I); + if (const GlobalVariable *GV = dyn_cast(UnderlyingObject)) Check(!GV->isConstant(), "Undefined behavior: Write to read-only memory", &I); @@ -480,6 +489,16 @@ void Lint::visitStoreInst(StoreInst &I) { I.getOperand(0)->getType(), MemRef::Write); } +void Lint::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) { + visitMemoryReference(I, MemoryLocation::get(&I), I.getAlign(), + I.getOperand(0)->getType(), MemRef::Write); +} + +void Lint::visitAtomicRMWInst(AtomicRMWInst &I) { + visitMemoryReference(I, MemoryLocation::get(&I), I.getAlign(), + I.getOperand(0)->getType(), MemRef::Write); +} + void Lint::visitXor(BinaryOperator &I) { Check(!isa(I.getOperand(0)) || !isa(I.getOperand(1)), "Undefined result: xor(undef, undef)", &I); diff --git a/llvm/test/Analysis/Lint/const-store.ll b/llvm/test/Analysis/Lint/const-store.ll new file mode 100644 index 00000000000000..030a0be3aecc2a --- /dev/null +++ b/llvm/test/Analysis/Lint/const-store.ll @@ -0,0 +1,49 @@ +; RUN: not opt --mtriple=amdgcn --passes=lint --lint-abort-on-error %s -disable-output 2>&1 | FileCheck %s +; RUN: opt --mtriple=amdgcn --mcpu=gfx1030 --passes=lint %s -disable-output 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK0 +; RUN: opt --mtriple=x86_64 --passes=lint --lint-abort-on-error %s -disable-output 2>&1 | FileCheck %s --allow-empty --check-prefix=NOERR +; NOERR: {{^$}} + +define amdgpu_kernel void @store_const(ptr addrspace(4) %out, i32 %a, i32 %b) { +; CHECK: Undefined behavior: Write to memory in const addrspace +; CHECK-NEXT: store i32 %r, ptr addrspace(4) %out + %r = add i32 %a, %b + store i32 %r, ptr addrspace(4) %out + ret void +} + +declare void @llvm.memset.p4.i64(ptr addrspace(4) noalias nocapture writeonly, i8, i64, i1) +define amdgpu_kernel void @memset_const(ptr addrspace(4) %dst) { +; CHECK0: Undefined behavior: Write to memory in const addrspace +; CHECK0-NEXT: call void @llvm.memset.p4.i64(ptr addrspace(4) %dst, i8 0, i64 256, i1 false) + call void @llvm.memset.p4.i64(ptr addrspace(4) %dst, i8 0, i64 256, i1 false) + ret void +} + +declare void @llvm.memcpy.p6.p0.i32(ptr addrspace(6) noalias nocapture writeonly, ptr noalias nocapture readonly, i32, i1) +define amdgpu_kernel void @memcpy_to_const(ptr addrspace(6) %dst, ptr %src) { +; CHECK0: Undefined behavior: Write to memory in const addrspace +; CHECK0-NEXT: call void @llvm.memcpy.p6.p0.i32(ptr addrspace(6) %dst, ptr %src, i32 256, i1 false) + call void @llvm.memcpy.p6.p0.i32(ptr addrspace(6) %dst, ptr %src, i32 256, i1 false) + ret void +} + +define amdgpu_kernel void @cmpxchg_to_const(ptr addrspace(4) %dst, i32 %src) { +; CHECK0: Undefined behavior: Write to memory in const addrspace +; CHECK0-NEXT: %void = cmpxchg ptr addrspace(4) %dst, i32 0, i32 %src seq_cst monotonic + %void = cmpxchg ptr addrspace(4) %dst, i32 0, i32 %src seq_cst monotonic + ret void +} + +define amdgpu_kernel void @atomicrmw_to_const(ptr addrspace(4) %dst, i32 %src) { +; CHECK0: Undefined behavior: Write to memory in const addrspace +; CHECK0-NEXT: %void = atomicrmw add ptr addrspace(4) %dst, i32 %src acquire + %void = atomicrmw add ptr addrspace(4) %dst, i32 %src acquire + ret void +} + +declare void @const_param(ptr addrspace(6)) +define amdgpu_kernel void @call_with_const(ptr addrspace(6) %dst) { +; CHECK0-NOT: call void @const_param(ptr addrspace(6) %dst) + call void @const_param(ptr addrspace(6) %dst) + ret void +}