17a7e6055SDimitry Andric //===-- AMDGPULowerIntrinsics.cpp -----------------------------------------===// 27a7e6055SDimitry Andric // 37a7e6055SDimitry Andric // The LLVM Compiler Infrastructure 47a7e6055SDimitry Andric // 57a7e6055SDimitry Andric // This file is distributed under the University of Illinois Open Source 67a7e6055SDimitry Andric // License. See LICENSE.TXT for details. 77a7e6055SDimitry Andric // 87a7e6055SDimitry Andric //===----------------------------------------------------------------------===// 97a7e6055SDimitry Andric 107a7e6055SDimitry Andric #include "AMDGPU.h" 117a7e6055SDimitry Andric #include "AMDGPUSubtarget.h" 12d8866befSDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 13c4394386SDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h" 147a7e6055SDimitry Andric #include "llvm/IR/Constants.h" 157a7e6055SDimitry Andric #include "llvm/IR/Instructions.h" 167a7e6055SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 177a7e6055SDimitry Andric #include "llvm/IR/Module.h" 187a7e6055SDimitry Andric #include "llvm/Transforms/Utils/LowerMemIntrinsics.h" 197a7e6055SDimitry Andric 207a7e6055SDimitry Andric #define DEBUG_TYPE "amdgpu-lower-intrinsics" 217a7e6055SDimitry Andric 227a7e6055SDimitry Andric using namespace llvm; 237a7e6055SDimitry Andric 247a7e6055SDimitry Andric namespace { 257a7e6055SDimitry Andric 267a7e6055SDimitry Andric const unsigned MaxStaticSize = 1024; 277a7e6055SDimitry Andric 287a7e6055SDimitry Andric class AMDGPULowerIntrinsics : public ModulePass { 297a7e6055SDimitry Andric private: 307a7e6055SDimitry Andric bool makeLIDRangeMetadata(Function &F) const; 317a7e6055SDimitry Andric 327a7e6055SDimitry Andric public: 337a7e6055SDimitry Andric static char ID; 347a7e6055SDimitry Andric AMDGPULowerIntrinsics()35d8866befSDimitry Andric AMDGPULowerIntrinsics() : ModulePass(ID) {} 36d8866befSDimitry Andric 377a7e6055SDimitry Andric bool runOnModule(Module &M) override; 38c4394386SDimitry Andric bool expandMemIntrinsicUses(Function &F); getPassName() const397a7e6055SDimitry Andric StringRef getPassName() const override { 407a7e6055SDimitry Andric return "AMDGPU Lower Intrinsics"; 417a7e6055SDimitry Andric } 42c4394386SDimitry Andric getAnalysisUsage(AnalysisUsage & AU) const43c4394386SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 44c4394386SDimitry Andric AU.addRequired<TargetTransformInfoWrapperPass>(); 45c4394386SDimitry Andric } 467a7e6055SDimitry Andric }; 477a7e6055SDimitry Andric 487a7e6055SDimitry Andric } 497a7e6055SDimitry Andric 507a7e6055SDimitry Andric char AMDGPULowerIntrinsics::ID = 0; 517a7e6055SDimitry Andric 527a7e6055SDimitry Andric char &llvm::AMDGPULowerIntrinsicsID = AMDGPULowerIntrinsics::ID; 537a7e6055SDimitry Andric 54d8866befSDimitry Andric INITIALIZE_PASS(AMDGPULowerIntrinsics, DEBUG_TYPE, "Lower intrinsics", false, 55d8866befSDimitry Andric false) 567a7e6055SDimitry Andric 577a7e6055SDimitry Andric // TODO: Should refine based on estimated number of accesses (e.g. does it 587a7e6055SDimitry Andric // require splitting based on alignment) shouldExpandOperationWithSize(Value * Size)597a7e6055SDimitry Andricstatic bool shouldExpandOperationWithSize(Value *Size) { 607a7e6055SDimitry Andric ConstantInt *CI = dyn_cast<ConstantInt>(Size); 617a7e6055SDimitry Andric return !CI || (CI->getZExtValue() > MaxStaticSize); 627a7e6055SDimitry Andric } 637a7e6055SDimitry Andric expandMemIntrinsicUses(Function & F)64c4394386SDimitry Andricbool AMDGPULowerIntrinsics::expandMemIntrinsicUses(Function &F) { 657a7e6055SDimitry Andric Intrinsic::ID ID = F.getIntrinsicID(); 667a7e6055SDimitry Andric bool Changed = false; 677a7e6055SDimitry Andric 687a7e6055SDimitry Andric for (auto I = F.user_begin(), E = F.user_end(); I != E;) { 697a7e6055SDimitry Andric Instruction *Inst = cast<Instruction>(*I); 707a7e6055SDimitry Andric ++I; 717a7e6055SDimitry Andric 727a7e6055SDimitry Andric switch (ID) { 737a7e6055SDimitry Andric case Intrinsic::memcpy: { 747a7e6055SDimitry Andric auto *Memcpy = cast<MemCpyInst>(Inst); 757a7e6055SDimitry Andric if (shouldExpandOperationWithSize(Memcpy->getLength())) { 76c4394386SDimitry Andric Function *ParentFunc = Memcpy->getParent()->getParent(); 77c4394386SDimitry Andric const TargetTransformInfo &TTI = 78c4394386SDimitry Andric getAnalysis<TargetTransformInfoWrapperPass>().getTTI(*ParentFunc); 79c4394386SDimitry Andric expandMemCpyAsLoop(Memcpy, TTI); 807a7e6055SDimitry Andric Changed = true; 817a7e6055SDimitry Andric Memcpy->eraseFromParent(); 827a7e6055SDimitry Andric } 837a7e6055SDimitry Andric 847a7e6055SDimitry Andric break; 857a7e6055SDimitry Andric } 867a7e6055SDimitry Andric case Intrinsic::memmove: { 877a7e6055SDimitry Andric auto *Memmove = cast<MemMoveInst>(Inst); 887a7e6055SDimitry Andric if (shouldExpandOperationWithSize(Memmove->getLength())) { 897a7e6055SDimitry Andric expandMemMoveAsLoop(Memmove); 907a7e6055SDimitry Andric Changed = true; 917a7e6055SDimitry Andric Memmove->eraseFromParent(); 927a7e6055SDimitry Andric } 937a7e6055SDimitry Andric 947a7e6055SDimitry Andric break; 957a7e6055SDimitry Andric } 967a7e6055SDimitry Andric case Intrinsic::memset: { 977a7e6055SDimitry Andric auto *Memset = cast<MemSetInst>(Inst); 987a7e6055SDimitry Andric if (shouldExpandOperationWithSize(Memset->getLength())) { 997a7e6055SDimitry Andric expandMemSetAsLoop(Memset); 1007a7e6055SDimitry Andric Changed = true; 1017a7e6055SDimitry Andric Memset->eraseFromParent(); 1027a7e6055SDimitry Andric } 1037a7e6055SDimitry Andric 1047a7e6055SDimitry Andric break; 1057a7e6055SDimitry Andric } 1067a7e6055SDimitry Andric default: 1077a7e6055SDimitry Andric break; 1087a7e6055SDimitry Andric } 1097a7e6055SDimitry Andric } 1107a7e6055SDimitry Andric 1117a7e6055SDimitry Andric return Changed; 1127a7e6055SDimitry Andric } 1137a7e6055SDimitry Andric makeLIDRangeMetadata(Function & F) const1147a7e6055SDimitry Andricbool AMDGPULowerIntrinsics::makeLIDRangeMetadata(Function &F) const { 115d8866befSDimitry Andric auto *TPC = getAnalysisIfAvailable<TargetPassConfig>(); 116d8866befSDimitry Andric if (!TPC) 1177a7e6055SDimitry Andric return false; 1187a7e6055SDimitry Andric 119d8866befSDimitry Andric const TargetMachine &TM = TPC->getTM<TargetMachine>(); 1207a7e6055SDimitry Andric bool Changed = false; 1217a7e6055SDimitry Andric 1227a7e6055SDimitry Andric for (auto *U : F.users()) { 1237a7e6055SDimitry Andric auto *CI = dyn_cast<CallInst>(U); 1247a7e6055SDimitry Andric if (!CI) 1257a7e6055SDimitry Andric continue; 1267a7e6055SDimitry Andric 127*4ba319b5SDimitry Andric Changed |= AMDGPUSubtarget::get(TM, F).makeLIDRangeMetadata(CI); 1287a7e6055SDimitry Andric } 1297a7e6055SDimitry Andric return Changed; 1307a7e6055SDimitry Andric } 1317a7e6055SDimitry Andric runOnModule(Module & M)1327a7e6055SDimitry Andricbool AMDGPULowerIntrinsics::runOnModule(Module &M) { 1337a7e6055SDimitry Andric bool Changed = false; 1347a7e6055SDimitry Andric 1357a7e6055SDimitry Andric for (Function &F : M) { 1367a7e6055SDimitry Andric if (!F.isDeclaration()) 1377a7e6055SDimitry Andric continue; 1387a7e6055SDimitry Andric 1397a7e6055SDimitry Andric switch (F.getIntrinsicID()) { 1407a7e6055SDimitry Andric case Intrinsic::memcpy: 1417a7e6055SDimitry Andric case Intrinsic::memmove: 1427a7e6055SDimitry Andric case Intrinsic::memset: 1437a7e6055SDimitry Andric if (expandMemIntrinsicUses(F)) 1447a7e6055SDimitry Andric Changed = true; 1457a7e6055SDimitry Andric break; 1467a7e6055SDimitry Andric 1477a7e6055SDimitry Andric case Intrinsic::amdgcn_workitem_id_x: 1487a7e6055SDimitry Andric case Intrinsic::r600_read_tidig_x: 1497a7e6055SDimitry Andric case Intrinsic::amdgcn_workitem_id_y: 1507a7e6055SDimitry Andric case Intrinsic::r600_read_tidig_y: 1517a7e6055SDimitry Andric case Intrinsic::amdgcn_workitem_id_z: 1527a7e6055SDimitry Andric case Intrinsic::r600_read_tidig_z: 1537a7e6055SDimitry Andric case Intrinsic::r600_read_local_size_x: 1547a7e6055SDimitry Andric case Intrinsic::r600_read_local_size_y: 1557a7e6055SDimitry Andric case Intrinsic::r600_read_local_size_z: 1567a7e6055SDimitry Andric Changed |= makeLIDRangeMetadata(F); 1577a7e6055SDimitry Andric break; 1587a7e6055SDimitry Andric 1597a7e6055SDimitry Andric default: 1607a7e6055SDimitry Andric break; 1617a7e6055SDimitry Andric } 1627a7e6055SDimitry Andric } 1637a7e6055SDimitry Andric 1647a7e6055SDimitry Andric return Changed; 1657a7e6055SDimitry Andric } 1667a7e6055SDimitry Andric createAMDGPULowerIntrinsicsPass()167d8866befSDimitry AndricModulePass *llvm::createAMDGPULowerIntrinsicsPass() { 168d8866befSDimitry Andric return new AMDGPULowerIntrinsics(); 1697a7e6055SDimitry Andric } 170