ir_to_mesa: Start building GLSL IR to Mesa IR conversion.
[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 * 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.
33 */
34
35 /* Quiet compiler warnings due to monoburg not marking functions defined
36 * in the header as inline.
37 */
38 #define g_new
39 #define g_error
40 #include "mesa_codegen.h"
41
42 #include "ir.h"
43 #include "ir_visitor.h"
44 #include "ir_print_visitor.h"
45 #include "ir_expression_flattening.h"
46 #include "glsl_types.h"
47
48 #include "shader/prog_instruction.h"
49
50 ir_to_mesa_src_reg ir_to_mesa_undef = {
51 PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP
52 };
53
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)
60 {
61 ir_to_mesa_instruction *inst = new ir_to_mesa_instruction();
62
63 inst->op = op;
64 inst->dst_reg = dst;
65 inst->src_reg[0] = src0;
66 inst->src_reg[1] = src1;
67 inst->src_reg[2] = src2;
68
69 tree->v->instructions.push_tail(inst);
70
71 return inst;
72 }
73
74
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)
80 {
81 return ir_to_mesa_emit_op3(tree, op, dst, src0, src1, ir_to_mesa_undef);
82 }
83
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)
88 {
89 return ir_to_mesa_emit_op3(tree, op,
90 dst, src0, ir_to_mesa_undef, ir_to_mesa_undef);
91 }
92
93 struct mbtree *
94 ir_to_mesa_visitor::create_tree(int op, struct mbtree *left, struct mbtree *right)
95 {
96 struct mbtree *tree = (struct mbtree *)calloc(sizeof(struct mbtree), 1);
97
98 tree->op = op;
99 tree->left = left;
100 tree->right = right;
101 tree->v = this;
102 tree->src_reg.swizzle = SWIZZLE_XYZW;
103
104 return tree;
105 }
106
107 const char *
108 produce_swizzle(int8_t *swizzle, const char *reg_name,
109 const char **swizzle_reg_name)
110 {
111 if (swizzle[0] == 0 &&
112 swizzle[1] == 1 &&
113 swizzle[2] == 2 &&
114 swizzle[3] == 3)
115 {
116 *swizzle_reg_name = reg_name;
117 } else {
118 char swizzle_letters[4] = { 'x', 'y', 'z', 'w' };
119 char *temp;
120 asprintf(&temp, "%s.%c%c%c%c",
121 reg_name,
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;
127 }
128 return *swizzle_reg_name;
129 }
130
131 /**
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.
136 */
137 void
138 ir_to_mesa_visitor::get_temp(struct mbtree *tree)
139 {
140 tree->src_reg.file = PROGRAM_TEMPORARY;
141 tree->src_reg.index = this->next_temp++;
142 }
143
144 void
145 ir_to_mesa_visitor::get_temp_for_var(ir_variable *var, struct mbtree *tree)
146 {
147 temp_entry *entry;
148
149 foreach_iter(exec_list_iterator, iter, this->variable_storage) {
150 entry = (temp_entry *)iter.get();
151
152 if (entry->var == var) {
153 tree->src_reg.file = entry->file;
154 tree->src_reg.index = entry->index;
155 return;
156 }
157 }
158
159 entry = new temp_entry(var, PROGRAM_TEMPORARY, this->next_temp++);
160 this->variable_storage.push_tail(entry);
161
162 tree->src_reg.file = entry->file;
163 tree->src_reg.index = entry->index;
164 }
165
166 static void
167 reduce(struct mbtree *t, int goal)
168 {
169 struct mbtree *kids[10];
170 int rule = mono_burg_rule((MBState *)t->state, goal);
171 const uint16_t *nts = mono_burg_nts[rule];
172 int i;
173
174 mono_burg_kids (t, rule, kids);
175
176 for (i = 0; nts[i]; i++) {
177 reduce(kids[i], nts[i]);
178 }
179
180 if (t->left) {
181 if (mono_burg_func[rule]) {
182 mono_burg_func[rule](t, NULL);
183 } else {
184 printf("no code for rules %s\n", mono_burg_rule_string[rule]);
185 exit(1);
186 }
187 } else {
188 if (mono_burg_func[rule]) {
189 printf("unused code for rule %s\n", mono_burg_rule_string[rule]);
190 exit(1);
191 }
192 }
193 }
194
195 void
196 ir_to_mesa_visitor::visit(ir_variable *ir)
197 {
198 (void)ir;
199 }
200
201 void
202 ir_to_mesa_visitor::visit(ir_loop *ir)
203 {
204 (void)ir;
205
206 printf("Can't support loops, should be flattened before here\n");
207 exit(1);
208 }
209
210 void
211 ir_to_mesa_visitor::visit(ir_loop_jump *ir)
212 {
213 (void) ir;
214 printf("Can't support loops, should be flattened before here\n");
215 exit(1);
216 }
217
218
219 void
220 ir_to_mesa_visitor::visit(ir_function_signature *ir)
221 {
222 assert(0);
223 (void)ir;
224 }
225
226 void
227 ir_to_mesa_visitor::visit(ir_function *ir)
228 {
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.
231 */
232 if (strcmp(ir->name, "main") == 0) {
233 const ir_function_signature *sig;
234 exec_list empty;
235
236 sig = ir->matching_signature(&empty);
237
238 assert(sig);
239
240 foreach_iter(exec_list_iterator, iter, sig->body) {
241 ir_instruction *ir = (ir_instruction *)iter.get();
242
243 ir->accept(this);
244 }
245 }
246 }
247
248 void
249 ir_to_mesa_visitor::visit(ir_expression *ir)
250 {
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);
256
257 for (operand = 0; operand < ir->get_num_operands(); operand++) {
258 this->result = NULL;
259 ir->operands[operand]->accept(this);
260 if (!this->result) {
261 ir_print_visitor v;
262 printf("Failed to get tree for expression operand:\n");
263 ir->operands[operand]->accept(&v);
264 exit(1);
265 }
266 op[operand] = this->result;
267 }
268
269 this->result = NULL;
270
271 switch (ir->operation) {
272 case ir_binop_add:
273 this->result = this->create_tree(MB_TERM_add_vec4_vec4, op[0], op[1]);
274 break;
275 case ir_binop_sub:
276 this->result = this->create_tree(MB_TERM_sub_vec4_vec4, op[0], op[1]);
277 break;
278 case ir_binop_mul:
279 this->result = this->create_tree(MB_TERM_mul_vec4_vec4, op[0], op[1]);
280 break;
281 case ir_binop_div:
282 this->result = this->create_tree(MB_TERM_div_vec4_vec4, op[0], op[1]);
283 break;
284 case ir_binop_dot:
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]);
294 }
295 break;
296 case ir_unop_sqrt:
297 this->result = this->create_tree(MB_TERM_sqrt_vec4, op[0], op[1]);
298 break;
299 default:
300 break;
301 }
302 if (!this->result) {
303 ir_print_visitor v;
304 printf("Failed to get tree for expression:\n");
305 ir->accept(&v);
306 exit(1);
307 }
308 }
309
310
311 void
312 ir_to_mesa_visitor::visit(ir_swizzle *ir)
313 {
314 struct mbtree *tree;
315 int i;
316 int swizzle[4];
317
318 /* FINISHME: Handle swizzles on the left side of an assignment. */
319
320 ir->val->accept(this);
321 assert(this->result);
322
323 tree = this->create_tree(MB_TERM_swizzle_vec4, this->result, NULL);
324
325 for (i = 0; i < 4; i++) {
326 if (i < ir->type->vector_elements) {
327 switch (i) {
328 case 0:
329 swizzle[i] = ir->mask.x;
330 break;
331 case 1:
332 swizzle[i] = ir->mask.y;
333 break;
334 case 2:
335 swizzle[i] = ir->mask.z;
336 break;
337 case 3:
338 swizzle[i] = ir->mask.w;
339 break;
340 }
341 } else {
342 /* If the type is smaller than a vec4, replicate the last
343 * channel out.
344 */
345 swizzle[i] = ir->type->vector_elements - 1;
346 }
347 }
348
349 tree->src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0],
350 swizzle[1],
351 swizzle[2],
352 swizzle[3]);
353
354 this->result = tree;
355 }
356
357
358 void
359 ir_to_mesa_visitor::visit(ir_dereference_variable *ir)
360 {
361 struct mbtree *tree;
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),
367 };
368
369 ir_variable *var = ir->var->as_variable();
370
371 /* By the time we make it to this stage, matric`es should be broken down
372 * to vectors.
373 */
374 assert(!var->type->is_matrix());
375
376 tree = this->create_tree(MB_TERM_reference_vec4, NULL, NULL);
377
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;
382 } else {
383 assert(0);
384 }
385 } else {
386 this->get_temp_for_var(var, tree);
387 }
388
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];
391
392 this->result = tree;
393 }
394
395 void
396 ir_to_mesa_visitor::visit(ir_dereference_array *ir)
397 {
398 struct mbtree *tree;
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),
404 };
405
406 ir_variable *var = ir->array->as_variable();
407 ir_constant *index = ir->array_index->constant_expression_value();
408 char *name;
409
410 assert(var);
411 assert(index);
412 assert(strcmp(var->name, "gl_TexCoord") == 0);
413
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;
417
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];
420
421 this->result = tree;
422 }
423
424 void
425 ir_to_mesa_visitor::visit(ir_dereference_record *ir)
426 {
427 (void)ir;
428 assert(0);
429 }
430
431 void
432 ir_to_mesa_visitor::visit(ir_assignment *ir)
433 {
434 struct mbtree *l, *r, *t;
435
436 ir->lhs->accept(this);
437 l = this->result;
438 ir->rhs->accept(this);
439 r = this->result;
440 assert(l);
441 assert(r);
442
443 assert(!ir->condition);
444
445 t = this->create_tree(MB_TERM_assign, l, r);
446 mono_burg_label(t, NULL);
447 reduce(t, MB_NTERM_stmt);
448 }
449
450
451 void
452 ir_to_mesa_visitor::visit(ir_constant *ir)
453 {
454 struct mbtree *tree;
455
456 assert(!ir->type->is_matrix());
457
458 tree = this->create_tree(MB_TERM_reference_vec4, NULL, NULL);
459
460 assert(ir->type->base_type == GLSL_TYPE_FLOAT);
461
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.
465 */
466 /* FINISHME: Do something with the constant values for now.
467 */
468 tree->src_reg.file = PROGRAM_CONSTANT;
469 tree->src_reg.index = this->next_constant++;
470 tree->src_reg.swizzle = SWIZZLE_NOOP;
471
472 this->result = tree;
473 }
474
475
476 void
477 ir_to_mesa_visitor::visit(ir_call *ir)
478 {
479 printf("Can't support call to %s\n", ir->callee_name());
480 exit(1);
481 }
482
483
484 void
485 ir_to_mesa_visitor::visit(ir_texture *ir)
486 {
487 assert(0);
488
489 ir->coordinate->accept(this);
490 }
491
492 void
493 ir_to_mesa_visitor::visit(ir_return *ir)
494 {
495 assert(0);
496
497 ir->get_value()->accept(this);
498 }
499
500
501 void
502 ir_to_mesa_visitor::visit(ir_if *ir)
503 {
504 (void)ir;
505 printf("Can't support conditionals, should be flattened before here.\n");
506 exit(1);
507 }
508
509 static struct prog_src_register
510 mesa_src_reg_from_ir_src_reg(ir_to_mesa_src_reg reg)
511 {
512 struct prog_src_register mesa_reg;
513
514 mesa_reg.File = reg.file;
515 mesa_reg.Index = reg.index;
516
517 return mesa_reg;
518 }
519
520 void
521 do_ir_to_mesa(exec_list *instructions)
522 {
523 ir_to_mesa_visitor v;
524 struct prog_instruction *mesa_instructions, *mesa_inst;
525
526 visit_exec_list(instructions, &v);
527
528 int num_instructions = 0;
529 foreach_iter(exec_list_iterator, iter, v.instructions) {
530 num_instructions++;
531 }
532
533 mesa_instructions =
534 (struct prog_instruction *)calloc(num_instructions,
535 sizeof(*mesa_instructions));
536
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]);
546 mesa_inst++;
547 }
548 }