304 lines
8.3 KiB
C++
304 lines
8.3 KiB
C++
//===-- R600TextureIntrinsicsReplacer.cpp ---------------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
/// \file
|
|
/// This pass translates tgsi-like texture intrinsics into R600 texture
|
|
/// closer to hardware intrinsics.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "AMDGPU.h"
|
|
#include "llvm/ADT/Statistic.h"
|
|
#include "llvm/Analysis/Passes.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/GlobalValue.h"
|
|
#include "llvm/IR/IRBuilder.h"
|
|
#include "llvm/IR/InstVisitor.h"
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
class R600TextureIntrinsicsReplacer :
|
|
public FunctionPass, public InstVisitor<R600TextureIntrinsicsReplacer> {
|
|
static char ID;
|
|
|
|
Module *Mod;
|
|
Type *FloatType;
|
|
Type *Int32Type;
|
|
Type *V4f32Type;
|
|
Type *V4i32Type;
|
|
FunctionType *TexSign;
|
|
FunctionType *TexQSign;
|
|
|
|
void getAdjustmentFromTextureTarget(unsigned TextureType, bool hasLOD,
|
|
unsigned SrcSelect[4], unsigned CT[4],
|
|
bool &useShadowVariant) {
|
|
enum TextureTypes {
|
|
TEXTURE_1D = 1,
|
|
TEXTURE_2D,
|
|
TEXTURE_3D,
|
|
TEXTURE_CUBE,
|
|
TEXTURE_RECT,
|
|
TEXTURE_SHADOW1D,
|
|
TEXTURE_SHADOW2D,
|
|
TEXTURE_SHADOWRECT,
|
|
TEXTURE_1D_ARRAY,
|
|
TEXTURE_2D_ARRAY,
|
|
TEXTURE_SHADOW1D_ARRAY,
|
|
TEXTURE_SHADOW2D_ARRAY,
|
|
TEXTURE_SHADOWCUBE,
|
|
TEXTURE_2D_MSAA,
|
|
TEXTURE_2D_ARRAY_MSAA,
|
|
TEXTURE_CUBE_ARRAY,
|
|
TEXTURE_SHADOWCUBE_ARRAY
|
|
};
|
|
|
|
switch (TextureType) {
|
|
case 0:
|
|
useShadowVariant = false;
|
|
return;
|
|
case TEXTURE_RECT:
|
|
case TEXTURE_1D:
|
|
case TEXTURE_2D:
|
|
case TEXTURE_3D:
|
|
case TEXTURE_CUBE:
|
|
case TEXTURE_1D_ARRAY:
|
|
case TEXTURE_2D_ARRAY:
|
|
case TEXTURE_CUBE_ARRAY:
|
|
case TEXTURE_2D_MSAA:
|
|
case TEXTURE_2D_ARRAY_MSAA:
|
|
useShadowVariant = false;
|
|
break;
|
|
case TEXTURE_SHADOW1D:
|
|
case TEXTURE_SHADOW2D:
|
|
case TEXTURE_SHADOWRECT:
|
|
case TEXTURE_SHADOW1D_ARRAY:
|
|
case TEXTURE_SHADOW2D_ARRAY:
|
|
case TEXTURE_SHADOWCUBE:
|
|
case TEXTURE_SHADOWCUBE_ARRAY:
|
|
useShadowVariant = true;
|
|
break;
|
|
default:
|
|
llvm_unreachable("Unknow Texture Type");
|
|
}
|
|
|
|
if (TextureType == TEXTURE_RECT ||
|
|
TextureType == TEXTURE_SHADOWRECT) {
|
|
CT[0] = 0;
|
|
CT[1] = 0;
|
|
}
|
|
|
|
if (TextureType == TEXTURE_CUBE_ARRAY ||
|
|
TextureType == TEXTURE_SHADOWCUBE_ARRAY)
|
|
CT[2] = 0;
|
|
|
|
if (TextureType == TEXTURE_1D_ARRAY ||
|
|
TextureType == TEXTURE_SHADOW1D_ARRAY) {
|
|
if (hasLOD && useShadowVariant) {
|
|
CT[1] = 0;
|
|
} else {
|
|
CT[2] = 0;
|
|
SrcSelect[2] = 1;
|
|
}
|
|
} else if (TextureType == TEXTURE_2D_ARRAY ||
|
|
TextureType == TEXTURE_SHADOW2D_ARRAY) {
|
|
CT[2] = 0;
|
|
}
|
|
|
|
if ((TextureType == TEXTURE_SHADOW1D ||
|
|
TextureType == TEXTURE_SHADOW2D ||
|
|
TextureType == TEXTURE_SHADOWRECT ||
|
|
TextureType == TEXTURE_SHADOW1D_ARRAY) &&
|
|
!(hasLOD && useShadowVariant))
|
|
SrcSelect[3] = 2;
|
|
}
|
|
|
|
void ReplaceCallInst(CallInst &I, FunctionType *FT, const char *Name,
|
|
unsigned SrcSelect[4], Value *Offset[3], Value *Resource,
|
|
Value *Sampler, unsigned CT[4], Value *Coord) {
|
|
IRBuilder<> Builder(&I);
|
|
Constant *Mask[] = {
|
|
ConstantInt::get(Int32Type, SrcSelect[0]),
|
|
ConstantInt::get(Int32Type, SrcSelect[1]),
|
|
ConstantInt::get(Int32Type, SrcSelect[2]),
|
|
ConstantInt::get(Int32Type, SrcSelect[3])
|
|
};
|
|
Value *SwizzleMask = ConstantVector::get(Mask);
|
|
Value *SwizzledCoord =
|
|
Builder.CreateShuffleVector(Coord, Coord, SwizzleMask);
|
|
|
|
Value *Args[] = {
|
|
SwizzledCoord,
|
|
Offset[0],
|
|
Offset[1],
|
|
Offset[2],
|
|
Resource,
|
|
Sampler,
|
|
ConstantInt::get(Int32Type, CT[0]),
|
|
ConstantInt::get(Int32Type, CT[1]),
|
|
ConstantInt::get(Int32Type, CT[2]),
|
|
ConstantInt::get(Int32Type, CT[3])
|
|
};
|
|
|
|
Function *F = Mod->getFunction(Name);
|
|
if (!F) {
|
|
F = Function::Create(FT, GlobalValue::ExternalLinkage, Name, Mod);
|
|
F->addFnAttr(Attribute::ReadNone);
|
|
}
|
|
I.replaceAllUsesWith(Builder.CreateCall(F, Args));
|
|
I.eraseFromParent();
|
|
}
|
|
|
|
void ReplaceTexIntrinsic(CallInst &I, bool hasLOD, FunctionType *FT,
|
|
const char *VanillaInt,
|
|
const char *ShadowInt) {
|
|
Value *Coord = I.getArgOperand(0);
|
|
Value *ResourceId = I.getArgOperand(1);
|
|
Value *SamplerId = I.getArgOperand(2);
|
|
|
|
unsigned TextureType =
|
|
cast<ConstantInt>(I.getArgOperand(3))->getZExtValue();
|
|
|
|
unsigned SrcSelect[4] = { 0, 1, 2, 3 };
|
|
unsigned CT[4] = {1, 1, 1, 1};
|
|
Value *Offset[3] = {
|
|
ConstantInt::get(Int32Type, 0),
|
|
ConstantInt::get(Int32Type, 0),
|
|
ConstantInt::get(Int32Type, 0)
|
|
};
|
|
bool useShadowVariant;
|
|
|
|
getAdjustmentFromTextureTarget(TextureType, hasLOD, SrcSelect, CT,
|
|
useShadowVariant);
|
|
|
|
ReplaceCallInst(I, FT, useShadowVariant?ShadowInt:VanillaInt, SrcSelect,
|
|
Offset, ResourceId, SamplerId, CT, Coord);
|
|
}
|
|
|
|
void ReplaceTXF(CallInst &I) {
|
|
Value *Coord = I.getArgOperand(0);
|
|
Value *ResourceId = I.getArgOperand(4);
|
|
Value *SamplerId = I.getArgOperand(5);
|
|
|
|
unsigned TextureType =
|
|
cast<ConstantInt>(I.getArgOperand(6))->getZExtValue();
|
|
|
|
unsigned SrcSelect[4] = { 0, 1, 2, 3 };
|
|
unsigned CT[4] = {1, 1, 1, 1};
|
|
Value *Offset[3] = {
|
|
I.getArgOperand(1),
|
|
I.getArgOperand(2),
|
|
I.getArgOperand(3),
|
|
};
|
|
bool useShadowVariant;
|
|
|
|
getAdjustmentFromTextureTarget(TextureType, false, SrcSelect, CT,
|
|
useShadowVariant);
|
|
|
|
ReplaceCallInst(I, TexQSign, "llvm.R600.txf", SrcSelect,
|
|
Offset, ResourceId, SamplerId, CT, Coord);
|
|
}
|
|
|
|
public:
|
|
R600TextureIntrinsicsReplacer():
|
|
FunctionPass(ID) {
|
|
}
|
|
|
|
bool doInitialization(Module &M) override {
|
|
LLVMContext &Ctx = M.getContext();
|
|
Mod = &M;
|
|
FloatType = Type::getFloatTy(Ctx);
|
|
Int32Type = Type::getInt32Ty(Ctx);
|
|
V4f32Type = VectorType::get(FloatType, 4);
|
|
V4i32Type = VectorType::get(Int32Type, 4);
|
|
Type *ArgsType[] = {
|
|
V4f32Type,
|
|
Int32Type,
|
|
Int32Type,
|
|
Int32Type,
|
|
Int32Type,
|
|
Int32Type,
|
|
Int32Type,
|
|
Int32Type,
|
|
Int32Type,
|
|
Int32Type,
|
|
};
|
|
TexSign = FunctionType::get(V4f32Type, ArgsType, /*isVarArg=*/false);
|
|
Type *ArgsQType[] = {
|
|
V4i32Type,
|
|
Int32Type,
|
|
Int32Type,
|
|
Int32Type,
|
|
Int32Type,
|
|
Int32Type,
|
|
Int32Type,
|
|
Int32Type,
|
|
Int32Type,
|
|
Int32Type,
|
|
};
|
|
TexQSign = FunctionType::get(V4f32Type, ArgsQType, /*isVarArg=*/false);
|
|
return false;
|
|
}
|
|
|
|
bool runOnFunction(Function &F) override {
|
|
visit(F);
|
|
return false;
|
|
}
|
|
|
|
const char *getPassName() const override {
|
|
return "R600 Texture Intrinsics Replacer";
|
|
}
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
}
|
|
|
|
void visitCallInst(CallInst &I) {
|
|
if (!I.getCalledFunction())
|
|
return;
|
|
|
|
StringRef Name = I.getCalledFunction()->getName();
|
|
if (Name == "llvm.AMDGPU.tex") {
|
|
ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.tex", "llvm.R600.texc");
|
|
return;
|
|
}
|
|
if (Name == "llvm.AMDGPU.txl") {
|
|
ReplaceTexIntrinsic(I, true, TexSign, "llvm.R600.txl", "llvm.R600.txlc");
|
|
return;
|
|
}
|
|
if (Name == "llvm.AMDGPU.txb") {
|
|
ReplaceTexIntrinsic(I, true, TexSign, "llvm.R600.txb", "llvm.R600.txbc");
|
|
return;
|
|
}
|
|
if (Name == "llvm.AMDGPU.txf") {
|
|
ReplaceTXF(I);
|
|
return;
|
|
}
|
|
if (Name == "llvm.AMDGPU.txq") {
|
|
ReplaceTexIntrinsic(I, false, TexQSign, "llvm.R600.txq", "llvm.R600.txq");
|
|
return;
|
|
}
|
|
if (Name == "llvm.AMDGPU.ddx") {
|
|
ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.ddx", "llvm.R600.ddx");
|
|
return;
|
|
}
|
|
if (Name == "llvm.AMDGPU.ddy") {
|
|
ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.ddy", "llvm.R600.ddy");
|
|
return;
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
char R600TextureIntrinsicsReplacer::ID = 0;
|
|
|
|
} // namespace
|
|
|
|
FunctionPass *llvm::createR600TextureIntrinsicsReplacer() {
|
|
return new R600TextureIntrinsicsReplacer();
|
|
}
|