llvm-6502/lib/Target/NVPTX/NVPTXImageOptimizer.cpp
Justin Holewinski 77f268945e [NVPTX] Add preliminary intrinsics and codegen support for textures/surfaces
This commit adds intrinsics and codegen support for the surface read/write and texture read instructions that take an explicit sampler parameter. Codegen operates on image handles at the PTX level, but falls back to direct replacement of handles with kernel arguments if image handles are not enabled. Note that image handles are explicitly disabled for all target architectures in this change (to be enabled later).

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@205907 91177308-0d34-0410-b5e6-96231b3b80d8
2014-04-09 15:39:15 +00:00

179 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/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/ConstantFolding.h"
using namespace llvm;
namespace {
class NVPTXImageOptimizer : public FunctionPass {
private:
static char ID;
SmallVector<Instruction*, 4> InstrToDelete;
public:
NVPTXImageOptimizer();
bool runOnFunction(Function &F);
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) {
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 (isImageWriteOnly(*TexHandle) ||
isImageReadWrite(*TexHandle) ||
isImageReadOnly(*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 elimiation 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();
}