1//===-- NVPTXImageOptimizer.cpp - Image optimization pass -----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This pass implements IR-level optimizations of image access code,
10// including:
11//
12// 1. Eliminate istypep intrinsics when image access qualifier is known
13//
14//===----------------------------------------------------------------------===//
15
16#include "NVPTX.h"
17#include "NVVMProperties.h"
18#include "llvm/Analysis/ConstantFolding.h"
19#include "llvm/IR/Constants.h"
20#include "llvm/IR/Instructions.h"
21#include "llvm/IR/Intrinsics.h"
22#include "llvm/IR/IntrinsicsNVPTX.h"
23#include "llvm/Pass.h"
24
25using namespace llvm;
26
27namespace {
28class NVPTXImageOptimizer : public FunctionPass {
29private:
30 static char ID;
31 SmallVector<Instruction*, 4> InstrToDelete;
32
33public:
34 NVPTXImageOptimizer();
35
36 bool runOnFunction(Function &F) override;
37
38 StringRef getPassName() const override { return "NVPTX Image Optimizer"; }
39
40private:
41 bool replaceIsTypeP(Instruction &I, PTXOpaqueType Expected);
42 Value *cleanupValue(Value *V);
43 void replaceWith(Instruction *From, ConstantInt *To);
44};
45}
46
47char NVPTXImageOptimizer::ID = 0;
48
49NVPTXImageOptimizer::NVPTXImageOptimizer()
50 : FunctionPass(ID) {}
51
52bool NVPTXImageOptimizer::runOnFunction(Function &F) {
53 if (skipFunction(F))
54 return false;
55
56 bool Changed = false;
57 InstrToDelete.clear();
58
59 // Look for call instructions in the function
60 for (BasicBlock &BB : F) {
61 for (Instruction &Instr : BB) {
62 if (CallInst *CI = dyn_cast<CallInst>(Val: &Instr)) {
63 Function *CalledF = CI->getCalledFunction();
64 if (CalledF && CalledF->isIntrinsic()) {
65 // This is an intrinsic function call, check if its an istypep
66 switch (CalledF->getIntrinsicID()) {
67 default: break;
68 case Intrinsic::nvvm_istypep_sampler:
69 Changed |= replaceIsTypeP(I&: Instr, Expected: PTXOpaqueType::Sampler);
70 break;
71 case Intrinsic::nvvm_istypep_surface:
72 Changed |= replaceIsTypeP(I&: Instr, Expected: PTXOpaqueType::Surface);
73 break;
74 case Intrinsic::nvvm_istypep_texture:
75 Changed |= replaceIsTypeP(I&: Instr, Expected: PTXOpaqueType::Texture);
76 break;
77 }
78 }
79 }
80 }
81 }
82
83 // Delete any istypep instances we replaced in the IR
84 for (Instruction *I : InstrToDelete)
85 I->eraseFromParent();
86
87 return Changed;
88}
89
90bool NVPTXImageOptimizer::replaceIsTypeP(Instruction &I,
91 PTXOpaqueType Expected) {
92 PTXOpaqueType OT = getPTXOpaqueType(*cleanupValue(V: I.getOperand(i: 0)));
93 if (OT == PTXOpaqueType::None)
94 return false;
95 replaceWith(From: &I, To: ConstantInt::getBool(Context&: I.getContext(), V: OT == Expected));
96 return true;
97}
98
99void NVPTXImageOptimizer::replaceWith(Instruction *From, ConstantInt *To) {
100 // We implement "poor man's DCE" here to make sure any code that is no longer
101 // live is actually unreachable and can be trivially eliminated by the
102 // unreachable block elimination pass.
103 for (Use &U : From->uses()) {
104 if (CondBrInst *BI = dyn_cast<CondBrInst>(Val&: U)) {
105 BasicBlock *Dest = BI->getSuccessor(i: To->isZero() ? 1 : 0);
106 UncondBrInst::Create(Target: Dest, InsertBefore: BI->getIterator());
107 InstrToDelete.push_back(Elt: BI);
108 }
109 }
110 From->replaceAllUsesWith(V: To);
111 InstrToDelete.push_back(Elt: From);
112}
113
114Value *NVPTXImageOptimizer::cleanupValue(Value *V) {
115 if (ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(Val: V)) {
116 return cleanupValue(V: EVI->getAggregateOperand());
117 }
118 return V;
119}
120
121FunctionPass *llvm::createNVPTXImageOptimizerPass() {
122 return new NVPTXImageOptimizer();
123}
124