[Mesa-dev] [PATCH 06/59] glsl: Add a C++ code generator that uses ir_builder to rebuild a program

Iago Toral itoral at igalia.com
Thu Oct 27 11:16:32 UTC 2016


I spent some time looking at this and trying and I did not find
anything that did not look reasonable to me in general. I have a
question below, but in any case this is:

Reviewed-by: Iago Toral Quiroga <itoral at igalia.com>

BTW, now I also see why you need patch 5, you want to use the
ir_builder for things like add() directly. When I was reading that
patch I was wondering why you would not just emit expressions with
ir_binop_*, which I guess would have also been perfectly possible and
would have made patch 5 unnecessary and also avoid the need for the
if/else you have in print_without_declaration(const ir_expression *ir),
but I guess that would've also made the generated code a bit less
readable.

Iago

On Tue, 2016-10-25 at 17:59 -0700, Ian Romanick wrote:
> From: Ian Romanick <ian.d.romanick at intel.com>
> 
(...)
> +ir_visitor_status
> +ir_builder_print_visitor::visit(ir_constant *ir)
> +{
> +   const unsigned my_index = next_ir_index++;
> +
> +   _mesa_hash_table_insert(index_map, ir, (void *)(uintptr_t)
> my_index);
> +
> +   if (ir->type == glsl_type::uint_type ||
> +       ir->type == glsl_type::int_type ||
> +       ir->type == glsl_type::float_type ||
> +       ir->type == glsl_type::bool_type) {
> +      print_with_indent("ir_constant *const r%04X = ", my_index);
> +      print_without_declaration(ir);
> +      print_without_indent(";\n");
> +      return visit_continue;
> +   }
> +
> +   ir_constant_data all_zero;
> +   memset(&all_zero, 0, sizeof(all_zero));
> +
> +   if (memcmp(&ir->value, &all_zero, sizeof(all_zero)) == 0) {
> +      print_with_indent("ir_constant *const r%04X = ", my_index);
> +      print_without_declaration(ir);
> +      print_without_indent(";\n");
> +   } else {
> +      print_with_indent("ir_constant_data r%04X_data;\n", my_index);
> +      print_with_indent("memset(&r%04X_data, 0,
> sizeof(ir_constant_data));\n",
> +                        my_index);
> +      for (unsigned i = 0; i < 16; i++) {
> +         switch (ir->type->base_type) {
> +         case GLSL_TYPE_UINT:
> +            if (ir->value.u[i] != 0)
> +               print_without_indent("r%04X_data.u[%u] = %u;\n",
> +                                    my_index, i, ir->value.u[i]);
> +            break;
> +         case GLSL_TYPE_INT:
> +            if (ir->value.i[i] != 0)
> +               print_without_indent("r%04X_data.i[%u] = %i;\n",
> +                                    my_index, i, ir->value.i[i]);
> +            break;
> +         case GLSL_TYPE_FLOAT:
> +            if (ir->value.u[i] != 0)
> +               print_without_indent("r%04X_data.u[%u] = 0x%08x; /*
> %f */\n",
> +                                    my_index,
> +                                    i,
> +                                    ir->value.u[i],
> +                                    ir->value.f[i]);
> +            break;
> +         case GLSL_TYPE_DOUBLE: {
> +            uint64_t v;
> +
> +            STATIC_ASSERT(sizeof(double) == sizeof(uint64_t));
> +
> +            memcpy(&v, &ir->value.d[i], sizeof(v));
> +            if (v != 0)
> +               /* FIXME: This won't actually work until
> ARB_gpu_shader_int64
> +                * support lands.
> +                */
> +               print_without_indent("r%04X_data.u64[%u] = 0x%016"
> PRIx64 "; /* %g */\n",
> +                                    my_index, i, v, ir->value.d[i]);

Why not just copy this to data.d (instead of data.u64) as a double
value directly?

> +            break;
> +         }
> +         case GLSL_TYPE_BOOL:
> +            if (ir->value.u[i] != 0)
> +               print_without_indent("r%04X_data.u[%u] = 1;\n",
> my_index, i);
> +            break;
> +         default:
> +            unreachable("Invalid constant type");
> +         }
> +      }
> +
> +      print_with_indent("ir_constant *const r%04X = new(mem_ctx)
> ir_constant(glsl_type::%s_type, &r%04X_data);\n",
> +                        my_index,
> +                        ir->type->name,
> +                        my_index);
> +   }
> +
> +   return visit_continue;
> +}
> +
> +void
> +ir_builder_print_visitor::print_without_declaration(const ir_swizzle
> *ir)
> +{
> +   const struct hash_entry *const he =
> +      _mesa_hash_table_search(index_map, ir->val);
> +
> +   if (ir->mask.num_components == 1) {
> +      static const char swiz[4] = { 'x', 'y', 'z', 'w' };
> +
> +      if (is_simple_operand(ir->val)) {
> +         print_without_indent("swizzle_%c(", swiz[ir->mask.x]);
> +         print_without_declaration(ir->val);
> +         print_without_indent(")");
> +      } else {
> +         print_without_indent("swizzle_%c(r%04X)",
> +                              swiz[ir->mask.x],
> +                              (unsigned)(uintptr_t) he->data);
> +      }
> +   } else {
> +      static const char swiz[4] = { 'X', 'Y', 'Z', 'W' };
> +
> +      print_without_indent("swizzle(r%04X, MAKE_SWIZZLE4(SWIZZLE_%c,
> SWIZZLE_%c, SWIZZLE_%c, SWIZZLE_%c), %u)",
> +                           (unsigned)(uintptr_t) he->data,
> +                           swiz[ir->mask.x],
> +                           swiz[ir->mask.y],
> +                           swiz[ir->mask.z],
> +                           swiz[ir->mask.w],
> +                           ir->mask.num_components);
> +   }
> +}
> +
> +ir_visitor_status
> +ir_builder_print_visitor::visit_leave(ir_swizzle *ir)
> +{
> +   const unsigned my_index = next_ir_index++;
> +
> +   _mesa_hash_table_insert(index_map, ir, (void *)(uintptr_t)
> my_index);
> +
> +   print_with_indent("ir_swizzle *const r%04X = ", my_index);
> +   print_without_declaration(ir);
> +   print_without_indent(";\n");
> +
> +   return visit_continue;
> +}
> +
> +ir_visitor_status
> +ir_builder_print_visitor::visit_enter(ir_assignment *ir)
> +{
> +   ir_expression *const rhs_expr = ir->rhs->as_expression();
> +
> +   if (!is_simple_operand(ir->rhs) && rhs_expr == NULL)
> +      return visit_continue;
> +
> +   if (rhs_expr != NULL) {
> +      const unsigned num_op = rhs_expr->get_num_operands();
> +
> +      for (unsigned i = 0; i < num_op; i++) {
> +         if (is_simple_operand(rhs_expr->operands[i]))
> +            continue;
> +
> +         rhs_expr->operands[i]->accept(this);
> +      }
> +   }
> +
> +   ir_visitor_status s;
> +
> +   this->in_assignee = true;
> +   s = ir->lhs->accept(this);
> +   this->in_assignee = false;
> +   if (s != visit_continue)
> +      return (s == visit_continue_with_parent) ? visit_continue : s;
> +
> +   assert(ir->condition == NULL);
> +
> +   const struct hash_entry *const he_lhs =
> +      _mesa_hash_table_search(index_map, ir->lhs);
> +
> +   print_with_indent("body.emit(assign(r%04X, ",
> +                     (unsigned)(uintptr_t) he_lhs->data);
> +   print_without_declaration(ir->rhs);
> +   print_without_indent(", 0x%02x));\n\n", ir->write_mask);
> +
> +   return visit_continue_with_parent;
> +}
> +
> +ir_visitor_status
> +ir_builder_print_visitor::visit_leave(ir_assignment *ir)
> +{
> +   const struct hash_entry *const he_lhs =
> +      _mesa_hash_table_search(index_map, ir->lhs);
> +
> +   const struct hash_entry *const he_rhs =
> +      _mesa_hash_table_search(index_map, ir->rhs);
> +
> +   assert(ir->condition == NULL);
> +
> +   print_with_indent("body.emit(assign(r%04X, r%04X, 0x%02x));\n\n",
> +                     (unsigned)(uintptr_t) he_lhs->data,
> +                     (unsigned)(uintptr_t) he_rhs->data,
> +                     ir->write_mask);
> +
> +   return visit_continue;
> +}
> +
> +void
> +ir_builder_print_visitor::print_without_declaration(const
> ir_expression *ir)
> +{
> +   const unsigned num_op = ir->get_num_operands();
> +
> +   static const char *const arity[] = {
> +      "", "unop", "binop", "triop", "quadop"
> +   };
> +
> +   switch (ir->operation) {
> +   case ir_unop_neg:
> +   case ir_binop_add:
> +   case ir_binop_sub:
> +   case ir_binop_mul:
> +   case ir_binop_imul_high:
> +   case ir_binop_less:
> +   case ir_binop_greater:
> +   case ir_binop_lequal:
> +   case ir_binop_gequal:
> +   case ir_binop_equal:
> +   case ir_binop_nequal:
> +   case ir_binop_lshift:
> +   case ir_binop_rshift:
> +   case ir_binop_bit_and:
> +   case ir_binop_bit_xor:
> +   case ir_binop_bit_or:
> +   case ir_binop_logic_and:
> +   case ir_binop_logic_xor:
> +   case ir_binop_logic_or:
> +      print_without_indent("%s(",
> +                           ir_expression_operation_enum_strings[ir-
> >operation]);
> +      break;
> +   default:
> +      print_without_indent("expr(ir_%s_%s, ",
> +                           arity[num_op],
> +                           ir_expression_operation_enum_strings[ir-
> >operation]);
> +      break;
> +   }
> +
> +   for (unsigned i = 0; i < num_op; i++) {
> +      if (is_simple_operand(ir->operands[i]))
> +         print_without_declaration(ir->operands[i]);
> +      else {
> +         const struct hash_entry *const he =
> +            _mesa_hash_table_search(index_map, ir->operands[i]);
> +
> +         print_without_indent("r%04X", (unsigned)(uintptr_t) he-
> >data);
> +      }
> +
> +      if (i < num_op - 1)
> +         print_without_indent(", ");
> +   }
> +
> +   print_without_indent(")");
> +}
> +
> +ir_visitor_status
> +ir_builder_print_visitor::visit_enter(ir_expression *ir)
> +{
> +   const unsigned num_op = ir->get_num_operands();
> +
> +   for (unsigned i = 0; i < num_op; i++) {
> +      if (is_simple_operand(ir->operands[i]))
> +         continue;
> +
> +      ir->operands[i]->accept(this);
> +   }
> +
> +   const unsigned my_index = next_ir_index++;
> +
> +   _mesa_hash_table_insert(index_map, ir, (void *)(uintptr_t)
> my_index);
> +
> +   print_with_indent("ir_expression *const r%04X = ", my_index);
> +   print_without_declaration(ir);
> +   print_without_indent(";\n");
> +
> +   return visit_continue_with_parent;
> +}
> +
> +ir_visitor_status
> +ir_builder_print_visitor::visit_enter(ir_if *ir)
> +{
> +   const unsigned my_index = next_ir_index++;
> +
> +   print_with_indent("/* IF CONDITION */\n");
> +
> +   ir_visitor_status s = ir->condition->accept(this);
> +   if (s != visit_continue)
> +      return (s == visit_continue_with_parent) ? visit_continue : s;
> +
> +   const struct hash_entry *const he =
> +      _mesa_hash_table_search(index_map, ir->condition);
> +
> +   print_with_indent("ir_if *f%04X = new(mem_ctx)
> ir_if(operand(r%04X).val);\n",
> +                     my_index,
> +                     (unsigned)(uintptr_t) he->data);
> +   print_with_indent("exec_list *const f%04X_parent_instructions =
> body.instructions;\n\n",
> +                     my_index);
> +
> +   indentation++;
> +   print_with_indent("/* THEN INSTRUCTIONS */\n");
> +   print_with_indent("body.instructions = &f%04X-
> >then_instructions;\n\n",
> +                     my_index);
> +
> +   if (s != visit_continue_with_parent) {
> +      s = visit_list_elements(this, &ir->then_instructions);
> +      if (s == visit_stop)
> +	 return s;
> +   }
> +
> +   print_without_indent("\n");
> +
> +   if (!ir->else_instructions.is_empty()) {
> +      print_with_indent("/* ELSE INSTRUCTIONS */\n");
> +      print_with_indent("body.instructions = &f%04X-
> >else_instructions;\n\n",
> +              my_index);
> +
> +      if (s != visit_continue_with_parent) {
> +         s = visit_list_elements(this, &ir->else_instructions);
> +         if (s == visit_stop)
> +            return s;
> +      }
> +
> +      print_without_indent("\n");
> +   }
> +
> +   indentation--;
> +
> +   print_with_indent("body.instructions =
> f%04X_parent_instructions;\n",
> +                     my_index);
> +   print_with_indent("body.emit(f%04X);\n\n",
> +                     my_index);
> +   print_with_indent("/* END IF */\n\n");
> +
> +   return visit_continue_with_parent;
> +}
> +
> +ir_visitor_status
> +ir_builder_print_visitor::visit_leave(ir_return *ir)
> +{
> +   const struct hash_entry *const he =
> +      _mesa_hash_table_search(index_map, ir->value);
> +
> +   print_with_indent("body.emit(ret(r%04X));\n\n",
> +                     (unsigned)(uintptr_t) he->data);
> +
> +   return visit_continue;
> +}
> +
> +ir_visitor_status
> +ir_builder_print_visitor::visit_leave(ir_call *ir)
> +{
> +   const unsigned my_index = next_ir_index++;
> +
> +   print_without_indent("\n");
> +   print_with_indent("/* CALL %s */\n", ir->callee_name());
> +   print_with_indent("exec_list r%04X_parameters;\n", my_index);
> +
> +   foreach_in_list(ir_dereference_variable, param, &ir-
> >actual_parameters) {
> +      const struct hash_entry *const he =
> +         _mesa_hash_table_search(index_map, param);
> +
> +      print_with_indent("r%04X_parameters.push_tail(operand(r%04X).v
> al);\n",
> +                        my_index,
> +                        (unsigned)(uintptr_t) he->data);
> +   }
> +
> +   char return_deref_string[32];
> +   if (ir->return_deref) {
> +      const struct hash_entry *const he =
> +         _mesa_hash_table_search(index_map, ir->return_deref);
> +
> +      snprintf(return_deref_string, sizeof(return_deref_string),
> +               "operand(r%04X).val",
> +               (unsigned)(uintptr_t) he->data);
> +   } else {
> +      strcpy(return_deref_string, "NULL");
> +   }
> +
> +   print_with_indent("body.emit(new(mem_ctx) ir_call(shader-
> >symbols->get_function(\"%s\"),\n",
> +                     ir->callee_name());
> +   print_with_indent("                               %s,
> &r%04X_parameters);\n\n",
> +                     return_deref_string,
> +                     my_index);
> +   return visit_continue;
> +}
> +
> +ir_visitor_status
> +ir_builder_print_visitor::visit_enter(ir_loop *ir)
> +{
> +   const unsigned my_index = next_ir_index++;
> +
> +   _mesa_hash_table_insert(index_map, ir, (void *)(uintptr_t)
> my_index);
> +
> +   print_with_indent("/* LOOP BEGIN */\n");
> +   print_with_indent("ir_loop *f%04X = new(mem_ctx) ir_loop();\n",
> my_index);
> +   print_with_indent("exec_list *const f%04X_parent_instructions =
> body.instructions;\n\n",
> +                     my_index);
> +
> +   indentation++;
> +
> +   print_with_indent("body.instructions = &f%04X-
> >body_instructions;\n\n",
> +                     my_index);
> +
> +   return visit_continue;
> +}
> +
> +ir_visitor_status
> +ir_builder_print_visitor::visit_leave(ir_loop *ir)
> +{
> +   const struct hash_entry *const he =
> +      _mesa_hash_table_search(index_map, ir);
> +
> +   indentation--;
> +
> +   print_with_indent("/* LOOP END */\n\n");
> +   print_with_indent("body.instructions =
> f%04X_parent_instructions;\n",
> +                     (unsigned)(uintptr_t) he->data);
> +   print_with_indent("body.emit(f%04X);\n\n",
> +                     (unsigned)(uintptr_t) he->data);
> +
> +   return visit_continue;
> +}
> +
> +ir_visitor_status
> +ir_builder_print_visitor::visit(ir_loop_jump *ir)
> +{
> +   print_with_indent("body.emit(new(mem_ctx)
> ir_loop_jump(ir_loop_jump::jump_%s));\n\n",
> +                     ir->is_break() ? "break" : "continue");
> +   return visit_continue;
> +}
> diff --git a/src/compiler/glsl/ir_builder_print_visitor.h
> b/src/compiler/glsl/ir_builder_print_visitor.h
> new file mode 100644
> index 0000000..a2deab2
> --- /dev/null
> +++ b/src/compiler/glsl/ir_builder_print_visitor.h
> @@ -0,0 +1,32 @@
> +/* -*- c++ -*- */
> +/*
> + * Copyright © 2016 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person
> obtaining a
> + * copy of this software and associated documentation files (the
> "Software"),
> + * to deal in the Software without restriction, including without
> limitation
> + * the rights to use, copy, modify, merge, publish, distribute,
> sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom
> the
> + * Software is furnished to do so, subject to the following
> conditions:
> + *
> + * The above copyright notice and this permission notice (including
> the next
> + * paragraph) shall be included in all copies or substantial
> portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO
> EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
> OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> OTHER
> + * DEALINGS IN THE SOFTWARE.
> + */
> +
> +#pragma once
> +#ifndef IR_BUILDER_PRINT_VISITOR_H
> +#define IR_BUILDER_PRINT_VISITOR_H
> +
> +extern void
> +_mesa_print_builder_for_ir(FILE *f, exec_list *instructions);
> +
> +#endif /* IR_BUILDER_PRINT_VISITOR_H */


More information about the mesa-dev mailing list