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#include "ir_print_visitor.h"
25#include "glsl_types.h"
26#include "glsl_parser_extras.h"
27#include "program/hash_table.h"
28
29static void print_type(const glsl_type *t);
30
31void
32ir_instruction::print(void) const
33{
34   ir_instruction *deconsted = const_cast<ir_instruction *>(this);
35
36   ir_print_visitor v;
37   deconsted->accept(&v);
38}
39
40void
41_mesa_print_ir(exec_list *instructions,
42	       struct _mesa_glsl_parse_state *state)
43{
44   if (state) {
45      for (unsigned i = 0; i < state->num_user_structures; i++) {
46	 const glsl_type *const s = state->user_structures[i];
47
48	 printf("(structure (%s) (%s@%p) (%u) (\n",
49		s->name, s->name, (void *) s, s->length);
50
51	 for (unsigned j = 0; j < s->length; j++) {
52	    printf("\t((");
53	    print_type(s->fields.structure[j].type);
54	    printf(")(%s))\n", s->fields.structure[j].name);
55	 }
56
57	 printf(")\n");
58      }
59   }
60
61   printf("(\n");
62   foreach_iter(exec_list_iterator, iter, *instructions) {
63      ir_instruction *ir = (ir_instruction *)iter.get();
64      ir->print();
65      if (ir->ir_type != ir_type_function)
66	 printf("\n");
67   }
68   printf("\n)");
69}
70
71ir_print_visitor::ir_print_visitor()
72{
73   indentation = 0;
74   printable_names =
75      hash_table_ctor(32, hash_table_pointer_hash, hash_table_pointer_compare);
76   symbols = _mesa_symbol_table_ctor();
77   mem_ctx = ralloc_context(NULL);
78}
79
80ir_print_visitor::~ir_print_visitor()
81{
82   hash_table_dtor(printable_names);
83   _mesa_symbol_table_dtor(symbols);
84   ralloc_free(mem_ctx);
85}
86
87void ir_print_visitor::indent(void)
88{
89   for (int i = 0; i < indentation; i++)
90      printf("  ");
91}
92
93const char *
94ir_print_visitor::unique_name(ir_variable *var)
95{
96   /* var->name can be NULL in function prototypes when a type is given for a
97    * parameter but no name is given.  In that case, just return an empty
98    * string.  Don't worry about tracking the generated name in the printable
99    * names hash because this is the only scope where it can ever appear.
100    */
101   if (var->name == NULL) {
102      static unsigned arg = 1;
103      return ralloc_asprintf(this->mem_ctx, "parameter@%u", arg++);
104   }
105
106   /* Do we already have a name for this variable? */
107   const char *name = (const char *) hash_table_find(this->printable_names, var);
108   if (name != NULL)
109      return name;
110
111   /* If there's no conflict, just use the original name */
112   if (_mesa_symbol_table_find_symbol(this->symbols, -1, var->name) == NULL) {
113      name = var->name;
114   } else {
115      static unsigned i = 1;
116      name = ralloc_asprintf(this->mem_ctx, "%s@%u", var->name, ++i);
117   }
118   hash_table_insert(this->printable_names, (void *) name, var);
119   _mesa_symbol_table_add_symbol(this->symbols, -1, name, var);
120   return name;
121}
122
123static void
124print_type(const glsl_type *t)
125{
126   if (t->base_type == GLSL_TYPE_ARRAY) {
127      printf("(array ");
128      print_type(t->fields.array);
129      printf(" %u)", t->length);
130   } else if ((t->base_type == GLSL_TYPE_STRUCT)
131	      && (strncmp("gl_", t->name, 3) != 0)) {
132      printf("%s@%p", t->name, (void *) t);
133   } else {
134      printf("%s", t->name);
135   }
136}
137
138void ir_print_visitor::visit(ir_rvalue *ir)
139{
140   printf("error");
141}
142
143void ir_print_visitor::visit(ir_variable *ir)
144{
145   printf("(declare ");
146
147   const char *const cent = (ir->centroid) ? "centroid " : "";
148   const char *const inv = (ir->invariant) ? "invariant " : "";
149   const char *const mode[] = { "", "uniform ", "in ", "out ", "inout ",
150			        "const_in ", "sys ", "temporary " };
151   const char *const interp[] = { "", "flat", "noperspective" };
152
153   printf("(%s%s%s%s) ",
154	  cent, inv, mode[ir->mode], interp[ir->interpolation]);
155
156   print_type(ir->type);
157   printf(" %s)", unique_name(ir));
158}
159
160
161void ir_print_visitor::visit(ir_function_signature *ir)
162{
163   _mesa_symbol_table_push_scope(symbols);
164   printf("(signature ");
165   indentation++;
166
167   print_type(ir->return_type);
168   printf("\n");
169   indent();
170
171   printf("(parameters\n");
172   indentation++;
173
174   foreach_iter(exec_list_iterator, iter, ir->parameters) {
175      ir_variable *const inst = (ir_variable *) iter.get();
176
177      indent();
178      inst->accept(this);
179      printf("\n");
180   }
181   indentation--;
182
183   indent();
184   printf(")\n");
185
186   indent();
187
188   printf("(\n");
189   indentation++;
190
191   foreach_iter(exec_list_iterator, iter, ir->body) {
192      ir_instruction *const inst = (ir_instruction *) iter.get();
193
194      indent();
195      inst->accept(this);
196      printf("\n");
197   }
198   indentation--;
199   indent();
200   printf("))\n");
201   indentation--;
202   _mesa_symbol_table_pop_scope(symbols);
203}
204
205
206void ir_print_visitor::visit(ir_function *ir)
207{
208   printf("(function %s\n", ir->name);
209   indentation++;
210   foreach_iter(exec_list_iterator, iter, *ir) {
211      ir_function_signature *const sig = (ir_function_signature *) iter.get();
212      indent();
213      sig->accept(this);
214      printf("\n");
215   }
216   indentation--;
217   indent();
218   printf(")\n\n");
219}
220
221
222void ir_print_visitor::visit(ir_expression *ir)
223{
224   printf("(expression ");
225
226   print_type(ir->type);
227
228   printf(" %s ", ir->operator_string());
229
230   for (unsigned i = 0; i < ir->get_num_operands(); i++) {
231      ir->operands[i]->accept(this);
232   }
233
234   printf(") ");
235}
236
237
238void ir_print_visitor::visit(ir_texture *ir)
239{
240   printf("(%s ", ir->opcode_string());
241
242   print_type(ir->type);
243   printf(" ");
244
245   ir->sampler->accept(this);
246   printf(" ");
247
248   if (ir->op != ir_txs) {
249      ir->coordinate->accept(this);
250
251      printf(" ");
252
253      if (ir->offset != NULL) {
254	 ir->offset->accept(this);
255      } else {
256	 printf("0");
257      }
258
259      printf(" ");
260   }
261
262   if (ir->op != ir_txf && ir->op != ir_txs) {
263      if (ir->projector)
264	 ir->projector->accept(this);
265      else
266	 printf("1");
267
268      if (ir->shadow_comparitor) {
269	 printf(" ");
270	 ir->shadow_comparitor->accept(this);
271      } else {
272	 printf(" ()");
273      }
274   }
275
276   printf(" ");
277   switch (ir->op)
278   {
279   case ir_tex:
280      break;
281   case ir_txb:
282      ir->lod_info.bias->accept(this);
283      break;
284   case ir_txl:
285   case ir_txf:
286   case ir_txs:
287      ir->lod_info.lod->accept(this);
288      break;
289   case ir_txd:
290      printf("(");
291      ir->lod_info.grad.dPdx->accept(this);
292      printf(" ");
293      ir->lod_info.grad.dPdy->accept(this);
294      printf(")");
295      break;
296   };
297   printf(")");
298}
299
300
301void ir_print_visitor::visit(ir_swizzle *ir)
302{
303   const unsigned swiz[4] = {
304      ir->mask.x,
305      ir->mask.y,
306      ir->mask.z,
307      ir->mask.w,
308   };
309
310   printf("(swiz ");
311   for (unsigned i = 0; i < ir->mask.num_components; i++) {
312      printf("%c", "xyzw"[swiz[i]]);
313   }
314   printf(" ");
315   ir->val->accept(this);
316   printf(")");
317}
318
319
320void ir_print_visitor::visit(ir_dereference_variable *ir)
321{
322   ir_variable *var = ir->variable_referenced();
323   printf("(var_ref %s) ", unique_name(var));
324}
325
326
327void ir_print_visitor::visit(ir_dereference_array *ir)
328{
329   printf("(array_ref ");
330   ir->array->accept(this);
331   ir->array_index->accept(this);
332   printf(") ");
333}
334
335
336void ir_print_visitor::visit(ir_dereference_record *ir)
337{
338   printf("(record_ref ");
339   ir->record->accept(this);
340   printf(" %s) ", ir->field);
341}
342
343
344void ir_print_visitor::visit(ir_assignment *ir)
345{
346   printf("(assign ");
347
348   if (ir->condition)
349      ir->condition->accept(this);
350
351   char mask[5];
352   unsigned j = 0;
353
354   for (unsigned i = 0; i < 4; i++) {
355      if ((ir->write_mask & (1 << i)) != 0) {
356	 mask[j] = "xyzw"[i];
357	 j++;
358      }
359   }
360   mask[j] = '\0';
361
362   printf(" (%s) ", mask);
363
364   ir->lhs->accept(this);
365
366   printf(" ");
367
368   ir->rhs->accept(this);
369   printf(") ");
370}
371
372
373void ir_print_visitor::visit(ir_constant *ir)
374{
375   printf("(constant ");
376   print_type(ir->type);
377   printf(" (");
378
379   if (ir->type->is_array()) {
380      for (unsigned i = 0; i < ir->type->length; i++)
381	 ir->get_array_element(i)->accept(this);
382   } else if (ir->type->is_record()) {
383      ir_constant *value = (ir_constant *) ir->components.get_head();
384      for (unsigned i = 0; i < ir->type->length; i++) {
385	 printf("(%s ", ir->type->fields.structure[i].name);
386	 value->accept(this);
387	 printf(")");
388
389	 value = (ir_constant *) value->next;
390      }
391   } else {
392      for (unsigned i = 0; i < ir->type->components(); i++) {
393	 if (i != 0)
394	    printf(" ");
395	 switch (ir->type->base_type) {
396	 case GLSL_TYPE_UINT:  printf("%u", ir->value.u[i]); break;
397	 case GLSL_TYPE_INT:   printf("%d", ir->value.i[i]); break;
398	 case GLSL_TYPE_FLOAT: printf("%f", ir->value.f[i]); break;
399	 case GLSL_TYPE_BOOL:  printf("%d", ir->value.b[i]); break;
400	 default: assert(0);
401	 }
402      }
403   }
404   printf(")) ");
405}
406
407
408void
409ir_print_visitor::visit(ir_call *ir)
410{
411   printf("(call %s ", ir->callee_name());
412   if (ir->return_deref)
413      ir->return_deref->accept(this);
414   printf(" (");
415   foreach_iter(exec_list_iterator, iter, *ir) {
416      ir_instruction *const inst = (ir_instruction *) iter.get();
417
418      inst->accept(this);
419   }
420   printf("))\n");
421}
422
423
424void
425ir_print_visitor::visit(ir_return *ir)
426{
427   printf("(return");
428
429   ir_rvalue *const value = ir->get_value();
430   if (value) {
431      printf(" ");
432      value->accept(this);
433   }
434
435   printf(")");
436}
437
438
439void
440ir_print_visitor::visit(ir_discard *ir)
441{
442   printf("(discard ");
443
444   if (ir->condition != NULL) {
445      printf(" ");
446      ir->condition->accept(this);
447   }
448
449   printf(")");
450}
451
452
453void
454ir_print_visitor::visit(ir_if *ir)
455{
456   printf("(if ");
457   ir->condition->accept(this);
458
459   printf("(\n");
460   indentation++;
461
462   foreach_iter(exec_list_iterator, iter, ir->then_instructions) {
463      ir_instruction *const inst = (ir_instruction *) iter.get();
464
465      indent();
466      inst->accept(this);
467      printf("\n");
468   }
469
470   indentation--;
471   indent();
472   printf(")\n");
473
474   indent();
475   if (!ir->else_instructions.is_empty()) {
476      printf("(\n");
477      indentation++;
478
479      foreach_iter(exec_list_iterator, iter, ir->else_instructions) {
480	 ir_instruction *const inst = (ir_instruction *) iter.get();
481
482	 indent();
483	 inst->accept(this);
484	 printf("\n");
485      }
486      indentation--;
487      indent();
488      printf("))\n");
489   } else {
490      printf("())\n");
491   }
492}
493
494
495void
496ir_print_visitor::visit(ir_loop *ir)
497{
498   printf("(loop (");
499   if (ir->counter != NULL)
500      ir->counter->accept(this);
501   printf(") (");
502   if (ir->from != NULL)
503      ir->from->accept(this);
504   printf(") (");
505   if (ir->to != NULL)
506      ir->to->accept(this);
507   printf(") (");
508   if (ir->increment != NULL)
509      ir->increment->accept(this);
510   printf(") (\n");
511   indentation++;
512
513   foreach_iter(exec_list_iterator, iter, ir->body_instructions) {
514      ir_instruction *const inst = (ir_instruction *) iter.get();
515
516      indent();
517      inst->accept(this);
518      printf("\n");
519   }
520   indentation--;
521   indent();
522   printf("))\n");
523}
524
525
526void
527ir_print_visitor::visit(ir_loop_jump *ir)
528{
529   printf("%s", ir->is_break() ? "break" : "continue");
530}
531