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 remove_assignment(false) 37 { 38 factory.instructions = &factory_instructions; 39 } 40 41 virtual ~vector_insert_visitor() 42 { 43 assert(factory_instructions.is_empty()); 44 } 45 46 virtual void handle_rvalue(ir_rvalue **rv); 47 virtual ir_visitor_status visit_leave(ir_assignment *expr); 48 49 ir_factory factory; 50 exec_list factory_instructions; 51 bool progress; 52 bool lower_nonconstant_index; 53 bool remove_assignment; 54}; 55 56} /* anonymous namespace */ 57 58void 59vector_insert_visitor::handle_rvalue(ir_rvalue **rv) 60{ 61 if (*rv == NULL || (*rv)->ir_type != ir_type_expression) 62 return; 63 64 ir_expression *const expr = (ir_expression *) *rv; 65 66 if (likely(expr->operation != ir_triop_vector_insert)) 67 return; 68 69 factory.mem_ctx = ralloc_parent(expr); 70 71 ir_constant *const idx = 72 expr->operands[2]->constant_expression_value(factory.mem_ctx); 73 if (idx != NULL) { 74 unsigned index = idx->value.u[0]; 75 76 if (index >= expr->operands[0]->type->vector_elements) { 77 /* Section 5.11 (Out-of-Bounds Accesses) of the GLSL 4.60 spec says: 78 * 79 * In the subsections described above for array, vector, matrix and 80 * structure accesses, any out-of-bounds access produced undefined 81 * behavior.... Out-of-bounds writes may be discarded or overwrite 82 * other variables of the active program. 83 */ 84 this->remove_assignment = true; 85 this->progress = true; 86 return; 87 } 88 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 * t.mask = scalar 94 * 95 * where mask is the component selected by index. 96 */ 97 ir_variable *const temp = 98 factory.make_temp(expr->operands[0]->type, "vec_tmp"); 99 100 const int mask = 1 << idx->value.i[0]; 101 102 factory.emit(assign(temp, expr->operands[0])); 103 factory.emit(assign(temp, expr->operands[1], mask)); 104 105 this->progress = true; 106 *rv = new(factory.mem_ctx) ir_dereference_variable(temp); 107 } else if (this->lower_nonconstant_index) { 108 /* Replace (vector_insert (vec) (scalar) (index)) with a dereference of 109 * a new temporary. The new temporary gets assigned as 110 * 111 * t = vec 112 * if (index == 0) 113 * t.x = scalar 114 * if (index == 1) 115 * t.y = scalar 116 * if (index == 2) 117 * t.z = scalar 118 * if (index == 3) 119 * t.w = scalar 120 */ 121 ir_variable *const temp = 122 factory.make_temp(expr->operands[0]->type, "vec_tmp"); 123 124 ir_variable *const src_temp = 125 factory.make_temp(expr->operands[1]->type, "src_temp"); 126 127 factory.emit(assign(temp, expr->operands[0])); 128 factory.emit(assign(src_temp, expr->operands[1])); 129 130 assert(expr->operands[2]->type == glsl_type::int_type || 131 expr->operands[2]->type == glsl_type::uint_type); 132 133 for (unsigned i = 0; i < expr->type->vector_elements; i++) { 134 ir_constant *const cmp_index = 135 ir_constant::zero(factory.mem_ctx, expr->operands[2]->type); 136 cmp_index->value.u[0] = i; 137 138 ir_variable *const cmp_result = 139 factory.make_temp(glsl_type::bool_type, "index_condition"); 140 141 factory.emit(assign(cmp_result, 142 equal(expr->operands[2]->clone(factory.mem_ctx, 143 NULL), 144 cmp_index))); 145 146 factory.emit(if_tree(cmp_result, 147 assign(temp, src_temp, WRITEMASK_X << i))); 148 } 149 150 this->progress = true; 151 *rv = new(factory.mem_ctx) ir_dereference_variable(temp); 152 } 153 154 base_ir->insert_before(factory.instructions); 155} 156 157ir_visitor_status 158vector_insert_visitor::visit_leave(ir_assignment *ir) 159{ 160 ir_rvalue_visitor::visit_leave(ir); 161 162 if (this->remove_assignment) { 163 ir->remove(); 164 this->remove_assignment = false; 165 } 166 167 return visit_continue; 168} 169 170bool 171lower_vector_insert(exec_list *instructions, bool lower_nonconstant_index) 172{ 173 vector_insert_visitor v(lower_nonconstant_index); 174 175 visit_list_elements(&v, instructions); 176 177 return v.progress; 178} 179