• 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,
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