| File: | root/firefox-clang/third_party/rust/glslopt/glsl-optimizer/src/compiler/glsl/lower_int64.cpp |
| Warning: | line 246, column 42 1st function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | * Copyright © 2016 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 | ||||
| 24 | /** | |||
| 25 | * \file lower_int64.cpp | |||
| 26 | * | |||
| 27 | * Lower 64-bit operations to 32-bit operations. Each 64-bit value is lowered | |||
| 28 | * to a uvec2. For each operation that can be lowered, there is a function | |||
| 29 | * called __builtin_foo with the same number of parameters that takes uvec2 | |||
| 30 | * sources and produces uvec2 results. An operation like | |||
| 31 | * | |||
| 32 | * uint64_t(x) * uint64_t(y) | |||
| 33 | * | |||
| 34 | * becomes | |||
| 35 | * | |||
| 36 | * packUint2x32(__builtin_umul64(unpackUint2x32(x), unpackUint2x32(y))); | |||
| 37 | */ | |||
| 38 | ||||
| 39 | #include "main/macros.h" | |||
| 40 | #include "compiler/glsl_types.h" | |||
| 41 | #include "ir.h" | |||
| 42 | #include "ir_rvalue_visitor.h" | |||
| 43 | #include "ir_builder.h" | |||
| 44 | #include "ir_optimization.h" | |||
| 45 | #include "util/hash_table.h" | |||
| 46 | #include "builtin_functions.h" | |||
| 47 | ||||
| 48 | typedef ir_function_signature *(*function_generator)(void *mem_ctx, | |||
| 49 | builtin_available_predicate avail); | |||
| 50 | ||||
| 51 | using namespace ir_builder; | |||
| 52 | ||||
| 53 | namespace lower_64bit { | |||
| 54 | void expand_source(ir_factory &, ir_rvalue *val, ir_variable **expanded_src); | |||
| 55 | ||||
| 56 | ir_dereference_variable *compact_destination(ir_factory &, | |||
| 57 | const glsl_type *type, | |||
| 58 | ir_variable *result[4]); | |||
| 59 | ||||
| 60 | ir_rvalue *lower_op_to_function_call(ir_instruction *base_ir, | |||
| 61 | ir_expression *ir, | |||
| 62 | ir_function_signature *callee); | |||
| 63 | }; | |||
| 64 | ||||
| 65 | using namespace lower_64bit; | |||
| 66 | ||||
| 67 | namespace { | |||
| 68 | ||||
| 69 | class lower_64bit_visitor : public ir_rvalue_visitor { | |||
| 70 | public: | |||
| 71 | lower_64bit_visitor(void *mem_ctx, exec_list *instructions, unsigned lower) | |||
| 72 | : progress(false), lower(lower), | |||
| 73 | function_list(), added_functions(&function_list, mem_ctx) | |||
| 74 | { | |||
| 75 | functions = _mesa_hash_table_create(mem_ctx, | |||
| 76 | _mesa_hash_string, | |||
| 77 | _mesa_key_string_equal); | |||
| 78 | ||||
| 79 | foreach_in_list(ir_instruction, node, instructions)for (ir_instruction *node = (!exec_node_is_tail_sentinel((instructions )->head_sentinel.next) ? (ir_instruction *) ((instructions )->head_sentinel.next) : __null); (node) != __null; (node) = (!exec_node_is_tail_sentinel((node)->next) ? (ir_instruction *) ((node)->next) : __null)) { | |||
| 80 | ir_function *const f = node->as_function(); | |||
| 81 | ||||
| 82 | if (f == NULL__null || strncmp(f->name, "__builtin_", 10) != 0) | |||
| 83 | continue; | |||
| 84 | ||||
| 85 | add_function(f); | |||
| 86 | } | |||
| 87 | } | |||
| 88 | ||||
| 89 | ~lower_64bit_visitor() | |||
| 90 | { | |||
| 91 | _mesa_hash_table_destroy(functions, NULL__null); | |||
| 92 | } | |||
| 93 | ||||
| 94 | void handle_rvalue(ir_rvalue **rvalue); | |||
| 95 | ||||
| 96 | void add_function(ir_function *f) | |||
| 97 | { | |||
| 98 | _mesa_hash_table_insert(functions, f->name, f); | |||
| 99 | } | |||
| 100 | ||||
| 101 | ir_function *find_function(const char *name) | |||
| 102 | { | |||
| 103 | struct hash_entry *const entry = | |||
| 104 | _mesa_hash_table_search(functions, name); | |||
| 105 | ||||
| 106 | return entry != NULL__null ? (ir_function *) entry->data : NULL__null; | |||
| 107 | } | |||
| 108 | ||||
| 109 | bool progress; | |||
| 110 | ||||
| 111 | private: | |||
| 112 | unsigned lower; /** Bitfield of which operations to lower */ | |||
| 113 | ||||
| 114 | /** Hashtable containing all of the known functions in the IR */ | |||
| 115 | struct hash_table *functions; | |||
| 116 | ||||
| 117 | public: | |||
| 118 | exec_list function_list; | |||
| 119 | ||||
| 120 | private: | |||
| 121 | ir_factory added_functions; | |||
| 122 | ||||
| 123 | ir_rvalue *handle_op(ir_expression *ir, const char *function_name, | |||
| 124 | function_generator generator); | |||
| 125 | }; | |||
| 126 | ||||
| 127 | } /* anonymous namespace */ | |||
| 128 | ||||
| 129 | /** | |||
| 130 | * Determine if a particular type of lowering should occur | |||
| 131 | */ | |||
| 132 | #define lowering(x)(this->lower & x) (this->lower & x) | |||
| 133 | ||||
| 134 | bool | |||
| 135 | lower_64bit_integer_instructions(exec_list *instructions, | |||
| 136 | unsigned what_to_lower) | |||
| 137 | { | |||
| 138 | if (instructions->is_empty()) | |||
| 139 | return false; | |||
| 140 | ||||
| 141 | ir_instruction *first_inst = (ir_instruction *) instructions->get_head_raw(); | |||
| 142 | void *const mem_ctx = ralloc_parent(first_inst); | |||
| 143 | lower_64bit_visitor v(mem_ctx, instructions, what_to_lower); | |||
| 144 | ||||
| 145 | visit_list_elements(&v, instructions); | |||
| 146 | ||||
| 147 | if (v.progress && !v.function_list.is_empty()) { | |||
| 148 | /* Move all of the nodes from function_list to the head if the incoming | |||
| 149 | * instruction list. | |||
| 150 | */ | |||
| 151 | exec_node *const after = &instructions->head_sentinel; | |||
| 152 | exec_node *const before = instructions->head_sentinel.next; | |||
| 153 | exec_node *const head = v.function_list.head_sentinel.next; | |||
| 154 | exec_node *const tail = v.function_list.tail_sentinel.prev; | |||
| 155 | ||||
| 156 | before->next = head; | |||
| 157 | head->prev = before; | |||
| 158 | ||||
| 159 | after->prev = tail; | |||
| 160 | tail->next = after; | |||
| 161 | } | |||
| 162 | ||||
| 163 | return v.progress; | |||
| 164 | } | |||
| 165 | ||||
| 166 | ||||
| 167 | /** | |||
| 168 | * Expand individual 64-bit values to uvec2 values | |||
| 169 | * | |||
| 170 | * Each operation is in one of a few forms. | |||
| 171 | * | |||
| 172 | * vector op vector | |||
| 173 | * vector op scalar | |||
| 174 | * scalar op vector | |||
| 175 | * scalar op scalar | |||
| 176 | * | |||
| 177 | * In the 'vector op vector' case, the two vectors must have the same size. | |||
| 178 | * In a way, the 'scalar op scalar' form is special case of the 'vector op | |||
| 179 | * vector' form. | |||
| 180 | * | |||
| 181 | * This method generates a new set of uvec2 values for each element of a | |||
| 182 | * single operand. If the operand is a scalar, the uvec2 is replicated | |||
| 183 | * multiple times. A value like | |||
| 184 | * | |||
| 185 | * u64vec3(a) + u64vec3(b) | |||
| 186 | * | |||
| 187 | * becomes | |||
| 188 | * | |||
| 189 | * u64vec3 tmp0 = u64vec3(a) + u64vec3(b); | |||
| 190 | * uvec2 tmp1 = unpackUint2x32(tmp0.x); | |||
| 191 | * uvec2 tmp2 = unpackUint2x32(tmp0.y); | |||
| 192 | * uvec2 tmp3 = unpackUint2x32(tmp0.z); | |||
| 193 | * | |||
| 194 | * and the returned operands array contains ir_variable pointers to | |||
| 195 | * | |||
| 196 | * { tmp1, tmp2, tmp3, tmp1 } | |||
| 197 | */ | |||
| 198 | void | |||
| 199 | lower_64bit::expand_source(ir_factory &body, | |||
| 200 | ir_rvalue *val, | |||
| 201 | ir_variable **expanded_src) | |||
| 202 | { | |||
| 203 | assert(val->type->is_integer_64())(static_cast <bool> (val->type->is_integer_64()) ? void (0) : __assert_fail ("val->type->is_integer_64()" , __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__ )); | |||
| 204 | ||||
| 205 | ir_variable *const temp = body.make_temp(val->type, "tmp"); | |||
| 206 | ||||
| 207 | body.emit(assign(temp, val)); | |||
| 208 | ||||
| 209 | const ir_expression_operation unpack_opcode = | |||
| 210 | val->type->base_type == GLSL_TYPE_UINT64 | |||
| 211 | ? ir_unop_unpack_uint_2x32 : ir_unop_unpack_int_2x32; | |||
| 212 | ||||
| 213 | const glsl_type *const type = | |||
| 214 | val->type->base_type == GLSL_TYPE_UINT64 | |||
| 215 | ? glsl_type::uvec2_type : glsl_type::ivec2_type; | |||
| 216 | ||||
| 217 | unsigned i; | |||
| 218 | for (i = 0; i < val->type->vector_elements; i++) { | |||
| 219 | expanded_src[i] = body.make_temp(type, "expanded_64bit_source"); | |||
| 220 | ||||
| 221 | body.emit(assign(expanded_src[i], | |||
| 222 | expr(unpack_opcode, swizzle(temp, i, 1)))); | |||
| 223 | } | |||
| 224 | ||||
| 225 | for (/* empty */; i < 4; i++) | |||
| 226 | expanded_src[i] = expanded_src[0]; | |||
| 227 | } | |||
| 228 | ||||
| 229 | /** | |||
| 230 | * Convert a series of uvec2 results into a single 64-bit integer vector | |||
| 231 | */ | |||
| 232 | ir_dereference_variable * | |||
| 233 | lower_64bit::compact_destination(ir_factory &body, | |||
| 234 | const glsl_type *type, | |||
| 235 | ir_variable *result[4]) | |||
| 236 | { | |||
| 237 | const ir_expression_operation pack_opcode = | |||
| 238 | type->base_type
| |||
| 239 | ? ir_unop_pack_uint_2x32 : ir_unop_pack_int_2x32; | |||
| 240 | ||||
| 241 | ir_variable *const compacted_result = | |||
| 242 | body.make_temp(type, "compacted_64bit_result"); | |||
| 243 | ||||
| 244 | for (unsigned i = 0; i < type->vector_elements; i++) { | |||
| 245 | body.emit(assign(compacted_result, | |||
| 246 | expr(pack_opcode, result[i]), | |||
| ||||
| 247 | 1U << i)); | |||
| 248 | } | |||
| 249 | ||||
| 250 | void *const mem_ctx = ralloc_parent(compacted_result); | |||
| 251 | return new(mem_ctx) ir_dereference_variable(compacted_result); | |||
| 252 | } | |||
| 253 | ||||
| 254 | ir_rvalue * | |||
| 255 | lower_64bit::lower_op_to_function_call(ir_instruction *base_ir, | |||
| 256 | ir_expression *ir, | |||
| 257 | ir_function_signature *callee) | |||
| 258 | { | |||
| 259 | const unsigned num_operands = ir->num_operands; | |||
| 260 | ir_variable *src[4][4]; | |||
| 261 | ir_variable *dst[4]; | |||
| 262 | void *const mem_ctx = ralloc_parent(ir); | |||
| 263 | exec_list instructions; | |||
| 264 | unsigned source_components = 0; | |||
| 265 | const glsl_type *const result_type = | |||
| 266 | ir->type->base_type == GLSL_TYPE_UINT64 | |||
| 267 | ? glsl_type::uvec2_type : glsl_type::ivec2_type; | |||
| 268 | ||||
| 269 | ir_factory body(&instructions, mem_ctx); | |||
| 270 | ||||
| 271 | for (unsigned i = 0; i < num_operands; i++) { | |||
| 272 | expand_source(body, ir->operands[i], src[i]); | |||
| 273 | ||||
| 274 | if (ir->operands[i]->type->vector_elements > source_components) | |||
| 275 | source_components = ir->operands[i]->type->vector_elements; | |||
| 276 | } | |||
| 277 | ||||
| 278 | for (unsigned i = 0; i < source_components; i++) { | |||
| 279 | dst[i] = body.make_temp(result_type, "expanded_64bit_result"); | |||
| 280 | ||||
| 281 | exec_list parameters; | |||
| 282 | ||||
| 283 | for (unsigned j = 0; j < num_operands; j++) | |||
| 284 | parameters.push_tail(new(mem_ctx) ir_dereference_variable(src[j][i])); | |||
| 285 | ||||
| 286 | ir_dereference_variable *const return_deref = | |||
| 287 | new(mem_ctx) ir_dereference_variable(dst[i]); | |||
| 288 | ||||
| 289 | ir_call *const c = new(mem_ctx) ir_call(callee, | |||
| 290 | return_deref, | |||
| 291 | ¶meters); | |||
| 292 | ||||
| 293 | body.emit(c); | |||
| 294 | } | |||
| 295 | ||||
| 296 | ir_rvalue *const rv = compact_destination(body, ir->type, dst); | |||
| 297 | ||||
| 298 | /* Move all of the nodes from instructions between base_ir and the | |||
| 299 | * instruction before it. | |||
| 300 | */ | |||
| 301 | exec_node *const after = base_ir; | |||
| 302 | exec_node *const before = after->prev; | |||
| 303 | exec_node *const head = instructions.head_sentinel.next; | |||
| 304 | exec_node *const tail = instructions.tail_sentinel.prev; | |||
| 305 | ||||
| 306 | before->next = head; | |||
| 307 | head->prev = before; | |||
| 308 | ||||
| 309 | after->prev = tail; | |||
| 310 | tail->next = after; | |||
| 311 | ||||
| 312 | return rv; | |||
| 313 | } | |||
| 314 | ||||
| 315 | ir_rvalue * | |||
| 316 | lower_64bit_visitor::handle_op(ir_expression *ir, | |||
| 317 | const char *function_name, | |||
| 318 | function_generator generator) | |||
| 319 | { | |||
| 320 | for (unsigned i = 0; i < ir->num_operands; i++) | |||
| 321 | if (!ir->operands[i]->type->is_integer_64()) | |||
| 322 | return ir; | |||
| 323 | ||||
| 324 | /* Get a handle to the correct ir_function_signature for the core | |||
| 325 | * operation. | |||
| 326 | */ | |||
| 327 | ir_function_signature *callee = NULL__null; | |||
| 328 | ir_function *f = find_function(function_name); | |||
| 329 | ||||
| 330 | if (f != NULL__null) { | |||
| 331 | callee = (ir_function_signature *) f->signatures.get_head(); | |||
| 332 | assert(callee != NULL && callee->ir_type == ir_type_function_signature)(static_cast <bool> (callee != __null && callee ->ir_type == ir_type_function_signature) ? void (0) : __assert_fail ("callee != NULL && callee->ir_type == ir_type_function_signature" , __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__ )); | |||
| 333 | } else { | |||
| 334 | f = new(base_ir) ir_function(function_name); | |||
| 335 | callee = generator(base_ir, NULL__null); | |||
| 336 | ||||
| 337 | f->add_signature(callee); | |||
| 338 | ||||
| 339 | add_function(f); | |||
| 340 | } | |||
| 341 | ||||
| 342 | this->progress = true; | |||
| 343 | return lower_op_to_function_call(this->base_ir, ir, callee); | |||
| 344 | } | |||
| 345 | ||||
| 346 | void | |||
| 347 | lower_64bit_visitor::handle_rvalue(ir_rvalue **rvalue) | |||
| 348 | { | |||
| 349 | if (*rvalue == NULL__null || (*rvalue)->ir_type != ir_type_expression) | |||
| ||||
| 350 | return; | |||
| 351 | ||||
| 352 | ir_expression *const ir = (*rvalue)->as_expression(); | |||
| 353 | assert(ir != NULL)(static_cast <bool> (ir != __null) ? void (0) : __assert_fail ("ir != NULL", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); | |||
| 354 | ||||
| 355 | switch (ir->operation) { | |||
| 356 | case ir_unop_sign: | |||
| 357 | if (lowering(SIGN64)(this->lower & (1U << 1))) { | |||
| 358 | *rvalue = handle_op(ir, "__builtin_sign64", generate_ir::sign64); | |||
| 359 | } | |||
| 360 | break; | |||
| 361 | ||||
| 362 | case ir_binop_div: | |||
| 363 | if (lowering(DIV64)(this->lower & (1U << 2))) { | |||
| 364 | if (ir->type->base_type == GLSL_TYPE_UINT64) { | |||
| 365 | *rvalue = handle_op(ir, "__builtin_udiv64", generate_ir::udiv64); | |||
| 366 | } else { | |||
| 367 | *rvalue = handle_op(ir, "__builtin_idiv64", generate_ir::idiv64); | |||
| 368 | } | |||
| 369 | } | |||
| 370 | break; | |||
| 371 | ||||
| 372 | case ir_binop_mod: | |||
| 373 | if (lowering(MOD64)(this->lower & (1U << 3))) { | |||
| 374 | if (ir->type->base_type == GLSL_TYPE_UINT64) { | |||
| 375 | *rvalue = handle_op(ir, "__builtin_umod64", generate_ir::umod64); | |||
| 376 | } else { | |||
| 377 | *rvalue = handle_op(ir, "__builtin_imod64", generate_ir::imod64); | |||
| 378 | } | |||
| 379 | } | |||
| 380 | break; | |||
| 381 | ||||
| 382 | case ir_binop_mul: | |||
| 383 | if (lowering(MUL64)(this->lower & (1U << 0))) { | |||
| 384 | *rvalue = handle_op(ir, "__builtin_umul64", generate_ir::umul64); | |||
| 385 | } | |||
| 386 | break; | |||
| 387 | ||||
| 388 | default: | |||
| 389 | break; | |||
| 390 | } | |||
| 391 | } |