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,
30 * The code generation is performed using monoburg. Because monoburg
31 * produces a single C file with the definitions of the node types in
32 * it, this file is included from the monoburg output.
35 /* Quiet compiler warnings due to monoburg not marking functions defined
36 * in the header as inline.
40 #include "mesa_codegen.h"
43 #include "ir_visitor.h"
44 #include "ir_print_visitor.h"
45 #include "ir_expression_flattening.h"
46 #include "glsl_types.h"
48 #include "shader/prog_instruction.h"
50 ir_to_mesa_src_reg ir_to_mesa_undef
= {
51 PROGRAM_UNDEFINED
, 0, SWIZZLE_NOOP
54 ir_to_mesa_instruction
*
55 ir_to_mesa_emit_op3(struct mbtree
*tree
, enum prog_opcode op
,
56 ir_to_mesa_dst_reg dst
,
57 ir_to_mesa_src_reg src0
,
58 ir_to_mesa_src_reg src1
,
59 ir_to_mesa_src_reg src2
)
61 ir_to_mesa_instruction
*inst
= new ir_to_mesa_instruction();
65 inst
->src_reg
[0] = src0
;
66 inst
->src_reg
[1] = src1
;
67 inst
->src_reg
[2] = src2
;
69 tree
->v
->instructions
.push_tail(inst
);
75 ir_to_mesa_instruction
*
76 ir_to_mesa_emit_op2(struct mbtree
*tree
, enum prog_opcode op
,
77 ir_to_mesa_dst_reg dst
,
78 ir_to_mesa_src_reg src0
,
79 ir_to_mesa_src_reg src1
)
81 return ir_to_mesa_emit_op3(tree
, op
, dst
, src0
, src1
, ir_to_mesa_undef
);
84 ir_to_mesa_instruction
*
85 ir_to_mesa_emit_op1(struct mbtree
*tree
, enum prog_opcode op
,
86 ir_to_mesa_dst_reg dst
,
87 ir_to_mesa_src_reg src0
)
89 return ir_to_mesa_emit_op3(tree
, op
,
90 dst
, src0
, ir_to_mesa_undef
, ir_to_mesa_undef
);
94 ir_to_mesa_visitor::create_tree(int op
, struct mbtree
*left
, struct mbtree
*right
)
96 struct mbtree
*tree
= (struct mbtree
*)calloc(sizeof(struct mbtree
), 1);
102 tree
->src_reg
.swizzle
= SWIZZLE_XYZW
;
108 produce_swizzle(int8_t *swizzle
, const char *reg_name
,
109 const char **swizzle_reg_name
)
111 if (swizzle
[0] == 0 &&
116 *swizzle_reg_name
= reg_name
;
118 char swizzle_letters
[4] = { 'x', 'y', 'z', 'w' };
120 asprintf(&temp
, "%s.%c%c%c%c",
122 swizzle_letters
[swizzle
[0]],
123 swizzle_letters
[swizzle
[1]],
124 swizzle_letters
[swizzle
[2]],
125 swizzle_letters
[swizzle
[3]]);
126 *swizzle_reg_name
= temp
;
128 return *swizzle_reg_name
;
132 * In the initial pass of codegen, we assign temporary numbers to
133 * intermediate results. (not SSA -- variable assignments will reuse
134 * storage). Actual register allocation for the Mesa VM occurs in a
135 * pass over the Mesa IR later.
138 ir_to_mesa_visitor::get_temp(struct mbtree
*tree
)
140 tree
->src_reg
.file
= PROGRAM_TEMPORARY
;
141 tree
->src_reg
.index
= this->next_temp
++;
145 ir_to_mesa_visitor::get_temp_for_var(ir_variable
*var
, struct mbtree
*tree
)
149 foreach_iter(exec_list_iterator
, iter
, this->variable_storage
) {
150 entry
= (temp_entry
*)iter
.get();
152 if (entry
->var
== var
) {
153 tree
->src_reg
.file
= entry
->file
;
154 tree
->src_reg
.index
= entry
->index
;
159 entry
= new temp_entry(var
, PROGRAM_TEMPORARY
, this->next_temp
++);
160 this->variable_storage
.push_tail(entry
);
162 tree
->src_reg
.file
= entry
->file
;
163 tree
->src_reg
.index
= entry
->index
;
167 reduce(struct mbtree
*t
, int goal
)
169 struct mbtree
*kids
[10];
170 int rule
= mono_burg_rule((MBState
*)t
->state
, goal
);
171 const uint16_t *nts
= mono_burg_nts
[rule
];
174 mono_burg_kids (t
, rule
, kids
);
176 for (i
= 0; nts
[i
]; i
++) {
177 reduce(kids
[i
], nts
[i
]);
181 if (mono_burg_func
[rule
]) {
182 mono_burg_func
[rule
](t
, NULL
);
184 printf("no code for rules %s\n", mono_burg_rule_string
[rule
]);
188 if (mono_burg_func
[rule
]) {
189 printf("unused code for rule %s\n", mono_burg_rule_string
[rule
]);
196 ir_to_mesa_visitor::visit(ir_variable
*ir
)
202 ir_to_mesa_visitor::visit(ir_loop
*ir
)
206 printf("Can't support loops, should be flattened before here\n");
211 ir_to_mesa_visitor::visit(ir_loop_jump
*ir
)
214 printf("Can't support loops, should be flattened before here\n");
220 ir_to_mesa_visitor::visit(ir_function_signature
*ir
)
227 ir_to_mesa_visitor::visit(ir_function
*ir
)
229 /* Ignore function bodies other than main() -- we shouldn't see calls to
230 * them since they should all be inlined before we get to ir_to_mesa.
232 if (strcmp(ir
->name
, "main") == 0) {
233 const ir_function_signature
*sig
;
236 sig
= ir
->matching_signature(&empty
);
240 foreach_iter(exec_list_iterator
, iter
, sig
->body
) {
241 ir_instruction
*ir
= (ir_instruction
*)iter
.get();
249 ir_to_mesa_visitor::visit(ir_expression
*ir
)
251 unsigned int operand
;
252 struct mbtree
*op
[2];
253 const glsl_type
*vec4_type
= glsl_type::get_instance(GLSL_TYPE_FLOAT
, 4, 1);
254 const glsl_type
*vec3_type
= glsl_type::get_instance(GLSL_TYPE_FLOAT
, 3, 1);
255 const glsl_type
*vec2_type
= glsl_type::get_instance(GLSL_TYPE_FLOAT
, 2, 1);
257 for (operand
= 0; operand
< ir
->get_num_operands(); operand
++) {
259 ir
->operands
[operand
]->accept(this);
262 printf("Failed to get tree for expression operand:\n");
263 ir
->operands
[operand
]->accept(&v
);
266 op
[operand
] = this->result
;
271 switch (ir
->operation
) {
273 this->result
= this->create_tree(MB_TERM_add_vec4_vec4
, op
[0], op
[1]);
276 this->result
= this->create_tree(MB_TERM_sub_vec4_vec4
, op
[0], op
[1]);
279 this->result
= this->create_tree(MB_TERM_mul_vec4_vec4
, op
[0], op
[1]);
282 this->result
= this->create_tree(MB_TERM_div_vec4_vec4
, op
[0], op
[1]);
285 if (ir
->operands
[0]->type
== vec4_type
) {
286 assert(ir
->operands
[1]->type
== vec4_type
);
287 this->result
= this->create_tree(MB_TERM_dp4_vec4_vec4
, op
[0], op
[1]);
288 } else if (ir
->operands
[0]->type
== vec3_type
) {
289 assert(ir
->operands
[1]->type
== vec3_type
);
290 this->result
= this->create_tree(MB_TERM_dp3_vec4_vec4
, op
[0], op
[1]);
291 } else if (ir
->operands
[0]->type
== vec2_type
) {
292 assert(ir
->operands
[1]->type
== vec2_type
);
293 this->result
= this->create_tree(MB_TERM_dp2_vec4_vec4
, op
[0], op
[1]);
297 this->result
= this->create_tree(MB_TERM_sqrt_vec4
, op
[0], op
[1]);
304 printf("Failed to get tree for expression:\n");
312 ir_to_mesa_visitor::visit(ir_swizzle
*ir
)
318 /* FINISHME: Handle swizzles on the left side of an assignment. */
320 ir
->val
->accept(this);
321 assert(this->result
);
323 tree
= this->create_tree(MB_TERM_swizzle_vec4
, this->result
, NULL
);
325 for (i
= 0; i
< 4; i
++) {
326 if (i
< ir
->type
->vector_elements
) {
329 swizzle
[i
] = ir
->mask
.x
;
332 swizzle
[i
] = ir
->mask
.y
;
335 swizzle
[i
] = ir
->mask
.z
;
338 swizzle
[i
] = ir
->mask
.w
;
342 /* If the type is smaller than a vec4, replicate the last
345 swizzle
[i
] = ir
->type
->vector_elements
- 1;
349 tree
->src_reg
.swizzle
= MAKE_SWIZZLE4(swizzle
[0],
359 ir_to_mesa_visitor::visit(ir_dereference_variable
*ir
)
362 int size_swizzles
[4] = {
363 MAKE_SWIZZLE4(SWIZZLE_X
, SWIZZLE_Y
, SWIZZLE_Z
, SWIZZLE_W
),
364 MAKE_SWIZZLE4(SWIZZLE_X
, SWIZZLE_Y
, SWIZZLE_Z
, SWIZZLE_Z
),
365 MAKE_SWIZZLE4(SWIZZLE_X
, SWIZZLE_Y
, SWIZZLE_Y
, SWIZZLE_Y
),
366 MAKE_SWIZZLE4(SWIZZLE_X
, SWIZZLE_X
, SWIZZLE_X
, SWIZZLE_X
),
369 ir_variable
*var
= ir
->var
->as_variable();
371 /* By the time we make it to this stage, matric`es should be broken down
374 assert(!var
->type
->is_matrix());
376 tree
= this->create_tree(MB_TERM_reference_vec4
, NULL
, NULL
);
378 if (strncmp(var
->name
, "gl_", 3) == 0) {
379 if (strcmp(var
->name
, "gl_FragColor") == 0) {
380 tree
->src_reg
.file
= PROGRAM_INPUT
;
381 tree
->src_reg
.index
= FRAG_ATTRIB_COL0
;
386 this->get_temp_for_var(var
, tree
);
389 /* If the type is smaller than a vec4, replicate the last channel out. */
390 tree
->src_reg
.swizzle
= size_swizzles
[ir
->type
->vector_elements
- 1];
396 ir_to_mesa_visitor::visit(ir_dereference_array
*ir
)
399 int size_swizzles
[4] = {
400 MAKE_SWIZZLE4(SWIZZLE_X
, SWIZZLE_Y
, SWIZZLE_Z
, SWIZZLE_W
),
401 MAKE_SWIZZLE4(SWIZZLE_X
, SWIZZLE_Y
, SWIZZLE_Z
, SWIZZLE_Z
),
402 MAKE_SWIZZLE4(SWIZZLE_X
, SWIZZLE_Y
, SWIZZLE_Y
, SWIZZLE_Y
),
403 MAKE_SWIZZLE4(SWIZZLE_X
, SWIZZLE_X
, SWIZZLE_X
, SWIZZLE_X
),
406 ir_variable
*var
= ir
->array
->as_variable();
407 ir_constant
*index
= ir
->array_index
->constant_expression_value();
412 assert(strcmp(var
->name
, "gl_TexCoord") == 0);
414 asprintf(&name
, "fragment.texcoord[%d]", index
->value
.i
[0]);
415 tree
= this->create_tree(MB_TERM_reference_vec4
, NULL
, NULL
);
416 tree
->reg_name
= name
;
418 /* If the type is smaller than a vec4, replicate the last channel out. */
419 tree
->src_reg
.swizzle
= size_swizzles
[ir
->type
->vector_elements
- 1];
425 ir_to_mesa_visitor::visit(ir_dereference_record
*ir
)
432 ir_to_mesa_visitor::visit(ir_assignment
*ir
)
434 struct mbtree
*l
, *r
, *t
;
436 ir
->lhs
->accept(this);
438 ir
->rhs
->accept(this);
443 assert(!ir
->condition
);
445 t
= this->create_tree(MB_TERM_assign
, l
, r
);
446 mono_burg_label(t
, NULL
);
447 reduce(t
, MB_NTERM_stmt
);
452 ir_to_mesa_visitor::visit(ir_constant
*ir
)
456 assert(!ir
->type
->is_matrix());
458 tree
= this->create_tree(MB_TERM_reference_vec4
, NULL
, NULL
);
460 assert(ir
->type
->base_type
== GLSL_TYPE_FLOAT
);
462 /* FINISHME: This will end up being _mesa_add_unnamed_constant,
463 * which handles sharing values and sharing channels of vec4
464 * constants for small values.
466 /* FINISHME: Do something with the constant values for now.
468 tree
->src_reg
.file
= PROGRAM_CONSTANT
;
469 tree
->src_reg
.index
= this->next_constant
++;
470 tree
->src_reg
.swizzle
= SWIZZLE_NOOP
;
477 ir_to_mesa_visitor::visit(ir_call
*ir
)
479 printf("Can't support call to %s\n", ir
->callee_name());
485 ir_to_mesa_visitor::visit(ir_texture
*ir
)
489 ir
->coordinate
->accept(this);
493 ir_to_mesa_visitor::visit(ir_return
*ir
)
497 ir
->get_value()->accept(this);
502 ir_to_mesa_visitor::visit(ir_if
*ir
)
505 printf("Can't support conditionals, should be flattened before here.\n");
509 static struct prog_src_register
510 mesa_src_reg_from_ir_src_reg(ir_to_mesa_src_reg reg
)
512 struct prog_src_register mesa_reg
;
514 mesa_reg
.File
= reg
.file
;
515 mesa_reg
.Index
= reg
.index
;
521 do_ir_to_mesa(exec_list
*instructions
)
523 ir_to_mesa_visitor v
;
524 struct prog_instruction
*mesa_instructions
, *mesa_inst
;
526 visit_exec_list(instructions
, &v
);
528 int num_instructions
= 0;
529 foreach_iter(exec_list_iterator
, iter
, v
.instructions
) {
534 (struct prog_instruction
*)calloc(num_instructions
,
535 sizeof(*mesa_instructions
));
537 mesa_inst
= mesa_instructions
;
538 foreach_iter(exec_list_iterator
, iter
, v
.instructions
) {
539 ir_to_mesa_instruction
*inst
= (ir_to_mesa_instruction
*)iter
.get();
540 mesa_inst
->Opcode
= inst
->op
;
541 mesa_inst
->DstReg
.File
= inst
->dst_reg
.file
;
542 mesa_inst
->DstReg
.Index
= inst
->dst_reg
.index
;
543 mesa_inst
->SrcReg
[0] = mesa_src_reg_from_ir_src_reg(inst
->src_reg
[0]);
544 mesa_inst
->SrcReg
[1] = mesa_src_reg_from_ir_src_reg(inst
->src_reg
[1]);
545 mesa_inst
->SrcReg
[2] = mesa_src_reg_from_ir_src_reg(inst
->src_reg
[2]);