Path: blob/21.2-virgl/src/compiler/glsl/ir_builder_print_visitor.cpp
4545 views
/*1* Copyright © 2016 Intel Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER20* DEALINGS IN THE SOFTWARE.21*/2223#include <inttypes.h> /* for PRIx64 macro */24#include "ir.h"25#include "ir_hierarchical_visitor.h"26#include "ir_builder_print_visitor.h"27#include "compiler/glsl_types.h"28#include "glsl_parser_extras.h"29#include "main/macros.h"30#include "util/hash_table.h"31#include "util/u_string.h"3233class ir_builder_print_visitor : public ir_hierarchical_visitor {34public:35ir_builder_print_visitor(FILE *f);36virtual ~ir_builder_print_visitor();3738void indent(void);3940virtual ir_visitor_status visit(class ir_variable *);41virtual ir_visitor_status visit(class ir_dereference_variable *);42virtual ir_visitor_status visit(class ir_constant *);43virtual ir_visitor_status visit(class ir_loop_jump *);4445virtual ir_visitor_status visit_enter(class ir_if *);4647virtual ir_visitor_status visit_enter(class ir_loop *);48virtual ir_visitor_status visit_leave(class ir_loop *);4950virtual ir_visitor_status visit_enter(class ir_function_signature *);51virtual ir_visitor_status visit_leave(class ir_function_signature *);5253virtual ir_visitor_status visit_enter(class ir_expression *);5455virtual ir_visitor_status visit_enter(class ir_assignment *);56virtual ir_visitor_status visit_leave(class ir_assignment *);5758virtual ir_visitor_status visit_leave(class ir_call *);59virtual ir_visitor_status visit_leave(class ir_swizzle *);60virtual ir_visitor_status visit_leave(class ir_return *);6162virtual ir_visitor_status visit_enter(ir_texture *ir);6364private:65void print_with_indent(const char *fmt, ...);66void print_without_indent(const char *fmt, ...);6768void print_without_declaration(const ir_rvalue *ir);69void print_without_declaration(const ir_constant *ir);70void print_without_declaration(const ir_dereference_variable *ir);71void print_without_declaration(const ir_swizzle *ir);72void print_without_declaration(const ir_expression *ir);7374unsigned next_ir_index;7576/**77* Mapping from ir_instruction * -> index used in the generated C code78* variable name.79*/80hash_table *index_map;8182FILE *f;8384int indentation;85};8687/* An operand is "simple" if it can be compactly printed on one line.88*/89static bool90is_simple_operand(const ir_rvalue *ir, unsigned depth = 1)91{92if (depth == 0)93return false;9495switch (ir->ir_type) {96case ir_type_dereference_variable:97return true;9899case ir_type_constant: {100if (ir->type == glsl_type::uint_type ||101ir->type == glsl_type::int_type ||102ir->type == glsl_type::float_type ||103ir->type == glsl_type::bool_type)104return true;105106const ir_constant *const c = (ir_constant *) ir;107ir_constant_data all_zero;108memset(&all_zero, 0, sizeof(all_zero));109110return memcmp(&c->value, &all_zero, sizeof(all_zero)) == 0;111}112113case ir_type_swizzle: {114const ir_swizzle *swiz = (ir_swizzle *) ir;115return swiz->mask.num_components == 1 &&116is_simple_operand(swiz->val, depth);117}118119case ir_type_expression: {120const ir_expression *expr = (ir_expression *) ir;121122for (unsigned i = 0; i < expr->num_operands; i++) {123if (!is_simple_operand(expr->operands[i], depth - 1))124return false;125}126127return true;128}129130default:131return false;132}133}134135void136_mesa_print_builder_for_ir(FILE *f, exec_list *instructions)137{138ir_builder_print_visitor v(f);139v.run(instructions);140}141142ir_builder_print_visitor::ir_builder_print_visitor(FILE *f)143: next_ir_index(1), f(f), indentation(0)144{145index_map = _mesa_pointer_hash_table_create(NULL);146}147148ir_builder_print_visitor::~ir_builder_print_visitor()149{150_mesa_hash_table_destroy(index_map, NULL);151}152153void ir_builder_print_visitor::indent(void)154{155for (int i = 0; i < indentation; i++)156fprintf(f, " ");157}158159void160ir_builder_print_visitor::print_with_indent(const char *fmt, ...)161{162va_list ap;163164indent();165166va_start(ap, fmt);167vfprintf(f, fmt, ap);168va_end(ap);169}170171void172ir_builder_print_visitor::print_without_indent(const char *fmt, ...)173{174va_list ap;175176va_start(ap, fmt);177vfprintf(f, fmt, ap);178va_end(ap);179}180181void182ir_builder_print_visitor::print_without_declaration(const ir_rvalue *ir)183{184switch (ir->ir_type) {185case ir_type_dereference_variable:186print_without_declaration((ir_dereference_variable *) ir);187break;188case ir_type_constant:189print_without_declaration((ir_constant *) ir);190break;191case ir_type_swizzle:192print_without_declaration((ir_swizzle *) ir);193break;194case ir_type_expression:195print_without_declaration((ir_expression *) ir);196break;197default:198unreachable("Invalid IR type.");199}200}201202ir_visitor_status203ir_builder_print_visitor::visit(ir_variable *ir)204{205const unsigned my_index = next_ir_index++;206207_mesa_hash_table_insert(index_map, ir, (void *)(uintptr_t) my_index);208209const char *mode_str;210switch (ir->data.mode) {211case ir_var_auto: mode_str = "ir_var_auto"; break;212case ir_var_uniform: mode_str = "ir_var_uniform"; break;213case ir_var_shader_storage: mode_str = "ir_var_shader_storage"; break;214case ir_var_shader_shared: mode_str = "ir_var_shader_shared"; break;215case ir_var_shader_in: mode_str = "ir_var_shader_in"; break;216case ir_var_shader_out: mode_str = "ir_var_shader_out"; break;217case ir_var_function_in: mode_str = "ir_var_function_in"; break;218case ir_var_function_out: mode_str = "ir_var_function_out"; break;219case ir_var_function_inout: mode_str = "ir_var_function_inout"; break;220case ir_var_const_in: mode_str = "ir_var_const_in"; break;221case ir_var_system_value: mode_str = "ir_var_system_value"; break;222case ir_var_temporary: mode_str = "ir_var_temporary"; break;223default:224unreachable("Invalid variable mode");225}226227if (ir->data.mode == ir_var_temporary) {228print_with_indent("ir_variable *const r%04X = body.make_temp(glsl_type::%s_type, \"%s\");\n",229my_index,230ir->type->name,231ir->name);232} else {233print_with_indent("ir_variable *const r%04X = new(mem_ctx) ir_variable(glsl_type::%s_type, \"%s\", %s);\n",234my_index,235ir->type->name,236ir->name,237mode_str);238239switch (ir->data.mode) {240case ir_var_function_in:241case ir_var_function_out:242case ir_var_function_inout:243case ir_var_const_in:244print_with_indent("sig_parameters.push_tail(r%04X);\n", my_index);245break;246default:247print_with_indent("body.emit(r%04X);\n", my_index);248break;249}250}251252return visit_continue;253}254255void256ir_builder_print_visitor::print_without_declaration(const ir_dereference_variable *ir)257{258const struct hash_entry *const he =259_mesa_hash_table_search(index_map, ir->var);260261print_without_indent("r%04X", (unsigned)(uintptr_t) he->data);262}263264ir_visitor_status265ir_builder_print_visitor::visit(ir_dereference_variable *ir)266{267const struct hash_entry *const he =268_mesa_hash_table_search(index_map, ir->var);269270if (he != NULL)271_mesa_hash_table_insert(index_map, ir, he->data);272273return visit_continue;274}275276ir_visitor_status277ir_builder_print_visitor::visit_enter(ir_function_signature *ir)278{279if (!ir->is_defined)280return visit_continue_with_parent;281282print_with_indent("ir_function_signature *\n"283"%s(void *mem_ctx, builtin_available_predicate avail)\n"284"{\n",285ir->function_name());286indentation++;287print_with_indent("ir_function_signature *const sig =\n");288print_with_indent(" new(mem_ctx) ir_function_signature(glsl_type::%s_type, avail);\n",289ir->return_type->name);290291print_with_indent("ir_factory body(&sig->body, mem_ctx);\n");292print_with_indent("sig->is_defined = true;\n\n");293294if (!ir->parameters.is_empty())295print_with_indent("exec_list sig_parameters;\n\n");296297return visit_continue;298}299300ir_visitor_status301ir_builder_print_visitor::visit_leave(ir_function_signature *ir)302{303if (!ir->parameters.is_empty())304print_with_indent("sig->replace_parameters(&sig_parameters);\n");305306print_with_indent("return sig;\n");307indentation--;308print_with_indent("}\n");309return visit_continue;310}311312void313ir_builder_print_visitor::print_without_declaration(const ir_constant *ir)314{315if (ir->type->is_scalar()) {316switch (ir->type->base_type) {317case GLSL_TYPE_UINT:318print_without_indent("body.constant(%uu)", ir->value.u[0]);319return;320case GLSL_TYPE_INT:321print_without_indent("body.constant(int(%d))", ir->value.i[0]);322return;323case GLSL_TYPE_FLOAT:324print_without_indent("body.constant(%ff)", ir->value.f[0]);325return;326case GLSL_TYPE_BOOL:327print_without_indent("body.constant(%s)",328ir->value.i[0] != 0 ? "true" : "false");329return;330default:331break;332}333}334335ir_constant_data all_zero;336memset(&all_zero, 0, sizeof(all_zero));337338if (memcmp(&ir->value, &all_zero, sizeof(all_zero)) == 0) {339print_without_indent("ir_constant::zero(mem_ctx, glsl_type::%s_type)",340ir->type->name);341}342}343344ir_visitor_status345ir_builder_print_visitor::visit(ir_constant *ir)346{347const unsigned my_index = next_ir_index++;348349_mesa_hash_table_insert(index_map, ir, (void *)(uintptr_t) my_index);350351if (ir->type == glsl_type::uint_type ||352ir->type == glsl_type::int_type ||353ir->type == glsl_type::float_type ||354ir->type == glsl_type::bool_type) {355print_with_indent("ir_constant *const r%04X = ", my_index);356print_without_declaration(ir);357print_without_indent(";\n");358return visit_continue;359}360361ir_constant_data all_zero;362memset(&all_zero, 0, sizeof(all_zero));363364if (memcmp(&ir->value, &all_zero, sizeof(all_zero)) == 0) {365print_with_indent("ir_constant *const r%04X = ", my_index);366print_without_declaration(ir);367print_without_indent(";\n");368} else {369print_with_indent("ir_constant_data r%04X_data;\n", my_index);370print_with_indent("memset(&r%04X_data, 0, sizeof(ir_constant_data));\n",371my_index);372for (unsigned i = 0; i < 16; i++) {373switch (ir->type->base_type) {374case GLSL_TYPE_UINT:375if (ir->value.u[i] != 0)376print_with_indent("r%04X_data.u[%u] = %u;\n",377my_index, i, ir->value.u[i]);378break;379case GLSL_TYPE_INT:380if (ir->value.i[i] != 0)381print_with_indent("r%04X_data.i[%u] = %i;\n",382my_index, i, ir->value.i[i]);383break;384case GLSL_TYPE_FLOAT:385if (ir->value.u[i] != 0)386print_with_indent("r%04X_data.u[%u] = 0x%08x; /* %f */\n",387my_index,388i,389ir->value.u[i],390ir->value.f[i]);391break;392case GLSL_TYPE_DOUBLE: {393uint64_t v;394395STATIC_ASSERT(sizeof(double) == sizeof(uint64_t));396397memcpy(&v, &ir->value.d[i], sizeof(v));398if (v != 0)399print_with_indent("r%04X_data.u64[%u] = 0x%016" PRIx64 "; /* %g */\n",400my_index, i, v, ir->value.d[i]);401break;402}403case GLSL_TYPE_UINT64:404if (ir->value.u64[i] != 0)405print_with_indent("r%04X_data.u64[%u] = %" PRIu64 ";\n",406my_index,407i,408ir->value.u64[i]);409break;410case GLSL_TYPE_INT64:411if (ir->value.i64[i] != 0)412print_with_indent("r%04X_data.i64[%u] = %" PRId64 ";\n",413my_index,414i,415ir->value.i64[i]);416break;417case GLSL_TYPE_BOOL:418if (ir->value.u[i] != 0)419print_with_indent("r%04X_data.u[%u] = 1;\n", my_index, i);420break;421default:422unreachable("Invalid constant type");423}424}425426print_with_indent("ir_constant *const r%04X = new(mem_ctx) ir_constant(glsl_type::%s_type, &r%04X_data);\n",427my_index,428ir->type->name,429my_index);430}431432return visit_continue;433}434435void436ir_builder_print_visitor::print_without_declaration(const ir_swizzle *ir)437{438const struct hash_entry *const he =439_mesa_hash_table_search(index_map, ir->val);440441if (ir->mask.num_components == 1) {442static const char swiz[4] = { 'x', 'y', 'z', 'w' };443444if (is_simple_operand(ir->val)) {445print_without_indent("swizzle_%c(", swiz[ir->mask.x]);446print_without_declaration(ir->val);447print_without_indent(")");448} else {449assert(he);450print_without_indent("swizzle_%c(r%04X)",451swiz[ir->mask.x],452(unsigned)(uintptr_t) he->data);453}454} else {455static const char swiz[4] = { 'X', 'Y', 'Z', 'W' };456457assert(he);458print_without_indent("swizzle(r%04X, MAKE_SWIZZLE4(SWIZZLE_%c, SWIZZLE_%c, SWIZZLE_%c, SWIZZLE_%c), %u)",459(unsigned)(uintptr_t) he->data,460swiz[ir->mask.x],461swiz[ir->mask.y],462swiz[ir->mask.z],463swiz[ir->mask.w],464ir->mask.num_components);465}466}467468ir_visitor_status469ir_builder_print_visitor::visit_leave(ir_swizzle *ir)470{471const unsigned my_index = next_ir_index++;472473_mesa_hash_table_insert(index_map, ir, (void *)(uintptr_t) my_index);474475print_with_indent("ir_swizzle *const r%04X = ", my_index);476print_without_declaration(ir);477print_without_indent(";\n");478479return visit_continue;480}481482ir_visitor_status483ir_builder_print_visitor::visit_enter(ir_assignment *ir)484{485ir_expression *const rhs_expr = ir->rhs->as_expression();486487if (!is_simple_operand(ir->rhs) && rhs_expr == NULL)488return visit_continue;489490if (rhs_expr != NULL) {491const unsigned num_op = rhs_expr->num_operands;492493for (unsigned i = 0; i < num_op; i++) {494if (is_simple_operand(rhs_expr->operands[i]))495continue;496497rhs_expr->operands[i]->accept(this);498}499}500501ir_visitor_status s;502503this->in_assignee = true;504s = ir->lhs->accept(this);505this->in_assignee = false;506if (s != visit_continue)507return (s == visit_continue_with_parent) ? visit_continue : s;508509assert(ir->condition == NULL);510511const struct hash_entry *const he_lhs =512_mesa_hash_table_search(index_map, ir->lhs);513514print_with_indent("body.emit(assign(r%04X, ",515(unsigned)(uintptr_t) he_lhs->data);516print_without_declaration(ir->rhs);517print_without_indent(", 0x%02x));\n\n", ir->write_mask);518519return visit_continue_with_parent;520}521522ir_visitor_status523ir_builder_print_visitor::visit_leave(ir_assignment *ir)524{525const struct hash_entry *const he_lhs =526_mesa_hash_table_search(index_map, ir->lhs);527528const struct hash_entry *const he_rhs =529_mesa_hash_table_search(index_map, ir->rhs);530531assert(ir->condition == NULL);532assert(ir->lhs && ir->rhs);533534print_with_indent("body.emit(assign(r%04X, r%04X, 0x%02x));\n\n",535(unsigned)(uintptr_t) he_lhs->data,536(unsigned)(uintptr_t) he_rhs->data,537ir->write_mask);538539return visit_continue;540}541542void543ir_builder_print_visitor::print_without_declaration(const ir_expression *ir)544{545const unsigned num_op = ir->num_operands;546547static const char *const arity[] = {548"", "unop", "binop", "triop", "quadop"549};550551switch (ir->operation) {552case ir_unop_neg:553case ir_binop_add:554case ir_binop_sub:555case ir_binop_mul:556case ir_binop_imul_high:557case ir_binop_less:558case ir_binop_gequal:559case ir_binop_equal:560case ir_binop_nequal:561case ir_binop_lshift:562case ir_binop_rshift:563case ir_binop_bit_and:564case ir_binop_bit_xor:565case ir_binop_bit_or:566case ir_binop_logic_and:567case ir_binop_logic_xor:568case ir_binop_logic_or:569print_without_indent("%s(",570ir_expression_operation_enum_strings[ir->operation]);571break;572default:573print_without_indent("expr(ir_%s_%s, ",574arity[num_op],575ir_expression_operation_enum_strings[ir->operation]);576break;577}578579for (unsigned i = 0; i < num_op; i++) {580if (is_simple_operand(ir->operands[i]))581print_without_declaration(ir->operands[i]);582else {583const struct hash_entry *const he =584_mesa_hash_table_search(index_map, ir->operands[i]);585586print_without_indent("r%04X", (unsigned)(uintptr_t) he->data);587}588589if (i < num_op - 1)590print_without_indent(", ");591}592593print_without_indent(")");594}595596ir_visitor_status597ir_builder_print_visitor::visit_enter(ir_expression *ir)598{599const unsigned num_op = ir->num_operands;600601for (unsigned i = 0; i < num_op; i++) {602if (is_simple_operand(ir->operands[i]))603continue;604605ir->operands[i]->accept(this);606}607608const unsigned my_index = next_ir_index++;609610_mesa_hash_table_insert(index_map, ir, (void *)(uintptr_t) my_index);611612print_with_indent("ir_expression *const r%04X = ", my_index);613print_without_declaration(ir);614print_without_indent(";\n");615616return visit_continue_with_parent;617}618619ir_visitor_status620ir_builder_print_visitor::visit_enter(ir_if *ir)621{622const unsigned my_index = next_ir_index++;623624print_with_indent("/* IF CONDITION */\n");625626ir_visitor_status s = ir->condition->accept(this);627if (s != visit_continue)628return (s == visit_continue_with_parent) ? visit_continue : s;629630const struct hash_entry *const he =631_mesa_hash_table_search(index_map, ir->condition);632633print_with_indent("ir_if *f%04X = new(mem_ctx) ir_if(operand(r%04X).val);\n",634my_index,635(unsigned)(uintptr_t) he->data);636print_with_indent("exec_list *const f%04X_parent_instructions = body.instructions;\n\n",637my_index);638639indentation++;640print_with_indent("/* THEN INSTRUCTIONS */\n");641print_with_indent("body.instructions = &f%04X->then_instructions;\n\n",642my_index);643644if (s != visit_continue_with_parent) {645s = visit_list_elements(this, &ir->then_instructions);646if (s == visit_stop)647return s;648}649650print_without_indent("\n");651652if (!ir->else_instructions.is_empty()) {653print_with_indent("/* ELSE INSTRUCTIONS */\n");654print_with_indent("body.instructions = &f%04X->else_instructions;\n\n",655my_index);656657if (s != visit_continue_with_parent) {658s = visit_list_elements(this, &ir->else_instructions);659if (s == visit_stop)660return s;661}662663print_without_indent("\n");664}665666indentation--;667668print_with_indent("body.instructions = f%04X_parent_instructions;\n",669my_index);670print_with_indent("body.emit(f%04X);\n\n",671my_index);672print_with_indent("/* END IF */\n\n");673674return visit_continue_with_parent;675}676677ir_visitor_status678ir_builder_print_visitor::visit_leave(ir_return *ir)679{680const struct hash_entry *const he =681_mesa_hash_table_search(index_map, ir->value);682683print_with_indent("body.emit(ret(r%04X));\n\n",684(unsigned)(uintptr_t) he->data);685686return visit_continue;687}688689ir_visitor_status690ir_builder_print_visitor::visit_enter(ir_texture *ir)691{692print_with_indent("\nUnsupported IR is encountered: texture functions are not supported. Exiting.\n");693694return visit_stop;695}696697ir_visitor_status698ir_builder_print_visitor::visit_leave(ir_call *ir)699{700const unsigned my_index = next_ir_index++;701702print_without_indent("\n");703print_with_indent("/* CALL %s */\n", ir->callee_name());704print_with_indent("exec_list r%04X_parameters;\n", my_index);705706foreach_in_list(ir_dereference_variable, param, &ir->actual_parameters) {707const struct hash_entry *const he =708_mesa_hash_table_search(index_map, param);709710print_with_indent("r%04X_parameters.push_tail(operand(r%04X).val);\n",711my_index,712(unsigned)(uintptr_t) he->data);713}714715char return_deref_string[32];716if (ir->return_deref) {717const struct hash_entry *const he =718_mesa_hash_table_search(index_map, ir->return_deref);719720snprintf(return_deref_string, sizeof(return_deref_string),721"operand(r%04X).val", (unsigned)(uintptr_t) he->data);722} else {723strcpy(return_deref_string, "NULL");724}725726print_with_indent("body.emit(new(mem_ctx) ir_call(shader->symbols->get_function(\"%s\"),\n",727ir->callee_name());728print_with_indent(" %s, &r%04X_parameters);\n\n",729return_deref_string,730my_index);731return visit_continue;732}733734ir_visitor_status735ir_builder_print_visitor::visit_enter(ir_loop *ir)736{737const unsigned my_index = next_ir_index++;738739_mesa_hash_table_insert(index_map, ir, (void *)(uintptr_t) my_index);740741print_with_indent("/* LOOP BEGIN */\n");742print_with_indent("ir_loop *f%04X = new(mem_ctx) ir_loop();\n", my_index);743print_with_indent("exec_list *const f%04X_parent_instructions = body.instructions;\n\n",744my_index);745746indentation++;747748print_with_indent("body.instructions = &f%04X->body_instructions;\n\n",749my_index);750751return visit_continue;752}753754ir_visitor_status755ir_builder_print_visitor::visit_leave(ir_loop *ir)756{757const struct hash_entry *const he =758_mesa_hash_table_search(index_map, ir);759760indentation--;761762print_with_indent("/* LOOP END */\n\n");763print_with_indent("body.instructions = f%04X_parent_instructions;\n",764(unsigned)(uintptr_t) he->data);765print_with_indent("body.emit(f%04X);\n\n",766(unsigned)(uintptr_t) he->data);767768return visit_continue;769}770771ir_visitor_status772ir_builder_print_visitor::visit(ir_loop_jump *ir)773{774print_with_indent("body.emit(new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_%s));\n\n",775ir->is_break() ? "break" : "continue");776return visit_continue;777}778779780