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 "llvm/IR/Constants.h"
12 #include "llvm/IR/Instructions.h"
13 #include "llvm/IR/IntrinsicInst.h"
14 #include "llvm/IR/Module.h"
15 #include "llvm/Transforms/Utils/LowerMemIntrinsics.h"
16 
17 #define DEBUG_TYPE "amdgpu-lower-intrinsics"
18 
19 using namespace llvm;
20 
21 namespace {
22 
23 const unsigned MaxStaticSize = 1024;
24 
25 class AMDGPULowerIntrinsics : public ModulePass {
26 public:
27   static char ID;
28 
29   AMDGPULowerIntrinsics() : ModulePass(ID) { }
30   bool runOnModule(Module &M) override;
31   StringRef getPassName() const override {
32     return "AMDGPU Lower Intrinsics";
33   }
34 };
35 
36 }
37 
38 char AMDGPULowerIntrinsics::ID = 0;
39 
40 char &llvm::AMDGPULowerIntrinsicsID = AMDGPULowerIntrinsics::ID;
41 
42 INITIALIZE_PASS(AMDGPULowerIntrinsics, DEBUG_TYPE,
43                 "Lower intrinsics", false, false)
44 
45 // TODO: Should refine based on estimated number of accesses (e.g. does it
46 // require splitting based on alignment)
47 static bool shouldExpandOperationWithSize(Value *Size) {
48   ConstantInt *CI = dyn_cast<ConstantInt>(Size);
49   return !CI || (CI->getZExtValue() > MaxStaticSize);
50 }
51 
52 static bool expandMemIntrinsicUses(Function &F) {
53   Intrinsic::ID ID = F.getIntrinsicID();
54   bool Changed = false;
55 
56   for (auto I = F.user_begin(), E = F.user_end(); I != E;) {
57     Instruction *Inst = cast<Instruction>(*I);
58     ++I;
59 
60     switch (ID) {
61     case Intrinsic::memcpy: {
62       auto *Memcpy = cast<MemCpyInst>(Inst);
63       if (shouldExpandOperationWithSize(Memcpy->getLength())) {
64         expandMemCpyAsLoop(Memcpy);
65         Changed = true;
66         Memcpy->eraseFromParent();
67       }
68 
69       break;
70     }
71     case Intrinsic::memmove: {
72       auto *Memmove = cast<MemMoveInst>(Inst);
73       if (shouldExpandOperationWithSize(Memmove->getLength())) {
74         expandMemMoveAsLoop(Memmove);
75         Changed = true;
76         Memmove->eraseFromParent();
77       }
78 
79       break;
80     }
81     case Intrinsic::memset: {
82       auto *Memset = cast<MemSetInst>(Inst);
83       if (shouldExpandOperationWithSize(Memset->getLength())) {
84         expandMemSetAsLoop(Memset);
85         Changed = true;
86         Memset->eraseFromParent();
87       }
88 
89       break;
90     }
91     default:
92       break;
93     }
94   }
95 
96   return Changed;
97 }
98 
99 bool AMDGPULowerIntrinsics::runOnModule(Module &M) {
100   bool Changed = false;
101 
102   for (Function &F : M) {
103     if (!F.isDeclaration())
104       continue;
105 
106     switch (F.getIntrinsicID()) {
107     case Intrinsic::memcpy:
108     case Intrinsic::memmove:
109     case Intrinsic::memset:
110       if (expandMemIntrinsicUses(F))
111         Changed = true;
112       break;
113     default:
114       break;
115     }
116   }
117 
118   return Changed;
119 }
120 
121 ModulePass *llvm::createAMDGPULowerIntrinsicsPass() {
122   return new AMDGPULowerIntrinsics();
123 }
124