1/* 2 * Copyright © 2013 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#include "ir.h" 24#include "ir_builder.h" 25#include "ir_rvalue_visitor.h" 26#include "ir_optimization.h" 27 28using namespace ir_builder; 29 30namespace { 31 32class vector_insert_visitor : public ir_rvalue_visitor { 33public: 34 vector_insert_visitor(bool lower_nonconstant_index) 35 : progress(false), lower_nonconstant_index(lower_nonconstant_index) 36 { 37 factory.instructions = &factory_instructions; 38 } 39 40 virtual ~vector_insert_visitor() 41 { 42 assert(factory_instructions.is_empty()); 43 } 44 45 virtual void handle_rvalue(ir_rvalue **rv); 46 47 ir_factory factory; 48 exec_list factory_instructions; 49 bool progress; 50 bool lower_nonconstant_index; 51}; 52 53} /* anonymous namespace */ 54 55void 56vector_insert_visitor::handle_rvalue(ir_rvalue **rv) 57{ 58 if (*rv == NULL || (*rv)->ir_type != ir_type_expression) 59 return; 60 61 ir_expression *const expr = (ir_expression *) *rv; 62 63 if (likely(expr->operation != ir_triop_vector_insert)) 64 return; 65 66 factory.mem_ctx = ralloc_parent(expr); 67 68 ir_constant *const idx = 69 expr->operands[2]->constant_expression_value(factory.mem_ctx); 70 if (idx != NULL) { 71 /* Replace (vector_insert (vec) (scalar) (index)) with a dereference of 72 * a new temporary. The new temporary gets assigned as 73 * 74 * t = vec 75 * t.mask = scalar 76 * 77 * where mask is the component selected by index. 78 */ 79 ir_variable *const temp = 80 factory.make_temp(expr->operands[0]->type, "vec_tmp"); 81 82 const int mask = 1 << idx->value.i[0]; 83 84 factory.emit(assign(temp, expr->operands[0])); 85 factory.emit(assign(temp, expr->operands[1], mask)); 86 87 this->progress = true; 88 *rv = new(factory.mem_ctx) ir_dereference_variable(temp); 89 } else if (this->lower_nonconstant_index) { 90 /* Replace (vector_insert (vec) (scalar) (index)) with a dereference of 91 * a new temporary. The new temporary gets assigned as 92 * 93 * t = vec 94 * if (index == 0) 95 * t.x = scalar 96 * if (index == 1) 97 * t.y = scalar 98 * if (index == 2) 99 * t.z = scalar 100 * if (index == 3) 101 * t.w = scalar 102 */ 103 ir_variable *const temp = 104 factory.make_temp(expr->operands[0]->type, "vec_tmp"); 105 106 ir_variable *const src_temp = 107 factory.make_temp(expr->operands[1]->type, "src_temp"); 108 109 factory.emit(assign(temp, expr->operands[0])); 110 factory.emit(assign(src_temp, expr->operands[1])); 111 112 assert(expr->operands[2]->type == glsl_type::int_type || 113 expr->operands[2]->type == glsl_type::uint_type); 114 115 for (unsigned i = 0; i < expr->type->vector_elements; i++) { 116 ir_constant *const cmp_index = 117 ir_constant::zero(factory.mem_ctx, expr->operands[2]->type); 118 cmp_index->value.u[0] = i; 119 120 ir_variable *const cmp_result = 121 factory.make_temp(glsl_type::bool_type, "index_condition"); 122 123 factory.emit(assign(cmp_result, 124 equal(expr->operands[2]->clone(factory.mem_ctx, 125 NULL), 126 cmp_index))); 127 128 factory.emit(if_tree(cmp_result, 129 assign(temp, src_temp, WRITEMASK_X << i))); 130 } 131 132 this->progress = true; 133 *rv = new(factory.mem_ctx) ir_dereference_variable(temp); 134 } 135 136 base_ir->insert_before(factory.instructions); 137} 138 139bool 140lower_vector_insert(exec_list *instructions, bool lower_nonconstant_index) 141{ 142 vector_insert_visitor v(lower_nonconstant_index); 143 144 visit_list_elements(&v, instructions); 145 146 return v.progress; 147} 148