//===-- NVPTXImageOptimizer.cpp - Image optimization pass -----------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This pass implements IR-level optimizations of image access code, // including: // // 1. Eliminate istypep intrinsics when image access qualifier is known // //===----------------------------------------------------------------------===// #include "NVPTX.h" #include "NVPTXUtilities.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Module.h" #include "llvm/Pass.h" #include "llvm/Analysis/ConstantFolding.h" using namespace llvm; namespace { class NVPTXImageOptimizer : public FunctionPass { private: static char ID; SmallVector InstrToDelete; public: NVPTXImageOptimizer(); bool runOnFunction(Function &F) override; private: bool replaceIsTypePSampler(Instruction &I); bool replaceIsTypePSurface(Instruction &I); bool replaceIsTypePTexture(Instruction &I); Value *cleanupValue(Value *V); void replaceWith(Instruction *From, ConstantInt *To); }; } char NVPTXImageOptimizer::ID = 0; NVPTXImageOptimizer::NVPTXImageOptimizer() : FunctionPass(ID) {} bool NVPTXImageOptimizer::runOnFunction(Function &F) { bool Changed = false; InstrToDelete.clear(); // Look for call instructions in the function for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE; ++BI) { for (BasicBlock::iterator I = (*BI).begin(), E = (*BI).end(); I != E; ++I) { Instruction &Instr = *I; if (CallInst *CI = dyn_cast(I)) { Function *CalledF = CI->getCalledFunction(); if (CalledF && CalledF->isIntrinsic()) { // This is an intrinsic function call, check if its an istypep switch (CalledF->getIntrinsicID()) { default: break; case Intrinsic::nvvm_istypep_sampler: Changed |= replaceIsTypePSampler(Instr); break; case Intrinsic::nvvm_istypep_surface: Changed |= replaceIsTypePSurface(Instr); break; case Intrinsic::nvvm_istypep_texture: Changed |= replaceIsTypePTexture(Instr); break; } } } } } // Delete any istypep instances we replaced in the IR for (unsigned i = 0, e = InstrToDelete.size(); i != e; ++i) InstrToDelete[i]->eraseFromParent(); return Changed; } bool NVPTXImageOptimizer::replaceIsTypePSampler(Instruction &I) { Value *TexHandle = cleanupValue(I.getOperand(0)); if (isSampler(*TexHandle)) { // This is an OpenCL sampler, so it must be a samplerref replaceWith(&I, ConstantInt::getTrue(I.getContext())); return true; } else if (isImageWriteOnly(*TexHandle) || isImageReadWrite(*TexHandle) || isImageReadOnly(*TexHandle)) { // This is an OpenCL image, so it cannot be a samplerref replaceWith(&I, ConstantInt::getFalse(I.getContext())); return true; } else { // The image type is unknown, so we cannot eliminate the intrinsic return false; } } bool NVPTXImageOptimizer::replaceIsTypePSurface(Instruction &I) { Value *TexHandle = cleanupValue(I.getOperand(0)); if (isImageReadWrite(*TexHandle) || isImageWriteOnly(*TexHandle)) { // This is an OpenCL read-only/read-write image, so it must be a surfref replaceWith(&I, ConstantInt::getTrue(I.getContext())); return true; } else if (isImageReadOnly(*TexHandle) || isSampler(*TexHandle)) { // This is an OpenCL read-only/ imageor sampler, so it cannot be // a surfref replaceWith(&I, ConstantInt::getFalse(I.getContext())); return true; } else { // The image type is unknown, so we cannot eliminate the intrinsic return false; } } bool NVPTXImageOptimizer::replaceIsTypePTexture(Instruction &I) { Value *TexHandle = cleanupValue(I.getOperand(0)); if (isImageReadOnly(*TexHandle)) { // This is an OpenCL read-only image, so it must be a texref replaceWith(&I, ConstantInt::getTrue(I.getContext())); return true; } else if (isImageWriteOnly(*TexHandle) || isImageReadWrite(*TexHandle) || isSampler(*TexHandle)) { // This is an OpenCL read-write/write-only image or a sampler, so it // cannot be a texref replaceWith(&I, ConstantInt::getFalse(I.getContext())); return true; } else { // The image type is unknown, so we cannot eliminate the intrinsic return false; } } void NVPTXImageOptimizer::replaceWith(Instruction *From, ConstantInt *To) { // We implement "poor man's DCE" here to make sure any code that is no longer // live is actually unreachable and can be trivially eliminated by the // unreachable block elimination pass. for (CallInst::use_iterator UI = From->use_begin(), UE = From->use_end(); UI != UE; ++UI) { if (BranchInst *BI = dyn_cast(*UI)) { if (BI->isUnconditional()) continue; BasicBlock *Dest; if (To->isZero()) // Get false block Dest = BI->getSuccessor(1); else // Get true block Dest = BI->getSuccessor(0); BranchInst::Create(Dest, BI); InstrToDelete.push_back(BI); } } From->replaceAllUsesWith(To); InstrToDelete.push_back(From); } Value *NVPTXImageOptimizer::cleanupValue(Value *V) { if (ExtractValueInst *EVI = dyn_cast(V)) { return cleanupValue(EVI->getAggregateOperand()); } return V; } FunctionPass *llvm::createNVPTXImageOptimizerPass() { return new NVPTXImageOptimizer(); }