1 //===-- AMDGPUMemoryUtils.cpp - -------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "AMDGPUMemoryUtils.h"
10 #include "AMDGPU.h"
11 #include "llvm/ADT/SmallSet.h"
12 #include "llvm/Analysis/AliasAnalysis.h"
13 #include "llvm/Analysis/MemorySSA.h"
14 #include "llvm/IR/Instructions.h"
15 #include "llvm/IR/IntrinsicsAMDGPU.h"
16 #include "llvm/IR/IntrinsicInst.h"
17 
18 #define DEBUG_TYPE "amdgpu-memory-utils"
19 
20 using namespace llvm;
21 
22 namespace llvm {
23 
24 namespace AMDGPU {
25 
26 bool isReallyAClobber(const Value *Ptr, MemoryDef *Def, AAResults *AA) {
27   Instruction *DefInst = Def->getMemoryInst();
28 
29   if (isa<FenceInst>(DefInst))
30     return false;
31 
32   if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(DefInst)) {
33     switch (II->getIntrinsicID()) {
34     case Intrinsic::amdgcn_s_barrier:
35     case Intrinsic::amdgcn_wave_barrier:
36       return false;
37     default:
38       break;
39     }
40   }
41 
42   // Ignore atomics not aliasing with the original load, any atomic is a
43   // universal MemoryDef from MSSA's point of view too, just like a fence.
44   const auto checkNoAlias = [AA, Ptr](auto I) -> bool {
45     return I && AA->isNoAlias(I->getPointerOperand(), Ptr);
46   };
47 
48   if (checkNoAlias(dyn_cast<AtomicCmpXchgInst>(DefInst)) ||
49       checkNoAlias(dyn_cast<AtomicRMWInst>(DefInst)))
50     return false;
51 
52   return true;
53 }
54 
55 bool isClobberedInFunction(const LoadInst *Load, MemorySSA *MSSA,
56                            AAResults *AA) {
57   MemorySSAWalker *Walker = MSSA->getWalker();
58   SmallVector<MemoryAccess *> WorkList{Walker->getClobberingMemoryAccess(Load)};
59   SmallSet<MemoryAccess *, 8> Visited;
60   MemoryLocation Loc(MemoryLocation::get(Load));
61 
62   LLVM_DEBUG(dbgs() << "Checking clobbering of: " << *Load << '\n');
63 
64   // Start with a nearest dominating clobbering access, it will be either
65   // live on entry (nothing to do, load is not clobbered), MemoryDef, or
66   // MemoryPhi if several MemoryDefs can define this memory state. In that
67   // case add all Defs to WorkList and continue going up and checking all
68   // the definitions of this memory location until the root. When all the
69   // defs are exhausted and came to the entry state we have no clobber.
70   // Along the scan ignore barriers and fences which are considered clobbers
71   // by the MemorySSA, but not really writing anything into the memory.
72   while (!WorkList.empty()) {
73     MemoryAccess *MA = WorkList.pop_back_val();
74     if (!Visited.insert(MA).second)
75       continue;
76 
77     if (MSSA->isLiveOnEntryDef(MA))
78       continue;
79 
80     if (MemoryDef *Def = dyn_cast<MemoryDef>(MA)) {
81       LLVM_DEBUG(dbgs() << "  Def: " << *Def->getMemoryInst() << '\n');
82 
83       if (isReallyAClobber(Load->getPointerOperand(), Def, AA)) {
84         LLVM_DEBUG(dbgs() << "      -> load is clobbered\n");
85         return true;
86       }
87 
88       WorkList.push_back(
89           Walker->getClobberingMemoryAccess(Def->getDefiningAccess(), Loc));
90       continue;
91     }
92 
93     const MemoryPhi *Phi = cast<MemoryPhi>(MA);
94     for (auto &Use : Phi->incoming_values())
95       WorkList.push_back(cast<MemoryAccess>(&Use));
96   }
97 
98   LLVM_DEBUG(dbgs() << "      -> no clobber\n");
99   return false;
100 }
101 
102 } // end namespace AMDGPU
103 
104 } // end namespace llvm
105