mesa/src/gallium/drivers/r600/sfn/sfn_liverangeevaluator_help...

189 lines
6.3 KiB
C++

/* -*- mesa-c++ -*-
*
* Copyright (c) 2022 Collabora LTD
*
* Author: Gert Wollny <gert.wollny@collabora.com>
*
* 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
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS 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.
*/
#ifndef SFN_LIFERANGEEVALUATOR_HELPERS_H
#define SFN_LIFERANGEEVALUATOR_HELPERS_H
#include "sfn_valuefactory.h"
namespace r600 {
enum ProgramScopeType {
outer_scope, /* Outer program scope */
loop_body, /* Inside a loop */
if_branch, /* Inside if branch */
else_branch, /* Inside else branch */
switch_body, /* Inside switch statement */
switch_case_branch, /* Inside switch case statement */
switch_default_branch, /* Inside switch default statement */
undefined_scope
};
class ProgramScope {
public:
ProgramScope();
ProgramScope(ProgramScope *parent, ProgramScopeType type, int id,
int depth, int begin);
ProgramScopeType type() const;
ProgramScope *parent() const;
int nesting_depth() const;
int id() const;
int end() const;
int begin() const;
int loop_break_line() const;
const ProgramScope *in_else_scope() const;
const ProgramScope *in_ifelse_scope() const;
const ProgramScope *in_parent_ifelse_scope() const;
const ProgramScope *innermost_loop() const;
const ProgramScope *outermost_loop() const;
const ProgramScope *enclosing_conditional() const;
bool is_loop() const;
bool is_in_loop() const;
bool is_switchcase_scope_in_loop() const;
bool is_conditional() const;
bool is_child_of(const ProgramScope *scope) const;
bool is_child_of_ifelse_id_sibling(const ProgramScope *scope) const;
bool break_is_for_switchcase() const;
bool contains_range_of(const ProgramScope& other) const;
void set_end(int end);
void set_loop_break_line(int line);
private:
ProgramScopeType scope_type;
int scope_id;
int scope_nesting_depth;
int scope_begin;
int scope_end;
int break_loop_line;
ProgramScope *parent_scope;
};
/* Class to track the access to a component of a temporary register. */
struct LiveRange;
class RegisterCompAccess {
public:
RegisterCompAccess();
RegisterCompAccess(LiveRange range);
void record_read(int line, ProgramScope *scope, LiveRangeEntry::EUse use);
void record_write(int line, ProgramScope *scope);
void update_required_live_range();
const auto& range() { return m_range;}
const auto& use_type() { return m_use_type; }
private:
void propagate_live_range_to_dominant_write_scope();
bool conditional_ifelse_write_in_loop() const;
void record_ifelse_write(const ProgramScope& scope);
void record_if_write(const ProgramScope& scope);
void record_else_write(const ProgramScope& scope);
ProgramScope *last_read_scope;
ProgramScope *first_read_scope;
ProgramScope *first_write_scope;
int first_write;
int last_read;
int last_write;
int first_read;
/* This member variable tracks the current resolution of conditional writing
* to this temporary in IF/ELSE clauses.
*
* The initial value "conditionality_untouched" indicates that this
* temporary has not yet been written to within an if clause.
*
* A positive (other than "conditionality_untouched") number refers to the
* last loop id for which the write was resolved as unconditional. With each
* new loop this value will be overwitten by "conditionality_unresolved"
* on entering the first IF clause writing this temporary.
*
* The value "conditionality_unresolved" indicates that no resolution has
* been achieved so far. If the variable is set to this value at the end of
* the processing of the whole shader it also indicates a conditional write.
*
* The value "write_is_conditional" marks that the variable is written
* conditionally (i.e. not in all relevant IF/ELSE code path pairs) in at
* least one loop.
*/
int conditionality_in_loop_id;
/* Helper constants to make the tracking code more readable. */
static const int write_is_conditional = -1;
static const int conditionality_unresolved = 0;
static const int conditionality_untouched;
static const int write_is_unconditional;
/* A bit field tracking the nexting levels of if-else clauses where the
* temporary has (so far) been written to in the if branch, but not in the
* else branch.
*/
unsigned int if_scope_write_flags;
int next_ifelse_nesting_depth;
static const int supported_ifelse_nesting_depth = 32;
/* Tracks the last if scope in which the temporary was written to
* without a write in the corresponding else branch. Is also used
* to track read-before-write in the according scope.
*/
const ProgramScope *current_unpaired_if_write_scope;
/* Flag to resolve read-before-write in the else scope. */
bool was_written_in_current_else_scope;
LiveRange m_range;
std::bitset<LiveRangeEntry::use_unspecified> m_use_type;
};
class RegisterAccess {
public:
using RegisterCompAccessVector = std::vector<RegisterCompAccess>;
RegisterAccess(const std::array<size_t, 4>& sizes);
RegisterCompAccess& operator() (const Register& reg);
auto& component(int i) { return m_access_record[i]; }
private:
std::array<RegisterCompAccessVector, 4> m_access_record;
};
}
#endif // SFN_LIFERANGEEVALUATOR_HELPERS_H