• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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