1 //===-- R600TextureIntrinsicsReplacer.cpp ---------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 /// \file
11 /// This pass translates tgsi-like texture intrinsics into R600 texture
12 /// closer to hardware intrinsics.
13 //===----------------------------------------------------------------------===//
14
15 #include "AMDGPU.h"
16 #include "llvm/ADT/Statistic.h"
17 #include "llvm/Analysis/Passes.h"
18 #include "llvm/IR/Function.h"
19 #include "llvm/IR/GlobalValue.h"
20 #include "llvm/IR/IRBuilder.h"
21 #include "llvm/InstVisitor.h"
22
23 using namespace llvm;
24
25 namespace {
26 class R600TextureIntrinsicsReplacer :
27 public FunctionPass, public InstVisitor<R600TextureIntrinsicsReplacer> {
28 static char ID;
29
30 Module *Mod;
31 Type *FloatType;
32 Type *Int32Type;
33 Type *V4f32Type;
34 Type *V4i32Type;
35 FunctionType *TexSign;
36 FunctionType *TexQSign;
37
getAdjustementFromTextureTarget(unsigned TextureType,bool hasLOD,unsigned SrcSelect[4],unsigned CT[4],bool & useShadowVariant)38 void getAdjustementFromTextureTarget(unsigned TextureType, bool hasLOD,
39 unsigned SrcSelect[4], unsigned CT[4],
40 bool &useShadowVariant) {
41 enum TextureTypes {
42 TEXTURE_1D = 1,
43 TEXTURE_2D,
44 TEXTURE_3D,
45 TEXTURE_CUBE,
46 TEXTURE_RECT,
47 TEXTURE_SHADOW1D,
48 TEXTURE_SHADOW2D,
49 TEXTURE_SHADOWRECT,
50 TEXTURE_1D_ARRAY,
51 TEXTURE_2D_ARRAY,
52 TEXTURE_SHADOW1D_ARRAY,
53 TEXTURE_SHADOW2D_ARRAY,
54 TEXTURE_SHADOWCUBE,
55 TEXTURE_2D_MSAA,
56 TEXTURE_2D_ARRAY_MSAA,
57 TEXTURE_CUBE_ARRAY,
58 TEXTURE_SHADOWCUBE_ARRAY
59 };
60
61 switch (TextureType) {
62 case 0:
63 return;
64 case TEXTURE_RECT:
65 case TEXTURE_1D:
66 case TEXTURE_2D:
67 case TEXTURE_3D:
68 case TEXTURE_CUBE:
69 case TEXTURE_1D_ARRAY:
70 case TEXTURE_2D_ARRAY:
71 case TEXTURE_CUBE_ARRAY:
72 case TEXTURE_2D_MSAA:
73 case TEXTURE_2D_ARRAY_MSAA:
74 useShadowVariant = false;
75 break;
76 case TEXTURE_SHADOW1D:
77 case TEXTURE_SHADOW2D:
78 case TEXTURE_SHADOWRECT:
79 case TEXTURE_SHADOW1D_ARRAY:
80 case TEXTURE_SHADOW2D_ARRAY:
81 case TEXTURE_SHADOWCUBE:
82 case TEXTURE_SHADOWCUBE_ARRAY:
83 useShadowVariant = true;
84 break;
85 default:
86 llvm_unreachable("Unknow Texture Type");
87 }
88
89 if (TextureType == TEXTURE_RECT ||
90 TextureType == TEXTURE_SHADOWRECT) {
91 CT[0] = 0;
92 CT[1] = 0;
93 }
94
95 if (TextureType == TEXTURE_CUBE_ARRAY ||
96 TextureType == TEXTURE_SHADOWCUBE_ARRAY) {
97 CT[2] = 0;
98 }
99
100 if (TextureType == TEXTURE_1D_ARRAY ||
101 TextureType == TEXTURE_SHADOW1D_ARRAY) {
102 if (hasLOD && useShadowVariant) {
103 CT[1] = 0;
104 } else {
105 CT[2] = 0;
106 SrcSelect[2] = 1;
107 }
108 } else if (TextureType == TEXTURE_2D_ARRAY ||
109 TextureType == TEXTURE_SHADOW2D_ARRAY) {
110 CT[2] = 0;
111 }
112
113 if ((TextureType == TEXTURE_SHADOW1D ||
114 TextureType == TEXTURE_SHADOW2D ||
115 TextureType == TEXTURE_SHADOWRECT ||
116 TextureType == TEXTURE_SHADOW1D_ARRAY) &&
117 !(hasLOD && useShadowVariant)) {
118 SrcSelect[3] = 2;
119 }
120 }
121
ReplaceCallInst(CallInst & I,FunctionType * FT,const char * Name,unsigned SrcSelect[4],Value * Offset[3],Value * Resource,Value * Sampler,unsigned CT[4],Value * Coord)122 void ReplaceCallInst(CallInst &I, FunctionType *FT, const char *Name,
123 unsigned SrcSelect[4], Value *Offset[3], Value *Resource,
124 Value *Sampler, unsigned CT[4], Value *Coord) {
125 IRBuilder<> Builder(&I);
126 Constant *Mask[] = {
127 ConstantInt::get(Int32Type, SrcSelect[0]),
128 ConstantInt::get(Int32Type, SrcSelect[1]),
129 ConstantInt::get(Int32Type, SrcSelect[2]),
130 ConstantInt::get(Int32Type, SrcSelect[3])
131 };
132 Value *SwizzleMask = ConstantVector::get(Mask);
133 Value *SwizzledCoord =
134 Builder.CreateShuffleVector(Coord, Coord, SwizzleMask);
135
136 Value *Args[] = {
137 SwizzledCoord,
138 Offset[0],
139 Offset[1],
140 Offset[2],
141 Resource,
142 Sampler,
143 ConstantInt::get(Int32Type, CT[0]),
144 ConstantInt::get(Int32Type, CT[1]),
145 ConstantInt::get(Int32Type, CT[2]),
146 ConstantInt::get(Int32Type, CT[3])
147 };
148
149 Function *F = Mod->getFunction(Name);
150 if (!F) {
151 F = Function::Create(FT, GlobalValue::ExternalLinkage, Name, Mod);
152 F->addFnAttr(Attribute::ReadNone);
153 }
154 I.replaceAllUsesWith(Builder.CreateCall(F, Args));
155 I.eraseFromParent();
156 }
157
ReplaceTexIntrinsic(CallInst & I,bool hasLOD,FunctionType * FT,const char * VanillaInt,const char * ShadowInt)158 void ReplaceTexIntrinsic(CallInst &I, bool hasLOD, FunctionType *FT,
159 const char *VanillaInt,
160 const char *ShadowInt) {
161 Value *Coord = I.getArgOperand(0);
162 Value *ResourceId = I.getArgOperand(1);
163 Value *SamplerId = I.getArgOperand(2);
164
165 unsigned TextureType =
166 dyn_cast<ConstantInt>(I.getArgOperand(3))->getZExtValue();
167
168 unsigned SrcSelect[4] = { 0, 1, 2, 3 };
169 unsigned CT[4] = {1, 1, 1, 1};
170 Value *Offset[3] = {
171 ConstantInt::get(Int32Type, 0),
172 ConstantInt::get(Int32Type, 0),
173 ConstantInt::get(Int32Type, 0)
174 };
175 bool useShadowVariant;
176
177 getAdjustementFromTextureTarget(TextureType, hasLOD, SrcSelect, CT,
178 useShadowVariant);
179
180 ReplaceCallInst(I, FT, useShadowVariant?ShadowInt:VanillaInt, SrcSelect,
181 Offset, ResourceId, SamplerId, CT, Coord);
182 }
183
ReplaceTXF(CallInst & I)184 void ReplaceTXF(CallInst &I) {
185 Value *Coord = I.getArgOperand(0);
186 Value *ResourceId = I.getArgOperand(4);
187 Value *SamplerId = I.getArgOperand(5);
188
189 unsigned TextureType =
190 dyn_cast<ConstantInt>(I.getArgOperand(6))->getZExtValue();
191
192 unsigned SrcSelect[4] = { 0, 1, 2, 3 };
193 unsigned CT[4] = {1, 1, 1, 1};
194 Value *Offset[3] = {
195 I.getArgOperand(1),
196 I.getArgOperand(2),
197 I.getArgOperand(3),
198 };
199 bool useShadowVariant;
200
201 getAdjustementFromTextureTarget(TextureType, false, SrcSelect, CT,
202 useShadowVariant);
203
204 ReplaceCallInst(I, TexQSign, "llvm.R600.txf", SrcSelect,
205 Offset, ResourceId, SamplerId, CT, Coord);
206 }
207
208 public:
R600TextureIntrinsicsReplacer()209 R600TextureIntrinsicsReplacer():
210 FunctionPass(ID) {
211 }
212
doInitialization(Module & M)213 virtual bool doInitialization(Module &M) {
214 LLVMContext &Ctx = M.getContext();
215 Mod = &M;
216 FloatType = Type::getFloatTy(Ctx);
217 Int32Type = Type::getInt32Ty(Ctx);
218 V4f32Type = VectorType::get(FloatType, 4);
219 V4i32Type = VectorType::get(Int32Type, 4);
220 Type *ArgsType[] = {
221 V4f32Type,
222 Int32Type,
223 Int32Type,
224 Int32Type,
225 Int32Type,
226 Int32Type,
227 Int32Type,
228 Int32Type,
229 Int32Type,
230 Int32Type,
231 };
232 TexSign = FunctionType::get(V4f32Type, ArgsType, /*isVarArg=*/false);
233 Type *ArgsQType[] = {
234 V4i32Type,
235 Int32Type,
236 Int32Type,
237 Int32Type,
238 Int32Type,
239 Int32Type,
240 Int32Type,
241 Int32Type,
242 Int32Type,
243 Int32Type,
244 };
245 TexQSign = FunctionType::get(V4f32Type, ArgsQType, /*isVarArg=*/false);
246 return false;
247 }
248
runOnFunction(Function & F)249 virtual bool runOnFunction(Function &F) {
250 visit(F);
251 return false;
252 }
253
getPassName() const254 virtual const char *getPassName() const {
255 return "R600 Texture Intrinsics Replacer";
256 }
257
getAnalysisUsage(AnalysisUsage & AU) const258 void getAnalysisUsage(AnalysisUsage &AU) const {
259 }
260
visitCallInst(CallInst & I)261 void visitCallInst(CallInst &I) {
262 StringRef Name = I.getCalledFunction()->getName();
263 if (Name == "llvm.AMDGPU.tex") {
264 ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.tex", "llvm.R600.texc");
265 return;
266 }
267 if (Name == "llvm.AMDGPU.txl") {
268 ReplaceTexIntrinsic(I, true, TexSign, "llvm.R600.txl", "llvm.R600.txlc");
269 return;
270 }
271 if (Name == "llvm.AMDGPU.txb") {
272 ReplaceTexIntrinsic(I, true, TexSign, "llvm.R600.txb", "llvm.R600.txbc");
273 return;
274 }
275 if (Name == "llvm.AMDGPU.txf") {
276 ReplaceTXF(I);
277 return;
278 }
279 if (Name == "llvm.AMDGPU.txq") {
280 ReplaceTexIntrinsic(I, false, TexQSign, "llvm.R600.txq", "llvm.R600.txq");
281 return;
282 }
283 if (Name == "llvm.AMDGPU.ddx") {
284 ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.ddx", "llvm.R600.ddx");
285 return;
286 }
287 if (Name == "llvm.AMDGPU.ddy") {
288 ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.ddy", "llvm.R600.ddy");
289 return;
290 }
291 }
292
293 };
294
295 char R600TextureIntrinsicsReplacer::ID = 0;
296
297 }
298
createR600TextureIntrinsicsReplacer()299 FunctionPass *llvm::createR600TextureIntrinsicsReplacer() {
300 return new R600TextureIntrinsicsReplacer();
301 }
302