1 //===-- AMDGPULowerIntrinsics.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 "AMDGPU.h"
10 #include "AMDGPUSubtarget.h"
11 #include "llvm/CodeGen/TargetPassConfig.h"
12 #include "llvm/Analysis/TargetTransformInfo.h"
13 #include "llvm/IR/Constants.h"
14 #include "llvm/IR/Instructions.h"
15 #include "llvm/IR/IntrinsicInst.h"
16 #include "llvm/IR/Module.h"
17 #include "llvm/Transforms/Utils/LowerMemIntrinsics.h"
18 
19 #define DEBUG_TYPE "amdgpu-lower-intrinsics"
20 
21 using namespace llvm;
22 
23 namespace {
24 
25 const unsigned MaxStaticSize = 1024;
26 
27 class AMDGPULowerIntrinsics : public ModulePass {
28 private:
29   bool makeLIDRangeMetadata(Function &F) const;
30 
31 public:
32   static char ID;
33 
AMDGPULowerIntrinsics()34   AMDGPULowerIntrinsics() : ModulePass(ID) {}
35 
36   bool runOnModule(Module &M) override;
37   bool expandMemIntrinsicUses(Function &F);
getPassName() const38   StringRef getPassName() const override {
39     return "AMDGPU Lower Intrinsics";
40   }
41 
getAnalysisUsage(AnalysisUsage & AU) const42   void getAnalysisUsage(AnalysisUsage &AU) const override {
43     AU.addRequired<TargetTransformInfoWrapperPass>();
44   }
45 };
46 
47 }
48 
49 char AMDGPULowerIntrinsics::ID = 0;
50 
51 char &llvm::AMDGPULowerIntrinsicsID = AMDGPULowerIntrinsics::ID;
52 
53 INITIALIZE_PASS(AMDGPULowerIntrinsics, DEBUG_TYPE, "Lower intrinsics", false,
54                 false)
55 
56 // TODO: Should refine based on estimated number of accesses (e.g. does it
57 // require splitting based on alignment)
shouldExpandOperationWithSize(Value * Size)58 static bool shouldExpandOperationWithSize(Value *Size) {
59   ConstantInt *CI = dyn_cast<ConstantInt>(Size);
60   return !CI || (CI->getZExtValue() > MaxStaticSize);
61 }
62 
expandMemIntrinsicUses(Function & F)63 bool AMDGPULowerIntrinsics::expandMemIntrinsicUses(Function &F) {
64   Intrinsic::ID ID = F.getIntrinsicID();
65   bool Changed = false;
66 
67   for (auto I = F.user_begin(), E = F.user_end(); I != E;) {
68     Instruction *Inst = cast<Instruction>(*I);
69     ++I;
70 
71     switch (ID) {
72     case Intrinsic::memcpy: {
73       auto *Memcpy = cast<MemCpyInst>(Inst);
74       if (shouldExpandOperationWithSize(Memcpy->getLength())) {
75         Function *ParentFunc = Memcpy->getParent()->getParent();
76         const TargetTransformInfo &TTI =
77             getAnalysis<TargetTransformInfoWrapperPass>().getTTI(*ParentFunc);
78         expandMemCpyAsLoop(Memcpy, TTI);
79         Changed = true;
80         Memcpy->eraseFromParent();
81       }
82 
83       break;
84     }
85     case Intrinsic::memmove: {
86       auto *Memmove = cast<MemMoveInst>(Inst);
87       if (shouldExpandOperationWithSize(Memmove->getLength())) {
88         expandMemMoveAsLoop(Memmove);
89         Changed = true;
90         Memmove->eraseFromParent();
91       }
92 
93       break;
94     }
95     case Intrinsic::memset: {
96       auto *Memset = cast<MemSetInst>(Inst);
97       if (shouldExpandOperationWithSize(Memset->getLength())) {
98         expandMemSetAsLoop(Memset);
99         Changed = true;
100         Memset->eraseFromParent();
101       }
102 
103       break;
104     }
105     default:
106       break;
107     }
108   }
109 
110   return Changed;
111 }
112 
makeLIDRangeMetadata(Function & F) const113 bool AMDGPULowerIntrinsics::makeLIDRangeMetadata(Function &F) const {
114   auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
115   if (!TPC)
116     return false;
117 
118   const TargetMachine &TM = TPC->getTM<TargetMachine>();
119   bool Changed = false;
120 
121   for (auto *U : F.users()) {
122     auto *CI = dyn_cast<CallInst>(U);
123     if (!CI)
124       continue;
125 
126     Changed |= AMDGPUSubtarget::get(TM, F).makeLIDRangeMetadata(CI);
127   }
128   return Changed;
129 }
130 
runOnModule(Module & M)131 bool AMDGPULowerIntrinsics::runOnModule(Module &M) {
132   bool Changed = false;
133 
134   for (Function &F : M) {
135     if (!F.isDeclaration())
136       continue;
137 
138     switch (F.getIntrinsicID()) {
139     case Intrinsic::memcpy:
140     case Intrinsic::memmove:
141     case Intrinsic::memset:
142       if (expandMemIntrinsicUses(F))
143         Changed = true;
144       break;
145 
146     case Intrinsic::amdgcn_workitem_id_x:
147     case Intrinsic::r600_read_tidig_x:
148     case Intrinsic::amdgcn_workitem_id_y:
149     case Intrinsic::r600_read_tidig_y:
150     case Intrinsic::amdgcn_workitem_id_z:
151     case Intrinsic::r600_read_tidig_z:
152     case Intrinsic::r600_read_local_size_x:
153     case Intrinsic::r600_read_local_size_y:
154     case Intrinsic::r600_read_local_size_z:
155       Changed |= makeLIDRangeMetadata(F);
156       break;
157 
158     default:
159       break;
160     }
161   }
162 
163   return Changed;
164 }
165 
createAMDGPULowerIntrinsicsPass()166 ModulePass *llvm::createAMDGPULowerIntrinsicsPass() {
167   return new AMDGPULowerIntrinsics();
168 }
169