10b57cec5SDimitry Andric //===-- NVPTXImageOptimizer.cpp - Image optimization pass -----------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This pass implements IR-level optimizations of image access code, 100b57cec5SDimitry Andric // including: 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric // 1. Eliminate istypep intrinsics when image access qualifier is known 130b57cec5SDimitry Andric // 140b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric #include "NVPTX.h" 170b57cec5SDimitry Andric #include "NVPTXUtilities.h" 180b57cec5SDimitry Andric #include "llvm/Analysis/ConstantFolding.h" 190b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 200b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h" 21*480093f4SDimitry Andric #include "llvm/IR/IntrinsicsNVPTX.h" 220b57cec5SDimitry Andric #include "llvm/IR/Module.h" 230b57cec5SDimitry Andric #include "llvm/Pass.h" 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric using namespace llvm; 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric namespace { 280b57cec5SDimitry Andric class NVPTXImageOptimizer : public FunctionPass { 290b57cec5SDimitry Andric private: 300b57cec5SDimitry Andric static char ID; 310b57cec5SDimitry Andric SmallVector<Instruction*, 4> InstrToDelete; 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric public: 340b57cec5SDimitry Andric NVPTXImageOptimizer(); 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric bool runOnFunction(Function &F) override; 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric private: 390b57cec5SDimitry Andric bool replaceIsTypePSampler(Instruction &I); 400b57cec5SDimitry Andric bool replaceIsTypePSurface(Instruction &I); 410b57cec5SDimitry Andric bool replaceIsTypePTexture(Instruction &I); 420b57cec5SDimitry Andric Value *cleanupValue(Value *V); 430b57cec5SDimitry Andric void replaceWith(Instruction *From, ConstantInt *To); 440b57cec5SDimitry Andric }; 450b57cec5SDimitry Andric } 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric char NVPTXImageOptimizer::ID = 0; 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric NVPTXImageOptimizer::NVPTXImageOptimizer() 500b57cec5SDimitry Andric : FunctionPass(ID) {} 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric bool NVPTXImageOptimizer::runOnFunction(Function &F) { 530b57cec5SDimitry Andric if (skipFunction(F)) 540b57cec5SDimitry Andric return false; 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric bool Changed = false; 570b57cec5SDimitry Andric InstrToDelete.clear(); 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric // Look for call instructions in the function 600b57cec5SDimitry Andric for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE; 610b57cec5SDimitry Andric ++BI) { 620b57cec5SDimitry Andric for (BasicBlock::iterator I = (*BI).begin(), E = (*BI).end(); 630b57cec5SDimitry Andric I != E; ++I) { 640b57cec5SDimitry Andric Instruction &Instr = *I; 650b57cec5SDimitry Andric if (CallInst *CI = dyn_cast<CallInst>(I)) { 660b57cec5SDimitry Andric Function *CalledF = CI->getCalledFunction(); 670b57cec5SDimitry Andric if (CalledF && CalledF->isIntrinsic()) { 680b57cec5SDimitry Andric // This is an intrinsic function call, check if its an istypep 690b57cec5SDimitry Andric switch (CalledF->getIntrinsicID()) { 700b57cec5SDimitry Andric default: break; 710b57cec5SDimitry Andric case Intrinsic::nvvm_istypep_sampler: 720b57cec5SDimitry Andric Changed |= replaceIsTypePSampler(Instr); 730b57cec5SDimitry Andric break; 740b57cec5SDimitry Andric case Intrinsic::nvvm_istypep_surface: 750b57cec5SDimitry Andric Changed |= replaceIsTypePSurface(Instr); 760b57cec5SDimitry Andric break; 770b57cec5SDimitry Andric case Intrinsic::nvvm_istypep_texture: 780b57cec5SDimitry Andric Changed |= replaceIsTypePTexture(Instr); 790b57cec5SDimitry Andric break; 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric } 820b57cec5SDimitry Andric } 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric } 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric // Delete any istypep instances we replaced in the IR 870b57cec5SDimitry Andric for (unsigned i = 0, e = InstrToDelete.size(); i != e; ++i) 880b57cec5SDimitry Andric InstrToDelete[i]->eraseFromParent(); 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric return Changed; 910b57cec5SDimitry Andric } 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric bool NVPTXImageOptimizer::replaceIsTypePSampler(Instruction &I) { 940b57cec5SDimitry Andric Value *TexHandle = cleanupValue(I.getOperand(0)); 950b57cec5SDimitry Andric if (isSampler(*TexHandle)) { 960b57cec5SDimitry Andric // This is an OpenCL sampler, so it must be a samplerref 970b57cec5SDimitry Andric replaceWith(&I, ConstantInt::getTrue(I.getContext())); 980b57cec5SDimitry Andric return true; 990b57cec5SDimitry Andric } else if (isImage(*TexHandle)) { 1000b57cec5SDimitry Andric // This is an OpenCL image, so it cannot be a samplerref 1010b57cec5SDimitry Andric replaceWith(&I, ConstantInt::getFalse(I.getContext())); 1020b57cec5SDimitry Andric return true; 1030b57cec5SDimitry Andric } else { 1040b57cec5SDimitry Andric // The image type is unknown, so we cannot eliminate the intrinsic 1050b57cec5SDimitry Andric return false; 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric } 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric bool NVPTXImageOptimizer::replaceIsTypePSurface(Instruction &I) { 1100b57cec5SDimitry Andric Value *TexHandle = cleanupValue(I.getOperand(0)); 1110b57cec5SDimitry Andric if (isImageReadWrite(*TexHandle) || 1120b57cec5SDimitry Andric isImageWriteOnly(*TexHandle)) { 1130b57cec5SDimitry Andric // This is an OpenCL read-only/read-write image, so it must be a surfref 1140b57cec5SDimitry Andric replaceWith(&I, ConstantInt::getTrue(I.getContext())); 1150b57cec5SDimitry Andric return true; 1160b57cec5SDimitry Andric } else if (isImageReadOnly(*TexHandle) || 1170b57cec5SDimitry Andric isSampler(*TexHandle)) { 1180b57cec5SDimitry Andric // This is an OpenCL read-only/ imageor sampler, so it cannot be 1190b57cec5SDimitry Andric // a surfref 1200b57cec5SDimitry Andric replaceWith(&I, ConstantInt::getFalse(I.getContext())); 1210b57cec5SDimitry Andric return true; 1220b57cec5SDimitry Andric } else { 1230b57cec5SDimitry Andric // The image type is unknown, so we cannot eliminate the intrinsic 1240b57cec5SDimitry Andric return false; 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric bool NVPTXImageOptimizer::replaceIsTypePTexture(Instruction &I) { 1290b57cec5SDimitry Andric Value *TexHandle = cleanupValue(I.getOperand(0)); 1300b57cec5SDimitry Andric if (isImageReadOnly(*TexHandle)) { 1310b57cec5SDimitry Andric // This is an OpenCL read-only image, so it must be a texref 1320b57cec5SDimitry Andric replaceWith(&I, ConstantInt::getTrue(I.getContext())); 1330b57cec5SDimitry Andric return true; 1340b57cec5SDimitry Andric } else if (isImageWriteOnly(*TexHandle) || 1350b57cec5SDimitry Andric isImageReadWrite(*TexHandle) || 1360b57cec5SDimitry Andric isSampler(*TexHandle)) { 1370b57cec5SDimitry Andric // This is an OpenCL read-write/write-only image or a sampler, so it 1380b57cec5SDimitry Andric // cannot be a texref 1390b57cec5SDimitry Andric replaceWith(&I, ConstantInt::getFalse(I.getContext())); 1400b57cec5SDimitry Andric return true; 1410b57cec5SDimitry Andric } else { 1420b57cec5SDimitry Andric // The image type is unknown, so we cannot eliminate the intrinsic 1430b57cec5SDimitry Andric return false; 1440b57cec5SDimitry Andric } 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric void NVPTXImageOptimizer::replaceWith(Instruction *From, ConstantInt *To) { 1480b57cec5SDimitry Andric // We implement "poor man's DCE" here to make sure any code that is no longer 1490b57cec5SDimitry Andric // live is actually unreachable and can be trivially eliminated by the 1500b57cec5SDimitry Andric // unreachable block elimination pass. 1510b57cec5SDimitry Andric for (CallInst::use_iterator UI = From->use_begin(), UE = From->use_end(); 1520b57cec5SDimitry Andric UI != UE; ++UI) { 1530b57cec5SDimitry Andric if (BranchInst *BI = dyn_cast<BranchInst>(*UI)) { 1540b57cec5SDimitry Andric if (BI->isUnconditional()) continue; 1550b57cec5SDimitry Andric BasicBlock *Dest; 1560b57cec5SDimitry Andric if (To->isZero()) 1570b57cec5SDimitry Andric // Get false block 1580b57cec5SDimitry Andric Dest = BI->getSuccessor(1); 1590b57cec5SDimitry Andric else 1600b57cec5SDimitry Andric // Get true block 1610b57cec5SDimitry Andric Dest = BI->getSuccessor(0); 1620b57cec5SDimitry Andric BranchInst::Create(Dest, BI); 1630b57cec5SDimitry Andric InstrToDelete.push_back(BI); 1640b57cec5SDimitry Andric } 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric From->replaceAllUsesWith(To); 1670b57cec5SDimitry Andric InstrToDelete.push_back(From); 1680b57cec5SDimitry Andric } 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric Value *NVPTXImageOptimizer::cleanupValue(Value *V) { 1710b57cec5SDimitry Andric if (ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(V)) { 1720b57cec5SDimitry Andric return cleanupValue(EVI->getAggregateOperand()); 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric return V; 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric FunctionPass *llvm::createNVPTXImageOptimizerPass() { 1780b57cec5SDimitry Andric return new NVPTXImageOptimizer(); 1790b57cec5SDimitry Andric } 180