1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2010 Intel Corporation 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci/** 25bf215546Sopenharmony_ci * \file opt_constant_variable.cpp 26bf215546Sopenharmony_ci * 27bf215546Sopenharmony_ci * Marks variables assigned a single constant value over the course 28bf215546Sopenharmony_ci * of the program as constant. 29bf215546Sopenharmony_ci * 30bf215546Sopenharmony_ci * The goal here is to trigger further constant folding and then dead 31bf215546Sopenharmony_ci * code elimination. This is common with vector/matrix constructors 32bf215546Sopenharmony_ci * and calls to builtin functions. 33bf215546Sopenharmony_ci */ 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_ci#include "ir.h" 36bf215546Sopenharmony_ci#include "ir_visitor.h" 37bf215546Sopenharmony_ci#include "ir_optimization.h" 38bf215546Sopenharmony_ci#include "compiler/glsl_types.h" 39bf215546Sopenharmony_ci#include "util/hash_table.h" 40bf215546Sopenharmony_ci 41bf215546Sopenharmony_cinamespace { 42bf215546Sopenharmony_ci 43bf215546Sopenharmony_cistruct assignment_entry { 44bf215546Sopenharmony_ci int assignment_count; 45bf215546Sopenharmony_ci ir_variable *var; 46bf215546Sopenharmony_ci ir_constant *constval; 47bf215546Sopenharmony_ci bool our_scope; 48bf215546Sopenharmony_ci}; 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_ciclass ir_constant_variable_visitor : public ir_hierarchical_visitor { 51bf215546Sopenharmony_cipublic: 52bf215546Sopenharmony_ci using ir_hierarchical_visitor::visit; 53bf215546Sopenharmony_ci using ir_hierarchical_visitor::visit_enter; 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ci virtual ir_visitor_status visit_enter(ir_dereference_variable *); 56bf215546Sopenharmony_ci virtual ir_visitor_status visit(ir_variable *); 57bf215546Sopenharmony_ci virtual ir_visitor_status visit_enter(ir_assignment *); 58bf215546Sopenharmony_ci virtual ir_visitor_status visit_enter(ir_call *); 59bf215546Sopenharmony_ci 60bf215546Sopenharmony_ci struct hash_table *ht; 61bf215546Sopenharmony_ci}; 62bf215546Sopenharmony_ci 63bf215546Sopenharmony_ci} /* unnamed namespace */ 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_cistatic struct assignment_entry * 66bf215546Sopenharmony_ciget_assignment_entry(ir_variable *var, struct hash_table *ht) 67bf215546Sopenharmony_ci{ 68bf215546Sopenharmony_ci struct hash_entry *hte = _mesa_hash_table_search(ht, var); 69bf215546Sopenharmony_ci struct assignment_entry *entry; 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_ci if (hte) { 72bf215546Sopenharmony_ci entry = (struct assignment_entry *) hte->data; 73bf215546Sopenharmony_ci } else { 74bf215546Sopenharmony_ci entry = (struct assignment_entry *) calloc(1, sizeof(*entry)); 75bf215546Sopenharmony_ci entry->var = var; 76bf215546Sopenharmony_ci _mesa_hash_table_insert(ht, var, entry); 77bf215546Sopenharmony_ci } 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ci return entry; 80bf215546Sopenharmony_ci} 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_ciir_visitor_status 83bf215546Sopenharmony_ciir_constant_variable_visitor::visit(ir_variable *ir) 84bf215546Sopenharmony_ci{ 85bf215546Sopenharmony_ci struct assignment_entry *entry = get_assignment_entry(ir, this->ht); 86bf215546Sopenharmony_ci entry->our_scope = true; 87bf215546Sopenharmony_ci return visit_continue; 88bf215546Sopenharmony_ci} 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_ci/* Skip derefs of variables so that we can detect declarations. */ 91bf215546Sopenharmony_ciir_visitor_status 92bf215546Sopenharmony_ciir_constant_variable_visitor::visit_enter(ir_dereference_variable *ir) 93bf215546Sopenharmony_ci{ 94bf215546Sopenharmony_ci (void)ir; 95bf215546Sopenharmony_ci return visit_continue_with_parent; 96bf215546Sopenharmony_ci} 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_ciir_visitor_status 99bf215546Sopenharmony_ciir_constant_variable_visitor::visit_enter(ir_assignment *ir) 100bf215546Sopenharmony_ci{ 101bf215546Sopenharmony_ci ir_constant *constval; 102bf215546Sopenharmony_ci struct assignment_entry *entry; 103bf215546Sopenharmony_ci 104bf215546Sopenharmony_ci entry = get_assignment_entry(ir->lhs->variable_referenced(), this->ht); 105bf215546Sopenharmony_ci assert(entry); 106bf215546Sopenharmony_ci entry->assignment_count++; 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_ci /* If there's more than one assignment, don't bother - we won't do anything 109bf215546Sopenharmony_ci * with this variable anyway, and continuing just wastes memory cloning 110bf215546Sopenharmony_ci * constant expressions. 111bf215546Sopenharmony_ci */ 112bf215546Sopenharmony_ci if (entry->assignment_count > 1) 113bf215546Sopenharmony_ci return visit_continue; 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_ci /* If it's already constant, don't do the work. */ 116bf215546Sopenharmony_ci if (entry->var->constant_value) 117bf215546Sopenharmony_ci return visit_continue; 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_ci ir_variable *var = ir->whole_variable_written(); 120bf215546Sopenharmony_ci if (!var) 121bf215546Sopenharmony_ci return visit_continue; 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ci /* Ignore buffer variables, since the underlying storage is shared 124bf215546Sopenharmony_ci * and we can't be sure that this variable won't be written by another 125bf215546Sopenharmony_ci * thread. 126bf215546Sopenharmony_ci */ 127bf215546Sopenharmony_ci if (var->data.mode == ir_var_shader_storage || 128bf215546Sopenharmony_ci var->data.mode == ir_var_shader_shared) 129bf215546Sopenharmony_ci return visit_continue; 130bf215546Sopenharmony_ci 131bf215546Sopenharmony_ci constval = ir->rhs->constant_expression_value(ralloc_parent(ir)); 132bf215546Sopenharmony_ci if (!constval) 133bf215546Sopenharmony_ci return visit_continue; 134bf215546Sopenharmony_ci 135bf215546Sopenharmony_ci /* Mark this entry as having a constant assignment (if the 136bf215546Sopenharmony_ci * assignment count doesn't go >1). do_constant_variable will fix 137bf215546Sopenharmony_ci * up the variable with the constant value later. 138bf215546Sopenharmony_ci */ 139bf215546Sopenharmony_ci entry->constval = constval; 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci return visit_continue; 142bf215546Sopenharmony_ci} 143bf215546Sopenharmony_ci 144bf215546Sopenharmony_ciir_visitor_status 145bf215546Sopenharmony_ciir_constant_variable_visitor::visit_enter(ir_call *ir) 146bf215546Sopenharmony_ci{ 147bf215546Sopenharmony_ci /* Mark any out parameters as assigned to */ 148bf215546Sopenharmony_ci foreach_two_lists(formal_node, &ir->callee->parameters, 149bf215546Sopenharmony_ci actual_node, &ir->actual_parameters) { 150bf215546Sopenharmony_ci ir_rvalue *param_rval = (ir_rvalue *) actual_node; 151bf215546Sopenharmony_ci ir_variable *param = (ir_variable *) formal_node; 152bf215546Sopenharmony_ci 153bf215546Sopenharmony_ci if (param->data.mode == ir_var_function_out || 154bf215546Sopenharmony_ci param->data.mode == ir_var_function_inout) { 155bf215546Sopenharmony_ci ir_variable *var = param_rval->variable_referenced(); 156bf215546Sopenharmony_ci struct assignment_entry *entry; 157bf215546Sopenharmony_ci 158bf215546Sopenharmony_ci assert(var); 159bf215546Sopenharmony_ci entry = get_assignment_entry(var, this->ht); 160bf215546Sopenharmony_ci entry->assignment_count++; 161bf215546Sopenharmony_ci } 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci /* We don't know if the variable passed to this function has been 164bf215546Sopenharmony_ci * assigned a value or if it is undefined, so for now we always assume 165bf215546Sopenharmony_ci * it has been assigned a value. Once functions have been inlined any 166bf215546Sopenharmony_ci * further potential optimisations will be taken care of. 167bf215546Sopenharmony_ci */ 168bf215546Sopenharmony_ci struct assignment_entry *entry; 169bf215546Sopenharmony_ci entry = get_assignment_entry(param, this->ht); 170bf215546Sopenharmony_ci entry->assignment_count++; 171bf215546Sopenharmony_ci } 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_ci /* Mark the return storage as having been assigned to */ 174bf215546Sopenharmony_ci if (ir->return_deref != NULL) { 175bf215546Sopenharmony_ci ir_variable *var = ir->return_deref->variable_referenced(); 176bf215546Sopenharmony_ci struct assignment_entry *entry; 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ci assert(var); 179bf215546Sopenharmony_ci entry = get_assignment_entry(var, this->ht); 180bf215546Sopenharmony_ci entry->assignment_count++; 181bf215546Sopenharmony_ci } 182bf215546Sopenharmony_ci 183bf215546Sopenharmony_ci return visit_continue; 184bf215546Sopenharmony_ci} 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_ci/** 187bf215546Sopenharmony_ci * Does a copy propagation pass on the code present in the instruction stream. 188bf215546Sopenharmony_ci */ 189bf215546Sopenharmony_cibool 190bf215546Sopenharmony_cido_constant_variable(exec_list *instructions) 191bf215546Sopenharmony_ci{ 192bf215546Sopenharmony_ci bool progress = false; 193bf215546Sopenharmony_ci ir_constant_variable_visitor v; 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_ci v.ht = _mesa_pointer_hash_table_create(NULL); 196bf215546Sopenharmony_ci v.run(instructions); 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_ci hash_table_foreach(v.ht, hte) { 199bf215546Sopenharmony_ci struct assignment_entry *entry = (struct assignment_entry *) hte->data; 200bf215546Sopenharmony_ci 201bf215546Sopenharmony_ci if (entry->assignment_count == 1 && entry->constval && entry->our_scope) { 202bf215546Sopenharmony_ci entry->var->constant_value = entry->constval; 203bf215546Sopenharmony_ci progress = true; 204bf215546Sopenharmony_ci } 205bf215546Sopenharmony_ci hte->data = NULL; 206bf215546Sopenharmony_ci free(entry); 207bf215546Sopenharmony_ci } 208bf215546Sopenharmony_ci _mesa_hash_table_destroy(v.ht, NULL); 209bf215546Sopenharmony_ci 210bf215546Sopenharmony_ci return progress; 211bf215546Sopenharmony_ci} 212bf215546Sopenharmony_ci 213bf215546Sopenharmony_cibool 214bf215546Sopenharmony_cido_constant_variable_unlinked(exec_list *instructions) 215bf215546Sopenharmony_ci{ 216bf215546Sopenharmony_ci bool progress = false; 217bf215546Sopenharmony_ci 218bf215546Sopenharmony_ci foreach_in_list(ir_instruction, ir, instructions) { 219bf215546Sopenharmony_ci ir_function *f = ir->as_function(); 220bf215546Sopenharmony_ci if (f) { 221bf215546Sopenharmony_ci foreach_in_list(ir_function_signature, sig, &f->signatures) { 222bf215546Sopenharmony_ci if (do_constant_variable(&sig->body)) 223bf215546Sopenharmony_ci progress = true; 224bf215546Sopenharmony_ci } 225bf215546Sopenharmony_ci } 226bf215546Sopenharmony_ci } 227bf215546Sopenharmony_ci 228bf215546Sopenharmony_ci return progress; 229bf215546Sopenharmony_ci} 230