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, 49 int depth, int begin); 50 51 ProgramScopeType type() const; 52 ProgramScope *parent() const; 53 int nesting_depth() const; 54 int id() const; 55 int end() const; 56 int begin() const; 57 int loop_break_line() const; 58 59 const ProgramScope *in_else_scope() const; 60 const ProgramScope *in_ifelse_scope() const; 61 const ProgramScope *in_parent_ifelse_scope() const; 62 const ProgramScope *innermost_loop() const; 63 const ProgramScope *outermost_loop() const; 64 const ProgramScope *enclosing_conditional() const; 65 66 bool is_loop() const; 67 bool is_in_loop() const; 68 bool is_switchcase_scope_in_loop() const; 69 bool is_conditional() const; 70 bool is_child_of(const ProgramScope *scope) const; 71 bool is_child_of_ifelse_id_sibling(const ProgramScope *scope) const; 72 73 bool break_is_for_switchcase() const; 74 bool contains_range_of(const ProgramScope& other) const; 75 76 void set_end(int end); 77 void set_loop_break_line(int line); 78 79 private: 80 ProgramScopeType scope_type; 81 int scope_id; 82 int scope_nesting_depth; 83 int scope_begin; 84 int scope_end; 85 int break_loop_line; 86 ProgramScope *parent_scope; 87 }; 88 89 /* Class to track the access to a component of a temporary register. */ 90 91 struct LiveRange; 92 93 class RegisterCompAccess { 94 public: 95 RegisterCompAccess(); 96 RegisterCompAccess(LiveRange range); 97 98 void record_read(int line, ProgramScope *scope, LiveRangeEntry::EUse use); 99 void record_write(int line, ProgramScope *scope); 100 101 void update_required_live_range(); 102 range()103 const auto& range() { return m_range;} 104 use_type()105 const auto& use_type() { return m_use_type; } 106 private: 107 void propagate_live_range_to_dominant_write_scope(); 108 bool conditional_ifelse_write_in_loop() const; 109 110 void record_ifelse_write(const ProgramScope& scope); 111 void record_if_write(const ProgramScope& scope); 112 void record_else_write(const ProgramScope& scope); 113 114 ProgramScope *last_read_scope; 115 ProgramScope *first_read_scope; 116 ProgramScope *first_write_scope; 117 118 int first_write; 119 int last_read; 120 int last_write; 121 int first_read; 122 123 /* This member variable tracks the current resolution of conditional writing 124 * to this temporary in IF/ELSE clauses. 125 * 126 * The initial value "conditionality_untouched" indicates that this 127 * temporary has not yet been written to within an if clause. 128 * 129 * A positive (other than "conditionality_untouched") number refers to the 130 * last loop id for which the write was resolved as unconditional. With each 131 * new loop this value will be overwitten by "conditionality_unresolved" 132 * on entering the first IF clause writing this temporary. 133 * 134 * The value "conditionality_unresolved" indicates that no resolution has 135 * been achieved so far. If the variable is set to this value at the end of 136 * the processing of the whole shader it also indicates a conditional write. 137 * 138 * The value "write_is_conditional" marks that the variable is written 139 * conditionally (i.e. not in all relevant IF/ELSE code path pairs) in at 140 * least one loop. 141 */ 142 int conditionality_in_loop_id; 143 144 /* Helper constants to make the tracking code more readable. */ 145 static const int write_is_conditional = -1; 146 static const int conditionality_unresolved = 0; 147 static const int conditionality_untouched; 148 static const int write_is_unconditional; 149 150 /* A bit field tracking the nexting levels of if-else clauses where the 151 * temporary has (so far) been written to in the if branch, but not in the 152 * else branch. 153 */ 154 unsigned int if_scope_write_flags; 155 156 int next_ifelse_nesting_depth; 157 static const int supported_ifelse_nesting_depth = 32; 158 159 /* Tracks the last if scope in which the temporary was written to 160 * without a write in the corresponding else branch. Is also used 161 * to track read-before-write in the according scope. 162 */ 163 const ProgramScope *current_unpaired_if_write_scope; 164 165 /* Flag to resolve read-before-write in the else scope. */ 166 bool was_written_in_current_else_scope; 167 168 LiveRange m_range; 169 170 std::bitset<LiveRangeEntry::use_unspecified> m_use_type; 171 }; 172 173 class RegisterAccess { 174 public: 175 using RegisterCompAccessVector = std::vector<RegisterCompAccess>; 176 177 RegisterAccess(const std::array<size_t, 4>& sizes); 178 179 RegisterCompAccess& operator() (const Register& reg); 180 component(int i)181 auto& component(int i) { return m_access_record[i]; } 182 183 private: 184 std::array<RegisterCompAccessVector, 4> m_access_record; 185 }; 186 187 } 188 #endif // SFN_LIFERANGEEVALUATOR_HELPERS_H 189