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]);