blob: 37d90596bd88150f74ad85d265b2930cb9617679 [file] [log] [blame]
Vincent Lejeuned3eed662013-05-17 16:50:20 +00001//===-- 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"
Vincent Lejeuned3eed662013-05-17 16:50:20 +000016#include "llvm/ADT/Statistic.h"
Benjamin Kramerd78bb462013-05-23 17:10:37 +000017#include "llvm/Analysis/Passes.h"
Vincent Lejeuned3eed662013-05-17 16:50:20 +000018#include "llvm/IR/Function.h"
Vincent Lejeuned3eed662013-05-17 16:50:20 +000019#include "llvm/IR/GlobalValue.h"
Benjamin Kramerd78bb462013-05-23 17:10:37 +000020#include "llvm/IR/IRBuilder.h"
21#include "llvm/InstVisitor.h"
Vincent Lejeuned3eed662013-05-17 16:50:20 +000022
23using namespace llvm;
24
25namespace {
26class 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
Matt Arsenault5cae8942013-08-15 23:11:03 +000038 void getAdjustmentFromTextureTarget(unsigned TextureType, bool hasLOD,
39 unsigned SrcSelect[4], unsigned CT[4],
40 bool &useShadowVariant) {
Vincent Lejeuned3eed662013-05-17 16:50:20 +000041 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:
Tom Stellard59ed08b2013-08-17 00:06:51 +000063 useShadowVariant = false;
Vincent Lejeuned3eed662013-05-17 16:50:20 +000064 return;
65 case TEXTURE_RECT:
66 case TEXTURE_1D:
67 case TEXTURE_2D:
68 case TEXTURE_3D:
69 case TEXTURE_CUBE:
70 case TEXTURE_1D_ARRAY:
71 case TEXTURE_2D_ARRAY:
72 case TEXTURE_CUBE_ARRAY:
73 case TEXTURE_2D_MSAA:
74 case TEXTURE_2D_ARRAY_MSAA:
75 useShadowVariant = false;
76 break;
77 case TEXTURE_SHADOW1D:
78 case TEXTURE_SHADOW2D:
79 case TEXTURE_SHADOWRECT:
80 case TEXTURE_SHADOW1D_ARRAY:
81 case TEXTURE_SHADOW2D_ARRAY:
82 case TEXTURE_SHADOWCUBE:
83 case TEXTURE_SHADOWCUBE_ARRAY:
84 useShadowVariant = true;
85 break;
86 default:
87 llvm_unreachable("Unknow Texture Type");
88 }
89
90 if (TextureType == TEXTURE_RECT ||
91 TextureType == TEXTURE_SHADOWRECT) {
92 CT[0] = 0;
93 CT[1] = 0;
94 }
95
96 if (TextureType == TEXTURE_CUBE_ARRAY ||
97 TextureType == TEXTURE_SHADOWCUBE_ARRAY) {
98 CT[2] = 0;
99 }
100
101 if (TextureType == TEXTURE_1D_ARRAY ||
102 TextureType == TEXTURE_SHADOW1D_ARRAY) {
103 if (hasLOD && useShadowVariant) {
104 CT[1] = 0;
105 } else {
106 CT[2] = 0;
107 SrcSelect[2] = 1;
108 }
109 } else if (TextureType == TEXTURE_2D_ARRAY ||
110 TextureType == TEXTURE_SHADOW2D_ARRAY) {
111 CT[2] = 0;
112 }
113
114 if ((TextureType == TEXTURE_SHADOW1D ||
115 TextureType == TEXTURE_SHADOW2D ||
116 TextureType == TEXTURE_SHADOWRECT ||
117 TextureType == TEXTURE_SHADOW1D_ARRAY) &&
118 !(hasLOD && useShadowVariant)) {
119 SrcSelect[3] = 2;
120 }
121 }
122
123 void ReplaceCallInst(CallInst &I, FunctionType *FT, const char *Name,
124 unsigned SrcSelect[4], Value *Offset[3], Value *Resource,
125 Value *Sampler, unsigned CT[4], Value *Coord) {
126 IRBuilder<> Builder(&I);
127 Constant *Mask[] = {
128 ConstantInt::get(Int32Type, SrcSelect[0]),
129 ConstantInt::get(Int32Type, SrcSelect[1]),
130 ConstantInt::get(Int32Type, SrcSelect[2]),
131 ConstantInt::get(Int32Type, SrcSelect[3])
132 };
133 Value *SwizzleMask = ConstantVector::get(Mask);
134 Value *SwizzledCoord =
135 Builder.CreateShuffleVector(Coord, Coord, SwizzleMask);
136
137 Value *Args[] = {
138 SwizzledCoord,
139 Offset[0],
140 Offset[1],
141 Offset[2],
142 Resource,
143 Sampler,
144 ConstantInt::get(Int32Type, CT[0]),
145 ConstantInt::get(Int32Type, CT[1]),
146 ConstantInt::get(Int32Type, CT[2]),
147 ConstantInt::get(Int32Type, CT[3])
148 };
149
150 Function *F = Mod->getFunction(Name);
151 if (!F) {
152 F = Function::Create(FT, GlobalValue::ExternalLinkage, Name, Mod);
153 F->addFnAttr(Attribute::ReadNone);
154 }
155 I.replaceAllUsesWith(Builder.CreateCall(F, Args));
156 I.eraseFromParent();
157 }
158
159 void ReplaceTexIntrinsic(CallInst &I, bool hasLOD, FunctionType *FT,
160 const char *VanillaInt,
161 const char *ShadowInt) {
162 Value *Coord = I.getArgOperand(0);
163 Value *ResourceId = I.getArgOperand(1);
164 Value *SamplerId = I.getArgOperand(2);
165
166 unsigned TextureType =
167 dyn_cast<ConstantInt>(I.getArgOperand(3))->getZExtValue();
168
169 unsigned SrcSelect[4] = { 0, 1, 2, 3 };
170 unsigned CT[4] = {1, 1, 1, 1};
171 Value *Offset[3] = {
172 ConstantInt::get(Int32Type, 0),
173 ConstantInt::get(Int32Type, 0),
174 ConstantInt::get(Int32Type, 0)
175 };
176 bool useShadowVariant;
177
Matt Arsenault5cae8942013-08-15 23:11:03 +0000178 getAdjustmentFromTextureTarget(TextureType, hasLOD, SrcSelect, CT,
179 useShadowVariant);
Vincent Lejeuned3eed662013-05-17 16:50:20 +0000180
181 ReplaceCallInst(I, FT, useShadowVariant?ShadowInt:VanillaInt, SrcSelect,
182 Offset, ResourceId, SamplerId, CT, Coord);
183 }
184
185 void ReplaceTXF(CallInst &I) {
186 Value *Coord = I.getArgOperand(0);
187 Value *ResourceId = I.getArgOperand(4);
188 Value *SamplerId = I.getArgOperand(5);
189
190 unsigned TextureType =
191 dyn_cast<ConstantInt>(I.getArgOperand(6))->getZExtValue();
192
193 unsigned SrcSelect[4] = { 0, 1, 2, 3 };
194 unsigned CT[4] = {1, 1, 1, 1};
195 Value *Offset[3] = {
196 I.getArgOperand(1),
197 I.getArgOperand(2),
198 I.getArgOperand(3),
199 };
200 bool useShadowVariant;
201
Matt Arsenault5cae8942013-08-15 23:11:03 +0000202 getAdjustmentFromTextureTarget(TextureType, false, SrcSelect, CT,
203 useShadowVariant);
Vincent Lejeuned3eed662013-05-17 16:50:20 +0000204
205 ReplaceCallInst(I, TexQSign, "llvm.R600.txf", SrcSelect,
206 Offset, ResourceId, SamplerId, CT, Coord);
207 }
208
209public:
210 R600TextureIntrinsicsReplacer():
211 FunctionPass(ID) {
212 }
213
214 virtual bool doInitialization(Module &M) {
215 LLVMContext &Ctx = M.getContext();
216 Mod = &M;
217 FloatType = Type::getFloatTy(Ctx);
218 Int32Type = Type::getInt32Ty(Ctx);
219 V4f32Type = VectorType::get(FloatType, 4);
220 V4i32Type = VectorType::get(Int32Type, 4);
221 Type *ArgsType[] = {
222 V4f32Type,
223 Int32Type,
224 Int32Type,
225 Int32Type,
226 Int32Type,
227 Int32Type,
228 Int32Type,
229 Int32Type,
230 Int32Type,
231 Int32Type,
232 };
Benjamin Kramer927ca942013-05-20 15:58:43 +0000233 TexSign = FunctionType::get(V4f32Type, ArgsType, /*isVarArg=*/false);
Vincent Lejeuned3eed662013-05-17 16:50:20 +0000234 Type *ArgsQType[] = {
235 V4i32Type,
236 Int32Type,
237 Int32Type,
238 Int32Type,
239 Int32Type,
240 Int32Type,
241 Int32Type,
242 Int32Type,
243 Int32Type,
244 Int32Type,
245 };
Benjamin Kramer927ca942013-05-20 15:58:43 +0000246 TexQSign = FunctionType::get(V4f32Type, ArgsQType, /*isVarArg=*/false);
Vincent Lejeuned3eed662013-05-17 16:50:20 +0000247 return false;
248 }
249
250 virtual bool runOnFunction(Function &F) {
251 visit(F);
252 return false;
253 }
254
255 virtual const char *getPassName() const {
256 return "R600 Texture Intrinsics Replacer";
257 }
258
259 void getAnalysisUsage(AnalysisUsage &AU) const {
260 }
261
262 void visitCallInst(CallInst &I) {
Rafael Espindolae3d83fb2013-05-22 15:31:11 +0000263 StringRef Name = I.getCalledFunction()->getName();
264 if (Name == "llvm.AMDGPU.tex") {
Vincent Lejeuned3eed662013-05-17 16:50:20 +0000265 ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.tex", "llvm.R600.texc");
Rafael Espindolae3d83fb2013-05-22 15:31:11 +0000266 return;
267 }
268 if (Name == "llvm.AMDGPU.txl") {
Vincent Lejeuned3eed662013-05-17 16:50:20 +0000269 ReplaceTexIntrinsic(I, true, TexSign, "llvm.R600.txl", "llvm.R600.txlc");
Rafael Espindolae3d83fb2013-05-22 15:31:11 +0000270 return;
271 }
272 if (Name == "llvm.AMDGPU.txb") {
Vincent Lejeuned3eed662013-05-17 16:50:20 +0000273 ReplaceTexIntrinsic(I, true, TexSign, "llvm.R600.txb", "llvm.R600.txbc");
Rafael Espindolae3d83fb2013-05-22 15:31:11 +0000274 return;
275 }
276 if (Name == "llvm.AMDGPU.txf") {
Vincent Lejeuned3eed662013-05-17 16:50:20 +0000277 ReplaceTXF(I);
Rafael Espindolae3d83fb2013-05-22 15:31:11 +0000278 return;
279 }
280 if (Name == "llvm.AMDGPU.txq") {
Vincent Lejeuned3eed662013-05-17 16:50:20 +0000281 ReplaceTexIntrinsic(I, false, TexQSign, "llvm.R600.txq", "llvm.R600.txq");
Rafael Espindolae3d83fb2013-05-22 15:31:11 +0000282 return;
283 }
284 if (Name == "llvm.AMDGPU.ddx") {
Vincent Lejeuned3eed662013-05-17 16:50:20 +0000285 ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.ddx", "llvm.R600.ddx");
Rafael Espindolae3d83fb2013-05-22 15:31:11 +0000286 return;
287 }
288 if (Name == "llvm.AMDGPU.ddy") {
Vincent Lejeuned3eed662013-05-17 16:50:20 +0000289 ReplaceTexIntrinsic(I, false, TexSign, "llvm.R600.ddy", "llvm.R600.ddy");
Rafael Espindolae3d83fb2013-05-22 15:31:11 +0000290 return;
291 }
Vincent Lejeuned3eed662013-05-17 16:50:20 +0000292 }
293
294};
295
296char R600TextureIntrinsicsReplacer::ID = 0;
297
298}
299
300FunctionPass *llvm::createR600TextureIntrinsicsReplacer() {
301 return new R600TextureIntrinsicsReplacer();
302}