radeon/llvm: Move kernel arg lowering into R600TargetLowering class
This commit is contained in:
parent
9fac1d1c3a
commit
059a56bddb
|
@ -53,8 +53,6 @@ SDValue AMDGPUTargetLowering::LowerFormalArguments(
|
|||
DebugLoc DL, SelectionDAG &DAG,
|
||||
SmallVectorImpl<SDValue> &InVals) const
|
||||
{
|
||||
// Lowering of arguments happens in R600LowerKernelParameters, so we can
|
||||
// ignore the arguments here.
|
||||
for (unsigned i = 0, e = Ins.size(); i < e; ++i) {
|
||||
InVals.push_back(SDValue());
|
||||
}
|
||||
|
|
|
@ -95,11 +95,6 @@ TargetPassConfig *AMDGPUTargetMachine::createPassConfig(PassManagerBase &PM) {
|
|||
bool
|
||||
AMDGPUPassConfig::addPreISel()
|
||||
{
|
||||
const AMDGPUSubtarget &ST = TM->getSubtarget<AMDGPUSubtarget>();
|
||||
if (ST.device()->getGeneration() <= AMDGPUDeviceInfo::HD6XXX) {
|
||||
PM->add(createR600KernelParametersPass(
|
||||
getAMDGPUTargetMachine().getTargetData()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,6 @@ CPP_SOURCES := \
|
|||
R600ExpandSpecialInstrs.cpp \
|
||||
R600ISelLowering.cpp \
|
||||
R600InstrInfo.cpp \
|
||||
R600KernelParameters.cpp \
|
||||
R600MachineFunctionInfo.cpp \
|
||||
R600RegisterInfo.cpp \
|
||||
SIAssignInterpRegs.cpp \
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "R600Defines.h"
|
||||
#include "R600InstrInfo.h"
|
||||
#include "R600MachineFunctionInfo.h"
|
||||
#include "llvm/Argument.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/SelectionDAG.h"
|
||||
|
@ -576,3 +577,30 @@ SDValue R600TargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const
|
|||
Cond);
|
||||
return Cond;
|
||||
}
|
||||
|
||||
// XXX Only kernel functions are supporte, so we can assume for now that
|
||||
// every function is a kernel function, but in the future we should use
|
||||
// separate calling conventions for kernel and non-kernel functions.
|
||||
// Only kernel functions are supported, so we can assume for now
|
||||
SDValue R600TargetLowering::LowerFormalArguments(
|
||||
SDValue Chain,
|
||||
CallingConv::ID CallConv,
|
||||
bool isVarArg,
|
||||
const SmallVectorImpl<ISD::InputArg> &Ins,
|
||||
DebugLoc DL, SelectionDAG &DAG,
|
||||
SmallVectorImpl<SDValue> &InVals) const
|
||||
{
|
||||
unsigned ParamOffsetBytes = 36;
|
||||
for (unsigned i = 0, e = Ins.size(); i < e; ++i) {
|
||||
EVT VT = Ins[i].VT;
|
||||
PointerType *PtrTy = PointerType::get(VT.getTypeForEVT(*DAG.getContext()),
|
||||
AMDGPUAS::PARAM_I_ADDRESS);
|
||||
SDValue Arg = DAG.getLoad(VT, DL, DAG.getRoot(),
|
||||
DAG.getConstant(ParamOffsetBytes, MVT::i32),
|
||||
MachinePointerInfo(new Argument(PtrTy)),
|
||||
false, false, false, 4);
|
||||
InVals.push_back(Arg);
|
||||
ParamOffsetBytes += (VT.getStoreSize());
|
||||
}
|
||||
return Chain;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,13 @@ public:
|
|||
void ReplaceNodeResults(SDNode * N,
|
||||
SmallVectorImpl<SDValue> &Results,
|
||||
SelectionDAG &DAG) const;
|
||||
virtual SDValue LowerFormalArguments(
|
||||
SDValue Chain,
|
||||
CallingConv::ID CallConv,
|
||||
bool isVarArg,
|
||||
const SmallVectorImpl<ISD::InputArg> &Ins,
|
||||
DebugLoc DL, SelectionDAG &DAG,
|
||||
SmallVectorImpl<SDValue> &InVals) const;
|
||||
private:
|
||||
const R600InstrInfo * TII;
|
||||
|
||||
|
|
|
@ -1,462 +0,0 @@
|
|||
//===-- R600KernelParameters.cpp - Lower kernel function arguments --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass lowers kernel function arguments to loads from the vertex buffer.
|
||||
//
|
||||
// Kernel arguemnts are stored in the vertex buffer at an offset of 9 dwords,
|
||||
// so arg0 needs to be loaded from VTX_BUFFER[9] and arg1 is loaded from
|
||||
// VTX_BUFFER[10], etc.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "AMDGPU.h"
|
||||
#include "AMDIL.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/Intrinsics.h"
|
||||
#include "llvm/Metadata.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include "llvm/Support/IRBuilder.h"
|
||||
#include "llvm/Support/TypeBuilder.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
#define CONSTANT_CACHE_SIZE_DW 127
|
||||
|
||||
class R600KernelParameters : public FunctionPass {
|
||||
const TargetData *TD;
|
||||
LLVMContext* Context;
|
||||
Module *Mod;
|
||||
|
||||
struct Param {
|
||||
Param() : Val(NULL), PtrVal(NULL), OffsetInDW(0), SizeInDW(0),
|
||||
IsIndirect(true), SpecialID(0) {}
|
||||
|
||||
Value* Val;
|
||||
Value* PtrVal;
|
||||
int OffsetInDW;
|
||||
int SizeInDW;
|
||||
|
||||
bool IsIndirect;
|
||||
|
||||
std::string SpecialType;
|
||||
int SpecialID;
|
||||
|
||||
int End() { return OffsetInDW + SizeInDW; }
|
||||
// The first 9 dwords are reserved for the grid sizes.
|
||||
int getRatOffset() { return 9 + OffsetInDW; }
|
||||
};
|
||||
|
||||
std::vector<Param> Params;
|
||||
|
||||
bool IsOpenCLKernel(const Function *Fun);
|
||||
int getLastSpecialID(const std::string& TypeName);
|
||||
|
||||
int getListSize();
|
||||
void AddParam(Argument *Arg);
|
||||
int CalculateArgumentSize(Argument *Arg);
|
||||
void RunAna(Function *Fun);
|
||||
void Replace(Function *Fun);
|
||||
bool IsIndirect(Value *Val, std::set<Value*> &Visited);
|
||||
void Propagate(Function* Fun);
|
||||
void Propagate(Value *V, const Twine &Name, bool IsIndirect = true);
|
||||
Value* ConstantRead(Function *Fun, Param &P);
|
||||
Value* handleSpecial(Function *Fun, Param &P);
|
||||
bool IsSpecialType(Type *T);
|
||||
std::string getSpecialTypeName(Type *T);
|
||||
public:
|
||||
static char ID;
|
||||
R600KernelParameters() : FunctionPass(ID) {};
|
||||
R600KernelParameters(const TargetData* TD) : FunctionPass(ID), TD(TD) {}
|
||||
bool runOnFunction (Function &F);
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const;
|
||||
const char *getPassName() const;
|
||||
bool doInitialization(Module &M);
|
||||
bool doFinalization(Module &M);
|
||||
};
|
||||
|
||||
char R600KernelParameters::ID = 0;
|
||||
|
||||
static RegisterPass<R600KernelParameters> X("kerparam",
|
||||
"OpenCL Kernel Parameter conversion", false, false);
|
||||
|
||||
bool R600KernelParameters::IsOpenCLKernel(const Function* Fun) {
|
||||
Module *Mod = const_cast<Function*>(Fun)->getParent();
|
||||
NamedMDNode * MD = Mod->getOrInsertNamedMetadata("opencl.kernels");
|
||||
|
||||
if (!MD || !MD->getNumOperands()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < int(MD->getNumOperands()); i++) {
|
||||
if (!MD->getOperand(i) || !MD->getOperand(i)->getOperand(0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(MD->getOperand(i)->getNumOperands() == 1);
|
||||
|
||||
if (MD->getOperand(i)->getOperand(0)->getName() == Fun->getName()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int R600KernelParameters::getLastSpecialID(const std::string &TypeName) {
|
||||
int LastID = -1;
|
||||
|
||||
for (std::vector<Param>::iterator i = Params.begin(); i != Params.end(); i++) {
|
||||
if (i->SpecialType == TypeName) {
|
||||
LastID = i->SpecialID;
|
||||
}
|
||||
}
|
||||
|
||||
return LastID;
|
||||
}
|
||||
|
||||
int R600KernelParameters::getListSize() {
|
||||
if (Params.size() == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Params.back().End();
|
||||
}
|
||||
|
||||
bool R600KernelParameters::IsIndirect(Value *Val, std::set<Value*> &Visited) {
|
||||
//XXX Direct parameters are not supported yet, so return true here.
|
||||
return true;
|
||||
#if 0
|
||||
if (isa<LoadInst>(Val)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isa<IntegerType>(Val->getType())) {
|
||||
assert(0 && "Internal error");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Visited.count(Val)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Visited.insert(Val);
|
||||
|
||||
if (isa<getElementPtrInst>(Val)) {
|
||||
getElementPtrInst* GEP = dyn_cast<getElementPtrInst>(Val);
|
||||
getElementPtrInst::op_iterator I = GEP->op_begin();
|
||||
|
||||
for (++I; I != GEP->op_end(); ++I) {
|
||||
if (!isa<Constant>(*I)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Value::use_iterator I = Val->use_begin(); i != Val->use_end(); ++I) {
|
||||
Value* V2 = dyn_cast<Value>(*I);
|
||||
|
||||
if (V2) {
|
||||
if (IsIndirect(V2, Visited)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void R600KernelParameters::AddParam(Argument *Arg) {
|
||||
Param P;
|
||||
|
||||
P.Val = dyn_cast<Value>(Arg);
|
||||
P.OffsetInDW = getListSize();
|
||||
P.SizeInDW = CalculateArgumentSize(Arg);
|
||||
|
||||
if (isa<PointerType>(Arg->getType()) && Arg->hasByValAttr()) {
|
||||
std::set<Value*> Visited;
|
||||
P.IsIndirect = IsIndirect(P.Val, Visited);
|
||||
}
|
||||
|
||||
Params.push_back(P);
|
||||
}
|
||||
|
||||
int R600KernelParameters::CalculateArgumentSize(Argument *Arg) {
|
||||
Type* T = Arg->getType();
|
||||
|
||||
if (Arg->hasByValAttr() && dyn_cast<PointerType>(T)) {
|
||||
T = dyn_cast<PointerType>(T)->getElementType();
|
||||
}
|
||||
|
||||
int StoreSizeInDW = (TD->getTypeStoreSize(T) + 3)/4;
|
||||
|
||||
assert(StoreSizeInDW);
|
||||
|
||||
return StoreSizeInDW;
|
||||
}
|
||||
|
||||
|
||||
void R600KernelParameters::RunAna(Function* Fun) {
|
||||
assert(IsOpenCLKernel(Fun));
|
||||
|
||||
for (Function::arg_iterator I = Fun->arg_begin(); I != Fun->arg_end(); ++I) {
|
||||
AddParam(I);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void R600KernelParameters::Replace(Function* Fun) {
|
||||
for (std::vector<Param>::iterator I = Params.begin(); I != Params.end(); ++I) {
|
||||
Value *NewVal;
|
||||
|
||||
if (IsSpecialType(I->Val->getType())) {
|
||||
NewVal = handleSpecial(Fun, *I);
|
||||
} else {
|
||||
NewVal = ConstantRead(Fun, *I);
|
||||
}
|
||||
if (NewVal) {
|
||||
I->Val->replaceAllUsesWith(NewVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void R600KernelParameters::Propagate(Function* Fun) {
|
||||
for (std::vector<Param>::iterator I = Params.begin(); I != Params.end(); ++I) {
|
||||
if (I->PtrVal) {
|
||||
Propagate(I->PtrVal, I->Val->getName(), I->IsIndirect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void R600KernelParameters::Propagate(Value* V, const Twine& Name, bool IsIndirect) {
|
||||
LoadInst* Load = dyn_cast<LoadInst>(V);
|
||||
GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(V);
|
||||
|
||||
unsigned Addrspace;
|
||||
|
||||
if (IsIndirect) {
|
||||
Addrspace = AMDGPUAS::PARAM_I_ADDRESS;
|
||||
} else {
|
||||
Addrspace = AMDGPUAS::PARAM_D_ADDRESS;
|
||||
}
|
||||
|
||||
if (GEP && GEP->getType()->getAddressSpace() != Addrspace) {
|
||||
Value *Op = GEP->getPointerOperand();
|
||||
|
||||
if (dyn_cast<PointerType>(Op->getType())->getAddressSpace() != Addrspace) {
|
||||
Op = new BitCastInst(Op, PointerType::get(dyn_cast<PointerType>(
|
||||
Op->getType())->getElementType(), Addrspace),
|
||||
Name, dyn_cast<Instruction>(V));
|
||||
}
|
||||
|
||||
std::vector<Value*> Params(GEP->idx_begin(), GEP->idx_end());
|
||||
|
||||
GetElementPtrInst* GEP2 = GetElementPtrInst::Create(Op, Params, Name,
|
||||
dyn_cast<Instruction>(V));
|
||||
GEP2->setIsInBounds(GEP->isInBounds());
|
||||
V = dyn_cast<Value>(GEP2);
|
||||
GEP->replaceAllUsesWith(GEP2);
|
||||
GEP->eraseFromParent();
|
||||
Load = NULL;
|
||||
}
|
||||
|
||||
if (Load) {
|
||||
///normally at this point we have the right address space
|
||||
if (Load->getPointerAddressSpace() != Addrspace) {
|
||||
Value *OrigPtr = Load->getPointerOperand();
|
||||
PointerType *OrigPtrType = dyn_cast<PointerType>(OrigPtr->getType());
|
||||
|
||||
Type* NewPtrType = PointerType::get(OrigPtrType->getElementType(),
|
||||
Addrspace);
|
||||
|
||||
Value* NewPtr = OrigPtr;
|
||||
|
||||
if (OrigPtr->getType() != NewPtrType) {
|
||||
NewPtr = new BitCastInst(OrigPtr, NewPtrType, "prop_cast", Load);
|
||||
}
|
||||
|
||||
Value* new_Load = new LoadInst(NewPtr, Name, Load);
|
||||
Load->replaceAllUsesWith(new_Load);
|
||||
Load->eraseFromParent();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<User*> Users(V->use_begin(), V->use_end());
|
||||
|
||||
for (int i = 0; i < int(Users.size()); i++) {
|
||||
Value* V2 = dyn_cast<Value>(Users[i]);
|
||||
|
||||
if (V2) {
|
||||
Propagate(V2, Name, IsIndirect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Value* R600KernelParameters::ConstantRead(Function *Fun, Param &P) {
|
||||
assert(Fun->front().begin() != Fun->front().end());
|
||||
|
||||
Instruction *FirstInst = Fun->front().begin();
|
||||
IRBuilder <> Builder (FirstInst);
|
||||
/* First 3 dwords are reserved for the dimmension info */
|
||||
|
||||
if (!P.Val->hasNUsesOrMore(1)) {
|
||||
return NULL;
|
||||
}
|
||||
unsigned Addrspace;
|
||||
|
||||
if (P.IsIndirect) {
|
||||
Addrspace = AMDGPUAS::PARAM_I_ADDRESS;
|
||||
} else {
|
||||
Addrspace = AMDGPUAS::PARAM_D_ADDRESS;
|
||||
}
|
||||
|
||||
Argument *Arg = dyn_cast<Argument>(P.Val);
|
||||
Type * ArgType = P.Val->getType();
|
||||
PointerType * ArgPtrType = dyn_cast<PointerType>(P.Val->getType());
|
||||
|
||||
if (ArgPtrType && Arg->hasByValAttr()) {
|
||||
Value* ParamAddrSpacePtr = ConstantPointerNull::get(
|
||||
PointerType::get(Type::getInt32Ty(*Context),
|
||||
Addrspace));
|
||||
Value* ParamPtr = GetElementPtrInst::Create(ParamAddrSpacePtr,
|
||||
ConstantInt::get(Type::getInt32Ty(*Context),
|
||||
P.getRatOffset()), Arg->getName(),
|
||||
FirstInst);
|
||||
ParamPtr = new BitCastInst(ParamPtr,
|
||||
PointerType::get(ArgPtrType->getElementType(),
|
||||
Addrspace),
|
||||
Arg->getName(), FirstInst);
|
||||
P.PtrVal = ParamPtr;
|
||||
return ParamPtr;
|
||||
} else {
|
||||
Value *ParamAddrSpacePtr = ConstantPointerNull::get(PointerType::get(
|
||||
ArgType, Addrspace));
|
||||
|
||||
Value *ParamPtr = Builder.CreateGEP(ParamAddrSpacePtr,
|
||||
ConstantInt::get(Type::getInt32Ty(*Context), P.getRatOffset()),
|
||||
Arg->getName());
|
||||
|
||||
Value *Param_Value = Builder.CreateLoad(ParamPtr, Arg->getName());
|
||||
|
||||
return Param_Value;
|
||||
}
|
||||
}
|
||||
|
||||
Value* R600KernelParameters::handleSpecial(Function* Fun, Param& P) {
|
||||
std::string Name = getSpecialTypeName(P.Val->getType());
|
||||
int ID;
|
||||
|
||||
assert(!Name.empty());
|
||||
|
||||
if (Name == "image2d_t" || Name == "image3d_t") {
|
||||
int LastID = std::max(getLastSpecialID("image2d_t"),
|
||||
getLastSpecialID("image3d_t"));
|
||||
|
||||
if (LastID == -1) {
|
||||
ID = 2; ///ID0 and ID1 are used internally by the driver
|
||||
} else {
|
||||
ID = LastID + 1;
|
||||
}
|
||||
} else if (Name == "sampler_t") {
|
||||
int LastID = getLastSpecialID("sampler_t");
|
||||
|
||||
if (LastID == -1) {
|
||||
ID = 0;
|
||||
} else {
|
||||
ID = LastID + 1;
|
||||
}
|
||||
} else {
|
||||
///TODO: give some error message
|
||||
return NULL;
|
||||
}
|
||||
|
||||
P.SpecialType = Name;
|
||||
P.SpecialID = ID;
|
||||
|
||||
Instruction *FirstInst = Fun->front().begin();
|
||||
|
||||
return new IntToPtrInst(ConstantInt::get(Type::getInt32Ty(*Context),
|
||||
P.SpecialID), P.Val->getType(),
|
||||
"resourceID", FirstInst);
|
||||
}
|
||||
|
||||
|
||||
bool R600KernelParameters::IsSpecialType(Type* T) {
|
||||
return !getSpecialTypeName(T).empty();
|
||||
}
|
||||
|
||||
std::string R600KernelParameters::getSpecialTypeName(Type* T) {
|
||||
PointerType *PT = dyn_cast<PointerType>(T);
|
||||
StructType *ST = NULL;
|
||||
|
||||
if (PT) {
|
||||
ST = dyn_cast<StructType>(PT->getElementType());
|
||||
}
|
||||
|
||||
if (ST) {
|
||||
std::string Prefix = "struct.opencl_builtin_type_";
|
||||
|
||||
std::string Name = ST->getName().str();
|
||||
|
||||
if (Name.substr(0, Prefix.length()) == Prefix) {
|
||||
return Name.substr(Prefix.length(), Name.length());
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
bool R600KernelParameters::runOnFunction (Function &F) {
|
||||
if (!IsOpenCLKernel(&F)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RunAna(&F);
|
||||
Replace(&F);
|
||||
Propagate(&F);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void R600KernelParameters::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
FunctionPass::getAnalysisUsage(AU);
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
|
||||
const char *R600KernelParameters::getPassName() const {
|
||||
return "OpenCL Kernel parameter conversion to memory";
|
||||
}
|
||||
|
||||
bool R600KernelParameters::doInitialization(Module &M) {
|
||||
Context = &M.getContext();
|
||||
Mod = &M;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool R600KernelParameters::doFinalization(Module &M) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End anonymous namespace
|
||||
|
||||
FunctionPass* llvm::createR600KernelParametersPass(const TargetData* TD) {
|
||||
return new R600KernelParameters(TD);
|
||||
}
|
Loading…
Reference in New Issue