1 /* -*- mesa-c++ -*- 2 * 3 * Copyright (c) 2022 Collabora LTD 4 * 5 * Author: Gert Wollny <gert.wollny@collabora.com> 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * on the rights to use, copy, modify, merge, publish, distribute, sub 11 * license, and/or sell copies of the Software, and to permit persons to whom 12 * the Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the next 15 * paragraph) shall be included in all copies or substantial portions of the 16 * Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24 * USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26 27 #ifndef SFN_LIFERANGEEVALUATOR_HELPERS_H 28 #define SFN_LIFERANGEEVALUATOR_HELPERS_H 29 30 #include "sfn_valuefactory.h" 31 32 namespace r600 { 33 34 enum ProgramScopeType { 35 outer_scope, /* Outer program scope */ 36 loop_body, /* Inside a loop */ 37 if_branch, /* Inside if branch */ 38 else_branch, /* Inside else branch */ 39 switch_body, /* Inside switch statement */ 40 switch_case_branch, /* Inside switch case statement */ 41 switch_default_branch, /* Inside switch default statement */ 42 undefined_scope 43 }; 44 45 class ProgramScope { 46 public: 47 ProgramScope(); 48 ProgramScope(ProgramScope *parent, ProgramScopeType type, int id, int depth, int begin); 49 50 ProgramScopeType type() const; 51 ProgramScope *parent() const; 52 int nesting_depth() const; 53 int id() const; 54 int end() const; 55 int begin() const; 56 int loop_break_line() const; 57 58 const ProgramScope *in_else_scope() const; 59 const ProgramScope *in_ifelse_scope() const; 60 const ProgramScope *in_parent_ifelse_scope() const; 61 const ProgramScope *innermost_loop() const; 62 const ProgramScope *outermost_loop() const; 63 const ProgramScope *enclosing_conditional() const; 64 65 bool is_loop() const; 66 bool is_in_loop() const; 67 bool is_switchcase_scope_in_loop() const; 68 bool is_conditional() const; 69 bool is_child_of(const ProgramScope *scope) const; 70 bool is_child_of_ifelse_id_sibling(const ProgramScope *scope) const; 71 72 bool break_is_for_switchcase() const; 73 bool contains_range_of(const ProgramScope& other) const; 74 75 void set_end(int end); 76 void set_loop_break_line(int line); 77 78 private: 79 ProgramScopeType scope_type; 80 int scope_id; 81 int scope_nesting_depth; 82 int scope_begin; 83 int scope_end; 84 int break_loop_line; 85 ProgramScope *parent_scope; 86 }; 87 88 /* Class to track the access to a component of a temporary register. */ 89 90 struct LiveRange; 91 92 class RegisterCompAccess { 93 public: 94 RegisterCompAccess(); 95 RegisterCompAccess(LiveRange range); 96 97 void record_read(int block,int line, ProgramScope *scope, LiveRangeEntry::EUse use); 98 void record_write(int block, int line, ProgramScope *scope); 99 100 void update_required_live_range(); 101 range()102 const auto& range() { return m_range; } 103 use_type()104 const auto& use_type() { return m_use_type; } 105 alu_clause_local()106 auto alu_clause_local() { return alu_block_id > block_id_uninitalized;} 107 108 private: 109 void propagate_live_range_to_dominant_write_scope(); 110 bool conditional_ifelse_write_in_loop() const; 111 112 void record_ifelse_write(const ProgramScope& scope); 113 void record_if_write(const ProgramScope& scope); 114 void record_else_write(const ProgramScope& scope); 115 116 ProgramScope *last_read_scope; 117 ProgramScope *first_read_scope; 118 ProgramScope *first_write_scope; 119 120 int first_write; 121 int last_read; 122 int last_write; 123 int first_read; 124 125 int alu_block_id{block_id_uninitalized}; 126 127 /* This member variable tracks the current resolution of conditional writing 128 * to this temporary in IF/ELSE clauses. 129 * 130 * The initial value "conditionality_untouched" indicates that this 131 * temporary has not yet been written to within an if clause. 132 * 133 * A positive (other than "conditionality_untouched") number refers to the 134 * last loop id for which the write was resolved as unconditional. With 135 * each new loop this value will be overwritten by 136 * "conditionality_unresolved" on entering the first IF clause writing this 137 * temporary. 138 * 139 * The value "conditionality_unresolved" indicates that no resolution has 140 * been achieved so far. If the variable is set to this value at the end of 141 * the processing of the whole shader it also indicates a conditional 142 * write. 143 * 144 * The value "write_is_conditional" marks that the variable is written 145 * conditionally (i.e. not in all relevant IF/ELSE code path pairs) in at 146 * least one loop. 147 */ 148 int conditionality_in_loop_id; 149 150 /* Helper constants to make the tracking code more readable. */ 151 static const int write_is_conditional = -1; 152 static const int conditionality_unresolved = 0; 153 static const int conditionality_untouched; 154 static const int write_is_unconditional; 155 static const int block_id_not_unique = -1; 156 static const int block_id_uninitalized = 0; 157 158 /* A bit field tracking the nexting levels of if-else clauses where the 159 * temporary has (so far) been written to in the if branch, but not in the 160 * else branch. 161 */ 162 unsigned int if_scope_write_flags; 163 164 int next_ifelse_nesting_depth; 165 static const int supported_ifelse_nesting_depth = 32; 166 167 /* Tracks the last if scope in which the temporary was written to 168 * without a write in the corresponding else branch. Is also used 169 * to track read-before-write in the according scope. 170 */ 171 const ProgramScope *current_unpaired_if_write_scope; 172 173 /* Flag to resolve read-before-write in the else scope. */ 174 bool was_written_in_current_else_scope; 175 176 LiveRange m_range; 177 178 std::bitset<LiveRangeEntry::use_unspecified> m_use_type; 179 }; 180 181 class RegisterAccess { 182 public: 183 using RegisterCompAccessVector = std::vector<RegisterCompAccess>; 184 185 RegisterAccess(const std::array<size_t, 4>& sizes); 186 187 RegisterCompAccess& operator()(const Register& reg); 188 component(int i)189 auto& component(int i) { return m_access_record[i]; } 190 191 private: 192 std::array<RegisterCompAccessVector, 4> m_access_record; 193 }; 194 195 } // namespace r600 196 #endif // SFN_LIFERANGEEVALUATOR_HELPERS_H 197