From 65122e9e8038488e8c586eb609e434a90188de27 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 12 May 2010 12:10:41 -0700 Subject: [PATCH] ir_constant_variable: New pass to mark constant-assigned variables constant. This removes a bunch of gratuitous moving around of constant values from constructors. Makes a shader ir I was looking at for structure handling almost readable. --- Makefile.am | 1 + glsl_parser_extras.cpp | 1 + ir_constant_variable.cpp | 165 +++++++++++++++++++++++++++++++++++++++++++++++ ir_optimization.h | 2 + linux_list.h | 93 ++++++++++++++++++++++++++ 5 files changed, 262 insertions(+) create mode 100644 ir_constant_variable.cpp create mode 100644 linux_list.h diff --git a/Makefile.am b/Makefile.am index 986b6fe..a62591d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,6 +34,7 @@ glsl_SOURCES = \ ir_basic_block.h \ ir_constant_expression.cpp \ ir_constant_folding.cpp \ + ir_constant_variable.cpp \ ir_copy_propagation.cpp \ ir_copy_propagation.h \ ir_dead_code.cpp \ diff --git a/glsl_parser_extras.cpp b/glsl_parser_extras.cpp index 316ac23..afce9d9 100644 --- a/glsl_parser_extras.cpp +++ b/glsl_parser_extras.cpp @@ -758,6 +758,7 @@ main(int argc, char **argv) progress = do_copy_propagation(&instructions) || progress; progress = do_dead_code_local(&instructions) || progress; progress = do_dead_code_unlinked(&instructions) || progress; + progress = do_constant_variable_unlinked(&instructions) || progress; progress = do_constant_folding(&instructions) || progress; progress = do_vec_index_to_swizzle(&instructions) || progress; progress = do_swizzle_swizzle(&instructions) || progress; diff --git a/ir_constant_variable.cpp b/ir_constant_variable.cpp new file mode 100644 index 0000000..75590df --- /dev/null +++ b/ir_constant_variable.cpp @@ -0,0 +1,165 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_constant_variable.cpp + * + * Marks variables assigned a single constant value over the course + * of the program as constant. + * + * The goal here is to trigger further constant folding and then dead + * code elimination. This is common with vector/matrix constructors + * and calls to builtin functions. + */ + +#include +#include +#include "ir.h" +#include "ir_print_visitor.h" +#include "ir_visitor.h" +#include "ir_optimization.h" +#include "glsl_types.h" +#include "linux_list.h" + +struct assignment_entry { + struct list link; + int assignment_count; + ir_variable *var; + ir_constant *constval; +}; + +class ir_constant_variable_visitor : public ir_hierarchical_visitor { +public: + ir_constant_variable_visitor() + { + list_init(&list); + } + + virtual ir_visitor_status visit_enter(ir_assignment *); + + struct list list; +}; + +static struct assignment_entry * +get_assignment_entry(ir_variable *var, struct list *list) +{ + struct assignment_entry *entry; + + list_foreach_entry(entry, struct assignment_entry, list, link) { + if (entry->var == var) + return entry; + } + + entry = (struct assignment_entry *)calloc(1, sizeof(*entry)); + entry->var = var; + list_add(&entry->link, list); + return entry; +} + +ir_visitor_status +ir_constant_variable_visitor::visit_enter(ir_assignment *ir) +{ + ir_constant *constval; + struct assignment_entry *entry; + + entry = get_assignment_entry(ir->lhs->variable_referenced(), &this->list); + assert(entry); + entry->assignment_count++; + + /* If it's already constant, don't do the work. */ + if (entry->var->constant_value) + return visit_continue; + + /* OK, now find if we actually have all the right conditions for + * this to be a constant value assigned to the var. + */ + if (ir->condition) { + constval = ir->condition->constant_expression_value(); + if (!constval || !constval->value.b[0]) + return visit_continue; + } + + ir_variable *var = ir->lhs->whole_variable_referenced(); + if (!var) + return visit_continue; + + constval = ir->rhs->constant_expression_value(); + if (!constval) + return visit_continue; + + /* Mark this entry as having a constant assignment (if the + * assignment count doesn't go >1). do_constant_variable will fix + * up the variable with the constant value later. + */ + entry->constval = constval; + + return visit_continue; +} + +/** + * Does a copy propagation pass on the code present in the instruction stream. + */ +bool +do_constant_variable(exec_list *instructions) +{ + bool progress = false; + ir_constant_variable_visitor v; + + v.run(instructions); + + while (!list_is_empty(&v.list)) { + + struct assignment_entry *entry; + entry = list_entry(v.list.next, struct assignment_entry, link); + + if (entry->assignment_count == 1 && entry->constval) { + entry->var->constant_value = entry->constval; + progress = true; + } + list_del(&entry->link); + free(entry); + } + + return progress; +} + +bool +do_constant_variable_unlinked(exec_list *instructions) +{ + bool progress = false; + + foreach_iter(exec_list_iterator, iter, *instructions) { + ir_instruction *ir = (ir_instruction *)iter.get(); + ir_function *f = ir->as_function(); + if (f) { + foreach_iter(exec_list_iterator, sigiter, *f) { + ir_function_signature *sig = + (ir_function_signature *) sigiter.get(); + if (do_constant_variable(&sig->body)) + progress = true; + } + } + } + + return progress; +} diff --git a/ir_optimization.h b/ir_optimization.h index 0660e72..432a334 100644 --- a/ir_optimization.h +++ b/ir_optimization.h @@ -29,6 +29,8 @@ */ bool do_constant_folding(exec_list *instructions); +bool do_constant_variable(exec_list *instructions); +bool do_constant_variable_unlinked(exec_list *instructions); bool do_copy_propagation(exec_list *instructions); bool do_dead_code(exec_list *instructions); bool do_dead_code_local(exec_list *instructions); diff --git a/linux_list.h b/linux_list.h new file mode 100644 index 0000000..88ec6fb --- /dev/null +++ b/linux_list.h @@ -0,0 +1,93 @@ +/* + * Copyright © 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Chris Wilson + * + */ + +/* classic doubly-link circular list */ +struct list { + struct list *next, *prev; +}; + +static void +list_init(struct list *list) +{ + list->next = list->prev = list; +} + +static inline void +__list_add(struct list *entry, + struct list *prev, + struct list *next) +{ + next->prev = entry; + entry->next = next; + entry->prev = prev; + prev->next = entry; +} + +static inline void +list_add(struct list *entry, struct list *head) +{ + __list_add(entry, head, head->next); +} + +static inline void +__list_del(struct list *prev, struct list *next) +{ + next->prev = prev; + prev->next = next; +} + +static inline void +list_del(struct list *entry) +{ + __list_del(entry->prev, entry->next); + list_init(entry); +} + +static inline bool +list_is_empty(struct list *head) +{ + return head->next == head; +} + +#ifndef container_of +#define container_of(ptr, type, member) \ + (type *)((char *)(ptr) - (char *) &((type *)0)->member) +#endif + +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +#define list_foreach(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +#define list_foreach_entry(pos, type, head, member) \ + for (pos = list_entry((head)->next, type, member);\ + &pos->member != (head); \ + pos = list_entry(pos->member.next, type, member)) -- 2.7.4