xref: /freebsd/contrib/llvm-project/llvm/lib/Target/NVPTX/NVPTXImageOptimizer.cpp (revision 04eeddc0aa8e0a417a16eaf9d7d095207f4a8623)
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"
21480093f4SDimitry 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
60*04eeddc0SDimitry Andric   for (BasicBlock &BB : F) {
61*04eeddc0SDimitry Andric     for (Instruction &Instr : BB) {
62*04eeddc0SDimitry Andric       if (CallInst *CI = dyn_cast<CallInst>(&Instr)) {
630b57cec5SDimitry Andric         Function *CalledF = CI->getCalledFunction();
640b57cec5SDimitry Andric         if (CalledF && CalledF->isIntrinsic()) {
650b57cec5SDimitry Andric           // This is an intrinsic function call, check if its an istypep
660b57cec5SDimitry Andric           switch (CalledF->getIntrinsicID()) {
670b57cec5SDimitry Andric           default: break;
680b57cec5SDimitry Andric           case Intrinsic::nvvm_istypep_sampler:
690b57cec5SDimitry Andric             Changed |= replaceIsTypePSampler(Instr);
700b57cec5SDimitry Andric             break;
710b57cec5SDimitry Andric           case Intrinsic::nvvm_istypep_surface:
720b57cec5SDimitry Andric             Changed |= replaceIsTypePSurface(Instr);
730b57cec5SDimitry Andric             break;
740b57cec5SDimitry Andric           case Intrinsic::nvvm_istypep_texture:
750b57cec5SDimitry Andric             Changed |= replaceIsTypePTexture(Instr);
760b57cec5SDimitry Andric             break;
770b57cec5SDimitry Andric           }
780b57cec5SDimitry Andric         }
790b57cec5SDimitry Andric       }
800b57cec5SDimitry Andric     }
810b57cec5SDimitry Andric   }
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric   // Delete any istypep instances we replaced in the IR
84*04eeddc0SDimitry Andric   for (Instruction *I : InstrToDelete)
85*04eeddc0SDimitry Andric     I->eraseFromParent();
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric   return Changed;
880b57cec5SDimitry Andric }
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric bool NVPTXImageOptimizer::replaceIsTypePSampler(Instruction &I) {
910b57cec5SDimitry Andric   Value *TexHandle = cleanupValue(I.getOperand(0));
920b57cec5SDimitry Andric   if (isSampler(*TexHandle)) {
930b57cec5SDimitry Andric     // This is an OpenCL sampler, so it must be a samplerref
940b57cec5SDimitry Andric     replaceWith(&I, ConstantInt::getTrue(I.getContext()));
950b57cec5SDimitry Andric     return true;
960b57cec5SDimitry Andric   } else if (isImage(*TexHandle)) {
970b57cec5SDimitry Andric     // This is an OpenCL image, so it cannot be a samplerref
980b57cec5SDimitry Andric     replaceWith(&I, ConstantInt::getFalse(I.getContext()));
990b57cec5SDimitry Andric     return true;
1000b57cec5SDimitry Andric   } else {
1010b57cec5SDimitry Andric     // The image type is unknown, so we cannot eliminate the intrinsic
1020b57cec5SDimitry Andric     return false;
1030b57cec5SDimitry Andric   }
1040b57cec5SDimitry Andric }
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric bool NVPTXImageOptimizer::replaceIsTypePSurface(Instruction &I) {
1070b57cec5SDimitry Andric   Value *TexHandle = cleanupValue(I.getOperand(0));
1080b57cec5SDimitry Andric   if (isImageReadWrite(*TexHandle) ||
1090b57cec5SDimitry Andric       isImageWriteOnly(*TexHandle)) {
1100b57cec5SDimitry Andric     // This is an OpenCL read-only/read-write image, so it must be a surfref
1110b57cec5SDimitry Andric     replaceWith(&I, ConstantInt::getTrue(I.getContext()));
1120b57cec5SDimitry Andric     return true;
1130b57cec5SDimitry Andric   } else if (isImageReadOnly(*TexHandle) ||
1140b57cec5SDimitry Andric              isSampler(*TexHandle)) {
1150b57cec5SDimitry Andric     // This is an OpenCL read-only/ imageor sampler, so it cannot be
1160b57cec5SDimitry Andric     // a surfref
1170b57cec5SDimitry Andric     replaceWith(&I, ConstantInt::getFalse(I.getContext()));
1180b57cec5SDimitry Andric     return true;
1190b57cec5SDimitry Andric   } else {
1200b57cec5SDimitry Andric     // The image type is unknown, so we cannot eliminate the intrinsic
1210b57cec5SDimitry Andric     return false;
1220b57cec5SDimitry Andric   }
1230b57cec5SDimitry Andric }
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric bool NVPTXImageOptimizer::replaceIsTypePTexture(Instruction &I) {
1260b57cec5SDimitry Andric   Value *TexHandle = cleanupValue(I.getOperand(0));
1270b57cec5SDimitry Andric   if (isImageReadOnly(*TexHandle)) {
1280b57cec5SDimitry Andric     // This is an OpenCL read-only image, so it must be a texref
1290b57cec5SDimitry Andric     replaceWith(&I, ConstantInt::getTrue(I.getContext()));
1300b57cec5SDimitry Andric     return true;
1310b57cec5SDimitry Andric   } else if (isImageWriteOnly(*TexHandle) ||
1320b57cec5SDimitry Andric              isImageReadWrite(*TexHandle) ||
1330b57cec5SDimitry Andric              isSampler(*TexHandle)) {
1340b57cec5SDimitry Andric     // This is an OpenCL read-write/write-only image or a sampler, so it
1350b57cec5SDimitry Andric     // cannot be a texref
1360b57cec5SDimitry Andric     replaceWith(&I, ConstantInt::getFalse(I.getContext()));
1370b57cec5SDimitry Andric     return true;
1380b57cec5SDimitry Andric   } else {
1390b57cec5SDimitry Andric     // The image type is unknown, so we cannot eliminate the intrinsic
1400b57cec5SDimitry Andric     return false;
1410b57cec5SDimitry Andric   }
1420b57cec5SDimitry Andric }
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric void NVPTXImageOptimizer::replaceWith(Instruction *From, ConstantInt *To) {
1450b57cec5SDimitry Andric   // We implement "poor man's DCE" here to make sure any code that is no longer
1460b57cec5SDimitry Andric   // live is actually unreachable and can be trivially eliminated by the
1470b57cec5SDimitry Andric   // unreachable block elimination pass.
148349cc55cSDimitry Andric   for (Use &U : From->uses()) {
149349cc55cSDimitry Andric     if (BranchInst *BI = dyn_cast<BranchInst>(U)) {
1500b57cec5SDimitry Andric       if (BI->isUnconditional()) continue;
1510b57cec5SDimitry Andric       BasicBlock *Dest;
1520b57cec5SDimitry Andric       if (To->isZero())
1530b57cec5SDimitry Andric         // Get false block
1540b57cec5SDimitry Andric         Dest = BI->getSuccessor(1);
1550b57cec5SDimitry Andric       else
1560b57cec5SDimitry Andric         // Get true block
1570b57cec5SDimitry Andric         Dest = BI->getSuccessor(0);
1580b57cec5SDimitry Andric       BranchInst::Create(Dest, BI);
1590b57cec5SDimitry Andric       InstrToDelete.push_back(BI);
1600b57cec5SDimitry Andric     }
1610b57cec5SDimitry Andric   }
1620b57cec5SDimitry Andric   From->replaceAllUsesWith(To);
1630b57cec5SDimitry Andric   InstrToDelete.push_back(From);
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric Value *NVPTXImageOptimizer::cleanupValue(Value *V) {
1670b57cec5SDimitry Andric   if (ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(V)) {
1680b57cec5SDimitry Andric     return cleanupValue(EVI->getAggregateOperand());
1690b57cec5SDimitry Andric   }
1700b57cec5SDimitry Andric   return V;
1710b57cec5SDimitry Andric }
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric FunctionPass *llvm::createNVPTXImageOptimizerPass() {
1740b57cec5SDimitry Andric   return new NVPTXImageOptimizer();
1750b57cec5SDimitry Andric }
176