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