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