[llvm] 79606ee - [AMDGPU] Check atomics aliasing in the clobbering annotation

Stanislav Mekhanoshin via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 1 12:33:38 PST 2022


Author: Stanislav Mekhanoshin
Date: 2022-02-01T12:33:25-08:00
New Revision: 79606ee85c5384819e34f20c7ebd28d3f8ba306b

URL: https://github.com/llvm/llvm-project/commit/79606ee85c5384819e34f20c7ebd28d3f8ba306b
DIFF: https://github.com/llvm/llvm-project/commit/79606ee85c5384819e34f20c7ebd28d3f8ba306b.diff

LOG: [AMDGPU] Check atomics aliasing in the clobbering annotation

MemorySSA considers any atomic a def to any operation it dominates
just like a barrier or fence. That is correct from memory state
perspective, but not required for the no-clobber metadata since
we are not using it for reordering. Skip such atomics during the
scan just like a barrier if it does not alias with the load.

Differential Revision: https://reviews.llvm.org/D118661

Added: 
    

Modified: 
    llvm/lib/Target/AMDGPU/AMDGPUAnnotateUniformValues.cpp
    llvm/test/CodeGen/AMDGPU/noclobber-barrier.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/AMDGPU/AMDGPUAnnotateUniformValues.cpp b/llvm/lib/Target/AMDGPU/AMDGPUAnnotateUniformValues.cpp
index 2aec4584a9e5..bebf032b5535 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUAnnotateUniformValues.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUAnnotateUniformValues.cpp
@@ -15,6 +15,7 @@
 #include "AMDGPU.h"
 #include "Utils/AMDGPUBaseInfo.h"
 #include "llvm/ADT/SmallSet.h"
+#include "llvm/Analysis/AliasAnalysis.h"
 #include "llvm/Analysis/LegacyDivergenceAnalysis.h"
 #include "llvm/Analysis/MemorySSA.h"
 #include "llvm/IR/InstVisitor.h"
@@ -31,6 +32,7 @@ class AMDGPUAnnotateUniformValues : public FunctionPass,
                        public InstVisitor<AMDGPUAnnotateUniformValues> {
   LegacyDivergenceAnalysis *DA;
   MemorySSA *MSSA;
+  AliasAnalysis *AA;
   DenseMap<Value*, GetElementPtrInst*> noClobberClones;
   bool isEntryFunc;
 
@@ -46,6 +48,7 @@ class AMDGPUAnnotateUniformValues : public FunctionPass,
   void getAnalysisUsage(AnalysisUsage &AU) const override {
     AU.addRequired<LegacyDivergenceAnalysis>();
     AU.addRequired<MemorySSAWrapperPass>();
+    AU.addRequired<AAResultsWrapperPass>();
     AU.setPreservesAll();
  }
 
@@ -60,6 +63,7 @@ INITIALIZE_PASS_BEGIN(AMDGPUAnnotateUniformValues, DEBUG_TYPE,
                       "Add AMDGPU uniform metadata", false, false)
 INITIALIZE_PASS_DEPENDENCY(LegacyDivergenceAnalysis)
 INITIALIZE_PASS_DEPENDENCY(MemorySSAWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
 INITIALIZE_PASS_END(AMDGPUAnnotateUniformValues, DEBUG_TYPE,
                     "Add AMDGPU uniform metadata", false, false)
 
@@ -78,7 +82,7 @@ bool AMDGPUAnnotateUniformValues::isClobberedInFunction(LoadInst *Load) {
   SmallSet<MemoryAccess *, 8> Visited;
   MemoryLocation Loc(MemoryLocation::get(Load));
 
-  const auto isReallyAClobber = [](MemoryDef *Def) -> bool {
+  const auto isReallyAClobber = [this, Load](MemoryDef *Def) -> bool {
     Instruction *DefInst = Def->getMemoryInst();
     LLVM_DEBUG(dbgs() << "  Def: " << *DefInst << '\n');
 
@@ -95,6 +99,17 @@ bool AMDGPUAnnotateUniformValues::isClobberedInFunction(LoadInst *Load) {
       }
     }
 
+    // Ignore atomics not aliasing with the original load, any atomic is a
+    // universal MemoryDef from MSSA's point of view too, just like a fence.
+    const auto checkNoAlias = [this, Load](auto I) -> bool {
+      return I && AA->isNoAlias(I->getPointerOperand(),
+                                Load->getPointerOperand());
+    };
+
+    if (checkNoAlias(dyn_cast<AtomicCmpXchgInst>(DefInst)) ||
+        checkNoAlias(dyn_cast<AtomicRMWInst>(DefInst)))
+      return false;
+
     return true;
   };
 
@@ -197,6 +212,7 @@ bool AMDGPUAnnotateUniformValues::runOnFunction(Function &F) {
 
   DA = &getAnalysis<LegacyDivergenceAnalysis>();
   MSSA = &getAnalysis<MemorySSAWrapperPass>().getMSSA();
+  AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
   isEntryFunc = AMDGPU::isEntryFunctionCC(F.getCallingConv());
 
   visit(F);

diff  --git a/llvm/test/CodeGen/AMDGPU/noclobber-barrier.ll b/llvm/test/CodeGen/AMDGPU/noclobber-barrier.ll
index a80b0827a94b..8858bca2934a 100644
--- a/llvm/test/CodeGen/AMDGPU/noclobber-barrier.ll
+++ b/llvm/test/CodeGen/AMDGPU/noclobber-barrier.ll
@@ -434,5 +434,201 @@ entry:
   ret void
 }
 
+; GCN-LABEL: {{^}}no_alias_atomic_rmw_relaxed:
+; GCN: ds_add_u32
+; GCN: s_load_dword s
+; GCN-NOT: global_load_dword
+; GCN: global_store_dword
+define protected amdgpu_kernel void @no_alias_atomic_rmw_relaxed(i32 addrspace(1)* %in, i32 addrspace(1)* %out) {
+; CHECK-LABEL: @no_alias_atomic_rmw_relaxed(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[UNUSED:%.*]] = atomicrmw add i32 addrspace(3)* @LDS, i32 5 monotonic, align 4
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i32, i32 addrspace(1)* [[IN:%.*]], i64 0, !amdgpu.uniform !0, !amdgpu.noclobber !0
+; CHECK-NEXT:    [[LD:%.*]] = load i32, i32 addrspace(1)* [[GEP]], align 4
+; CHECK-NEXT:    store i32 [[LD]], i32 addrspace(1)* [[OUT:%.*]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %unused = atomicrmw add i32 addrspace(3)* @LDS, i32 5 monotonic
+  %gep = getelementptr inbounds i32, i32 addrspace(1)* %in, i64 0
+  %ld = load i32, i32 addrspace(1)* %gep, align 4
+  store i32 %ld, i32 addrspace(1)* %out, align 4
+  ret void
+}
+
+; GCN-LABEL: {{^}}no_alias_atomic_cmpxchg:
+; GCN: ds_cmpst_b32
+; GCN: s_load_dword s
+; GCN-NOT: global_load_dword
+; GCN: global_store_dword
+define protected amdgpu_kernel void @no_alias_atomic_cmpxchg(i32 addrspace(1)* %in, i32 addrspace(1)* %out, i32 %swap) {
+; CHECK-LABEL: @no_alias_atomic_cmpxchg(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[UNUSED:%.*]] = cmpxchg i32 addrspace(3)* @LDS, i32 7, i32 [[SWAP:%.*]] seq_cst monotonic, align 4
+; CHECK-NEXT:    fence syncscope("workgroup") release
+; CHECK-NEXT:    tail call void @llvm.amdgcn.s.barrier()
+; CHECK-NEXT:    fence syncscope("workgroup") acquire
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i32, i32 addrspace(1)* [[IN:%.*]], i64 0, !amdgpu.uniform !0, !amdgpu.noclobber !0
+; CHECK-NEXT:    [[LD:%.*]] = load i32, i32 addrspace(1)* [[GEP]], align 4
+; CHECK-NEXT:    store i32 [[LD]], i32 addrspace(1)* [[OUT:%.*]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %unused = cmpxchg i32 addrspace(3)* @LDS, i32 7, i32 %swap seq_cst monotonic
+  fence syncscope("workgroup") release
+  tail call void @llvm.amdgcn.s.barrier()
+  fence syncscope("workgroup") acquire
+  %gep = getelementptr inbounds i32, i32 addrspace(1)* %in, i64 0
+  %ld = load i32, i32 addrspace(1)* %gep, align 4
+  store i32 %ld, i32 addrspace(1)* %out, align 4
+  ret void
+}
+
+; GCN-LABEL: {{^}}no_alias_atomic_rmw:
+; GCN: ds_add_u32
+; GCN: s_load_dword s
+; GCN-NOT: global_load_dword
+; GCN: global_store_dword
+define protected amdgpu_kernel void @no_alias_atomic_rmw(i32 addrspace(1)* %in, i32 addrspace(1)* %out) {
+; CHECK-LABEL: @no_alias_atomic_rmw(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[UNUSED:%.*]] = atomicrmw add i32 addrspace(3)* @LDS, i32 5 seq_cst, align 4
+; CHECK-NEXT:    fence syncscope("workgroup") release
+; CHECK-NEXT:    tail call void @llvm.amdgcn.s.barrier()
+; CHECK-NEXT:    fence syncscope("workgroup") acquire
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i32, i32 addrspace(1)* [[IN:%.*]], i64 0, !amdgpu.uniform !0, !amdgpu.noclobber !0
+; CHECK-NEXT:    [[LD:%.*]] = load i32, i32 addrspace(1)* [[GEP]], align 4
+; CHECK-NEXT:    store i32 [[LD]], i32 addrspace(1)* [[OUT:%.*]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %unused = atomicrmw add i32 addrspace(3)* @LDS, i32 5 seq_cst
+  fence syncscope("workgroup") release
+  tail call void @llvm.amdgcn.s.barrier()
+  fence syncscope("workgroup") acquire
+  %gep = getelementptr inbounds i32, i32 addrspace(1)* %in, i64 0
+  %ld = load i32, i32 addrspace(1)* %gep, align 4
+  store i32 %ld, i32 addrspace(1)* %out, align 4
+  ret void
+}
+
+; GCN-LABEL: {{^}}may_alias_atomic_cmpxchg:
+; GCN: global_atomic_cmpswap
+; GCN: global_load_dword
+; GCN: global_store_dword
+define protected amdgpu_kernel void @may_alias_atomic_cmpxchg(i32 addrspace(1)* %in, i32 addrspace(1)* %out, i32 %swap) {
+; CHECK-LABEL: @may_alias_atomic_cmpxchg(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[UNUSED:%.*]] = cmpxchg i32 addrspace(1)* [[OUT:%.*]], i32 7, i32 [[SWAP:%.*]] seq_cst monotonic, align 4
+; CHECK-NEXT:    fence syncscope("workgroup") release
+; CHECK-NEXT:    tail call void @llvm.amdgcn.s.barrier()
+; CHECK-NEXT:    fence syncscope("workgroup") acquire
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i32, i32 addrspace(1)* [[IN:%.*]], i64 0, !amdgpu.uniform !0
+; CHECK-NEXT:    [[LD:%.*]] = load i32, i32 addrspace(1)* [[GEP]], align 4
+; CHECK-NEXT:    store i32 [[LD]], i32 addrspace(1)* [[OUT]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %unused = cmpxchg i32 addrspace(1)* %out, i32 7, i32 %swap seq_cst monotonic
+  fence syncscope("workgroup") release
+  tail call void @llvm.amdgcn.s.barrier()
+  fence syncscope("workgroup") acquire
+  %gep = getelementptr inbounds i32, i32 addrspace(1)* %in, i64 0
+  %ld = load i32, i32 addrspace(1)* %gep, align 4
+  store i32 %ld, i32 addrspace(1)* %out, align 4
+  ret void
+}
+
+; GCN-LABEL: {{^}}may_alias_atomic_rmw:
+; GCN: global_atomic_add
+; GCN: global_load_dword
+; GCN: global_store_dword
+define protected amdgpu_kernel void @may_alias_atomic_rmw(i32 addrspace(1)* %in, i32 addrspace(1)* %out) {
+; CHECK-LABEL: @may_alias_atomic_rmw(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[UNUSED:%.*]] = atomicrmw add i32 addrspace(1)* [[OUT:%.*]], i32 5 seq_cst, align 4
+; CHECK-NEXT:    fence syncscope("workgroup") release
+; CHECK-NEXT:    tail call void @llvm.amdgcn.s.barrier()
+; CHECK-NEXT:    fence syncscope("workgroup") acquire
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i32, i32 addrspace(1)* [[IN:%.*]], i64 0, !amdgpu.uniform !0
+; CHECK-NEXT:    [[LD:%.*]] = load i32, i32 addrspace(1)* [[GEP]], align 4
+; CHECK-NEXT:    store i32 [[LD]], i32 addrspace(1)* [[OUT]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %unused = atomicrmw add i32 addrspace(1)* %out, i32 5 seq_cst
+  fence syncscope("workgroup") release
+  tail call void @llvm.amdgcn.s.barrier()
+  fence syncscope("workgroup") acquire
+  %gep = getelementptr inbounds i32, i32 addrspace(1)* %in, i64 0
+  %ld = load i32, i32 addrspace(1)* %gep, align 4
+  store i32 %ld, i32 addrspace(1)* %out, align 4
+  ret void
+}
+
+; GCN-LABEL: {{^}}no_alias_atomic_rmw_then_clobber:
+; CGN: global_store_dword
+; CGN: global_store_dword
+; GCN: ds_add_u32
+; GCN: global_load_dword
+; GCN: global_store_dword
+define protected amdgpu_kernel void @no_alias_atomic_rmw_then_clobber(i32 addrspace(1)* %in, i32 addrspace(1)* %out, i32 addrspace(1)* noalias %noalias) {
+; CHECK-LABEL: @no_alias_atomic_rmw_then_clobber(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    store i32 1, i32 addrspace(1)* [[OUT:%.*]], align 4
+; CHECK-NEXT:    store i32 2, i32 addrspace(1)* [[NOALIAS:%.*]], align 4
+; CHECK-NEXT:    [[UNUSED:%.*]] = atomicrmw add i32 addrspace(3)* @LDS, i32 5 seq_cst, align 4
+; CHECK-NEXT:    fence syncscope("workgroup") release
+; CHECK-NEXT:    tail call void @llvm.amdgcn.s.barrier()
+; CHECK-NEXT:    fence syncscope("workgroup") acquire
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i32, i32 addrspace(1)* [[IN:%.*]], i64 0, !amdgpu.uniform !0
+; CHECK-NEXT:    [[LD:%.*]] = load i32, i32 addrspace(1)* [[GEP]], align 4
+; CHECK-NEXT:    store i32 [[LD]], i32 addrspace(1)* [[OUT]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  store i32 1, i32 addrspace(1)* %out, align 4
+  store i32 2, i32 addrspace(1)* %noalias, align 4
+  %unused = atomicrmw add i32 addrspace(3)* @LDS, i32 5 seq_cst
+  fence syncscope("workgroup") release
+  tail call void @llvm.amdgcn.s.barrier()
+  fence syncscope("workgroup") acquire
+  %gep = getelementptr inbounds i32, i32 addrspace(1)* %in, i64 0
+  %ld = load i32, i32 addrspace(1)* %gep, align 4
+  store i32 %ld, i32 addrspace(1)* %out, align 4
+  ret void
+}
+
+; GCN-LABEL: {{^}}no_alias_atomic_rmw_then_no_alias_store:
+; CGN: global_store_dword
+; GCN: ds_add_u32
+; GCN: s_load_dword s
+; GCN-NOT: global_load_dword
+; GCN: global_store_dword
+define protected amdgpu_kernel void @no_alias_atomic_rmw_then_no_alias_store(i32 addrspace(1)* %in, i32 addrspace(1)* %out, i32 addrspace(1)* noalias %noalias) {
+; CHECK-LABEL: @no_alias_atomic_rmw_then_no_alias_store(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    store i32 2, i32 addrspace(1)* [[NOALIAS:%.*]], align 4
+; CHECK-NEXT:    [[UNUSED:%.*]] = atomicrmw add i32 addrspace(3)* @LDS, i32 5 seq_cst, align 4
+; CHECK-NEXT:    fence syncscope("workgroup") release
+; CHECK-NEXT:    tail call void @llvm.amdgcn.s.barrier()
+; CHECK-NEXT:    fence syncscope("workgroup") acquire
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i32, i32 addrspace(1)* [[IN:%.*]], i64 0, !amdgpu.uniform !0, !amdgpu.noclobber !0
+; CHECK-NEXT:    [[LD:%.*]] = load i32, i32 addrspace(1)* [[GEP]], align 4
+; CHECK-NEXT:    store i32 [[LD]], i32 addrspace(1)* [[OUT:%.*]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  store i32 2, i32 addrspace(1)* %noalias, align 4
+  %unused = atomicrmw add i32 addrspace(3)* @LDS, i32 5 seq_cst
+  fence syncscope("workgroup") release
+  tail call void @llvm.amdgcn.s.barrier()
+  fence syncscope("workgroup") acquire
+  %gep = getelementptr inbounds i32, i32 addrspace(1)* %in, i64 0
+  %ld = load i32, i32 addrspace(1)* %gep, align 4
+  store i32 %ld, i32 addrspace(1)* %out, align 4
+  ret void
+}
+
 declare void @llvm.amdgcn.s.barrier()
 declare void @llvm.amdgcn.wave.barrier()


        


More information about the llvm-commits mailing list