180 lines
5.6 KiB
C++
180 lines
5.6 KiB
C++
//===-- NVPTXImageOptimizer.cpp - Image optimization pass -----------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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/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();
|
|
}
|