Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/llvm/lib/Target/NVPTX/NVPTXImageOptimizer.cpp
Line
Count
Source (jump to first uncovered line)
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 "NVPTXUtilities.h"
18
#include "llvm/Analysis/ConstantFolding.h"
19
#include "llvm/IR/Instructions.h"
20
#include "llvm/IR/Intrinsics.h"
21
#include "llvm/IR/IntrinsicsNVPTX.h"
22
#include "llvm/IR/Module.h"
23
#include "llvm/Pass.h"
24
25
using namespace llvm;
26
27
namespace {
28
class NVPTXImageOptimizer : public FunctionPass {
29
private:
30
  static char ID;
31
  SmallVector<Instruction*, 4> InstrToDelete;
32
33
public:
34
  NVPTXImageOptimizer();
35
36
  bool runOnFunction(Function &F) override;
37
38
0
  StringRef getPassName() const override { return "NVPTX Image Optimizer"; }
39
40
private:
41
  bool replaceIsTypePSampler(Instruction &I);
42
  bool replaceIsTypePSurface(Instruction &I);
43
  bool replaceIsTypePTexture(Instruction &I);
44
  Value *cleanupValue(Value *V);
45
  void replaceWith(Instruction *From, ConstantInt *To);
46
};
47
}
48
49
char NVPTXImageOptimizer::ID = 0;
50
51
NVPTXImageOptimizer::NVPTXImageOptimizer()
52
740
  : FunctionPass(ID) {}
53
54
738
bool NVPTXImageOptimizer::runOnFunction(Function &F) {
55
738
  if (skipFunction(F))
56
0
    return false;
57
58
738
  bool Changed = false;
59
738
  InstrToDelete.clear();
60
61
  // Look for call instructions in the function
62
767
  for (BasicBlock &BB : F) {
63
17.9k
    for (Instruction &Instr : BB) {
64
17.9k
      if (CallInst *CI = dyn_cast<CallInst>(&Instr)) {
65
0
        Function *CalledF = CI->getCalledFunction();
66
0
        if (CalledF && CalledF->isIntrinsic()) {
67
          // This is an intrinsic function call, check if its an istypep
68
0
          switch (CalledF->getIntrinsicID()) {
69
0
          default: break;
70
0
          case Intrinsic::nvvm_istypep_sampler:
71
0
            Changed |= replaceIsTypePSampler(Instr);
72
0
            break;
73
0
          case Intrinsic::nvvm_istypep_surface:
74
0
            Changed |= replaceIsTypePSurface(Instr);
75
0
            break;
76
0
          case Intrinsic::nvvm_istypep_texture:
77
0
            Changed |= replaceIsTypePTexture(Instr);
78
0
            break;
79
0
          }
80
0
        }
81
0
      }
82
17.9k
    }
83
767
  }
84
85
  // Delete any istypep instances we replaced in the IR
86
738
  for (Instruction *I : InstrToDelete)
87
0
    I->eraseFromParent();
88
89
738
  return Changed;
90
738
}
91
92
0
bool NVPTXImageOptimizer::replaceIsTypePSampler(Instruction &I) {
93
0
  Value *TexHandle = cleanupValue(I.getOperand(0));
94
0
  if (isSampler(*TexHandle)) {
95
    // This is an OpenCL sampler, so it must be a samplerref
96
0
    replaceWith(&I, ConstantInt::getTrue(I.getContext()));
97
0
    return true;
98
0
  } else if (isImage(*TexHandle)) {
99
    // This is an OpenCL image, so it cannot be a samplerref
100
0
    replaceWith(&I, ConstantInt::getFalse(I.getContext()));
101
0
    return true;
102
0
  } else {
103
    // The image type is unknown, so we cannot eliminate the intrinsic
104
0
    return false;
105
0
  }
106
0
}
107
108
0
bool NVPTXImageOptimizer::replaceIsTypePSurface(Instruction &I) {
109
0
  Value *TexHandle = cleanupValue(I.getOperand(0));
110
0
  if (isImageReadWrite(*TexHandle) ||
111
0
      isImageWriteOnly(*TexHandle)) {
112
    // This is an OpenCL read-only/read-write image, so it must be a surfref
113
0
    replaceWith(&I, ConstantInt::getTrue(I.getContext()));
114
0
    return true;
115
0
  } else if (isImageReadOnly(*TexHandle) ||
116
0
             isSampler(*TexHandle)) {
117
    // This is an OpenCL read-only/ imageor sampler, so it cannot be
118
    // a surfref
119
0
    replaceWith(&I, ConstantInt::getFalse(I.getContext()));
120
0
    return true;
121
0
  } else {
122
    // The image type is unknown, so we cannot eliminate the intrinsic
123
0
    return false;
124
0
  }
125
0
}
126
127
0
bool NVPTXImageOptimizer::replaceIsTypePTexture(Instruction &I) {
128
0
  Value *TexHandle = cleanupValue(I.getOperand(0));
129
0
  if (isImageReadOnly(*TexHandle)) {
130
    // This is an OpenCL read-only image, so it must be a texref
131
0
    replaceWith(&I, ConstantInt::getTrue(I.getContext()));
132
0
    return true;
133
0
  } else if (isImageWriteOnly(*TexHandle) ||
134
0
             isImageReadWrite(*TexHandle) ||
135
0
             isSampler(*TexHandle)) {
136
    // This is an OpenCL read-write/write-only image or a sampler, so it
137
    // cannot be a texref
138
0
    replaceWith(&I, ConstantInt::getFalse(I.getContext()));
139
0
    return true;
140
0
  } else {
141
    // The image type is unknown, so we cannot eliminate the intrinsic
142
0
    return false;
143
0
  }
144
0
}
145
146
0
void NVPTXImageOptimizer::replaceWith(Instruction *From, ConstantInt *To) {
147
  // We implement "poor man's DCE" here to make sure any code that is no longer
148
  // live is actually unreachable and can be trivially eliminated by the
149
  // unreachable block elimination pass.
150
0
  for (Use &U : From->uses()) {
151
0
    if (BranchInst *BI = dyn_cast<BranchInst>(U)) {
152
0
      if (BI->isUnconditional()) continue;
153
0
      BasicBlock *Dest;
154
0
      if (To->isZero())
155
        // Get false block
156
0
        Dest = BI->getSuccessor(1);
157
0
      else
158
        // Get true block
159
0
        Dest = BI->getSuccessor(0);
160
0
      BranchInst::Create(Dest, BI);
161
0
      InstrToDelete.push_back(BI);
162
0
    }
163
0
  }
164
0
  From->replaceAllUsesWith(To);
165
0
  InstrToDelete.push_back(From);
166
0
}
167
168
0
Value *NVPTXImageOptimizer::cleanupValue(Value *V) {
169
0
  if (ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(V)) {
170
0
    return cleanupValue(EVI->getAggregateOperand());
171
0
  }
172
0
  return V;
173
0
}
174
175
740
FunctionPass *llvm::createNVPTXImageOptimizerPass() {
176
740
  return new NVPTXImageOptimizer();
177
740
}