180 lines
5.6 KiB
C++
180 lines
5.6 KiB
C++
|
//===-- NVPTXImageOptimizer.cpp - Image optimization pass -----------------===//
|
||
|
//
|
||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
//
|
||
|
// This pass implements IR-level optimizations of image access code,
|
||
|
// including:
|
||
|
//
|
||
|
// 1. Eliminate istypep intrinsics when image access qualifier is known
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
#include "NVPTX.h"
|
||
|
#include "NVPTXUtilities.h"
|
||
|
#include "llvm/Analysis/ConstantFolding.h"
|
||
|
#include "llvm/IR/Instructions.h"
|
||
|
#include "llvm/IR/Intrinsics.h"
|
||
|
#include "llvm/IR/IntrinsicsNVPTX.h"
|
||
|
#include "llvm/IR/Module.h"
|
||
|
#include "llvm/Pass.h"
|
||
|
|
||
|
using namespace llvm;
|
||
|
|
||
|
namespace {
|
||
|
class NVPTXImageOptimizer : public FunctionPass {
|
||
|
private:
|
||
|
static char ID;
|
||
|
SmallVector<Instruction*, 4> InstrToDelete;
|
||
|
|
||
|
public:
|
||
|
NVPTXImageOptimizer();
|
||
|
|
||
|
bool runOnFunction(Function &F) override;
|
||
|
|
||
|
private:
|
||
|
bool replaceIsTypePSampler(Instruction &I);
|
||
|
bool replaceIsTypePSurface(Instruction &I);
|
||
|
bool replaceIsTypePTexture(Instruction &I);
|
||
|
Value *cleanupValue(Value *V);
|
||
|
void replaceWith(Instruction *From, ConstantInt *To);
|
||
|
};
|
||
|
}
|
||
|
|
||
|
char NVPTXImageOptimizer::ID = 0;
|
||
|
|
||
|
NVPTXImageOptimizer::NVPTXImageOptimizer()
|
||
|
: FunctionPass(ID) {}
|
||
|
|
||
|
bool NVPTXImageOptimizer::runOnFunction(Function &F) {
|
||
|
if (skipFunction(F))
|
||
|
return false;
|
||
|
|
||
|
bool Changed = false;
|
||
|
InstrToDelete.clear();
|
||
|
|
||
|
// Look for call instructions in the function
|
||
|
for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE;
|
||
|
++BI) {
|
||
|
for (BasicBlock::iterator I = (*BI).begin(), E = (*BI).end();
|
||
|
I != E; ++I) {
|
||
|
Instruction &Instr = *I;
|
||
|
if (CallInst *CI = dyn_cast<CallInst>(I)) {
|
||
|
Function *CalledF = CI->getCalledFunction();
|
||
|
if (CalledF && CalledF->isIntrinsic()) {
|
||
|
// This is an intrinsic function call, check if its an istypep
|
||
|
switch (CalledF->getIntrinsicID()) {
|
||
|
default: break;
|
||
|
case Intrinsic::nvvm_istypep_sampler:
|
||
|
Changed |= replaceIsTypePSampler(Instr);
|
||
|
break;
|
||
|
case Intrinsic::nvvm_istypep_surface:
|
||
|
Changed |= replaceIsTypePSurface(Instr);
|
||
|
break;
|
||
|
case Intrinsic::nvvm_istypep_texture:
|
||
|
Changed |= replaceIsTypePTexture(Instr);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Delete any istypep instances we replaced in the IR
|
||
|
for (unsigned i = 0, e = InstrToDelete.size(); i != e; ++i)
|
||
|
InstrToDelete[i]->eraseFromParent();
|
||
|
|
||
|
return Changed;
|
||
|
}
|
||
|
|
||
|
bool NVPTXImageOptimizer::replaceIsTypePSampler(Instruction &I) {
|
||
|
Value *TexHandle = cleanupValue(I.getOperand(0));
|
||
|
if (isSampler(*TexHandle)) {
|
||
|
// This is an OpenCL sampler, so it must be a samplerref
|
||
|
replaceWith(&I, ConstantInt::getTrue(I.getContext()));
|
||
|
return true;
|
||
|
} else if (isImage(*TexHandle)) {
|
||
|
// This is an OpenCL image, so it cannot be a samplerref
|
||
|
replaceWith(&I, ConstantInt::getFalse(I.getContext()));
|
||
|
return true;
|
||
|
} else {
|
||
|
// The image type is unknown, so we cannot eliminate the intrinsic
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool NVPTXImageOptimizer::replaceIsTypePSurface(Instruction &I) {
|
||
|
Value *TexHandle = cleanupValue(I.getOperand(0));
|
||
|
if (isImageReadWrite(*TexHandle) ||
|
||
|
isImageWriteOnly(*TexHandle)) {
|
||
|
// This is an OpenCL read-only/read-write image, so it must be a surfref
|
||
|
replaceWith(&I, ConstantInt::getTrue(I.getContext()));
|
||
|
return true;
|
||
|
} else if (isImageReadOnly(*TexHandle) ||
|
||
|
isSampler(*TexHandle)) {
|
||
|
// This is an OpenCL read-only/ imageor sampler, so it cannot be
|
||
|
// a surfref
|
||
|
replaceWith(&I, ConstantInt::getFalse(I.getContext()));
|
||
|
return true;
|
||
|
} else {
|
||
|
// The image type is unknown, so we cannot eliminate the intrinsic
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool NVPTXImageOptimizer::replaceIsTypePTexture(Instruction &I) {
|
||
|
Value *TexHandle = cleanupValue(I.getOperand(0));
|
||
|
if (isImageReadOnly(*TexHandle)) {
|
||
|
// This is an OpenCL read-only image, so it must be a texref
|
||
|
replaceWith(&I, ConstantInt::getTrue(I.getContext()));
|
||
|
return true;
|
||
|
} else if (isImageWriteOnly(*TexHandle) ||
|
||
|
isImageReadWrite(*TexHandle) ||
|
||
|
isSampler(*TexHandle)) {
|
||
|
// This is an OpenCL read-write/write-only image or a sampler, so it
|
||
|
// cannot be a texref
|
||
|
replaceWith(&I, ConstantInt::getFalse(I.getContext()));
|
||
|
return true;
|
||
|
} else {
|
||
|
// The image type is unknown, so we cannot eliminate the intrinsic
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void NVPTXImageOptimizer::replaceWith(Instruction *From, ConstantInt *To) {
|
||
|
// We implement "poor man's DCE" here to make sure any code that is no longer
|
||
|
// live is actually unreachable and can be trivially eliminated by the
|
||
|
// unreachable block elimination pass.
|
||
|
for (CallInst::use_iterator UI = From->use_begin(), UE = From->use_end();
|
||
|
UI != UE; ++UI) {
|
||
|
if (BranchInst *BI = dyn_cast<BranchInst>(*UI)) {
|
||
|
if (BI->isUnconditional()) continue;
|
||
|
BasicBlock *Dest;
|
||
|
if (To->isZero())
|
||
|
// Get false block
|
||
|
Dest = BI->getSuccessor(1);
|
||
|
else
|
||
|
// Get true block
|
||
|
Dest = BI->getSuccessor(0);
|
||
|
BranchInst::Create(Dest, BI);
|
||
|
InstrToDelete.push_back(BI);
|
||
|
}
|
||
|
}
|
||
|
From->replaceAllUsesWith(To);
|
||
|
InstrToDelete.push_back(From);
|
||
|
}
|
||
|
|
||
|
Value *NVPTXImageOptimizer::cleanupValue(Value *V) {
|
||
|
if (ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(V)) {
|
||
|
return cleanupValue(EVI->getAggregateOperand());
|
||
|
}
|
||
|
return V;
|
||
|
}
|
||
|
|
||
|
FunctionPass *llvm::createNVPTXImageOptimizerPass() {
|
||
|
return new NVPTXImageOptimizer();
|
||
|
}
|