10699ef39SMatt Arsenault //===-- AMDGPULowerIntrinsics.cpp -----------------------------------------===//
20699ef39SMatt Arsenault //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60699ef39SMatt Arsenault //
70699ef39SMatt Arsenault //===----------------------------------------------------------------------===//
80699ef39SMatt Arsenault 
90699ef39SMatt Arsenault #include "AMDGPU.h"
10c90347d7SStanislav Mekhanoshin #include "AMDGPUSubtarget.h"
119cd1cdf8SSean Fertile #include "llvm/Analysis/TargetTransformInfo.h"
126a87e9b0Sdfukalov #include "llvm/CodeGen/TargetPassConfig.h"
130699ef39SMatt Arsenault #include "llvm/IR/Constants.h"
140699ef39SMatt Arsenault #include "llvm/IR/Instructions.h"
150699ef39SMatt Arsenault #include "llvm/IR/IntrinsicInst.h"
166a87e9b0Sdfukalov #include "llvm/IR/IntrinsicsR600.h"
170699ef39SMatt Arsenault #include "llvm/IR/Module.h"
18560d7e04Sdfukalov #include "llvm/Support/CommandLine.h"
196a87e9b0Sdfukalov #include "llvm/Target/TargetMachine.h"
200699ef39SMatt Arsenault #include "llvm/Transforms/Utils/LowerMemIntrinsics.h"
210699ef39SMatt Arsenault 
220699ef39SMatt Arsenault #define DEBUG_TYPE "amdgpu-lower-intrinsics"
230699ef39SMatt Arsenault 
240699ef39SMatt Arsenault using namespace llvm;
250699ef39SMatt Arsenault 
260699ef39SMatt Arsenault namespace {
270699ef39SMatt Arsenault 
287d3aace3SMatt Arsenault static int MaxStaticSize;
297d3aace3SMatt Arsenault 
307d3aace3SMatt Arsenault static cl::opt<int, true> MemIntrinsicExpandSizeThresholdOpt(
317d3aace3SMatt Arsenault   "amdgpu-mem-intrinsic-expand-size",
327d3aace3SMatt Arsenault   cl::desc("Set minimum mem intrinsic size to expand in IR"),
337d3aace3SMatt Arsenault   cl::location(MaxStaticSize),
347d3aace3SMatt Arsenault   cl::init(1024),
357d3aace3SMatt Arsenault   cl::Hidden);
367d3aace3SMatt Arsenault 
370699ef39SMatt Arsenault 
380699ef39SMatt Arsenault class AMDGPULowerIntrinsics : public ModulePass {
39c90347d7SStanislav Mekhanoshin private:
40c90347d7SStanislav Mekhanoshin   bool makeLIDRangeMetadata(Function &F) const;
41c90347d7SStanislav Mekhanoshin 
420699ef39SMatt Arsenault public:
430699ef39SMatt Arsenault   static char ID;
440699ef39SMatt Arsenault 
AMDGPULowerIntrinsics()458b61764cSFrancis Visoiu Mistrih   AMDGPULowerIntrinsics() : ModulePass(ID) {}
468b61764cSFrancis Visoiu Mistrih 
470699ef39SMatt Arsenault   bool runOnModule(Module &M) override;
489cd1cdf8SSean Fertile   bool expandMemIntrinsicUses(Function &F);
getPassName() const490699ef39SMatt Arsenault   StringRef getPassName() const override {
500699ef39SMatt Arsenault     return "AMDGPU Lower Intrinsics";
510699ef39SMatt Arsenault   }
529cd1cdf8SSean Fertile 
getAnalysisUsage(AnalysisUsage & AU) const539cd1cdf8SSean Fertile   void getAnalysisUsage(AnalysisUsage &AU) const override {
549cd1cdf8SSean Fertile     AU.addRequired<TargetTransformInfoWrapperPass>();
559cd1cdf8SSean Fertile   }
560699ef39SMatt Arsenault };
570699ef39SMatt Arsenault 
580699ef39SMatt Arsenault }
590699ef39SMatt Arsenault 
600699ef39SMatt Arsenault char AMDGPULowerIntrinsics::ID = 0;
610699ef39SMatt Arsenault 
620699ef39SMatt Arsenault char &llvm::AMDGPULowerIntrinsicsID = AMDGPULowerIntrinsics::ID;
630699ef39SMatt Arsenault 
648b61764cSFrancis Visoiu Mistrih INITIALIZE_PASS(AMDGPULowerIntrinsics, DEBUG_TYPE, "Lower intrinsics", false,
658b61764cSFrancis Visoiu Mistrih                 false)
660699ef39SMatt Arsenault 
670699ef39SMatt Arsenault // TODO: Should refine based on estimated number of accesses (e.g. does it
680699ef39SMatt Arsenault // require splitting based on alignment)
shouldExpandOperationWithSize(Value * Size)690699ef39SMatt Arsenault static bool shouldExpandOperationWithSize(Value *Size) {
700699ef39SMatt Arsenault   ConstantInt *CI = dyn_cast<ConstantInt>(Size);
717d3aace3SMatt Arsenault   return !CI || (CI->getSExtValue() > MaxStaticSize);
720699ef39SMatt Arsenault }
730699ef39SMatt Arsenault 
expandMemIntrinsicUses(Function & F)749cd1cdf8SSean Fertile bool AMDGPULowerIntrinsics::expandMemIntrinsicUses(Function &F) {
750699ef39SMatt Arsenault   Intrinsic::ID ID = F.getIntrinsicID();
76022c6e4fSNAKAMURA Takumi   bool Changed = false;
770699ef39SMatt Arsenault 
78*4bef0304SKazu Hirata   for (User *U : llvm::make_early_inc_range(F.users())) {
79*4bef0304SKazu Hirata     Instruction *Inst = cast<Instruction>(U);
800699ef39SMatt Arsenault 
810699ef39SMatt Arsenault     switch (ID) {
820699ef39SMatt Arsenault     case Intrinsic::memcpy: {
830699ef39SMatt Arsenault       auto *Memcpy = cast<MemCpyInst>(Inst);
840699ef39SMatt Arsenault       if (shouldExpandOperationWithSize(Memcpy->getLength())) {
859cd1cdf8SSean Fertile         Function *ParentFunc = Memcpy->getParent()->getParent();
869cd1cdf8SSean Fertile         const TargetTransformInfo &TTI =
879cd1cdf8SSean Fertile             getAnalysis<TargetTransformInfoWrapperPass>().getTTI(*ParentFunc);
889cd1cdf8SSean Fertile         expandMemCpyAsLoop(Memcpy, TTI);
890699ef39SMatt Arsenault         Changed = true;
900699ef39SMatt Arsenault         Memcpy->eraseFromParent();
910699ef39SMatt Arsenault       }
920699ef39SMatt Arsenault 
930699ef39SMatt Arsenault       break;
940699ef39SMatt Arsenault     }
950699ef39SMatt Arsenault     case Intrinsic::memmove: {
960699ef39SMatt Arsenault       auto *Memmove = cast<MemMoveInst>(Inst);
970699ef39SMatt Arsenault       if (shouldExpandOperationWithSize(Memmove->getLength())) {
980699ef39SMatt Arsenault         expandMemMoveAsLoop(Memmove);
990699ef39SMatt Arsenault         Changed = true;
1000699ef39SMatt Arsenault         Memmove->eraseFromParent();
1010699ef39SMatt Arsenault       }
1020699ef39SMatt Arsenault 
1030699ef39SMatt Arsenault       break;
1040699ef39SMatt Arsenault     }
1050699ef39SMatt Arsenault     case Intrinsic::memset: {
1060699ef39SMatt Arsenault       auto *Memset = cast<MemSetInst>(Inst);
1070699ef39SMatt Arsenault       if (shouldExpandOperationWithSize(Memset->getLength())) {
1080699ef39SMatt Arsenault         expandMemSetAsLoop(Memset);
1090699ef39SMatt Arsenault         Changed = true;
1100699ef39SMatt Arsenault         Memset->eraseFromParent();
1110699ef39SMatt Arsenault       }
1120699ef39SMatt Arsenault 
1130699ef39SMatt Arsenault       break;
1140699ef39SMatt Arsenault     }
1150699ef39SMatt Arsenault     default:
1160699ef39SMatt Arsenault       break;
1170699ef39SMatt Arsenault     }
1180699ef39SMatt Arsenault   }
1190699ef39SMatt Arsenault 
1200699ef39SMatt Arsenault   return Changed;
1210699ef39SMatt Arsenault }
1220699ef39SMatt Arsenault 
makeLIDRangeMetadata(Function & F) const123c90347d7SStanislav Mekhanoshin bool AMDGPULowerIntrinsics::makeLIDRangeMetadata(Function &F) const {
1248b61764cSFrancis Visoiu Mistrih   auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
1258b61764cSFrancis Visoiu Mistrih   if (!TPC)
126c90347d7SStanislav Mekhanoshin     return false;
127c90347d7SStanislav Mekhanoshin 
1288b61764cSFrancis Visoiu Mistrih   const TargetMachine &TM = TPC->getTM<TargetMachine>();
129c90347d7SStanislav Mekhanoshin   bool Changed = false;
130c90347d7SStanislav Mekhanoshin 
131c90347d7SStanislav Mekhanoshin   for (auto *U : F.users()) {
132c90347d7SStanislav Mekhanoshin     auto *CI = dyn_cast<CallInst>(U);
133c90347d7SStanislav Mekhanoshin     if (!CI)
134c90347d7SStanislav Mekhanoshin       continue;
135c90347d7SStanislav Mekhanoshin 
136a1bc37c9SMatt Arsenault     Function *Caller = CI->getParent()->getParent();
137a1bc37c9SMatt Arsenault     const AMDGPUSubtarget &ST = AMDGPUSubtarget::get(TM, *Caller);
1386c770a09SMatt Arsenault     Changed |= ST.makeLIDRangeMetadata(CI);
139c90347d7SStanislav Mekhanoshin   }
140c90347d7SStanislav Mekhanoshin   return Changed;
141c90347d7SStanislav Mekhanoshin }
142c90347d7SStanislav Mekhanoshin 
runOnModule(Module & M)1430699ef39SMatt Arsenault bool AMDGPULowerIntrinsics::runOnModule(Module &M) {
1440699ef39SMatt Arsenault   bool Changed = false;
1450699ef39SMatt Arsenault 
1460699ef39SMatt Arsenault   for (Function &F : M) {
1470699ef39SMatt Arsenault     if (!F.isDeclaration())
1480699ef39SMatt Arsenault       continue;
1490699ef39SMatt Arsenault 
1500699ef39SMatt Arsenault     switch (F.getIntrinsicID()) {
1510699ef39SMatt Arsenault     case Intrinsic::memcpy:
1520699ef39SMatt Arsenault     case Intrinsic::memmove:
1530699ef39SMatt Arsenault     case Intrinsic::memset:
1540699ef39SMatt Arsenault       if (expandMemIntrinsicUses(F))
1550699ef39SMatt Arsenault         Changed = true;
1560699ef39SMatt Arsenault       break;
157c90347d7SStanislav Mekhanoshin 
158c90347d7SStanislav Mekhanoshin     case Intrinsic::r600_read_tidig_x:
159c90347d7SStanislav Mekhanoshin     case Intrinsic::r600_read_tidig_y:
160c90347d7SStanislav Mekhanoshin     case Intrinsic::r600_read_tidig_z:
161c90347d7SStanislav Mekhanoshin     case Intrinsic::r600_read_local_size_x:
162c90347d7SStanislav Mekhanoshin     case Intrinsic::r600_read_local_size_y:
163c90347d7SStanislav Mekhanoshin     case Intrinsic::r600_read_local_size_z:
164c90347d7SStanislav Mekhanoshin       Changed |= makeLIDRangeMetadata(F);
165c90347d7SStanislav Mekhanoshin       break;
166c90347d7SStanislav Mekhanoshin 
1670699ef39SMatt Arsenault     default:
1680699ef39SMatt Arsenault       break;
1690699ef39SMatt Arsenault     }
1700699ef39SMatt Arsenault   }
1710699ef39SMatt Arsenault 
1720699ef39SMatt Arsenault   return Changed;
1730699ef39SMatt Arsenault }
1740699ef39SMatt Arsenault 
createAMDGPULowerIntrinsicsPass()1758b61764cSFrancis Visoiu Mistrih ModulePass *llvm::createAMDGPULowerIntrinsicsPass() {
1768b61764cSFrancis Visoiu Mistrih   return new AMDGPULowerIntrinsics();
1770699ef39SMatt Arsenault }
178