xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/NVPTX/NVPTXImageOptimizer.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
38753f127fSDimitry Andric   StringRef getPassName() const override { return "NVPTX Image Optimizer"; }
39753f127fSDimitry Andric 
400b57cec5SDimitry Andric private:
410b57cec5SDimitry Andric   bool replaceIsTypePSampler(Instruction &I);
420b57cec5SDimitry Andric   bool replaceIsTypePSurface(Instruction &I);
430b57cec5SDimitry Andric   bool replaceIsTypePTexture(Instruction &I);
440b57cec5SDimitry Andric   Value *cleanupValue(Value *V);
450b57cec5SDimitry Andric   void replaceWith(Instruction *From, ConstantInt *To);
460b57cec5SDimitry Andric };
470b57cec5SDimitry Andric }
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric char NVPTXImageOptimizer::ID = 0;
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric NVPTXImageOptimizer::NVPTXImageOptimizer()
520b57cec5SDimitry Andric   : FunctionPass(ID) {}
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric bool NVPTXImageOptimizer::runOnFunction(Function &F) {
550b57cec5SDimitry Andric   if (skipFunction(F))
560b57cec5SDimitry Andric     return false;
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric   bool Changed = false;
590b57cec5SDimitry Andric   InstrToDelete.clear();
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   // Look for call instructions in the function
6204eeddc0SDimitry Andric   for (BasicBlock &BB : F) {
6304eeddc0SDimitry Andric     for (Instruction &Instr : BB) {
6404eeddc0SDimitry Andric       if (CallInst *CI = dyn_cast<CallInst>(&Instr)) {
650b57cec5SDimitry Andric         Function *CalledF = CI->getCalledFunction();
660b57cec5SDimitry Andric         if (CalledF && CalledF->isIntrinsic()) {
670b57cec5SDimitry Andric           // This is an intrinsic function call, check if its an istypep
680b57cec5SDimitry Andric           switch (CalledF->getIntrinsicID()) {
690b57cec5SDimitry Andric           default: break;
700b57cec5SDimitry Andric           case Intrinsic::nvvm_istypep_sampler:
710b57cec5SDimitry Andric             Changed |= replaceIsTypePSampler(Instr);
720b57cec5SDimitry Andric             break;
730b57cec5SDimitry Andric           case Intrinsic::nvvm_istypep_surface:
740b57cec5SDimitry Andric             Changed |= replaceIsTypePSurface(Instr);
750b57cec5SDimitry Andric             break;
760b57cec5SDimitry Andric           case Intrinsic::nvvm_istypep_texture:
770b57cec5SDimitry Andric             Changed |= replaceIsTypePTexture(Instr);
780b57cec5SDimitry Andric             break;
790b57cec5SDimitry Andric           }
800b57cec5SDimitry Andric         }
810b57cec5SDimitry Andric       }
820b57cec5SDimitry Andric     }
830b57cec5SDimitry Andric   }
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric   // Delete any istypep instances we replaced in the IR
8604eeddc0SDimitry Andric   for (Instruction *I : InstrToDelete)
8704eeddc0SDimitry Andric     I->eraseFromParent();
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric   return Changed;
900b57cec5SDimitry Andric }
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric bool NVPTXImageOptimizer::replaceIsTypePSampler(Instruction &I) {
930b57cec5SDimitry Andric   Value *TexHandle = cleanupValue(I.getOperand(0));
940b57cec5SDimitry Andric   if (isSampler(*TexHandle)) {
950b57cec5SDimitry Andric     // This is an OpenCL sampler, so it must be a samplerref
960b57cec5SDimitry Andric     replaceWith(&I, ConstantInt::getTrue(I.getContext()));
970b57cec5SDimitry Andric     return true;
980b57cec5SDimitry Andric   } else if (isImage(*TexHandle)) {
990b57cec5SDimitry Andric     // This is an OpenCL image, so it cannot be a samplerref
1000b57cec5SDimitry Andric     replaceWith(&I, ConstantInt::getFalse(I.getContext()));
1010b57cec5SDimitry Andric     return true;
1020b57cec5SDimitry Andric   } else {
1030b57cec5SDimitry Andric     // The image type is unknown, so we cannot eliminate the intrinsic
1040b57cec5SDimitry Andric     return false;
1050b57cec5SDimitry Andric   }
1060b57cec5SDimitry Andric }
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric bool NVPTXImageOptimizer::replaceIsTypePSurface(Instruction &I) {
1090b57cec5SDimitry Andric   Value *TexHandle = cleanupValue(I.getOperand(0));
1100b57cec5SDimitry Andric   if (isImageReadWrite(*TexHandle) ||
1110b57cec5SDimitry Andric       isImageWriteOnly(*TexHandle)) {
1120b57cec5SDimitry Andric     // This is an OpenCL read-only/read-write image, so it must be a surfref
1130b57cec5SDimitry Andric     replaceWith(&I, ConstantInt::getTrue(I.getContext()));
1140b57cec5SDimitry Andric     return true;
1150b57cec5SDimitry Andric   } else if (isImageReadOnly(*TexHandle) ||
1160b57cec5SDimitry Andric              isSampler(*TexHandle)) {
1170b57cec5SDimitry Andric     // This is an OpenCL read-only/ imageor sampler, so it cannot be
1180b57cec5SDimitry Andric     // a surfref
1190b57cec5SDimitry Andric     replaceWith(&I, ConstantInt::getFalse(I.getContext()));
1200b57cec5SDimitry Andric     return true;
1210b57cec5SDimitry Andric   } else {
1220b57cec5SDimitry Andric     // The image type is unknown, so we cannot eliminate the intrinsic
1230b57cec5SDimitry Andric     return false;
1240b57cec5SDimitry Andric   }
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric bool NVPTXImageOptimizer::replaceIsTypePTexture(Instruction &I) {
1280b57cec5SDimitry Andric   Value *TexHandle = cleanupValue(I.getOperand(0));
1290b57cec5SDimitry Andric   if (isImageReadOnly(*TexHandle)) {
1300b57cec5SDimitry Andric     // This is an OpenCL read-only image, so it must be a texref
1310b57cec5SDimitry Andric     replaceWith(&I, ConstantInt::getTrue(I.getContext()));
1320b57cec5SDimitry Andric     return true;
1330b57cec5SDimitry Andric   } else if (isImageWriteOnly(*TexHandle) ||
1340b57cec5SDimitry Andric              isImageReadWrite(*TexHandle) ||
1350b57cec5SDimitry Andric              isSampler(*TexHandle)) {
1360b57cec5SDimitry Andric     // This is an OpenCL read-write/write-only image or a sampler, so it
1370b57cec5SDimitry Andric     // cannot be a texref
1380b57cec5SDimitry Andric     replaceWith(&I, ConstantInt::getFalse(I.getContext()));
1390b57cec5SDimitry Andric     return true;
1400b57cec5SDimitry Andric   } else {
1410b57cec5SDimitry Andric     // The image type is unknown, so we cannot eliminate the intrinsic
1420b57cec5SDimitry Andric     return false;
1430b57cec5SDimitry Andric   }
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric void NVPTXImageOptimizer::replaceWith(Instruction *From, ConstantInt *To) {
1470b57cec5SDimitry Andric   // We implement "poor man's DCE" here to make sure any code that is no longer
1480b57cec5SDimitry Andric   // live is actually unreachable and can be trivially eliminated by the
1490b57cec5SDimitry Andric   // unreachable block elimination pass.
150349cc55cSDimitry Andric   for (Use &U : From->uses()) {
151349cc55cSDimitry Andric     if (BranchInst *BI = dyn_cast<BranchInst>(U)) {
1520b57cec5SDimitry Andric       if (BI->isUnconditional()) continue;
1530b57cec5SDimitry Andric       BasicBlock *Dest;
1540b57cec5SDimitry Andric       if (To->isZero())
1550b57cec5SDimitry Andric         // Get false block
1560b57cec5SDimitry Andric         Dest = BI->getSuccessor(1);
1570b57cec5SDimitry Andric       else
1580b57cec5SDimitry Andric         // Get true block
1590b57cec5SDimitry Andric         Dest = BI->getSuccessor(0);
160*0fca6ea1SDimitry Andric       BranchInst::Create(Dest, BI->getIterator());
1610b57cec5SDimitry Andric       InstrToDelete.push_back(BI);
1620b57cec5SDimitry Andric     }
1630b57cec5SDimitry Andric   }
1640b57cec5SDimitry Andric   From->replaceAllUsesWith(To);
1650b57cec5SDimitry Andric   InstrToDelete.push_back(From);
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric Value *NVPTXImageOptimizer::cleanupValue(Value *V) {
1690b57cec5SDimitry Andric   if (ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(V)) {
1700b57cec5SDimitry Andric     return cleanupValue(EVI->getAggregateOperand());
1710b57cec5SDimitry Andric   }
1720b57cec5SDimitry Andric   return V;
1730b57cec5SDimitry Andric }
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric FunctionPass *llvm::createNVPTXImageOptimizerPass() {
1760b57cec5SDimitry Andric   return new NVPTXImageOptimizer();
1770b57cec5SDimitry Andric }
178