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