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 28 using namespace ir_builder; 29 30 namespace { 31 32 class vector_insert_visitor : public ir_rvalue_visitor { 33 public: 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 55 void 56 vector_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 = expr->operands[2]->constant_expression_value(); 69 if (idx != NULL) { 70 /* Replace (vector_insert (vec) (scalar) (index)) with a dereference of 71 * a new temporary. The new temporary gets assigned as 72 * 73 * t = vec 74 * t.mask = scalar 75 * 76 * where mask is the component selected by index. 77 */ 78 ir_variable *const temp = 79 factory.make_temp(expr->operands[0]->type, "vec_tmp"); 80 81 const int mask = 1 << idx->value.i[0]; 82 83 factory.emit(assign(temp, expr->operands[0])); 84 factory.emit(assign(temp, expr->operands[1], mask)); 85 86 this->progress = true; 87 *rv = new(factory.mem_ctx) ir_dereference_variable(temp); 88 } else if (this->lower_nonconstant_index) { 89 /* Replace (vector_insert (vec) (scalar) (index)) with a dereference of 90 * a new temporary. The new temporary gets assigned as 91 * 92 * t = vec 93 * if (index == 0) 94 * t.x = scalar 95 * if (index == 1) 96 * t.y = scalar 97 * if (index == 2) 98 * t.z = scalar 99 * if (index == 3) 100 * t.w = scalar 101 */ 102 ir_variable *const temp = 103 factory.make_temp(expr->operands[0]->type, "vec_tmp"); 104 105 ir_variable *const src_temp = 106 factory.make_temp(expr->operands[1]->type, "src_temp"); 107 108 factory.emit(assign(temp, expr->operands[0])); 109 factory.emit(assign(src_temp, expr->operands[1])); 110 111 assert(expr->operands[2]->type == glsl_type::int_type || 112 expr->operands[2]->type == glsl_type::uint_type); 113 114 for (unsigned i = 0; i < expr->type->vector_elements; i++) { 115 ir_constant *const cmp_index = 116 ir_constant::zero(factory.mem_ctx, expr->operands[2]->type); 117 cmp_index->value.u[0] = i; 118 119 ir_variable *const cmp_result = 120 factory.make_temp(glsl_type::bool_type, "index_condition"); 121 122 factory.emit(assign(cmp_result, 123 equal(expr->operands[2]->clone(factory.mem_ctx, 124 NULL), 125 cmp_index))); 126 127 factory.emit(if_tree(cmp_result, 128 assign(temp, src_temp, WRITEMASK_X << i))); 129 } 130 131 this->progress = true; 132 *rv = new(factory.mem_ctx) ir_dereference_variable(temp); 133 } 134 135 base_ir->insert_before(factory.instructions); 136 } 137 138 bool 139 lower_vector_insert(exec_list *instructions, bool lower_nonconstant_index) 140 { 141 vector_insert_visitor v(lower_nonconstant_index); 142 143 visit_list_elements(&v, instructions); 144 145 return v.progress; 146 } 147