ir_to_mesa: Try to fix up the dereference handling for the visitor rework.
[mesa.git] / ir_to_mesa.cpp
1 /*
2 * Copyright © 2010 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 /**
25 * \file ir_to_mesa.cpp
26 *
27 * Translates the IR to ARB_fragment_program text if possible,
28 * printing the result
29 */
30
31 /* Quiet compiler warnings due to monoburg not marking functions defined
32 * in the header as inline.
33 */
34 #define g_new
35 #define g_error
36 #include "mesa_codegen.h"
37
38 #include "ir.h"
39 #include "ir_visitor.h"
40 #include "ir_print_visitor.h"
41 #include "ir_expression_flattening.h"
42 #include "glsl_types.h"
43
44 extern "C" {
45 #include "shader/prog_instruction.h"
46 #include "shader/prog_print.h"
47 }
48
49 ir_to_mesa_src_reg ir_to_mesa_undef = {
50 PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP, NEGATE_NONE, false,
51 };
52
53 ir_to_mesa_dst_reg ir_to_mesa_undef_dst = {
54 PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP
55 };
56
57 ir_to_mesa_instruction *
58 ir_to_mesa_emit_op3(ir_to_mesa_visitor *v, ir_instruction *ir,
59 enum prog_opcode op,
60 ir_to_mesa_dst_reg dst,
61 ir_to_mesa_src_reg src0,
62 ir_to_mesa_src_reg src1,
63 ir_to_mesa_src_reg src2)
64 {
65 ir_to_mesa_instruction *inst = new ir_to_mesa_instruction();
66
67 inst->op = op;
68 inst->dst_reg = dst;
69 inst->src_reg[0] = src0;
70 inst->src_reg[1] = src1;
71 inst->src_reg[2] = src2;
72 inst->ir = ir;
73
74 v->instructions.push_tail(inst);
75
76 return inst;
77 }
78
79
80 ir_to_mesa_instruction *
81 ir_to_mesa_emit_op2_full(ir_to_mesa_visitor *v, ir_instruction *ir,
82 enum prog_opcode op,
83 ir_to_mesa_dst_reg dst,
84 ir_to_mesa_src_reg src0,
85 ir_to_mesa_src_reg src1)
86 {
87 return ir_to_mesa_emit_op3(v, ir,
88 op, dst, src0, src1, ir_to_mesa_undef);
89 }
90
91 ir_to_mesa_instruction *
92 ir_to_mesa_emit_op2(struct mbtree *tree, enum prog_opcode op)
93 {
94 return ir_to_mesa_emit_op2_full(tree->v, tree->ir, op,
95 tree->dst_reg,
96 tree->left->src_reg,
97 tree->right->src_reg);
98 }
99
100 ir_to_mesa_instruction *
101 ir_to_mesa_emit_op1_full(ir_to_mesa_visitor *v, ir_instruction *ir,
102 enum prog_opcode op,
103 ir_to_mesa_dst_reg dst,
104 ir_to_mesa_src_reg src0)
105 {
106 return ir_to_mesa_emit_op3(v, ir, op,
107 dst, src0, ir_to_mesa_undef, ir_to_mesa_undef);
108 }
109
110 ir_to_mesa_instruction *
111 ir_to_mesa_emit_op1(struct mbtree *tree, enum prog_opcode op)
112 {
113 return ir_to_mesa_emit_op1_full(tree->v, tree->ir, op,
114 tree->dst_reg,
115 tree->left->src_reg);
116 }
117
118 /**
119 * Emits Mesa scalar opcodes to produce unique answers across channels.
120 *
121 * Some Mesa opcodes are scalar-only, like ARB_fp/vp. The src X
122 * channel determines the result across all channels. So to do a vec4
123 * of this operation, we want to emit a scalar per source channel used
124 * to produce dest channels.
125 */
126 void
127 ir_to_mesa_emit_scalar_op1(struct mbtree *tree, enum prog_opcode op,
128 ir_to_mesa_dst_reg dst,
129 ir_to_mesa_src_reg src0)
130 {
131 int i, j;
132 int done_mask = ~dst.writemask;
133
134 /* Mesa RCP is a scalar operation splatting results to all channels,
135 * like ARB_fp/vp. So emit as many RCPs as necessary to cover our
136 * dst channels.
137 */
138 for (i = 0; i < 4; i++) {
139 int this_mask = (1 << i);
140 ir_to_mesa_instruction *inst;
141 ir_to_mesa_src_reg src = src0;
142
143 if (done_mask & this_mask)
144 continue;
145
146 int src_swiz = GET_SWZ(src.swizzle, i);
147 for (j = i + 1; j < 4; j++) {
148 if (!(done_mask & (1 << j)) && GET_SWZ(src.swizzle, j) == src_swiz) {
149 this_mask |= (1 << j);
150 }
151 }
152 src.swizzle = MAKE_SWIZZLE4(src_swiz, src_swiz,
153 src_swiz, src_swiz);
154
155 inst = ir_to_mesa_emit_op1_full(tree->v, tree->ir, op,
156 dst,
157 src);
158 inst->dst_reg.writemask = this_mask;
159 done_mask |= this_mask;
160 }
161 }
162
163 static void
164 ir_to_mesa_set_tree_reg(struct mbtree *tree, int file, int index)
165 {
166 tree->dst_reg.file = file;
167 tree->dst_reg.index = index;
168
169 tree->src_reg.file = file;
170 tree->src_reg.index = index;
171 }
172
173 struct mbtree *
174 ir_to_mesa_visitor::create_tree(int op,
175 ir_instruction *ir,
176 struct mbtree *left, struct mbtree *right)
177 {
178 struct mbtree *tree = (struct mbtree *)calloc(sizeof(struct mbtree), 1);
179
180 assert(ir);
181
182 tree->op = op;
183 tree->left = left;
184 tree->right = right;
185 tree->v = this;
186 tree->src_reg.swizzle = SWIZZLE_XYZW;
187 tree->src_reg.negate = 0;
188 tree->dst_reg.writemask = WRITEMASK_XYZW;
189 ir_to_mesa_set_tree_reg(tree, PROGRAM_UNDEFINED, 0);
190 tree->ir = ir;
191
192 return tree;
193 }
194
195 struct mbtree *
196 ir_to_mesa_visitor::create_tree_for_float(ir_instruction *ir, float val)
197 {
198 struct mbtree *tree = (struct mbtree *)calloc(sizeof(struct mbtree), 1);
199
200 tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL);
201
202 /* FINISHME: This will end up being _mesa_add_unnamed_constant,
203 * which handles sharing values and sharing channels of vec4
204 * constants for small values.
205 */
206 /* FINISHME: Do something with the constant values for now.
207 */
208 (void)val;
209 ir_to_mesa_set_tree_reg(tree, PROGRAM_CONSTANT, this->next_constant++);
210 tree->src_reg.swizzle = SWIZZLE_NOOP;
211
212 this->result = tree;
213 return tree;
214 }
215
216 /**
217 * In the initial pass of codegen, we assign temporary numbers to
218 * intermediate results. (not SSA -- variable assignments will reuse
219 * storage). Actual register allocation for the Mesa VM occurs in a
220 * pass over the Mesa IR later.
221 */
222 void
223 ir_to_mesa_visitor::get_temp(struct mbtree *tree, int size)
224 {
225 int swizzle[4];
226 int i;
227
228 ir_to_mesa_set_tree_reg(tree, PROGRAM_TEMPORARY, this->next_temp++);
229
230 for (i = 0; i < size; i++)
231 swizzle[i] = i;
232 for (; i < 4; i++)
233 swizzle[i] = size - 1;
234 tree->src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0], swizzle[1],
235 swizzle[2], swizzle[3]);
236 tree->dst_reg.writemask = (1 << size) - 1;
237 }
238
239 static int
240 type_size(const struct glsl_type *type)
241 {
242 unsigned int i;
243 int size;
244
245 switch (type->base_type) {
246 case GLSL_TYPE_UINT:
247 case GLSL_TYPE_INT:
248 case GLSL_TYPE_FLOAT:
249 case GLSL_TYPE_BOOL:
250 assert(!type->is_matrix());
251 /* Regardless of size of vector, it gets a vec4. This is bad
252 * packing for things like floats, but otherwise arrays become a
253 * mess. Hopefully a later pass over the code can pack scalars
254 * down if appropriate.
255 */
256 return 1;
257 case GLSL_TYPE_ARRAY:
258 return type_size(type->fields.array) * type->length;
259 case GLSL_TYPE_STRUCT:
260 size = 0;
261 for (i = 0; i < type->length; i++) {
262 size += type_size(type->fields.structure[i].type);
263 }
264 return size;
265 default:
266 assert(0);
267 }
268 }
269
270 void
271 ir_to_mesa_visitor::get_temp_for_var(ir_variable *var, struct mbtree *tree)
272 {
273 temp_entry *entry;
274
275 foreach_iter(exec_list_iterator, iter, this->variable_storage) {
276 entry = (temp_entry *)iter.get();
277
278 if (entry->var == var) {
279 ir_to_mesa_set_tree_reg(tree, entry->file, entry->index);
280 return;
281 }
282 }
283
284 entry = new temp_entry(var, PROGRAM_TEMPORARY, this->next_temp);
285 this->variable_storage.push_tail(entry);
286
287 next_temp += type_size(var->type);
288
289 ir_to_mesa_set_tree_reg(tree, entry->file, entry->index);
290 }
291
292 static void
293 reduce(struct mbtree *t, int goal)
294 {
295 struct mbtree *kids[10];
296 int rule = mono_burg_rule((MBState *)t->state, goal);
297 const uint16_t *nts = mono_burg_nts[rule];
298 int i;
299
300 mono_burg_kids (t, rule, kids);
301
302 for (i = 0; nts[i]; i++) {
303 reduce(kids[i], nts[i]);
304 }
305
306 if (t->left) {
307 if (mono_burg_func[rule]) {
308 mono_burg_func[rule](t, NULL);
309 } else {
310 printf("no code for rules %s\n", mono_burg_rule_string[rule]);
311 exit(1);
312 }
313 } else {
314 if (mono_burg_func[rule]) {
315 printf("unused code for rule %s\n", mono_burg_rule_string[rule]);
316 exit(1);
317 }
318 }
319 }
320
321 void
322 ir_to_mesa_visitor::visit(ir_variable *ir)
323 {
324 (void)ir;
325 }
326
327 void
328 ir_to_mesa_visitor::visit(ir_loop *ir)
329 {
330 assert(!ir->from);
331 assert(!ir->to);
332 assert(!ir->increment);
333 assert(!ir->counter);
334
335 ir_to_mesa_emit_op1_full(this, NULL,
336 OPCODE_BGNLOOP, ir_to_mesa_undef_dst,
337 ir_to_mesa_undef);
338
339 visit_exec_list(&ir->body_instructions, this);
340
341 ir_to_mesa_emit_op1_full(this, NULL,
342 OPCODE_ENDLOOP, ir_to_mesa_undef_dst,
343 ir_to_mesa_undef);
344 }
345
346 void
347 ir_to_mesa_visitor::visit(ir_loop_jump *ir)
348 {
349 switch (ir->mode) {
350 case ir_loop_jump::jump_break:
351 ir_to_mesa_emit_op1_full(this, NULL,
352 OPCODE_BRK, ir_to_mesa_undef_dst,
353 ir_to_mesa_undef);
354 break;
355 case ir_loop_jump::jump_continue:
356 ir_to_mesa_emit_op1_full(this, NULL,
357 OPCODE_CONT, ir_to_mesa_undef_dst,
358 ir_to_mesa_undef);
359 break;
360 }
361 }
362
363
364 void
365 ir_to_mesa_visitor::visit(ir_function_signature *ir)
366 {
367 assert(0);
368 (void)ir;
369 }
370
371 void
372 ir_to_mesa_visitor::visit(ir_function *ir)
373 {
374 /* Ignore function bodies other than main() -- we shouldn't see calls to
375 * them since they should all be inlined before we get to ir_to_mesa.
376 */
377 if (strcmp(ir->name, "main") == 0) {
378 const ir_function_signature *sig;
379 exec_list empty;
380
381 sig = ir->matching_signature(&empty);
382
383 assert(sig);
384
385 foreach_iter(exec_list_iterator, iter, sig->body) {
386 ir_instruction *ir = (ir_instruction *)iter.get();
387
388 ir->accept(this);
389 }
390 }
391 }
392
393 void
394 ir_to_mesa_visitor::visit(ir_expression *ir)
395 {
396 unsigned int operand;
397 struct mbtree *op[2];
398 const glsl_type *vec4_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 4, 1);
399 const glsl_type *vec3_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 3, 1);
400 const glsl_type *vec2_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 2, 1);
401
402 for (operand = 0; operand < ir->get_num_operands(); operand++) {
403 this->result = NULL;
404 ir->operands[operand]->accept(this);
405 if (!this->result) {
406 ir_print_visitor v;
407 printf("Failed to get tree for expression operand:\n");
408 ir->operands[operand]->accept(&v);
409 exit(1);
410 }
411 op[operand] = this->result;
412 }
413
414 this->result = NULL;
415
416 switch (ir->operation) {
417 case ir_unop_logic_not:
418 this->result = this->create_tree_for_float(ir, 0.0);
419 this->result = this->create_tree(MB_TERM_seq_vec4_vec4, ir,
420 op[0], this->result);
421 break;
422 case ir_unop_neg:
423 op[0]->src_reg.negate = ~op[0]->src_reg.negate;
424 this->result = op[0];
425 break;
426 case ir_unop_exp:
427 this->result = this->create_tree(MB_TERM_exp_vec4, ir, op[0], NULL);
428 break;
429 case ir_unop_exp2:
430 this->result = this->create_tree(MB_TERM_exp2_vec4, ir, op[0], NULL);
431 break;
432 case ir_unop_log:
433 this->result = this->create_tree(MB_TERM_log_vec4, ir, op[0], NULL);
434 break;
435 case ir_unop_log2:
436 this->result = this->create_tree(MB_TERM_log2_vec4, ir, op[0], NULL);
437 break;
438 case ir_unop_sin:
439 this->result = this->create_tree(MB_TERM_sin_vec4, ir, op[0], NULL);
440 break;
441 case ir_unop_cos:
442 this->result = this->create_tree(MB_TERM_cos_vec4, ir, op[0], NULL);
443 break;
444 case ir_binop_add:
445 this->result = this->create_tree(MB_TERM_add_vec4_vec4, ir, op[0], op[1]);
446 break;
447 case ir_binop_sub:
448 this->result = this->create_tree(MB_TERM_sub_vec4_vec4, ir, op[0], op[1]);
449 break;
450 case ir_binop_mul:
451 this->result = this->create_tree(MB_TERM_mul_vec4_vec4, ir, op[0], op[1]);
452 break;
453 case ir_binop_div:
454 this->result = this->create_tree(MB_TERM_div_vec4_vec4, ir, op[0], op[1]);
455 break;
456
457 case ir_binop_less:
458 this->result = this->create_tree(MB_TERM_slt_vec4_vec4, ir, op[0], op[1]);
459 break;
460 case ir_binop_greater:
461 this->result = this->create_tree(MB_TERM_sgt_vec4_vec4, ir, op[0], op[1]);
462 break;
463 case ir_binop_lequal:
464 this->result = this->create_tree(MB_TERM_sle_vec4_vec4, ir, op[0], op[1]);
465 break;
466 case ir_binop_gequal:
467 this->result = this->create_tree(MB_TERM_sge_vec4_vec4, ir, op[0], op[1]);
468 break;
469 case ir_binop_equal:
470 this->result = this->create_tree(MB_TERM_seq_vec4_vec4, ir, op[0], op[1]);
471 break;
472 case ir_binop_logic_xor:
473 case ir_binop_nequal:
474 this->result = this->create_tree(MB_TERM_sne_vec4_vec4, ir, op[0], op[1]);
475 break;
476
477 case ir_binop_logic_or:
478 /* This could be a saturated add. */
479 this->result = this->create_tree(MB_TERM_add_vec4_vec4, ir, op[0], op[1]);
480 this->result = this->create_tree(MB_TERM_sne_vec4_vec4, ir,
481 this->create_tree_for_float(ir, 0.0),
482 this->result);
483 break;
484
485 case ir_binop_logic_and:
486 /* the bool args are stored as float 0.0 or 1.0, so "mul" gives us "and". */
487 this->result = this->create_tree(MB_TERM_mul_vec4_vec4, ir, op[0], op[1]);
488 break;
489
490 case ir_binop_dot:
491 if (ir->operands[0]->type == vec4_type) {
492 assert(ir->operands[1]->type == vec4_type);
493 this->result = this->create_tree(MB_TERM_dp4_vec4_vec4,
494 ir, op[0], op[1]);
495 } else if (ir->operands[0]->type == vec3_type) {
496 assert(ir->operands[1]->type == vec3_type);
497 this->result = this->create_tree(MB_TERM_dp3_vec4_vec4,
498 ir, op[0], op[1]);
499 } else if (ir->operands[0]->type == vec2_type) {
500 assert(ir->operands[1]->type == vec2_type);
501 this->result = this->create_tree(MB_TERM_dp2_vec4_vec4,
502 ir, op[0], op[1]);
503 }
504 break;
505 case ir_unop_sqrt:
506 this->result = this->create_tree(MB_TERM_sqrt_vec4, ir, op[0], op[1]);
507 break;
508 case ir_unop_rsq:
509 this->result = this->create_tree(MB_TERM_rsq_vec4, ir, op[0], op[1]);
510 break;
511 case ir_unop_i2f:
512 /* Mesa IR lacks types, ints are stored as truncated floats. */
513 this->result = op[0];
514 break;
515 case ir_unop_f2i:
516 this->result = this->create_tree(MB_TERM_trunc_vec4, ir, op[0], NULL);
517 break;
518 case ir_unop_f2b:
519 this->result = this->create_tree_for_float(ir, 0.0);
520 this->result = this->create_tree(MB_TERM_sne_vec4_vec4, ir,
521 op[0], this->result);
522 break;
523 case ir_unop_trunc:
524 this->result = this->create_tree(MB_TERM_trunc_vec4, ir, op[0], NULL);
525 break;
526 case ir_unop_ceil:
527 this->result = this->create_tree(MB_TERM_ceil_vec4, ir, op[0], NULL);
528 break;
529 case ir_unop_floor:
530 this->result = this->create_tree(MB_TERM_floor_vec4, ir, op[0], NULL);
531 break;
532 case ir_binop_min:
533 this->result = this->create_tree(MB_TERM_min_vec4_vec4, ir, op[0], op[1]);
534 break;
535 case ir_binop_max:
536 this->result = this->create_tree(MB_TERM_max_vec4_vec4, ir, op[0], op[1]);
537 break;
538 default:
539 break;
540 }
541 if (!this->result) {
542 ir_print_visitor v;
543 printf("Failed to get tree for expression:\n");
544 ir->accept(&v);
545 exit(1);
546 }
547
548 /* Allocate a temporary for the result. */
549 this->get_temp(this->result, ir->type->vector_elements);
550 }
551
552
553 void
554 ir_to_mesa_visitor::visit(ir_swizzle *ir)
555 {
556 struct mbtree *tree;
557 int i;
558 int swizzle[4];
559
560 /* Note that this is only swizzles in expressions, not those on the left
561 * hand side of an assignment, which do write masking. See ir_assignment
562 * for that.
563 */
564
565 ir->val->accept(this);
566 assert(this->result);
567
568 tree = this->create_tree(MB_TERM_swizzle_vec4, ir, this->result, NULL);
569 this->get_temp(tree, 4);
570
571 for (i = 0; i < 4; i++) {
572 if (i < ir->type->vector_elements) {
573 switch (i) {
574 case 0:
575 swizzle[i] = ir->mask.x;
576 break;
577 case 1:
578 swizzle[i] = ir->mask.y;
579 break;
580 case 2:
581 swizzle[i] = ir->mask.z;
582 break;
583 case 3:
584 swizzle[i] = ir->mask.w;
585 break;
586 }
587 } else {
588 /* If the type is smaller than a vec4, replicate the last
589 * channel out.
590 */
591 swizzle[i] = ir->type->vector_elements - 1;
592 }
593 }
594
595 tree->src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0],
596 swizzle[1],
597 swizzle[2],
598 swizzle[3]);
599
600 this->result = tree;
601 }
602
603 /* This list should match up with builtin_variables.h */
604 static const struct {
605 const char *name;
606 int file;
607 int index;
608 } builtin_var_to_mesa_reg[] = {
609 /* core_vs */
610 {"gl_Position", PROGRAM_OUTPUT, VERT_RESULT_HPOS},
611 {"gl_PointSize", PROGRAM_OUTPUT, VERT_RESULT_PSIZ},
612
613 /* core_fs */
614 {"gl_FragCoord", PROGRAM_INPUT, FRAG_ATTRIB_WPOS},
615 {"gl_FrontFacing", PROGRAM_INPUT, FRAG_ATTRIB_FACE},
616 {"gl_FragColor", PROGRAM_INPUT, FRAG_ATTRIB_COL0},
617 {"gl_FragDepth", PROGRAM_UNDEFINED, FRAG_ATTRIB_WPOS}, /* FINISHME: WPOS.z */
618
619 /* 110_deprecated_fs */
620 {"gl_Color", PROGRAM_INPUT, FRAG_ATTRIB_COL0},
621 {"gl_SecondaryColor", PROGRAM_INPUT, FRAG_ATTRIB_COL1},
622 {"gl_FogFragCoord", PROGRAM_INPUT, FRAG_ATTRIB_FOGC},
623
624 /* 110_deprecated_vs */
625 {"gl_Vertex", PROGRAM_INPUT, VERT_ATTRIB_POS},
626 {"gl_Normal", PROGRAM_INPUT, VERT_ATTRIB_NORMAL},
627 {"gl_Color", PROGRAM_INPUT, VERT_ATTRIB_COLOR0},
628 {"gl_SecondaryColor", PROGRAM_INPUT, VERT_ATTRIB_COLOR1},
629 {"gl_MultiTexCoord0", PROGRAM_INPUT, VERT_ATTRIB_TEX0},
630 {"gl_MultiTexCoord1", PROGRAM_INPUT, VERT_ATTRIB_TEX1},
631 {"gl_MultiTexCoord2", PROGRAM_INPUT, VERT_ATTRIB_TEX2},
632 {"gl_MultiTexCoord3", PROGRAM_INPUT, VERT_ATTRIB_TEX3},
633 {"gl_MultiTexCoord4", PROGRAM_INPUT, VERT_ATTRIB_TEX4},
634 {"gl_MultiTexCoord5", PROGRAM_INPUT, VERT_ATTRIB_TEX5},
635 {"gl_MultiTexCoord6", PROGRAM_INPUT, VERT_ATTRIB_TEX6},
636 {"gl_MultiTexCoord7", PROGRAM_INPUT, VERT_ATTRIB_TEX7},
637 {"gl_TexCoord", PROGRAM_OUTPUT, VERT_RESULT_TEX0}, /* array */
638 {"gl_FogCoord", PROGRAM_INPUT, VERT_RESULT_FOGC},
639 /*{"gl_ClipVertex", PROGRAM_OUTPUT, VERT_ATTRIB_FOGC},*/ /* FINISHME */
640 {"gl_FrontColor", PROGRAM_OUTPUT, VERT_RESULT_COL0},
641 {"gl_BackColor", PROGRAM_OUTPUT, VERT_RESULT_BFC0},
642 {"gl_FrontSecondaryColor", PROGRAM_OUTPUT, VERT_RESULT_COL1},
643 {"gl_BackSecondaryColor", PROGRAM_OUTPUT, VERT_RESULT_BFC1},
644 {"gl_FogFragCoord", PROGRAM_OUTPUT, VERT_RESULT_FOGC},
645
646 /* 130_vs */
647 /*{"gl_VertexID", PROGRAM_INPUT, VERT_ATTRIB_FOGC},*/ /* FINISHME */
648
649 {"gl_FragData", PROGRAM_OUTPUT, FRAG_RESULT_DATA0}, /* array */
650 };
651
652 void
653 ir_to_mesa_visitor::visit(ir_dereference_variable *ir)
654 {
655 struct mbtree *tree;
656 int size_swizzles[4] = {
657 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X),
658 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y),
659 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z),
660 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W),
661 };
662
663 /* By the time we make it to this stage, matrices should be broken down
664 * to vectors.
665 */
666 assert(!ir->var->type->is_matrix());
667
668 tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL);
669
670 if (strncmp(ir->var->name, "gl_", 3) == 0) {
671 unsigned int i;
672
673 for (i = 0; i < ARRAY_SIZE(builtin_var_to_mesa_reg); i++) {
674 if (strcmp(ir->var->name, builtin_var_to_mesa_reg[i].name) == 0)
675 break;
676 }
677 assert(i != ARRAY_SIZE(builtin_var_to_mesa_reg));
678 ir_to_mesa_set_tree_reg(tree, builtin_var_to_mesa_reg[i].file,
679 builtin_var_to_mesa_reg[i].index);
680 } else {
681 this->get_temp_for_var(ir->var, tree);
682 }
683
684 /* If the type is smaller than a vec4, replicate the last channel out. */
685 tree->src_reg.swizzle = size_swizzles[ir->type->vector_elements - 1];
686
687 this->result = tree;
688 }
689
690 void
691 ir_to_mesa_visitor::visit(ir_dereference_array *ir)
692 {
693 struct mbtree *tree;
694 int size_swizzles[4] = {
695 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W),
696 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z),
697 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y),
698 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X),
699 };
700 ir_constant *index;
701
702 index = ir->array_index->constant_expression_value();
703
704 /* By the time we make it to this stage, matrices should be broken down
705 * to vectors.
706 */
707 assert(!ir->type->is_matrix());
708
709 ir->array->accept(this);
710 tree = this->result;
711
712 if (tree->src_reg.file == PROGRAM_INPUT ||
713 tree->src_reg.file == PROGRAM_OUTPUT) {
714 assert(index); /* FINISHME: Handle variable indexing of builtins. */
715
716 tree->src_reg.index += index->value.i[0];
717 tree->dst_reg.index += index->value.i[0];
718 } else {
719 if (index) {
720 tree->src_reg.index += index->value.i[0];
721 tree->dst_reg.index += index->value.i[0];
722 } else {
723 /* Variable index array dereference. It eats the "vec4" of the
724 * base of the array and an index that offsets the Mesa register
725 * index.
726 */
727 ir->array_index->accept(this);
728
729 tree->src_reg.reladdr = true;
730 tree = this->create_tree(MB_TERM_array_reference_vec4_vec4,
731 ir, tree, this->result);
732 this->get_temp(tree, ir->type->vector_elements);
733 }
734 }
735
736 /* If the type is smaller than a vec4, replicate the last channel out. */
737 tree->src_reg.swizzle = size_swizzles[ir->type->vector_elements - 1];
738
739 this->result = tree;
740 }
741
742 void
743 ir_to_mesa_visitor::visit(ir_dereference_record *ir)
744 {
745 ir_variable *var = ir->variable_referenced();
746 const char *field = ir->field;
747 struct mbtree *tree;
748 unsigned int i;
749
750 const glsl_type *struct_type = var->type;
751 int offset = 0;
752
753 tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL);
754 this->get_temp_for_var(var, tree);
755
756 for (i = 0; i < struct_type->length; i++) {
757 if (strcmp(struct_type->fields.structure[i].name, field) == 0)
758 break;
759 offset += type_size(struct_type->fields.structure[i].type);
760 }
761 tree->src_reg.index += offset;
762 tree->dst_reg.index += offset;
763 }
764
765 /**
766 * We want to be careful in assignment setup to hit the actual storage
767 * instead of potentially using a temporary like we might with the
768 * ir_dereference handler.
769 *
770 * Thanks to ir_swizzle_swizzle, and ir_vec_index_to_swizzle, we
771 * should only see potentially one variable array index of a vector,
772 * and one swizzle, before getting to actual vec4 storage. So handle
773 * those, then go use ir_dereference to handle the rest.
774 */
775 static struct mbtree *
776 get_assignment_lhs(ir_instruction *ir, ir_to_mesa_visitor *v)
777 {
778 struct mbtree *tree = NULL;
779 ir_dereference *deref;
780 ir_swizzle *swiz;
781
782 ir->accept(v);
783 tree = v->result;
784
785 if ((deref = ir->as_dereference())) {
786 ir_dereference_array *deref_array = ir->as_dereference_array();
787 assert(!deref_array || deref_array->array->type->is_array());
788
789 ir->accept(v);
790 tree = v->result;
791 } else if ((swiz = ir->as_swizzle())) {
792 tree->dst_reg.writemask = 0;
793 if (swiz->mask.num_components >= 1)
794 tree->dst_reg.writemask |= (1 << swiz->mask.x);
795 if (swiz->mask.num_components >= 2)
796 tree->dst_reg.writemask |= (1 << swiz->mask.y);
797 if (swiz->mask.num_components >= 3)
798 tree->dst_reg.writemask |= (1 << swiz->mask.z);
799 if (swiz->mask.num_components >= 4)
800 tree->dst_reg.writemask |= (1 << swiz->mask.w);
801 }
802
803 assert(tree);
804
805 return tree;
806 }
807
808 void
809 ir_to_mesa_visitor::visit(ir_assignment *ir)
810 {
811 struct mbtree *l, *r, *t;
812
813 assert(!ir->lhs->type->is_matrix());
814 assert(!ir->lhs->type->is_array());
815 assert(ir->lhs->type->base_type != GLSL_TYPE_STRUCT);
816
817 l = get_assignment_lhs(ir->lhs, this);
818
819 ir->rhs->accept(this);
820 r = this->result;
821 assert(l);
822 assert(r);
823
824 if (ir->condition) {
825 ir_constant *condition_constant;
826
827 condition_constant = ir->condition->constant_expression_value();
828
829 assert(condition_constant && condition_constant->value.b[0]);
830 }
831
832 t = this->create_tree(MB_TERM_assign, ir, l, r);
833 mono_burg_label(t, NULL);
834 reduce(t, MB_NTERM_stmt);
835 }
836
837
838 void
839 ir_to_mesa_visitor::visit(ir_constant *ir)
840 {
841 struct mbtree *tree;
842
843 assert(!ir->type->is_matrix());
844
845 tree = this->create_tree(MB_TERM_reference_vec4, ir, NULL, NULL);
846
847 assert(ir->type->base_type == GLSL_TYPE_FLOAT ||
848 ir->type->base_type == GLSL_TYPE_UINT ||
849 ir->type->base_type == GLSL_TYPE_INT ||
850 ir->type->base_type == GLSL_TYPE_BOOL);
851
852 /* FINISHME: This will end up being _mesa_add_unnamed_constant,
853 * which handles sharing values and sharing channels of vec4
854 * constants for small values.
855 */
856 /* FINISHME: Do something with the constant values for now.
857 */
858 ir_to_mesa_set_tree_reg(tree, PROGRAM_CONSTANT, this->next_constant++);
859 tree->src_reg.swizzle = SWIZZLE_NOOP;
860
861 this->result = tree;
862 }
863
864
865 void
866 ir_to_mesa_visitor::visit(ir_call *ir)
867 {
868 printf("Can't support call to %s\n", ir->callee_name());
869 exit(1);
870 }
871
872
873 void
874 ir_to_mesa_visitor::visit(ir_texture *ir)
875 {
876 assert(0);
877
878 ir->coordinate->accept(this);
879 }
880
881 void
882 ir_to_mesa_visitor::visit(ir_return *ir)
883 {
884 assert(0);
885
886 ir->get_value()->accept(this);
887 }
888
889
890 void
891 ir_to_mesa_visitor::visit(ir_if *ir)
892 {
893 ir_to_mesa_instruction *if_inst, *else_inst = NULL;
894
895 ir->condition->accept(this);
896 assert(this->result);
897
898 if_inst = ir_to_mesa_emit_op1_full(this, ir->condition,
899 OPCODE_IF, ir_to_mesa_undef_dst,
900 this->result->src_reg);
901
902 this->instructions.push_tail(if_inst);
903
904 visit_exec_list(&ir->then_instructions, this);
905
906 if (!ir->else_instructions.is_empty()) {
907 else_inst = ir_to_mesa_emit_op1_full(this, ir->condition,
908 OPCODE_ELSE, ir_to_mesa_undef_dst,
909 ir_to_mesa_undef);
910 visit_exec_list(&ir->then_instructions, this);
911 }
912
913 if_inst = ir_to_mesa_emit_op1_full(this, ir->condition,
914 OPCODE_ENDIF, ir_to_mesa_undef_dst,
915 ir_to_mesa_undef);
916 }
917
918 ir_to_mesa_visitor::ir_to_mesa_visitor()
919 {
920 result = NULL;
921 next_temp = 1;
922 next_constant = 0;
923 }
924
925 static struct prog_src_register
926 mesa_src_reg_from_ir_src_reg(ir_to_mesa_src_reg reg)
927 {
928 struct prog_src_register mesa_reg;
929
930 mesa_reg.File = reg.file;
931 assert(reg.index < (1 << INST_INDEX_BITS) - 1);
932 mesa_reg.Index = reg.index;
933 mesa_reg.Swizzle = reg.swizzle;
934 mesa_reg.RelAddr = reg.reladdr;
935
936 return mesa_reg;
937 }
938
939 static void
940 set_branchtargets(struct prog_instruction *mesa_instructions,
941 int num_instructions)
942 {
943 int if_count = 0, loop_count;
944 int *if_stack, *loop_stack;
945 int if_stack_pos = 0, loop_stack_pos = 0;
946 int i, j;
947
948 for (i = 0; i < num_instructions; i++) {
949 switch (mesa_instructions[i].Opcode) {
950 case OPCODE_IF:
951 if_count++;
952 break;
953 case OPCODE_BGNLOOP:
954 loop_count++;
955 break;
956 case OPCODE_BRK:
957 case OPCODE_CONT:
958 mesa_instructions[i].BranchTarget = -1;
959 break;
960 default:
961 break;
962 }
963 }
964
965 if_stack = (int *)calloc(if_count, sizeof(*if_stack));
966 loop_stack = (int *)calloc(loop_count, sizeof(*loop_stack));
967
968 for (i = 0; i < num_instructions; i++) {
969 switch (mesa_instructions[i].Opcode) {
970 case OPCODE_IF:
971 if_stack[if_stack_pos] = i;
972 if_stack_pos++;
973 break;
974 case OPCODE_ELSE:
975 mesa_instructions[if_stack[if_stack_pos - 1]].BranchTarget = i;
976 if_stack[if_stack_pos - 1] = i;
977 break;
978 case OPCODE_ENDIF:
979 mesa_instructions[if_stack[if_stack_pos - 1]].BranchTarget = i;
980 if_stack_pos--;
981 break;
982 case OPCODE_BGNLOOP:
983 loop_stack[loop_stack_pos] = i;
984 loop_stack_pos++;
985 break;
986 case OPCODE_ENDLOOP:
987 loop_stack_pos--;
988 /* Rewrite any breaks/conts at this nesting level (haven't
989 * already had a BranchTarget assigned) to point to the end
990 * of the loop.
991 */
992 for (j = loop_stack[loop_stack_pos]; j < i; j++) {
993 if (mesa_instructions[j].Opcode == OPCODE_BRK ||
994 mesa_instructions[j].Opcode == OPCODE_CONT) {
995 if (mesa_instructions[j].BranchTarget == -1) {
996 mesa_instructions[j].BranchTarget = i;
997 }
998 }
999 }
1000 /* The loop ends point at each other. */
1001 mesa_instructions[i].BranchTarget = loop_stack[loop_stack_pos];
1002 mesa_instructions[loop_stack[loop_stack_pos]].BranchTarget = i;
1003 default:
1004 break;
1005 }
1006 }
1007
1008 free(if_stack);
1009 }
1010
1011 static void
1012 print_program(struct prog_instruction *mesa_instructions,
1013 ir_instruction **mesa_instruction_annotation,
1014 int num_instructions)
1015 {
1016 ir_instruction *last_ir = NULL;
1017 int i;
1018
1019 for (i = 0; i < num_instructions; i++) {
1020 struct prog_instruction *mesa_inst = mesa_instructions + i;
1021 ir_instruction *ir = mesa_instruction_annotation[i];
1022
1023 if (last_ir != ir && ir) {
1024 ir_print_visitor print;
1025 ir->accept(&print);
1026 printf("\n");
1027 last_ir = ir;
1028 }
1029
1030 _mesa_print_instruction(mesa_inst);
1031 }
1032 }
1033
1034 void
1035 do_ir_to_mesa(exec_list *instructions)
1036 {
1037 ir_to_mesa_visitor v;
1038 struct prog_instruction *mesa_instructions, *mesa_inst;
1039 ir_instruction **mesa_instruction_annotation;
1040 int i;
1041
1042 visit_exec_list(instructions, &v);
1043
1044 int num_instructions = 0;
1045 foreach_iter(exec_list_iterator, iter, v.instructions) {
1046 num_instructions++;
1047 }
1048
1049 mesa_instructions =
1050 (struct prog_instruction *)calloc(num_instructions,
1051 sizeof(*mesa_instructions));
1052 mesa_instruction_annotation =
1053 (ir_instruction **)calloc(num_instructions,
1054 sizeof(*mesa_instruction_annotation));
1055
1056 mesa_inst = mesa_instructions;
1057 i = 0;
1058 foreach_iter(exec_list_iterator, iter, v.instructions) {
1059 ir_to_mesa_instruction *inst = (ir_to_mesa_instruction *)iter.get();
1060
1061 mesa_inst->Opcode = inst->op;
1062 mesa_inst->DstReg.File = inst->dst_reg.file;
1063 mesa_inst->DstReg.Index = inst->dst_reg.index;
1064 mesa_inst->DstReg.CondMask = COND_TR;
1065 mesa_inst->DstReg.WriteMask = inst->dst_reg.writemask;
1066 mesa_inst->SrcReg[0] = mesa_src_reg_from_ir_src_reg(inst->src_reg[0]);
1067 mesa_inst->SrcReg[1] = mesa_src_reg_from_ir_src_reg(inst->src_reg[1]);
1068 mesa_inst->SrcReg[2] = mesa_src_reg_from_ir_src_reg(inst->src_reg[2]);
1069 mesa_instruction_annotation[i] = inst->ir;
1070
1071 mesa_inst++;
1072 i++;
1073 }
1074
1075 set_branchtargets(mesa_instructions, num_instructions);
1076 print_program(mesa_instructions, mesa_instruction_annotation, num_instructions);
1077
1078 free(mesa_instruction_annotation);
1079 }