2 * Copyright © 2010 Intel Corporation
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:
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
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.
25 * \file ir_to_mesa.cpp
27 * Translates the IR to ARB_fragment_program text if possible,
33 #include "ir_visitor.h"
34 #include "ir_print_visitor.h"
35 #include "ir_expression_flattening.h"
36 #include "glsl_types.h"
39 #include "shader/prog_instruction.h"
40 #include "shader/prog_print.h"
44 * This struct is a corresponding struct to Mesa prog_src_register, with
47 typedef struct ir_to_mesa_src_reg {
48 int file; /**< PROGRAM_* from Mesa */
49 int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */
50 int swizzle; /**< SWIZZLE_XYZWONEZERO swizzles from Mesa. */
51 int negate; /**< NEGATE_XYZW mask from mesa */
52 bool reladdr; /**< Register index should be offset by address reg. */
55 typedef struct ir_to_mesa_dst_reg {
56 int file; /**< PROGRAM_* from Mesa */
57 int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */
58 int writemask; /**< Bitfield of WRITEMASK_[XYZW] */
61 extern ir_to_mesa_src_reg ir_to_mesa_undef;
63 class ir_to_mesa_instruction : public exec_node {
66 ir_to_mesa_dst_reg dst_reg;
67 ir_to_mesa_src_reg src_reg[3];
68 /** Pointer to the ir source this tree came from for debugging */
72 class temp_entry : public exec_node {
74 temp_entry(ir_variable *var, int file, int index)
75 : file(file), index(index), var(var)
82 ir_variable *var; /* variable that maps to this, if any */
85 class ir_to_mesa_visitor : public ir_visitor {
93 temp_entry *find_variable_storage(ir_variable *var);
95 ir_to_mesa_src_reg get_temp(const glsl_type *type);
97 struct ir_to_mesa_src_reg src_reg_for_float(float val);
100 * \name Visit methods
102 * As typical for the visitor pattern, there must be one \c visit method for
103 * each concrete subclass of \c ir_instruction. Virtual base classes within
104 * the hierarchy should not have \c visit methods.
107 virtual void visit(ir_variable *);
108 virtual void visit(ir_loop *);
109 virtual void visit(ir_loop_jump *);
110 virtual void visit(ir_function_signature *);
111 virtual void visit(ir_function *);
112 virtual void visit(ir_expression *);
113 virtual void visit(ir_swizzle *);
114 virtual void visit(ir_dereference_variable *);
115 virtual void visit(ir_dereference_array *);
116 virtual void visit(ir_dereference_record *);
117 virtual void visit(ir_assignment *);
118 virtual void visit(ir_constant *);
119 virtual void visit(ir_call *);
120 virtual void visit(ir_return *);
121 virtual void visit(ir_texture *);
122 virtual void visit(ir_if *);
125 struct ir_to_mesa_src_reg result;
127 /** List of temp_entry */
128 exec_list variable_storage;
130 /** List of ir_to_mesa_instruction */
131 exec_list instructions;
133 ir_to_mesa_instruction *ir_to_mesa_emit_op1(ir_instruction *ir,
135 ir_to_mesa_dst_reg dst,
136 ir_to_mesa_src_reg src0);
138 ir_to_mesa_instruction *ir_to_mesa_emit_op2(ir_instruction *ir,
140 ir_to_mesa_dst_reg dst,
141 ir_to_mesa_src_reg src0,
142 ir_to_mesa_src_reg src1);
144 ir_to_mesa_instruction *ir_to_mesa_emit_op3(ir_instruction *ir,
146 ir_to_mesa_dst_reg dst,
147 ir_to_mesa_src_reg src0,
148 ir_to_mesa_src_reg src1,
149 ir_to_mesa_src_reg src2);
151 void ir_to_mesa_emit_scalar_op1(ir_instruction *ir,
153 ir_to_mesa_dst_reg dst,
154 ir_to_mesa_src_reg src0);
156 /* talloc context (the ) */
160 ir_to_mesa_src_reg ir_to_mesa_undef = {
161 PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP, NEGATE_NONE, false,
164 ir_to_mesa_dst_reg ir_to_mesa_undef_dst = {
165 PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP
168 ir_to_mesa_dst_reg ir_to_mesa_address_reg = {
169 PROGRAM_ADDRESS, 0, WRITEMASK_X
172 static int swizzle_for_size(int size)
174 int size_swizzles[4] = {
175 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X),
176 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y),
177 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z),
178 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W),
181 return size_swizzles[size - 1];
184 /* This list should match up with builtin_variables.h */
185 static const struct {
189 } builtin_var_to_mesa_reg[] = {
191 {"gl_Position", PROGRAM_OUTPUT, VERT_RESULT_HPOS},
192 {"gl_PointSize", PROGRAM_OUTPUT, VERT_RESULT_PSIZ},
195 {"gl_FragCoord", PROGRAM_INPUT, FRAG_ATTRIB_WPOS},
196 {"gl_FrontFacing", PROGRAM_INPUT, FRAG_ATTRIB_FACE},
197 {"gl_FragColor", PROGRAM_OUTPUT, FRAG_ATTRIB_COL0},
198 {"gl_FragDepth", PROGRAM_UNDEFINED, FRAG_ATTRIB_WPOS}, /* FINISHME: WPOS.z */
200 /* 110_deprecated_fs */
201 {"gl_Color", PROGRAM_INPUT, FRAG_ATTRIB_COL0},
202 {"gl_SecondaryColor", PROGRAM_INPUT, FRAG_ATTRIB_COL1},
203 {"gl_FogFragCoord", PROGRAM_INPUT, FRAG_ATTRIB_FOGC},
204 {"gl_TexCoord", PROGRAM_INPUT, FRAG_ATTRIB_TEX0}, /* array */
206 /* 110_deprecated_vs */
207 {"gl_Vertex", PROGRAM_INPUT, VERT_ATTRIB_POS},
208 {"gl_Normal", PROGRAM_INPUT, VERT_ATTRIB_NORMAL},
209 {"gl_Color", PROGRAM_INPUT, VERT_ATTRIB_COLOR0},
210 {"gl_SecondaryColor", PROGRAM_INPUT, VERT_ATTRIB_COLOR1},
211 {"gl_MultiTexCoord0", PROGRAM_INPUT, VERT_ATTRIB_TEX0},
212 {"gl_MultiTexCoord1", PROGRAM_INPUT, VERT_ATTRIB_TEX1},
213 {"gl_MultiTexCoord2", PROGRAM_INPUT, VERT_ATTRIB_TEX2},
214 {"gl_MultiTexCoord3", PROGRAM_INPUT, VERT_ATTRIB_TEX3},
215 {"gl_MultiTexCoord4", PROGRAM_INPUT, VERT_ATTRIB_TEX4},
216 {"gl_MultiTexCoord5", PROGRAM_INPUT, VERT_ATTRIB_TEX5},
217 {"gl_MultiTexCoord6", PROGRAM_INPUT, VERT_ATTRIB_TEX6},
218 {"gl_MultiTexCoord7", PROGRAM_INPUT, VERT_ATTRIB_TEX7},
219 {"gl_TexCoord", PROGRAM_OUTPUT, VERT_RESULT_TEX0}, /* array */
220 {"gl_FogCoord", PROGRAM_INPUT, VERT_RESULT_FOGC},
221 /*{"gl_ClipVertex", PROGRAM_OUTPUT, VERT_ATTRIB_FOGC},*/ /* FINISHME */
222 {"gl_FrontColor", PROGRAM_OUTPUT, VERT_RESULT_COL0},
223 {"gl_BackColor", PROGRAM_OUTPUT, VERT_RESULT_BFC0},
224 {"gl_FrontSecondaryColor", PROGRAM_OUTPUT, VERT_RESULT_COL1},
225 {"gl_BackSecondaryColor", PROGRAM_OUTPUT, VERT_RESULT_BFC1},
226 {"gl_FogFragCoord", PROGRAM_OUTPUT, VERT_RESULT_FOGC},
229 /*{"gl_VertexID", PROGRAM_INPUT, VERT_ATTRIB_FOGC},*/ /* FINISHME */
231 {"gl_FragData", PROGRAM_OUTPUT, FRAG_RESULT_DATA0}, /* array */
234 ir_to_mesa_instruction *
235 ir_to_mesa_visitor::ir_to_mesa_emit_op3(ir_instruction *ir,
237 ir_to_mesa_dst_reg dst,
238 ir_to_mesa_src_reg src0,
239 ir_to_mesa_src_reg src1,
240 ir_to_mesa_src_reg src2)
242 ir_to_mesa_instruction *inst = new(ctx) ir_to_mesa_instruction();
246 inst->src_reg[0] = src0;
247 inst->src_reg[1] = src1;
248 inst->src_reg[2] = src2;
251 this->instructions.push_tail(inst);
257 ir_to_mesa_instruction *
258 ir_to_mesa_visitor::ir_to_mesa_emit_op2(ir_instruction *ir,
260 ir_to_mesa_dst_reg dst,
261 ir_to_mesa_src_reg src0,
262 ir_to_mesa_src_reg src1)
264 return ir_to_mesa_emit_op3(ir, op, dst, src0, src1, ir_to_mesa_undef);
267 ir_to_mesa_instruction *
268 ir_to_mesa_visitor::ir_to_mesa_emit_op1(ir_instruction *ir,
270 ir_to_mesa_dst_reg dst,
271 ir_to_mesa_src_reg src0)
273 return ir_to_mesa_emit_op3(ir, op, dst,
274 src0, ir_to_mesa_undef, ir_to_mesa_undef);
277 inline ir_to_mesa_dst_reg
278 ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg reg)
280 ir_to_mesa_dst_reg dst_reg;
282 dst_reg.file = reg.file;
283 dst_reg.index = reg.index;
284 dst_reg.writemask = WRITEMASK_XYZW;
290 * Emits Mesa scalar opcodes to produce unique answers across channels.
292 * Some Mesa opcodes are scalar-only, like ARB_fp/vp. The src X
293 * channel determines the result across all channels. So to do a vec4
294 * of this operation, we want to emit a scalar per source channel used
295 * to produce dest channels.
298 ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op1(ir_instruction *ir,
300 ir_to_mesa_dst_reg dst,
301 ir_to_mesa_src_reg src0)
304 int done_mask = ~dst.writemask;
306 /* Mesa RCP is a scalar operation splatting results to all channels,
307 * like ARB_fp/vp. So emit as many RCPs as necessary to cover our
310 for (i = 0; i < 4; i++) {
311 int this_mask = (1 << i);
312 ir_to_mesa_instruction *inst;
313 ir_to_mesa_src_reg src = src0;
315 if (done_mask & this_mask)
318 int src_swiz = GET_SWZ(src.swizzle, i);
319 for (j = i + 1; j < 4; j++) {
320 if (!(done_mask & (1 << j)) && GET_SWZ(src.swizzle, j) == src_swiz) {
321 this_mask |= (1 << j);
324 src.swizzle = MAKE_SWIZZLE4(src_swiz, src_swiz,
327 inst = ir_to_mesa_emit_op1(ir, op,
330 inst->dst_reg.writemask = this_mask;
331 done_mask |= this_mask;
335 struct ir_to_mesa_src_reg
336 ir_to_mesa_visitor::src_reg_for_float(float val)
338 ir_to_mesa_src_reg src_reg;
340 /* FINISHME: This will end up being _mesa_add_unnamed_constant,
341 * which handles sharing values and sharing channels of vec4
342 * constants for small values.
344 /* FINISHME: Do something with the constant values for now.
347 src_reg.file = PROGRAM_CONSTANT;
348 src_reg.index = this->next_constant++;
349 src_reg.swizzle = SWIZZLE_NOOP;
355 * In the initial pass of codegen, we assign temporary numbers to
356 * intermediate results. (not SSA -- variable assignments will reuse
357 * storage). Actual register allocation for the Mesa VM occurs in a
358 * pass over the Mesa IR later.
361 ir_to_mesa_visitor::get_temp(const glsl_type *type)
363 ir_to_mesa_src_reg src_reg;
367 assert(!type->is_array());
369 src_reg.file = PROGRAM_TEMPORARY;
370 src_reg.index = type->matrix_columns;
371 src_reg.reladdr = false;
373 for (i = 0; i < type->vector_elements; i++)
376 swizzle[i] = type->vector_elements - 1;
377 src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0], swizzle[1],
378 swizzle[2], swizzle[3]);
384 type_size(const struct glsl_type *type)
389 switch (type->base_type) {
392 case GLSL_TYPE_FLOAT:
394 if (type->is_matrix()) {
395 return 4; /* FINISHME: Not all matrices are 4x4. */
397 /* Regardless of size of vector, it gets a vec4. This is bad
398 * packing for things like floats, but otherwise arrays become a
399 * mess. Hopefully a later pass over the code can pack scalars
400 * down if appropriate.
404 case GLSL_TYPE_ARRAY:
405 return type_size(type->fields.array) * type->length;
406 case GLSL_TYPE_STRUCT:
408 for (i = 0; i < type->length; i++) {
409 size += type_size(type->fields.structure[i].type);
418 ir_to_mesa_visitor::find_variable_storage(ir_variable *var)
423 foreach_iter(exec_list_iterator, iter, this->variable_storage) {
424 entry = (temp_entry *)iter.get();
426 if (entry->var == var)
434 ir_to_mesa_visitor::visit(ir_variable *ir)
440 ir_to_mesa_visitor::visit(ir_loop *ir)
444 assert(!ir->increment);
445 assert(!ir->counter);
447 ir_to_mesa_emit_op1(NULL, OPCODE_BGNLOOP,
448 ir_to_mesa_undef_dst, ir_to_mesa_undef);
450 visit_exec_list(&ir->body_instructions, this);
452 ir_to_mesa_emit_op1(NULL, OPCODE_ENDLOOP,
453 ir_to_mesa_undef_dst, ir_to_mesa_undef);
457 ir_to_mesa_visitor::visit(ir_loop_jump *ir)
460 case ir_loop_jump::jump_break:
461 ir_to_mesa_emit_op1(NULL, OPCODE_BRK,
462 ir_to_mesa_undef_dst, ir_to_mesa_undef);
464 case ir_loop_jump::jump_continue:
465 ir_to_mesa_emit_op1(NULL, OPCODE_CONT,
466 ir_to_mesa_undef_dst, ir_to_mesa_undef);
473 ir_to_mesa_visitor::visit(ir_function_signature *ir)
480 ir_to_mesa_visitor::visit(ir_function *ir)
482 /* Ignore function bodies other than main() -- we shouldn't see calls to
483 * them since they should all be inlined before we get to ir_to_mesa.
485 if (strcmp(ir->name, "main") == 0) {
486 const ir_function_signature *sig;
489 sig = ir->matching_signature(&empty);
493 foreach_iter(exec_list_iterator, iter, sig->body) {
494 ir_instruction *ir = (ir_instruction *)iter.get();
502 ir_to_mesa_visitor::visit(ir_expression *ir)
504 unsigned int operand;
505 struct ir_to_mesa_src_reg op[2];
506 struct ir_to_mesa_src_reg result_src;
507 struct ir_to_mesa_dst_reg result_dst;
508 const glsl_type *vec4_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 4, 1);
509 const glsl_type *vec3_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 3, 1);
510 const glsl_type *vec2_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 2, 1);
512 for (operand = 0; operand < ir->get_num_operands(); operand++) {
513 this->result.file = PROGRAM_UNDEFINED;
514 ir->operands[operand]->accept(this);
515 if (this->result.file == PROGRAM_UNDEFINED) {
517 printf("Failed to get tree for expression operand:\n");
518 ir->operands[operand]->accept(&v);
521 op[operand] = this->result;
523 /* Only expression implemented for matrices yet */
524 assert(!ir->operands[operand]->type->is_matrix() ||
525 ir->operation == ir_binop_mul);
528 this->result.file = PROGRAM_UNDEFINED;
530 /* Storage for our result. Ideally for an assignment we'd be using
531 * the actual storage for the result here, instead.
533 result_src = get_temp(ir->type);
534 /* convenience for the emit functions below. */
535 result_dst = ir_to_mesa_dst_reg_from_src(result_src);
536 /* Limit writes to the channels that will be used by result_src later.
537 * This does limit this temp's use as a temporary for multi-instruction
540 result_dst.writemask = (1 << ir->type->vector_elements) - 1;
542 switch (ir->operation) {
543 case ir_unop_logic_not:
544 ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst,
545 op[0], src_reg_for_float(0.0));
548 op[0].negate = ~op[0].negate;
552 ir_to_mesa_emit_scalar_op1(ir, OPCODE_EXP, result_dst, op[0]);
555 ir_to_mesa_emit_scalar_op1(ir, OPCODE_EX2, result_dst, op[0]);
558 ir_to_mesa_emit_scalar_op1(ir, OPCODE_LOG, result_dst, op[0]);
561 ir_to_mesa_emit_scalar_op1(ir, OPCODE_LG2, result_dst, op[0]);
564 ir_to_mesa_emit_scalar_op1(ir, OPCODE_SIN, result_dst, op[0]);
567 ir_to_mesa_emit_scalar_op1(ir, OPCODE_COS, result_dst, op[0]);
570 ir_to_mesa_emit_op2(ir, OPCODE_ADD, result_dst, op[0], op[1]);
573 ir_to_mesa_emit_op2(ir, OPCODE_SUB, result_dst, op[0], op[1]);
576 if (ir->operands[0]->type->is_matrix() &&
577 !ir->operands[1]->type->is_matrix()) {
578 if (ir->operands[0]->type->is_scalar()) {
579 ir_to_mesa_dst_reg dst_column = result_dst;
580 ir_to_mesa_src_reg src_column = op[0];
581 for (int i = 0; i < ir->operands[0]->type->matrix_columns; i++) {
582 ir_to_mesa_emit_op2(ir, OPCODE_MUL,
583 dst_column, src_column, op[1]);
588 ir_to_mesa_dst_reg dst_chan = result_dst;
589 ir_to_mesa_src_reg src_column = op[0];
590 ir_to_mesa_src_reg src_chan = op[1];
591 for (int i = 0; i < ir->operands[0]->type->matrix_columns; i++) {
592 dst_chan.writemask = (1 << i);
593 src_chan.swizzle = MAKE_SWIZZLE4(i, i, i, i);
594 ir_to_mesa_emit_op2(ir, OPCODE_MUL,
595 dst_chan, src_column, src_chan);
600 assert(!ir->operands[0]->type->is_matrix());
601 assert(!ir->operands[1]->type->is_matrix());
602 ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, op[0], op[1]);
606 ir_to_mesa_emit_scalar_op1(ir, OPCODE_RCP, result_dst, op[1]);
607 ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, op[0], result_src);
611 ir_to_mesa_emit_op2(ir, OPCODE_SLT, result_dst, op[0], op[1]);
613 case ir_binop_greater:
614 ir_to_mesa_emit_op2(ir, OPCODE_SGT, result_dst, op[0], op[1]);
616 case ir_binop_lequal:
617 ir_to_mesa_emit_op2(ir, OPCODE_SLE, result_dst, op[0], op[1]);
619 case ir_binop_gequal:
620 ir_to_mesa_emit_op2(ir, OPCODE_SGE, result_dst, op[0], op[1]);
623 ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, op[0], op[1]);
625 case ir_binop_logic_xor:
626 case ir_binop_nequal:
627 ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]);
630 case ir_binop_logic_or:
631 /* This could be a saturated add and skip the SNE. */
632 ir_to_mesa_emit_op2(ir, OPCODE_ADD,
636 ir_to_mesa_emit_op2(ir, OPCODE_SNE,
638 result_src, src_reg_for_float(0.0));
641 case ir_binop_logic_and:
642 /* the bool args are stored as float 0.0 or 1.0, so "mul" gives us "and". */
643 ir_to_mesa_emit_op2(ir, OPCODE_MUL,
649 if (ir->operands[0]->type == vec4_type) {
650 assert(ir->operands[1]->type == vec4_type);
651 ir_to_mesa_emit_op2(ir, OPCODE_DP4,
654 } else if (ir->operands[0]->type == vec3_type) {
655 assert(ir->operands[1]->type == vec3_type);
656 ir_to_mesa_emit_op2(ir, OPCODE_DP3,
659 } else if (ir->operands[0]->type == vec2_type) {
660 assert(ir->operands[1]->type == vec2_type);
661 ir_to_mesa_emit_op2(ir, OPCODE_DP2,
667 ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]);
668 ir_to_mesa_emit_op1(ir, OPCODE_RCP, result_dst, result_src);
671 ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]);
674 /* Mesa IR lacks types, ints are stored as truncated floats. */
678 ir_to_mesa_emit_op1(ir, OPCODE_TRUNC, result_dst, op[0]);
681 ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst,
682 result_src, src_reg_for_float(0.0));
685 ir_to_mesa_emit_op1(ir, OPCODE_TRUNC, result_dst, op[0]);
688 op[0].negate = ~op[0].negate;
689 ir_to_mesa_emit_op1(ir, OPCODE_FLR, result_dst, op[0]);
690 result_src.negate = ~result_src.negate;
693 ir_to_mesa_emit_op1(ir, OPCODE_FLR, result_dst, op[0]);
696 ir_to_mesa_emit_op2(ir, OPCODE_MIN, result_dst, op[0], op[1]);
699 ir_to_mesa_emit_op2(ir, OPCODE_MAX, result_dst, op[0], op[1]);
703 printf("Failed to get tree for expression:\n");
709 this->result = result_src;
714 ir_to_mesa_visitor::visit(ir_swizzle *ir)
716 ir_to_mesa_src_reg src_reg;
720 /* Note that this is only swizzles in expressions, not those on the left
721 * hand side of an assignment, which do write masking. See ir_assignment
725 ir->val->accept(this);
726 src_reg = this->result;
727 assert(src_reg.file != PROGRAM_UNDEFINED);
729 for (i = 0; i < 4; i++) {
730 if (i < ir->type->vector_elements) {
733 swizzle[i] = ir->mask.x;
736 swizzle[i] = ir->mask.y;
739 swizzle[i] = ir->mask.z;
742 swizzle[i] = ir->mask.w;
746 /* If the type is smaller than a vec4, replicate the last
749 swizzle[i] = ir->type->vector_elements - 1;
753 src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0],
758 this->result = src_reg;
762 ir_to_mesa_visitor::visit(ir_dereference_variable *ir)
764 ir_to_mesa_src_reg src_reg;
765 temp_entry *entry = find_variable_storage(ir->var);
770 switch (ir->var->mode) {
772 entry = new(ctx) temp_entry(ir->var, PROGRAM_UNIFORM,
774 this->variable_storage.push_tail(entry);
776 this->next_uniform += type_size(ir->var->type);
781 var_in = (ir->var->mode == ir_var_in ||
782 ir->var->mode == ir_var_inout);
784 for (i = 0; i < ARRAY_SIZE(builtin_var_to_mesa_reg); i++) {
785 bool in = builtin_var_to_mesa_reg[i].file == PROGRAM_INPUT;
787 if (strcmp(ir->var->name, builtin_var_to_mesa_reg[i].name) == 0 &&
791 if (i == ARRAY_SIZE(builtin_var_to_mesa_reg)) {
792 printf("Failed to find builtin for %s variable %s\n",
793 var_in ? "in" : "out",
797 entry = new(ctx) temp_entry(ir->var,
798 builtin_var_to_mesa_reg[i].file,
799 builtin_var_to_mesa_reg[i].index);
802 entry = new(ctx) temp_entry(ir->var, PROGRAM_TEMPORARY,
804 this->variable_storage.push_tail(entry);
806 next_temp += type_size(ir->var->type);
811 printf("Failed to make storage for %s\n", ir->var->name);
816 src_reg.file = entry->file;
817 src_reg.index = entry->index;
818 /* If the type is smaller than a vec4, replicate the last channel out. */
819 src_reg.swizzle = swizzle_for_size(ir->var->type->vector_elements);
820 src_reg.reladdr = false;
823 this->result = src_reg;
827 ir_to_mesa_visitor::visit(ir_dereference_array *ir)
830 ir_to_mesa_src_reg src_reg;
832 index = ir->array_index->constant_expression_value();
834 /* By the time we make it to this stage, matrices should be broken down
837 assert(!ir->type->is_matrix());
839 ir->array->accept(this);
840 src_reg = this->result;
842 if (src_reg.file == PROGRAM_INPUT ||
843 src_reg.file == PROGRAM_OUTPUT) {
844 assert(index); /* FINISHME: Handle variable indexing of builtins. */
846 src_reg.index += index->value.i[0];
849 src_reg.index += index->value.i[0];
851 ir_to_mesa_src_reg array_base = this->result;
852 /* Variable index array dereference. It eats the "vec4" of the
853 * base of the array and an index that offsets the Mesa register
856 ir->array_index->accept(this);
858 /* FINISHME: This doesn't work when we're trying to do the LHS
861 src_reg.reladdr = true;
862 ir_to_mesa_emit_op1(ir, OPCODE_ARL, ir_to_mesa_address_reg,
865 this->result = get_temp(ir->type);
866 ir_to_mesa_emit_op1(ir, OPCODE_MOV,
867 ir_to_mesa_dst_reg_from_src(this->result),
872 /* If the type is smaller than a vec4, replicate the last channel out. */
873 src_reg.swizzle = swizzle_for_size(ir->type->vector_elements);
875 this->result = src_reg;
879 ir_to_mesa_visitor::visit(ir_dereference_record *ir)
882 const glsl_type *struct_type = ir->record->type;
885 ir->record->accept(this);
887 for (i = 0; i < struct_type->length; i++) {
888 if (strcmp(struct_type->fields.structure[i].name, ir->field) == 0)
890 offset += type_size(struct_type->fields.structure[i].type);
892 this->result.index += offset;
896 * We want to be careful in assignment setup to hit the actual storage
897 * instead of potentially using a temporary like we might with the
898 * ir_dereference handler.
900 * Thanks to ir_swizzle_swizzle, and ir_vec_index_to_swizzle, we
901 * should only see potentially one variable array index of a vector,
902 * and one swizzle, before getting to actual vec4 storage. So handle
903 * those, then go use ir_dereference to handle the rest.
905 static struct ir_to_mesa_dst_reg
906 get_assignment_lhs(ir_instruction *ir, ir_to_mesa_visitor *v)
908 struct ir_to_mesa_dst_reg dst_reg;
909 ir_dereference *deref;
912 /* Use the rvalue deref handler for the most part. We'll ignore
913 * swizzles in it and write swizzles using writemask, though.
916 dst_reg = ir_to_mesa_dst_reg_from_src(v->result);
918 if ((deref = ir->as_dereference())) {
919 ir_dereference_array *deref_array = ir->as_dereference_array();
920 assert(!deref_array || deref_array->array->type->is_array());
923 } else if ((swiz = ir->as_swizzle())) {
924 dst_reg.writemask = 0;
925 if (swiz->mask.num_components >= 1)
926 dst_reg.writemask |= (1 << swiz->mask.x);
927 if (swiz->mask.num_components >= 2)
928 dst_reg.writemask |= (1 << swiz->mask.y);
929 if (swiz->mask.num_components >= 3)
930 dst_reg.writemask |= (1 << swiz->mask.z);
931 if (swiz->mask.num_components >= 4)
932 dst_reg.writemask |= (1 << swiz->mask.w);
939 ir_to_mesa_visitor::visit(ir_assignment *ir)
941 struct ir_to_mesa_dst_reg l;
942 struct ir_to_mesa_src_reg r;
944 assert(!ir->lhs->type->is_matrix());
945 assert(!ir->lhs->type->is_array());
946 assert(ir->lhs->type->base_type != GLSL_TYPE_STRUCT);
948 l = get_assignment_lhs(ir->lhs, this);
950 ir->rhs->accept(this);
952 assert(l.file != PROGRAM_UNDEFINED);
953 assert(r.file != PROGRAM_UNDEFINED);
956 ir_constant *condition_constant;
958 condition_constant = ir->condition->constant_expression_value();
960 assert(condition_constant && condition_constant->value.b[0]);
963 ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
968 ir_to_mesa_visitor::visit(ir_constant *ir)
970 ir_to_mesa_src_reg src_reg;
972 assert(ir->type->base_type == GLSL_TYPE_FLOAT ||
973 ir->type->base_type == GLSL_TYPE_UINT ||
974 ir->type->base_type == GLSL_TYPE_INT ||
975 ir->type->base_type == GLSL_TYPE_BOOL);
977 /* FINISHME: This will end up being _mesa_add_unnamed_constant,
978 * which handles sharing values and sharing channels of vec4
979 * constants for small values.
981 /* FINISHME: Do something with the constant values for now.
983 src_reg.file = PROGRAM_CONSTANT;
984 src_reg.index = this->next_constant;
985 src_reg.swizzle = SWIZZLE_NOOP;
986 src_reg.reladdr = false;
989 this->next_constant += type_size(ir->type);
991 this->result = src_reg;
996 ir_to_mesa_visitor::visit(ir_call *ir)
998 printf("Can't support call to %s\n", ir->callee_name());
1004 ir_to_mesa_visitor::visit(ir_texture *ir)
1008 ir->coordinate->accept(this);
1012 ir_to_mesa_visitor::visit(ir_return *ir)
1016 ir->get_value()->accept(this);
1021 ir_to_mesa_visitor::visit(ir_if *ir)
1023 ir_to_mesa_instruction *if_inst, *else_inst = NULL;
1025 ir->condition->accept(this);
1026 assert(this->result.file != PROGRAM_UNDEFINED);
1028 if_inst = ir_to_mesa_emit_op1(ir->condition,
1029 OPCODE_IF, ir_to_mesa_undef_dst,
1032 this->instructions.push_tail(if_inst);
1034 visit_exec_list(&ir->then_instructions, this);
1036 if (!ir->else_instructions.is_empty()) {
1037 else_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_ELSE,
1038 ir_to_mesa_undef_dst,
1040 visit_exec_list(&ir->then_instructions, this);
1043 if_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_ENDIF,
1044 ir_to_mesa_undef_dst, ir_to_mesa_undef);
1047 ir_to_mesa_visitor::ir_to_mesa_visitor()
1049 result.file = PROGRAM_UNDEFINED;
1055 static struct prog_src_register
1056 mesa_src_reg_from_ir_src_reg(ir_to_mesa_src_reg reg)
1058 struct prog_src_register mesa_reg;
1060 mesa_reg.File = reg.file;
1061 assert(reg.index < (1 << INST_INDEX_BITS) - 1);
1062 mesa_reg.Index = reg.index;
1063 mesa_reg.Swizzle = reg.swizzle;
1064 mesa_reg.RelAddr = reg.reladdr;
1070 set_branchtargets(struct prog_instruction *mesa_instructions,
1071 int num_instructions)
1073 int if_count = 0, loop_count;
1074 int *if_stack, *loop_stack;
1075 int if_stack_pos = 0, loop_stack_pos = 0;
1078 for (i = 0; i < num_instructions; i++) {
1079 switch (mesa_instructions[i].Opcode) {
1083 case OPCODE_BGNLOOP:
1088 mesa_instructions[i].BranchTarget = -1;
1095 if_stack = (int *)calloc(if_count, sizeof(*if_stack));
1096 loop_stack = (int *)calloc(loop_count, sizeof(*loop_stack));
1098 for (i = 0; i < num_instructions; i++) {
1099 switch (mesa_instructions[i].Opcode) {
1101 if_stack[if_stack_pos] = i;
1105 mesa_instructions[if_stack[if_stack_pos - 1]].BranchTarget = i;
1106 if_stack[if_stack_pos - 1] = i;
1109 mesa_instructions[if_stack[if_stack_pos - 1]].BranchTarget = i;
1112 case OPCODE_BGNLOOP:
1113 loop_stack[loop_stack_pos] = i;
1116 case OPCODE_ENDLOOP:
1118 /* Rewrite any breaks/conts at this nesting level (haven't
1119 * already had a BranchTarget assigned) to point to the end
1122 for (j = loop_stack[loop_stack_pos]; j < i; j++) {
1123 if (mesa_instructions[j].Opcode == OPCODE_BRK ||
1124 mesa_instructions[j].Opcode == OPCODE_CONT) {
1125 if (mesa_instructions[j].BranchTarget == -1) {
1126 mesa_instructions[j].BranchTarget = i;
1130 /* The loop ends point at each other. */
1131 mesa_instructions[i].BranchTarget = loop_stack[loop_stack_pos];
1132 mesa_instructions[loop_stack[loop_stack_pos]].BranchTarget = i;
1142 print_program(struct prog_instruction *mesa_instructions,
1143 ir_instruction **mesa_instruction_annotation,
1144 int num_instructions)
1146 ir_instruction *last_ir = NULL;
1149 for (i = 0; i < num_instructions; i++) {
1150 struct prog_instruction *mesa_inst = mesa_instructions + i;
1151 ir_instruction *ir = mesa_instruction_annotation[i];
1153 if (last_ir != ir && ir) {
1154 ir_print_visitor print;
1160 _mesa_print_instruction(mesa_inst);
1165 do_ir_to_mesa(exec_list *instructions)
1167 ir_to_mesa_visitor v;
1168 struct prog_instruction *mesa_instructions, *mesa_inst;
1169 ir_instruction **mesa_instruction_annotation;
1172 v.ctx = talloc_new(NULL);
1173 visit_exec_list(instructions, &v);
1175 int num_instructions = 0;
1176 foreach_iter(exec_list_iterator, iter, v.instructions) {
1181 (struct prog_instruction *)calloc(num_instructions,
1182 sizeof(*mesa_instructions));
1183 mesa_instruction_annotation =
1184 (ir_instruction **)calloc(num_instructions,
1185 sizeof(*mesa_instruction_annotation));
1187 mesa_inst = mesa_instructions;
1189 foreach_iter(exec_list_iterator, iter, v.instructions) {
1190 ir_to_mesa_instruction *inst = (ir_to_mesa_instruction *)iter.get();
1192 mesa_inst->Opcode = inst->op;
1193 mesa_inst->DstReg.File = inst->dst_reg.file;
1194 mesa_inst->DstReg.Index = inst->dst_reg.index;
1195 mesa_inst->DstReg.CondMask = COND_TR;
1196 mesa_inst->DstReg.WriteMask = inst->dst_reg.writemask;
1197 mesa_inst->SrcReg[0] = mesa_src_reg_from_ir_src_reg(inst->src_reg[0]);
1198 mesa_inst->SrcReg[1] = mesa_src_reg_from_ir_src_reg(inst->src_reg[1]);
1199 mesa_inst->SrcReg[2] = mesa_src_reg_from_ir_src_reg(inst->src_reg[2]);
1200 mesa_instruction_annotation[i] = inst->ir;
1206 set_branchtargets(mesa_instructions, num_instructions);
1207 print_program(mesa_instructions, mesa_instruction_annotation, num_instructions);
1209 free(mesa_instruction_annotation);