xref: /freebsd/contrib/llvm-project/llvm/lib/Target/NVPTX/NVPTXImageOptimizer.cpp (revision 480093f4440d54b30b3025afeac24b48f2ba7a2e)
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