gallivm: More detailed analysis of tgsi shaders.
[mesa.git] / src / gallium / auxiliary / gallivm / lp_bld_tgsi_info.c
1 /**************************************************************************
2 *
3 * Copyright 2010 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
24 * of the Software.
25 *
26 **************************************************************************/
27
28
29 #include "util/u_memory.h"
30 #include "util/u_math.h"
31 #include "tgsi/tgsi_parse.h"
32 #include "tgsi/tgsi_text.h"
33 #include "tgsi/tgsi_util.h"
34 #include "tgsi/tgsi_dump.h"
35 #include "lp_bld_debug.h"
36 #include "lp_bld_tgsi.h"
37
38
39 /**
40 * Analysis context.
41 *
42 * This is where we keep store the value of each channel of the IMM/TEMP/OUT
43 * register values, as we walk the shader.
44 */
45 struct analysis_context
46 {
47 struct lp_tgsi_info *info;
48
49 unsigned num_imms;
50 float imm[32][4];
51
52 struct lp_tgsi_channel_info temp[32][4];
53 };
54
55
56 /**
57 * Describe the specified channel of the src register.
58 */
59 static void
60 analyse_src(struct analysis_context *ctx,
61 struct lp_tgsi_channel_info *chan_info,
62 const struct tgsi_src_register *src,
63 unsigned chan)
64 {
65 chan_info->file = TGSI_FILE_NULL;
66 if (!src->Indirect && !src->Absolute && !src->Negate) {
67 unsigned swizzle = tgsi_util_get_src_register_swizzle(src, chan);
68 if (src->File == TGSI_FILE_TEMPORARY) {
69 if (src->Index < Elements(ctx->temp)) {
70 *chan_info = ctx->temp[src->Index][swizzle];
71 }
72 } else {
73 chan_info->file = src->File;
74 if (src->File == TGSI_FILE_IMMEDIATE) {
75 assert(src->Index < Elements(ctx->imm));
76 if (src->Index < Elements(ctx->imm)) {
77 chan_info->value = ctx->imm[src->Index][swizzle];
78 }
79 } else {
80 chan_info->index = src->Index;
81 chan_info->swizzle = swizzle;
82 }
83 }
84 }
85 }
86
87
88 /**
89 * Whether this register channel refers to a specific immediate value.
90 */
91 static boolean
92 is_immediate(const struct lp_tgsi_channel_info *chan_info, float value)
93 {
94 return chan_info->file == TGSI_FILE_IMMEDIATE &&
95 chan_info->value == value;
96 }
97
98
99 static void
100 analyse_tex(struct analysis_context *ctx,
101 const struct tgsi_full_instruction *inst,
102 enum lp_build_tex_modifier modifier)
103 {
104 struct lp_tgsi_info *info = ctx->info;
105 unsigned chan;
106
107 if (info->num_texs < Elements(info->tex)) {
108 struct lp_tgsi_texture_info *tex_info = &info->tex[info->num_texs];
109 bool indirect = FALSE;
110 unsigned readmask = 0;
111
112 tex_info->target = inst->Texture.Texture;
113 switch (inst->Texture.Texture) {
114 case TGSI_TEXTURE_1D:
115 readmask = TGSI_WRITEMASK_X;
116 break;
117 case TGSI_TEXTURE_2D:
118 case TGSI_TEXTURE_RECT:
119 readmask = TGSI_WRITEMASK_XY;
120 break;
121 case TGSI_TEXTURE_SHADOW1D:
122 case TGSI_TEXTURE_SHADOW2D:
123 case TGSI_TEXTURE_SHADOWRECT:
124 case TGSI_TEXTURE_3D:
125 case TGSI_TEXTURE_CUBE:
126 readmask = TGSI_WRITEMASK_XYZ;
127 break;
128 default:
129 assert(0);
130 return;
131 }
132
133 if (modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV) {
134 /* We don't track explicit derivatives, although we could */
135 indirect = TRUE;
136 tex_info->unit = inst->Src[3].Register.Index;
137 } else {
138 if (modifier == LP_BLD_TEX_MODIFIER_PROJECTED ||
139 modifier == LP_BLD_TEX_MODIFIER_LOD_BIAS ||
140 modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_LOD) {
141 readmask |= TGSI_WRITEMASK_W;
142 }
143 tex_info->unit = inst->Src[1].Register.Index;
144 }
145
146 for (chan = 0; chan < 4; ++chan) {
147 struct lp_tgsi_channel_info *chan_info = &tex_info->coord[chan];
148 if (readmask & (1 << chan)) {
149 analyse_src(ctx, chan_info, &inst->Src[0].Register, chan);
150 if (chan_info->file != TGSI_FILE_INPUT) {
151 indirect = TRUE;
152 }
153 } else {
154 memset(chan_info, 0, sizeof *chan_info);
155 }
156 }
157
158 if (indirect) {
159 info->indirect_textures = TRUE;
160 }
161
162 ++info->num_texs;
163 } else {
164 info->indirect_textures = TRUE;
165 }
166 }
167
168
169 /**
170 * Process an instruction, and update the register values accordingly.
171 */
172 static void
173 analyse_instruction(struct analysis_context *ctx,
174 struct tgsi_full_instruction *inst)
175 {
176 struct lp_tgsi_info *info = ctx->info;
177 struct lp_tgsi_channel_info (*regs)[4];
178 unsigned max_regs;
179 unsigned i;
180 unsigned index;
181 unsigned chan;
182
183 for (i = 0; i < inst->Instruction.NumDstRegs; ++i) {
184 const struct tgsi_dst_register *dst = &inst->Dst[i].Register;
185
186 /*
187 * Get the lp_tgsi_channel_info array corresponding to the destination
188 * register file.
189 */
190
191 if (dst->File == TGSI_FILE_TEMPORARY) {
192 regs = ctx->temp;
193 max_regs = Elements(ctx->temp);
194 } else if (dst->File == TGSI_FILE_OUTPUT) {
195 regs = info->output;
196 max_regs = Elements(info->output);
197 } else if (dst->File == TGSI_FILE_ADDRESS ||
198 dst->File == TGSI_FILE_PREDICATE) {
199 continue;
200 } else {
201 assert(0);
202 continue;
203 }
204
205 /*
206 * Detect direct TEX instructions
207 */
208
209 switch (inst->Instruction.Opcode) {
210 case TGSI_OPCODE_TEX:
211 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_NONE);
212 break;
213 case TGSI_OPCODE_TXD:
214 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV);
215 break;
216 case TGSI_OPCODE_TXB:
217 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS);
218 break;
219 case TGSI_OPCODE_TXL:
220 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD);
221 break;
222 case TGSI_OPCODE_TXP:
223 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_PROJECTED);
224 break;
225 default:
226 break;
227 }
228
229 /*
230 * Keep track of assignments and writes
231 */
232
233 if (dst->Indirect) {
234 /*
235 * It could be any register index so clear all register indices.
236 */
237
238 for (chan = 0; chan < 4; ++chan) {
239 if (dst->WriteMask & (1 << chan)) {
240 for (index = 0; index < max_regs; ++index) {
241 regs[index][chan].file = TGSI_FILE_NULL;
242 }
243 }
244 }
245 } else if (dst->Index < max_regs) {
246 /*
247 * Update this destination register value.
248 */
249
250 struct lp_tgsi_channel_info res[4];
251
252 memset(res, 0, sizeof res);
253
254 if (!inst->Instruction.Predicate &&
255 !inst->Instruction.Saturate) {
256 for (chan = 0; chan < 4; ++chan) {
257 if (dst->WriteMask & (1 << chan)) {
258 if (inst->Instruction.Opcode == TGSI_OPCODE_MOV) {
259 analyse_src(ctx, &res[chan],
260 &inst->Src[0].Register, chan);
261 } else if (inst->Instruction.Opcode == TGSI_OPCODE_MUL) {
262 /*
263 * Propagate values across 1.0 and 0.0 multiplications.
264 */
265
266 struct lp_tgsi_channel_info src0;
267 struct lp_tgsi_channel_info src1;
268
269 analyse_src(ctx, &src0, &inst->Src[0].Register, chan);
270 analyse_src(ctx, &src1, &inst->Src[1].Register, chan);
271
272 if (is_immediate(&src0, 0.0f)) {
273 res[chan] = src0;
274 } else if (is_immediate(&src1, 0.0f)) {
275 res[chan] = src1;
276 } else if (is_immediate(&src0, 1.0f)) {
277 res[chan] = src1;
278 } else if (is_immediate(&src1, 1.0f)) {
279 res[chan] = src0;
280 }
281 }
282 }
283 }
284 }
285
286 for (chan = 0; chan < 4; ++chan) {
287 if (dst->WriteMask & (1 << chan)) {
288 regs[dst->Index][chan] = res[chan];
289 }
290 }
291 }
292 }
293
294 /*
295 * Clear all temporaries information in presence of a control flow opcode.
296 */
297
298 switch (inst->Instruction.Opcode) {
299 case TGSI_OPCODE_IF:
300 case TGSI_OPCODE_IFC:
301 case TGSI_OPCODE_ELSE:
302 case TGSI_OPCODE_ENDIF:
303 case TGSI_OPCODE_BGNLOOP:
304 case TGSI_OPCODE_BRK:
305 case TGSI_OPCODE_BREAKC:
306 case TGSI_OPCODE_CONT:
307 case TGSI_OPCODE_ENDLOOP:
308 case TGSI_OPCODE_CALLNZ:
309 case TGSI_OPCODE_CAL:
310 case TGSI_OPCODE_BGNSUB:
311 case TGSI_OPCODE_ENDSUB:
312 case TGSI_OPCODE_SWITCH:
313 case TGSI_OPCODE_CASE:
314 case TGSI_OPCODE_DEFAULT:
315 case TGSI_OPCODE_ENDSWITCH:
316 case TGSI_OPCODE_RET:
317 case TGSI_OPCODE_END:
318 /* XXX: Are there more cases? */
319 memset(&ctx->temp, 0, sizeof ctx->temp);
320 memset(&info->output, 0, sizeof info->output);
321 default:
322 break;
323 }
324 }
325
326
327 static INLINE void
328 dump_info(const struct tgsi_token *tokens,
329 struct lp_tgsi_info *info)
330 {
331 unsigned index;
332 unsigned chan;
333
334 tgsi_dump(tokens, 0);
335
336 for (index = 0; index < info->num_texs; ++index) {
337 const struct lp_tgsi_texture_info *tex_info = &info->tex[index];
338 debug_printf("TEX[%u] =", index);
339 for (chan = 0; chan < 4; ++chan) {
340 const struct lp_tgsi_channel_info *chan_info =
341 &tex_info->coord[chan];
342 if (chan_info->file != TGSI_FILE_NULL) {
343 debug_printf(" %s[%u].%c",
344 tgsi_file_names[chan_info->file],
345 chan_info->index,
346 "xyzw01"[chan_info->swizzle]);
347 } else {
348 debug_printf(" _");
349 }
350 }
351 debug_printf(", SAMP[%u], %s\n",
352 tex_info->unit,
353 tgsi_texture_names[tex_info->target]);
354 }
355
356 for (index = 0; index < PIPE_MAX_SHADER_OUTPUTS; ++index) {
357 for (chan = 0; chan < 4; ++chan) {
358 const struct lp_tgsi_channel_info *chan_info =
359 &info->output[index][chan];
360 if (chan_info->file != TGSI_FILE_NULL) {
361 debug_printf("OUT[%u].%c = ", index, "xyzw"[chan]);
362 if (chan_info->file == TGSI_FILE_IMMEDIATE) {
363 debug_printf("%f", chan_info->value);
364 } else {
365 const char *file_name;
366 switch (chan_info->file) {
367 case TGSI_FILE_CONSTANT:
368 file_name = "CONST";
369 break;
370 case TGSI_FILE_INPUT:
371 file_name = "IN";
372 break;
373 default:
374 file_name = "???";
375 break;
376 }
377 debug_printf("%s[%u].%c",
378 file_name,
379 chan_info->index,
380 "xyzw01"[chan_info->swizzle]);
381 }
382 debug_printf("\n");
383 }
384 }
385 }
386 }
387
388
389 /**
390 * Detect any direct relationship between the output color
391 */
392 void
393 lp_build_tgsi_info(const struct tgsi_token *tokens,
394 struct lp_tgsi_info *info)
395 {
396 struct tgsi_parse_context parse;
397 struct analysis_context ctx;
398 unsigned index;
399 unsigned chan;
400
401 memset(info, 0, sizeof *info);
402
403 tgsi_scan_shader(tokens, &info->base);
404
405 memset(&ctx, 0, sizeof ctx);
406 ctx.info = info;
407
408 tgsi_parse_init(&parse, tokens);
409
410 while (!tgsi_parse_end_of_tokens(&parse)) {
411 tgsi_parse_token(&parse);
412
413 switch (parse.FullToken.Token.Type) {
414 case TGSI_TOKEN_TYPE_DECLARATION:
415 break;
416
417 case TGSI_TOKEN_TYPE_INSTRUCTION:
418 {
419 struct tgsi_full_instruction *inst =
420 &parse.FullToken.FullInstruction;
421
422 if (inst->Instruction.Opcode == TGSI_OPCODE_END ||
423 inst->Instruction.Opcode == TGSI_OPCODE_BGNSUB) {
424 /* We reached the end of main function body. */
425 goto finished;
426 }
427
428 analyse_instruction(&ctx, inst);
429 }
430 break;
431
432 case TGSI_TOKEN_TYPE_IMMEDIATE:
433 {
434 const unsigned size =
435 parse.FullToken.FullImmediate.Immediate.NrTokens - 1;
436 assert(size <= 4);
437 if (ctx.num_imms < Elements(ctx.imm)) {
438 for (chan = 0; chan < size; ++chan) {
439 ctx.imm[ctx.num_imms][chan] =
440 parse.FullToken.FullImmediate.u[chan].Float;
441 }
442 ++ctx.num_imms;
443 }
444 }
445 break;
446
447 case TGSI_TOKEN_TYPE_PROPERTY:
448 break;
449
450 default:
451 assert(0);
452 }
453 }
454 finished:
455
456 tgsi_parse_free(&parse);
457
458
459 /*
460 * Link the output color values.
461 */
462
463 for (index = 0; index < PIPE_MAX_COLOR_BUFS; ++index) {
464 const struct lp_tgsi_channel_info null_output[4];
465 info->cbuf[index] = null_output;
466 }
467
468 for (index = 0; index < info->base.num_outputs; ++index) {
469 unsigned semantic_name = info->base.output_semantic_name[index];
470 unsigned semantic_index = info->base.output_semantic_index[index];
471 if (semantic_name == TGSI_SEMANTIC_COLOR &&
472 semantic_index < PIPE_MAX_COLOR_BUFS) {
473 info->cbuf[semantic_index] = info->output[index];
474 }
475 }
476
477 if (gallivm_debug & GALLIVM_DEBUG_TGSI) {
478 dump_info(tokens, info);
479 }
480 }