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 {
29 SmallVector<Instruction *, 4> InstrToDelete;
30
31public:
32 bool run(Function &F);
33
34private:
35 bool replaceIsTypeP(Instruction &I, PTXOpaqueType Expected);
36 Value *cleanupValue(Value *V);
37 void replaceWith(Instruction *From, ConstantInt *To);
38};
39} // namespace
40
41bool NVPTXImageOptimizer::run(Function &F) {
42 bool Changed = false;
43 InstrToDelete.clear();
44
45 // Look for call instructions in the function
46 for (BasicBlock &BB : F) {
47 for (Instruction &Instr : BB) {
48 if (CallInst *CI = dyn_cast<CallInst>(Val: &Instr)) {
49 Function *CalledF = CI->getCalledFunction();
50 if (CalledF && CalledF->isIntrinsic()) {
51 // This is an intrinsic function call, check if its an istypep
52 switch (CalledF->getIntrinsicID()) {
53 default: break;
54 case Intrinsic::nvvm_istypep_sampler:
55 Changed |= replaceIsTypeP(I&: Instr, Expected: PTXOpaqueType::Sampler);
56 break;
57 case Intrinsic::nvvm_istypep_surface:
58 Changed |= replaceIsTypeP(I&: Instr, Expected: PTXOpaqueType::Surface);
59 break;
60 case Intrinsic::nvvm_istypep_texture:
61 Changed |= replaceIsTypeP(I&: Instr, Expected: PTXOpaqueType::Texture);
62 break;
63 }
64 }
65 }
66 }
67 }
68
69 // Delete any istypep instances we replaced in the IR
70 for (Instruction *I : InstrToDelete)
71 I->eraseFromParent();
72
73 return Changed;
74}
75
76bool NVPTXImageOptimizer::replaceIsTypeP(Instruction &I,
77 PTXOpaqueType Expected) {
78 PTXOpaqueType OT = getPTXOpaqueType(*cleanupValue(V: I.getOperand(i: 0)));
79 if (OT == PTXOpaqueType::None)
80 return false;
81 replaceWith(From: &I, To: ConstantInt::getBool(Context&: I.getContext(), V: OT == Expected));
82 return true;
83}
84
85void NVPTXImageOptimizer::replaceWith(Instruction *From, ConstantInt *To) {
86 // We implement "poor man's DCE" here to make sure any code that is no longer
87 // live is actually unreachable and can be trivially eliminated by the
88 // unreachable block elimination pass.
89 for (Use &U : From->uses()) {
90 if (CondBrInst *BI = dyn_cast<CondBrInst>(Val&: U)) {
91 BasicBlock *Dest = BI->getSuccessor(i: To->isZero() ? 1 : 0);
92 UncondBrInst::Create(Target: Dest, InsertBefore: BI->getIterator());
93 InstrToDelete.push_back(Elt: BI);
94 }
95 }
96 From->replaceAllUsesWith(V: To);
97 InstrToDelete.push_back(Elt: From);
98}
99
100Value *NVPTXImageOptimizer::cleanupValue(Value *V) {
101 if (ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(Val: V)) {
102 return cleanupValue(V: EVI->getAggregateOperand());
103 }
104 return V;
105}
106
107namespace {
108class NVPTXImageOptimizerLegacyPass : public FunctionPass {
109public:
110 static char ID;
111 NVPTXImageOptimizerLegacyPass() : FunctionPass(ID) {}
112
113 bool runOnFunction(Function &F) override {
114 if (skipFunction(F))
115 return false;
116 return NVPTXImageOptimizer().run(F);
117 }
118
119 StringRef getPassName() const override { return "NVPTX Image Optimizer"; }
120};
121} // namespace
122
123char NVPTXImageOptimizerLegacyPass::ID = 0;
124
125FunctionPass *llvm::createNVPTXImageOptimizerLegacyPass() {
126 return new NVPTXImageOptimizerLegacyPass();
127}
128
129PreservedAnalyses NVPTXImageOptimizerPass::run(Function &F,
130 FunctionAnalysisManager &FAM) {
131 // The transform replaces conditional branches with unconditional ones, so
132 // the CFG is not preserved.
133 return NVPTXImageOptimizer().run(F) ? PreservedAnalyses::none()
134 : PreservedAnalyses::all();
135}
136