1*0b57cec5SDimitry Andric //===-- NVPTXImageOptimizer.cpp - Image optimization pass -----------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This pass implements IR-level optimizations of image access code, 10*0b57cec5SDimitry Andric // including: 11*0b57cec5SDimitry Andric // 12*0b57cec5SDimitry Andric // 1. Eliminate istypep intrinsics when image access qualifier is known 13*0b57cec5SDimitry Andric // 14*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 15*0b57cec5SDimitry Andric 16*0b57cec5SDimitry Andric #include "NVPTX.h" 17*0b57cec5SDimitry Andric #include "NVPTXUtilities.h" 18*0b57cec5SDimitry Andric #include "llvm/Analysis/ConstantFolding.h" 19*0b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 20*0b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h" 21*0b57cec5SDimitry Andric #include "llvm/IR/Module.h" 22*0b57cec5SDimitry Andric #include "llvm/Pass.h" 23*0b57cec5SDimitry Andric 24*0b57cec5SDimitry Andric using namespace llvm; 25*0b57cec5SDimitry Andric 26*0b57cec5SDimitry Andric namespace { 27*0b57cec5SDimitry Andric class NVPTXImageOptimizer : public FunctionPass { 28*0b57cec5SDimitry Andric private: 29*0b57cec5SDimitry Andric static char ID; 30*0b57cec5SDimitry Andric SmallVector<Instruction*, 4> InstrToDelete; 31*0b57cec5SDimitry Andric 32*0b57cec5SDimitry Andric public: 33*0b57cec5SDimitry Andric NVPTXImageOptimizer(); 34*0b57cec5SDimitry Andric 35*0b57cec5SDimitry Andric bool runOnFunction(Function &F) override; 36*0b57cec5SDimitry Andric 37*0b57cec5SDimitry Andric private: 38*0b57cec5SDimitry Andric bool replaceIsTypePSampler(Instruction &I); 39*0b57cec5SDimitry Andric bool replaceIsTypePSurface(Instruction &I); 40*0b57cec5SDimitry Andric bool replaceIsTypePTexture(Instruction &I); 41*0b57cec5SDimitry Andric Value *cleanupValue(Value *V); 42*0b57cec5SDimitry Andric void replaceWith(Instruction *From, ConstantInt *To); 43*0b57cec5SDimitry Andric }; 44*0b57cec5SDimitry Andric } 45*0b57cec5SDimitry Andric 46*0b57cec5SDimitry Andric char NVPTXImageOptimizer::ID = 0; 47*0b57cec5SDimitry Andric 48*0b57cec5SDimitry Andric NVPTXImageOptimizer::NVPTXImageOptimizer() 49*0b57cec5SDimitry Andric : FunctionPass(ID) {} 50*0b57cec5SDimitry Andric 51*0b57cec5SDimitry Andric bool NVPTXImageOptimizer::runOnFunction(Function &F) { 52*0b57cec5SDimitry Andric if (skipFunction(F)) 53*0b57cec5SDimitry Andric return false; 54*0b57cec5SDimitry Andric 55*0b57cec5SDimitry Andric bool Changed = false; 56*0b57cec5SDimitry Andric InstrToDelete.clear(); 57*0b57cec5SDimitry Andric 58*0b57cec5SDimitry Andric // Look for call instructions in the function 59*0b57cec5SDimitry Andric for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE; 60*0b57cec5SDimitry Andric ++BI) { 61*0b57cec5SDimitry Andric for (BasicBlock::iterator I = (*BI).begin(), E = (*BI).end(); 62*0b57cec5SDimitry Andric I != E; ++I) { 63*0b57cec5SDimitry Andric Instruction &Instr = *I; 64*0b57cec5SDimitry Andric if (CallInst *CI = dyn_cast<CallInst>(I)) { 65*0b57cec5SDimitry Andric Function *CalledF = CI->getCalledFunction(); 66*0b57cec5SDimitry Andric if (CalledF && CalledF->isIntrinsic()) { 67*0b57cec5SDimitry Andric // This is an intrinsic function call, check if its an istypep 68*0b57cec5SDimitry Andric switch (CalledF->getIntrinsicID()) { 69*0b57cec5SDimitry Andric default: break; 70*0b57cec5SDimitry Andric case Intrinsic::nvvm_istypep_sampler: 71*0b57cec5SDimitry Andric Changed |= replaceIsTypePSampler(Instr); 72*0b57cec5SDimitry Andric break; 73*0b57cec5SDimitry Andric case Intrinsic::nvvm_istypep_surface: 74*0b57cec5SDimitry Andric Changed |= replaceIsTypePSurface(Instr); 75*0b57cec5SDimitry Andric break; 76*0b57cec5SDimitry Andric case Intrinsic::nvvm_istypep_texture: 77*0b57cec5SDimitry Andric Changed |= replaceIsTypePTexture(Instr); 78*0b57cec5SDimitry Andric break; 79*0b57cec5SDimitry Andric } 80*0b57cec5SDimitry Andric } 81*0b57cec5SDimitry Andric } 82*0b57cec5SDimitry Andric } 83*0b57cec5SDimitry Andric } 84*0b57cec5SDimitry Andric 85*0b57cec5SDimitry Andric // Delete any istypep instances we replaced in the IR 86*0b57cec5SDimitry Andric for (unsigned i = 0, e = InstrToDelete.size(); i != e; ++i) 87*0b57cec5SDimitry Andric InstrToDelete[i]->eraseFromParent(); 88*0b57cec5SDimitry Andric 89*0b57cec5SDimitry Andric return Changed; 90*0b57cec5SDimitry Andric } 91*0b57cec5SDimitry Andric 92*0b57cec5SDimitry Andric bool NVPTXImageOptimizer::replaceIsTypePSampler(Instruction &I) { 93*0b57cec5SDimitry Andric Value *TexHandle = cleanupValue(I.getOperand(0)); 94*0b57cec5SDimitry Andric if (isSampler(*TexHandle)) { 95*0b57cec5SDimitry Andric // This is an OpenCL sampler, so it must be a samplerref 96*0b57cec5SDimitry Andric replaceWith(&I, ConstantInt::getTrue(I.getContext())); 97*0b57cec5SDimitry Andric return true; 98*0b57cec5SDimitry Andric } else if (isImage(*TexHandle)) { 99*0b57cec5SDimitry Andric // This is an OpenCL image, so it cannot be a samplerref 100*0b57cec5SDimitry Andric replaceWith(&I, ConstantInt::getFalse(I.getContext())); 101*0b57cec5SDimitry Andric return true; 102*0b57cec5SDimitry Andric } else { 103*0b57cec5SDimitry Andric // The image type is unknown, so we cannot eliminate the intrinsic 104*0b57cec5SDimitry Andric return false; 105*0b57cec5SDimitry Andric } 106*0b57cec5SDimitry Andric } 107*0b57cec5SDimitry Andric 108*0b57cec5SDimitry Andric bool NVPTXImageOptimizer::replaceIsTypePSurface(Instruction &I) { 109*0b57cec5SDimitry Andric Value *TexHandle = cleanupValue(I.getOperand(0)); 110*0b57cec5SDimitry Andric if (isImageReadWrite(*TexHandle) || 111*0b57cec5SDimitry Andric isImageWriteOnly(*TexHandle)) { 112*0b57cec5SDimitry Andric // This is an OpenCL read-only/read-write image, so it must be a surfref 113*0b57cec5SDimitry Andric replaceWith(&I, ConstantInt::getTrue(I.getContext())); 114*0b57cec5SDimitry Andric return true; 115*0b57cec5SDimitry Andric } else if (isImageReadOnly(*TexHandle) || 116*0b57cec5SDimitry Andric isSampler(*TexHandle)) { 117*0b57cec5SDimitry Andric // This is an OpenCL read-only/ imageor sampler, so it cannot be 118*0b57cec5SDimitry Andric // a surfref 119*0b57cec5SDimitry Andric replaceWith(&I, ConstantInt::getFalse(I.getContext())); 120*0b57cec5SDimitry Andric return true; 121*0b57cec5SDimitry Andric } else { 122*0b57cec5SDimitry Andric // The image type is unknown, so we cannot eliminate the intrinsic 123*0b57cec5SDimitry Andric return false; 124*0b57cec5SDimitry Andric } 125*0b57cec5SDimitry Andric } 126*0b57cec5SDimitry Andric 127*0b57cec5SDimitry Andric bool NVPTXImageOptimizer::replaceIsTypePTexture(Instruction &I) { 128*0b57cec5SDimitry Andric Value *TexHandle = cleanupValue(I.getOperand(0)); 129*0b57cec5SDimitry Andric if (isImageReadOnly(*TexHandle)) { 130*0b57cec5SDimitry Andric // This is an OpenCL read-only image, so it must be a texref 131*0b57cec5SDimitry Andric replaceWith(&I, ConstantInt::getTrue(I.getContext())); 132*0b57cec5SDimitry Andric return true; 133*0b57cec5SDimitry Andric } else if (isImageWriteOnly(*TexHandle) || 134*0b57cec5SDimitry Andric isImageReadWrite(*TexHandle) || 135*0b57cec5SDimitry Andric isSampler(*TexHandle)) { 136*0b57cec5SDimitry Andric // This is an OpenCL read-write/write-only image or a sampler, so it 137*0b57cec5SDimitry Andric // cannot be a texref 138*0b57cec5SDimitry Andric replaceWith(&I, ConstantInt::getFalse(I.getContext())); 139*0b57cec5SDimitry Andric return true; 140*0b57cec5SDimitry Andric } else { 141*0b57cec5SDimitry Andric // The image type is unknown, so we cannot eliminate the intrinsic 142*0b57cec5SDimitry Andric return false; 143*0b57cec5SDimitry Andric } 144*0b57cec5SDimitry Andric } 145*0b57cec5SDimitry Andric 146*0b57cec5SDimitry Andric void NVPTXImageOptimizer::replaceWith(Instruction *From, ConstantInt *To) { 147*0b57cec5SDimitry Andric // We implement "poor man's DCE" here to make sure any code that is no longer 148*0b57cec5SDimitry Andric // live is actually unreachable and can be trivially eliminated by the 149*0b57cec5SDimitry Andric // unreachable block elimination pass. 150*0b57cec5SDimitry Andric for (CallInst::use_iterator UI = From->use_begin(), UE = From->use_end(); 151*0b57cec5SDimitry Andric UI != UE; ++UI) { 152*0b57cec5SDimitry Andric if (BranchInst *BI = dyn_cast<BranchInst>(*UI)) { 153*0b57cec5SDimitry Andric if (BI->isUnconditional()) continue; 154*0b57cec5SDimitry Andric BasicBlock *Dest; 155*0b57cec5SDimitry Andric if (To->isZero()) 156*0b57cec5SDimitry Andric // Get false block 157*0b57cec5SDimitry Andric Dest = BI->getSuccessor(1); 158*0b57cec5SDimitry Andric else 159*0b57cec5SDimitry Andric // Get true block 160*0b57cec5SDimitry Andric Dest = BI->getSuccessor(0); 161*0b57cec5SDimitry Andric BranchInst::Create(Dest, BI); 162*0b57cec5SDimitry Andric InstrToDelete.push_back(BI); 163*0b57cec5SDimitry Andric } 164*0b57cec5SDimitry Andric } 165*0b57cec5SDimitry Andric From->replaceAllUsesWith(To); 166*0b57cec5SDimitry Andric InstrToDelete.push_back(From); 167*0b57cec5SDimitry Andric } 168*0b57cec5SDimitry Andric 169*0b57cec5SDimitry Andric Value *NVPTXImageOptimizer::cleanupValue(Value *V) { 170*0b57cec5SDimitry Andric if (ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(V)) { 171*0b57cec5SDimitry Andric return cleanupValue(EVI->getAggregateOperand()); 172*0b57cec5SDimitry Andric } 173*0b57cec5SDimitry Andric return V; 174*0b57cec5SDimitry Andric } 175*0b57cec5SDimitry Andric 176*0b57cec5SDimitry Andric FunctionPass *llvm::createNVPTXImageOptimizerPass() { 177*0b57cec5SDimitry Andric return new NVPTXImageOptimizer(); 178*0b57cec5SDimitry Andric } 179