diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2018-10-23 05:51:41 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2018-10-23 05:51:41 +0000 |
commit | 6cb9ed16dbefce87ec66640575ee58997b0770ca (patch) | |
tree | 22e63481f9ba42bdfdc80bad6f89703d72069d0b | |
parent | 88a8b3efd937a485138a2493e90645d2cb79f1cc (diff) |
Import Mesa 17.3.9
5 files changed, 854 insertions, 1724 deletions
diff --git a/lib/mesa/src/mesa/state_tracker/st_glsl_to_tgsi_private.cpp b/lib/mesa/src/mesa/state_tracker/st_glsl_to_tgsi_private.cpp index f259442cc..b664fa7ec 100644 --- a/lib/mesa/src/mesa/state_tracker/st_glsl_to_tgsi_private.cpp +++ b/lib/mesa/src/mesa/state_tracker/st_glsl_to_tgsi_private.cpp @@ -24,9 +24,8 @@ */ #include "st_glsl_to_tgsi_private.h" -#include "tgsi/tgsi_info.h" -#include "mesa/program/prog_instruction.h" -#include "mesa/program/prog_print.h" +#include <tgsi/tgsi_info.h> +#include <mesa/program/prog_instruction.h> static int swizzle_for_type(const glsl_type *type, int component = 0) { @@ -116,7 +115,7 @@ st_src_reg::st_src_reg(gl_register_file file, int index, enum glsl_base_type typ this->is_double_vertex_input = false; } -void st_src_reg::reset() +st_src_reg::st_src_reg() { this->type = GLSL_TYPE_ERROR; this->file = PROGRAM_UNDEFINED; @@ -133,11 +132,6 @@ void st_src_reg::reset() this->is_double_vertex_input = false; } -st_src_reg::st_src_reg() -{ - reset(); -} - st_src_reg::st_src_reg(const st_src_reg ®) { *this = reg; @@ -185,80 +179,6 @@ st_src_reg st_src_reg::get_abs() return reg; } -bool operator == (const st_src_reg& lhs, const st_src_reg& rhs) -{ - bool result; - - if (lhs.type != rhs.type || - lhs.file != rhs.file || - lhs.index != rhs.index || - lhs.swizzle != rhs.swizzle || - lhs.index2D != rhs.index2D || - lhs.has_index2 != rhs.has_index2 || - lhs.array_id != rhs.array_id || - lhs.negate != rhs.negate || - lhs.abs != rhs.abs || - lhs.double_reg2 != rhs.double_reg2 || - lhs.is_double_vertex_input != rhs.is_double_vertex_input) - return false; - - if (lhs.reladdr) { - if (!rhs.reladdr) - return false; - result = (*lhs.reladdr == *rhs.reladdr); - } else { - result = !rhs.reladdr; - } - - if (lhs.reladdr2) { - if (!rhs.reladdr2) - return false; - result &= (*lhs.reladdr2 == *rhs.reladdr2); - } else { - result &= !rhs.reladdr2; - } - - return result; -} - -static const char swz_txt[] = "xyzw"; - -std::ostream& operator << (std::ostream& os, const st_src_reg& reg) -{ - if (reg.negate) - os << "-"; - if (reg.abs) - os << "|"; - - os << _mesa_register_file_name(reg.file); - - if (reg.file == PROGRAM_ARRAY) { - os << "(" << reg.array_id << ")"; - } - if (reg.has_index2) { - os << "["; - if (reg.reladdr2) { - os << *reg.reladdr2; - } - os << "+" << reg.index2D << "]"; - } - os << "["; - if (reg.reladdr) { - os << *reg.reladdr; - } - os << reg.index << "]."; - for (int i = 0; i < 4; ++i) { - int swz = GET_SWZ(reg.swizzle, i); - if (swz < 4) - os << swz_txt[swz]; - else - os << "_"; - } - if (reg.abs) - os << "|"; - return os; -} - st_dst_reg::st_dst_reg(st_src_reg reg) { this->type = reg.type; @@ -330,94 +250,3 @@ void st_dst_reg::operator=(const st_dst_reg ®) this->has_index2 = reg.has_index2; this->array_id = reg.array_id; } - -bool operator == (const st_dst_reg& lhs, const st_dst_reg& rhs) -{ - bool result; - - if (lhs.type != rhs.type || - lhs.file != rhs.file || - lhs.index != rhs.index || - lhs.writemask != rhs.writemask || - lhs.index2D != rhs.index2D || - lhs.has_index2 != rhs.has_index2 || - lhs.array_id != rhs.array_id) - return false; - - if (lhs.reladdr) { - if (!rhs.reladdr) - return false; - result = (*lhs.reladdr == *rhs.reladdr); - } else { - result = !rhs.reladdr; - } - - if (lhs.reladdr2) { - if (!rhs.reladdr2) - return false; - result &= (*lhs.reladdr2 == *rhs.reladdr2); - } else { - result &= !rhs.reladdr2; - } - - return result; -} - -std::ostream& operator << (std::ostream& os, const st_dst_reg& reg) -{ - os << _mesa_register_file_name(reg.file); - if (reg.file == PROGRAM_ARRAY) { - os << "(" << reg.array_id << ")"; - } - if (reg.has_index2) { - os << "["; - if (reg.reladdr2) { - os << *reg.reladdr2; - } - os << "+" << reg.index2D << "]"; - } - os << "["; - if (reg.reladdr) { - os << *reg.reladdr; - } - os << reg.index << "]."; - for (int i = 0; i < 4; ++i) { - if (1 << i & reg.writemask) - os << swz_txt[i]; - else - os << "_"; - } - - return os; -} - -void glsl_to_tgsi_instruction::print(std::ostream& os) const -{ - os << tgsi_get_opcode_name(info->opcode) << " "; - - bool has_operators = false; - for (unsigned j = 0; j < num_inst_dst_regs(this); j++) { - has_operators = true; - if (j > 0) - os << ", "; - os << dst[j]; - } - - if (has_operators) - os << " := "; - - for (unsigned j = 0; j < num_inst_src_regs(this); j++) { - if (j > 0) - os << ", "; - os << src[j]; - } - - if (tex_offset_num_offset > 0) { - os << ", TEXOFS: "; - for (unsigned j = 0; j < tex_offset_num_offset; j++) { - if (j > 0) - os << ", "; - os << tex_offsets[j]; - } - } -} diff --git a/lib/mesa/src/mesa/state_tracker/st_glsl_to_tgsi_private.h b/lib/mesa/src/mesa/state_tracker/st_glsl_to_tgsi_private.h index 19dfa952e..d57525d9c 100644 --- a/lib/mesa/src/mesa/state_tracker/st_glsl_to_tgsi_private.h +++ b/lib/mesa/src/mesa/state_tracker/st_glsl_to_tgsi_private.h @@ -26,12 +26,10 @@ #ifndef ST_GLSL_TO_TGSI_PRIVATE_H #define ST_GLSL_TO_TGSI_PRIVATE_H -#include "mesa/main/mtypes.h" -#include "program/prog_parameter.h" -#include "compiler/glsl_types.h" -#include "compiler/glsl/ir.h" -#include "tgsi/tgsi_info.h" -#include <ostream> +#include <mesa/main/mtypes.h> +#include <compiler/glsl_types.h> +#include <compiler/glsl/ir.h> +#include <tgsi/tgsi_info.h> int swizzle_for_size(int size); @@ -51,7 +49,6 @@ public: st_src_reg(); st_src_reg(const st_src_reg ®); void operator=(const st_src_reg ®); - void reset(); explicit st_src_reg(st_dst_reg reg); @@ -63,9 +60,9 @@ public: uint16_t swizzle; /**< SWIZZLE_XYZWONEZERO swizzles from Mesa. */ int negate:4; /**< NEGATE_XYZW mask from mesa */ unsigned abs:1; - enum glsl_base_type type:6; /** GLSL_TYPE_* from GLSL IR (enum glsl_base_type) */ + enum glsl_base_type type:5; /** GLSL_TYPE_* from GLSL IR (enum glsl_base_type) */ unsigned has_index2:1; - gl_register_file file:6; /**< PROGRAM_* from Mesa */ + gl_register_file file:5; /**< PROGRAM_* from Mesa */ /* * Is this the second half of a double register pair? * currently used for input mapping only. @@ -87,10 +84,6 @@ public: } }; -bool operator == (const st_src_reg& lhs, const st_src_reg& rhs); - -std::ostream& operator << (std::ostream& os, const st_src_reg& reg); - class st_dst_reg { public: st_dst_reg(gl_register_file file, int writemask, enum glsl_base_type type, int index); @@ -105,9 +98,9 @@ public: int32_t index; /**< temporary index, VERT_ATTRIB_*, VARYING_SLOT_*, etc. */ int16_t index2D; - gl_register_file file:6; /**< PROGRAM_* from Mesa */ + gl_register_file file:5; /**< PROGRAM_* from Mesa */ unsigned writemask:4; /**< Bitfield of WRITEMASK_[XYZW] */ - enum glsl_base_type type:6; /** GLSL_TYPE_* from GLSL IR (enum glsl_base_type) */ + enum glsl_base_type type:5; /** GLSL_TYPE_* from GLSL IR (enum glsl_base_type) */ unsigned has_index2:1; unsigned array_id:10; @@ -116,11 +109,6 @@ public: st_src_reg *reladdr2; }; -bool operator == (const st_dst_reg& lhs, const st_dst_reg& rhs); - -std::ostream& operator << (std::ostream& os, const st_dst_reg& reg); - - class glsl_to_tgsi_instruction : public exec_node { public: DECLARE_RALLOC_CXX_OPERATORS(glsl_to_tgsi_instruction) @@ -133,34 +121,23 @@ public: /** Pointer to the ir source this tree came fe02549fdrom for debugging */ ir_instruction *ir; - enum tgsi_opcode op:10; /**< TGSI opcode */ + unsigned op:8; /**< TGSI opcode */ unsigned precise:1; unsigned saturate:1; unsigned is_64bit_expanded:1; unsigned sampler_base:5; unsigned sampler_array_size:6; /**< 1-based size of sampler array, 1 if not array */ - gl_texture_index tex_target:5; - glsl_base_type tex_type:6; + unsigned tex_target:4; /**< One of TEXTURE_*_INDEX */ + glsl_base_type tex_type:5; unsigned tex_shadow:1; - enum pipe_format image_format:10; + unsigned image_format:9; unsigned tex_offset_num_offset:3; unsigned dead_mask:4; /**< Used in dead code elimination */ - unsigned buffer_access:3; /**< bitmask of TGSI_MEMORY_x bits */ - unsigned read_only:1; - unsigned gather_component:2; /* 0, 1, 2, 3 */ + unsigned buffer_access:3; /**< buffer access type */ const struct tgsi_opcode_info *info; - - void print(std::ostream& os) const; }; -inline std::ostream& -operator << (std::ostream& os, const glsl_to_tgsi_instruction& instr) -{ - instr.print(os); - return os; -} - struct rename_reg_pair { bool valid; int new_reg; @@ -182,10 +159,6 @@ is_resource_instruction(unsigned opcode) case TGSI_OPCODE_ATOMUMAX: case TGSI_OPCODE_ATOMIMIN: case TGSI_OPCODE_ATOMIMAX: - case TGSI_OPCODE_ATOMFADD: - case TGSI_OPCODE_ATOMINC_WRAP: - case TGSI_OPCODE_ATOMDEC_WRAP: - case TGSI_OPCODE_IMG2HND: return true; default: return false; diff --git a/lib/mesa/src/mesa/state_tracker/st_glsl_to_tgsi_temprename.cpp b/lib/mesa/src/mesa/state_tracker/st_glsl_to_tgsi_temprename.cpp index 32cde9fc3..76c198e16 100644 --- a/lib/mesa/src/mesa/state_tracker/st_glsl_to_tgsi_temprename.cpp +++ b/lib/mesa/src/mesa/state_tracker/st_glsl_to_tgsi_temprename.cpp @@ -22,11 +22,9 @@ */ #include "st_glsl_to_tgsi_temprename.h" -#include "st_glsl_to_tgsi_array_merge.h" -#include "tgsi/tgsi_info.h" -#include "tgsi/tgsi_strings.h" -#include "program/prog_instruction.h" -#include "util/bitscan.h" +#include <tgsi/tgsi_info.h> +#include <tgsi/tgsi_strings.h> +#include <program/prog_instruction.h> #include <limits> #include <cstdlib> @@ -39,11 +37,10 @@ #ifndef NDEBUG #include <iostream> #include <iomanip> -#include "program/prog_print.h" -#include "util/debug.h" +#include <program/prog_print.h> +#include <util/debug.h> using std::cerr; using std::setw; -using std::ostream; #endif /* If <windows.h> is included this is defined and clashes with @@ -62,9 +59,6 @@ using std::numeric_limits; #endif #ifndef NDEBUG -/* Prepare to make it possible to specify log file */ -static std::ostream& debug_log = cerr; - /* Helper function to check whether we want to seen debugging output */ static inline bool is_debug_enabled () { @@ -104,19 +98,15 @@ public: int begin() const; int loop_break_line() const; - const prog_scope *in_else_scope() const; const prog_scope *in_ifelse_scope() const; - const prog_scope *in_parent_ifelse_scope() const; + const prog_scope *in_switchcase_scope() const; const prog_scope *innermost_loop() const; const prog_scope *outermost_loop() const; const prog_scope *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 prog_scope *scope) const; - bool is_child_of_ifelse_id_sibling(const prog_scope *scope) const; bool break_is_for_switchcase() const; bool contains_range_of(const prog_scope& other) const; @@ -147,91 +137,31 @@ private: prog_scope *storage; }; -/* Class to track the access to a component of a temporary register. */ - class temp_comp_access { public: temp_comp_access(); - void record_read(int line, prog_scope *scope); void record_write(int line, prog_scope *scope); - register_live_range get_required_live_range(); + lifetime get_required_lifetime(); private: - void propagate_live_range_to_dominant_write_scope(); - bool conditional_ifelse_write_in_loop() const; - - void record_ifelse_write(const prog_scope& scope); - void record_if_write(const prog_scope& scope); - void record_else_write(const prog_scope& scope); + void propagate_lifetime_to_dominant_write_scope(); prog_scope *last_read_scope; prog_scope *first_read_scope; prog_scope *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 correspondig else branch. Is also used - * to track read-before-write in the according scope. - */ - const prog_scope *current_unpaired_if_write_scope; - - /* Flag to resolve read-before-write in the else scope. */ - bool was_written_in_current_else_scope; + bool keep_for_full_loop; }; -const int -temp_comp_access::conditionality_untouched = numeric_limits<int>::max(); - -const int -temp_comp_access::write_is_unconditional = numeric_limits<int>::max() - 1; - -/* Class to track the access to all components of a temporary register. */ class temp_access { public: temp_access(); void record_read(int line, prog_scope *scope, int swizzle); void record_write(int line, prog_scope *scope, int writemask); - register_live_range get_required_live_range(); + lifetime get_required_lifetime(); private: void update_access_mask(int mask); @@ -240,27 +170,6 @@ private: bool needs_component_tracking; }; -/* Class to track array access. - * Compared to the temporary tracking this is very simplified, mainly because - * with the likely indirect access one can not really establish access - * patterns for individual elements. Instead the life range evaluation is - * always for the whole array, handles only loops and the fact whether a - * value was accessed conditionally in a loop. - */ -class array_access { -public: - array_access(); - void record_access(int line, prog_scope *scope, int swizzle); - void get_required_live_range(array_live_range &lr); -private: - int first_access; - int last_access; - prog_scope *first_access_scope; - prog_scope *last_access_scope; - unsigned accumulated_swizzle:4; - int conditional_access_in_loop:1; -}; - prog_scope_storage::prog_scope_storage(void *mc, int n): mem_ctx(mc), current_slot(0) @@ -349,32 +258,6 @@ const prog_scope *prog_scope::outermost_loop() const return loop; } -bool prog_scope::is_child_of_ifelse_id_sibling(const prog_scope *scope) const -{ - const prog_scope *my_parent = in_parent_ifelse_scope(); - while (my_parent) { - /* is a direct child? */ - if (my_parent == scope) - return false; - /* is a child of the conditions sibling? */ - if (my_parent->id() == scope->id()) - return true; - my_parent = my_parent->in_parent_ifelse_scope(); - } - return false; -} - -bool prog_scope::is_child_of(const prog_scope *scope) const -{ - const prog_scope *my_parent = parent(); - while (my_parent) { - if (my_parent == scope) - return true; - my_parent = my_parent->parent(); - } - return false; -} - const prog_scope *prog_scope::enclosing_conditional() const { if (is_conditional()) @@ -399,44 +282,30 @@ bool prog_scope::is_conditional() const scope_type == switch_default_branch; } -const prog_scope *prog_scope::in_else_scope() const +const prog_scope *prog_scope::in_ifelse_scope() const { - if (scope_type == else_branch) + if (scope_type == if_branch || + scope_type == else_branch) return this; if (parent_scope) - return parent_scope->in_else_scope(); + return parent_scope->in_ifelse_scope(); return nullptr; } -const prog_scope *prog_scope::in_parent_ifelse_scope() const +const prog_scope *prog_scope::in_switchcase_scope() const { - if (parent_scope) - return parent_scope->in_ifelse_scope(); - else - return nullptr; -} - -const prog_scope *prog_scope::in_ifelse_scope() const -{ - if (scope_type == if_branch || - scope_type == else_branch) + if (scope_type == switch_case_branch || + scope_type == switch_default_branch) return this; if (parent_scope) - return parent_scope->in_ifelse_scope(); + return parent_scope->in_switchcase_scope(); return nullptr; } -bool prog_scope::is_switchcase_scope_in_loop() const -{ - return (scope_type == switch_case_branch || - scope_type == switch_default_branch) && - is_in_loop(); -} - bool prog_scope::break_is_for_switchcase() const { if (scope_type == loop_body) @@ -516,8 +385,13 @@ void temp_access::record_write(int line, prog_scope *scope, int writemask) comp[3].record_write(line, scope); } -void temp_access::record_read(int line, prog_scope *scope, int readmask) +void temp_access::record_read(int line, prog_scope *scope, int swizzle) { + int readmask = 0; + for (int idx = 0; idx < 4; ++idx) { + int swz = GET_SWZ(swizzle, idx); + readmask |= (1 << swz) & 0xF; + } update_access_mask(readmask); if (readmask & WRITEMASK_X) @@ -530,102 +404,22 @@ void temp_access::record_read(int line, prog_scope *scope, int readmask) comp[3].record_read(line, scope); } -array_access::array_access(): - first_access(-1), - last_access(-1), - first_access_scope(nullptr), - last_access_scope(nullptr), - accumulated_swizzle(0), - conditional_access_in_loop(false) -{ -} - -void array_access::record_access(int line, prog_scope *scope, int swizzle) +inline static lifetime make_lifetime(int b, int e) { - if (!first_access_scope) { - first_access = line; - first_access_scope = scope; - } - last_access_scope = scope; - last_access = line; - accumulated_swizzle |= swizzle; - if (scope->in_ifelse_scope() && scope->innermost_loop()) - conditional_access_in_loop = true; -} - -void array_access::get_required_live_range(array_live_range& lr) -{ - RENAME_DEBUG(debug_log << "first_access_scope=" << first_access_scope << "\n"); - RENAME_DEBUG(debug_log << "last_access_scope=" << last_access_scope << "\n"); - - if (first_access_scope == last_access_scope) { - lr.set_live_range(first_access, last_access); - lr.set_access_mask(accumulated_swizzle); - return; - } - - const prog_scope *shared_scope = first_access_scope; - const prog_scope *other_scope = last_access_scope; - - assert(shared_scope); - RENAME_DEBUG(debug_log << "shared_scope=" << shared_scope << "\n"); - - if (conditional_access_in_loop) { - const prog_scope *help = shared_scope->outermost_loop(); - if (help) { - shared_scope = help; - } else { - help = other_scope->outermost_loop(); - if (help) - other_scope = help; - } - if (first_access > shared_scope->begin()) - first_access = shared_scope->begin(); - if (last_access < shared_scope->end()) - last_access = shared_scope->end(); - } - - /* See if any of the two is the parent of the other. */ - if (other_scope->contains_range_of(*shared_scope)) { - shared_scope = other_scope; - } else while (!shared_scope->contains_range_of(*other_scope)) { - assert(shared_scope->parent()); - if (shared_scope->type() == loop_body) { - if (last_access < shared_scope->end()) - last_access = shared_scope->end(); - } - shared_scope = shared_scope->parent(); - } - - while (shared_scope != other_scope) { - if (other_scope->type() == loop_body) { - if (last_access < other_scope->end()) - last_access = other_scope->end(); - } - other_scope = other_scope->parent(); - } - - lr.set_live_range(first_access, last_access); - lr.set_access_mask(accumulated_swizzle); -} - - -inline static register_live_range make_live_range(int b, int e) -{ - register_live_range lt; + lifetime lt; lt.begin = b; lt.end = e; return lt; } -register_live_range temp_access::get_required_live_range() +lifetime temp_access::get_required_lifetime() { - register_live_range result = make_live_range(-1, -1); + lifetime result = make_lifetime(-1, -1); unsigned mask = access_mask; while (mask) { unsigned chan = u_bit_scan(&mask); - register_live_range lt = comp[chan].get_required_live_range(); + lifetime lt = comp[chan].get_required_lifetime(); if (lt.begin >= 0) { if ((result.begin < 0) || (result.begin > lt.begin)) @@ -648,12 +442,7 @@ temp_comp_access::temp_comp_access(): first_write(-1), last_read(-1), last_write(-1), - first_read(numeric_limits<int>::max()), - conditionality_in_loop_id(conditionality_untouched), - if_scope_write_flags(0), - next_ifelse_nesting_depth(0), - current_unpaired_if_write_scope(nullptr), - was_written_in_current_else_scope(false) + first_read(numeric_limits<int>::max()) { } @@ -666,51 +455,6 @@ void temp_comp_access::record_read(int line, prog_scope *scope) first_read = line; first_read_scope = scope; } - - /* If the conditionality of the first write is already resolved then - * no further checks are required. - */ - if (conditionality_in_loop_id == write_is_unconditional || - conditionality_in_loop_id == write_is_conditional) - return; - - /* Check whether we are in a condition within a loop */ - const prog_scope *ifelse_scope = scope->in_ifelse_scope(); - const prog_scope *enclosing_loop; - if (ifelse_scope && (enclosing_loop = ifelse_scope->innermost_loop())) { - - /* If we have either not yet written to this register nor writes are - * resolved as unconditional in the enclosing loop then check whether - * we read before write in an IF/ELSE branch. - */ - if ((conditionality_in_loop_id != write_is_conditional) && - (conditionality_in_loop_id != enclosing_loop->id())) { - - if (current_unpaired_if_write_scope) { - - /* Has been written in this or a parent scope? - this makes the temporary - * unconditionally set at this point. - */ - if (scope->is_child_of(current_unpaired_if_write_scope)) - return; - - /* Has been written in the same scope before it was read? */ - if (ifelse_scope->type() == if_branch) { - if (current_unpaired_if_write_scope->id() == scope->id()) - return; - } else { - if (was_written_in_current_else_scope) - return; - } - } - - /* The temporary was read (conditionally) before it is written, hence - * it should survive a loop. This can be signaled like if it were - * conditionally written. - */ - conditionality_in_loop_id = write_is_conditional; - } - } } void temp_comp_access::record_write(int line, prog_scope *scope) @@ -720,164 +464,10 @@ void temp_comp_access::record_write(int line, prog_scope *scope) if (first_write < 0) { first_write = line; first_write_scope = scope; - - /* If the first write we encounter is not in a conditional branch, or - * the conditional write is not within a loop, then this is to be - * considered an unconditional dominant write. - */ - const prog_scope *conditional = scope->enclosing_conditional(); - if (!conditional || !conditional->innermost_loop()) { - conditionality_in_loop_id = write_is_unconditional; - } - } - - /* The conditionality of the first write is already resolved. */ - if (conditionality_in_loop_id == write_is_unconditional || - conditionality_in_loop_id == write_is_conditional) - return; - - /* If the nesting depth is larger than the supported level, - * then we assume conditional writes. - */ - if (next_ifelse_nesting_depth >= supported_ifelse_nesting_depth) { - conditionality_in_loop_id = write_is_conditional; - return; - } - - /* If we are in an IF/ELSE scope within a loop and the loop has not - * been resolved already, then record this write. - */ - const prog_scope *ifelse_scope = scope->in_ifelse_scope(); - if (ifelse_scope && ifelse_scope->innermost_loop() && - ifelse_scope->innermost_loop()->id() != conditionality_in_loop_id) - record_ifelse_write(*ifelse_scope); -} - -void temp_comp_access::record_ifelse_write(const prog_scope& scope) -{ - if (scope.type() == if_branch) { - /* The first write in an IF branch within a loop implies unresolved - * conditionality (if it was untouched or unconditional before). - */ - conditionality_in_loop_id = conditionality_unresolved; - was_written_in_current_else_scope = false; - record_if_write(scope); - } else { - was_written_in_current_else_scope = true; - record_else_write(scope); } } -void temp_comp_access::record_if_write(const prog_scope& scope) -{ - /* Don't record write if this IF scope if it ... - * - is not the first write in this IF scope, - * - has already been written in a parent IF scope. - * In both cases this write is a secondary write that doesn't contribute - * to resolve conditionality. - * - * Record the write if it - * - is the first one (obviously), - * - happens in an IF branch that is a child of the ELSE branch of the - * last active IF/ELSE pair. In this case recording this write is used to - * established whether the write is (un-)conditional in the scope enclosing - * this outer IF/ELSE pair. - */ - if (!current_unpaired_if_write_scope || - (current_unpaired_if_write_scope->id() != scope.id() && - scope.is_child_of_ifelse_id_sibling(current_unpaired_if_write_scope))) { - if_scope_write_flags |= 1 << next_ifelse_nesting_depth; - current_unpaired_if_write_scope = &scope; - next_ifelse_nesting_depth++; - } -} - -void temp_comp_access::record_else_write(const prog_scope& scope) -{ - int mask = 1 << (next_ifelse_nesting_depth - 1); - - /* If the temporary was written in an IF branch on the same scope level - * and this branch is the sibling of this ELSE branch, then we have a - * pair of writes that makes write access to this temporary unconditional - * in the enclosing scope. - */ - - if ((if_scope_write_flags & mask) && - (scope.id() == current_unpaired_if_write_scope->id())) { - --next_ifelse_nesting_depth; - if_scope_write_flags &= ~mask; - - /* The following code deals with propagating unconditionality from - * inner levels of nested IF/ELSE to the outer levels like in - * - * 1: var t; - * 2: if (a) { <- start scope A - * 3: if (b) - * 4: t = ... - * 5: else - * 6: t = ... - * 7: } else { <- start scope B - * 8: if (c) - * 9: t = ... - * A: else <- start scope C - * B: t = ... - * C: } - * - */ - - const prog_scope *parent_ifelse = scope.parent()->in_ifelse_scope(); - - if (1 << (next_ifelse_nesting_depth - 1) & if_scope_write_flags) { - /* We are at the end of scope C and already recorded a write - * within an IF scope (A), the sibling of the parent ELSE scope B, - * and it is not yet resolved. Mark that as the last relevant - * IF scope. Below the write will be resolved for the A/B - * scope pair. - */ - current_unpaired_if_write_scope = parent_ifelse; - } else { - current_unpaired_if_write_scope = nullptr; - } - /* Promote the first write scope to the enclosing scope because - * the current IF/ELSE pair is now irrelevant for the analysis. - * This is also required to evaluate the minimum life time for t in - * { - * var t; - * if (a) - * t = ... - * else - * t = ... - * x = t; - * ... - * } - */ - first_write_scope = scope.parent(); - - /* If some parent is IF/ELSE and in a loop then propagate the - * write to that scope. Otherwise the write is unconditional - * because it happens in both corresponding IF/ELSE branches - * in this loop, and hence, record the loop id to signal the - * resolution. - */ - if (parent_ifelse && parent_ifelse->is_in_loop()) { - record_ifelse_write(*parent_ifelse); - } else { - conditionality_in_loop_id = scope.innermost_loop()->id(); - } - } else { - /* The temporary was not written in the IF branch corresponding - * to this ELSE branch, hence the write is conditional. - */ - conditionality_in_loop_id = write_is_conditional; - } -} - -bool temp_comp_access::conditional_ifelse_write_in_loop() const -{ - return conditionality_in_loop_id <= conditionality_unresolved; -} - -void temp_comp_access::propagate_live_range_to_dominant_write_scope() +void temp_comp_access::propagate_lifetime_to_dominant_write_scope() { first_write = first_write_scope->begin(); int lr = first_write_scope->end(); @@ -886,7 +476,7 @@ void temp_comp_access::propagate_live_range_to_dominant_write_scope() last_read = lr; } -register_live_range temp_comp_access::get_required_live_range() +lifetime temp_comp_access::get_required_lifetime() { bool keep_for_full_loop = false; @@ -896,7 +486,7 @@ register_live_range temp_comp_access::get_required_live_range() * eliminating registers that are not written to. */ if (last_write < 0) - return make_live_range(-1, -1); + return make_lifetime(-1, -1); assert(first_write_scope); @@ -904,7 +494,7 @@ register_live_range temp_comp_access::get_required_live_range() * reused in the range it is used to write to */ if (!last_read_scope) - return make_live_range(first_write, last_write + 1); + return make_lifetime(first_write, last_write + 1); const prog_scope *enclosing_scope_first_read = first_read_scope; const prog_scope *enclosing_scope_first_write = first_write_scope; @@ -918,15 +508,15 @@ register_live_range temp_comp_access::get_required_live_range() enclosing_scope_first_read = first_read_scope->outermost_loop(); } - /* A conditional write within a (nested) loop must survive the outermost - * loop if the last read was not within the same scope. + /* A conditional write within a nested loop must survive + * the outermost loop, but only if it is read outside + * the condition scope where we write. */ const prog_scope *conditional = enclosing_scope_first_write->enclosing_conditional(); - if (conditional && !conditional->contains_range_of(*last_read_scope) && - (conditional->is_switchcase_scope_in_loop() || - conditional_ifelse_write_in_loop())) { - keep_for_full_loop = true; - enclosing_scope_first_write = conditional->outermost_loop(); + if (conditional && conditional->is_in_loop() && + !conditional->contains_range_of(*last_read_scope)) { + keep_for_full_loop = true; + enclosing_scope_first_write = conditional->outermost_loop(); } /* Evaluate the scope that is shared by all: required first write scope, @@ -948,7 +538,7 @@ register_live_range temp_comp_access::get_required_live_range() /* Propagate the last read scope to the target scope */ while (enclosing_scope->nesting_depth() < last_read_scope->nesting_depth()) { /* If the read is in a loop and we have to move up the scope we need to - * extend the live range to the end of this current loop because at this + * extend the life time to the end of this current loop because at this * point we don't know whether the component was written before * un-conditionally in the same loop. */ @@ -959,176 +549,75 @@ register_live_range temp_comp_access::get_required_live_range() } /* If the variable has to be kept for the whole loop, and we - * are currently in a loop, then propagate the live range. + * are currently in a loop, then propagate the life time. */ if (keep_for_full_loop && first_write_scope->is_loop()) - propagate_live_range_to_dominant_write_scope(); + propagate_lifetime_to_dominant_write_scope(); /* Propagate the first_dominant_write scope to the target scope */ while (enclosing_scope->nesting_depth() < first_write_scope->nesting_depth()) { - /* Propagate live_range if there was a break in a loop and the write was + /* Propagate lifetime if there was a break in a loop and the write was * after the break inside that loop. Note, that this is only needed if * we move up in the scopes. */ if (first_write_scope->loop_break_line() < first_write) { keep_for_full_loop = true; - propagate_live_range_to_dominant_write_scope(); + propagate_lifetime_to_dominant_write_scope(); } first_write_scope = first_write_scope->parent(); - /* Propagte live_range if we are now in a loop */ + /* Propagte lifetime if we are now in a loop */ if (keep_for_full_loop && first_write_scope->is_loop()) - propagate_live_range_to_dominant_write_scope(); + propagate_lifetime_to_dominant_write_scope(); } /* The last write past the last read is dead code, but we have to * ensure that the component is not reused too early, hence extend the - * live_range past the last write. + * lifetime past the last write. */ if (last_write >= last_read) last_read = last_write + 1; /* Here we are at the same scope, all is resolved */ - return make_live_range(first_write, last_read); + return make_lifetime(first_write, last_read); } /* Helper class for sorting and searching the registers based - * on live ranges. */ -class register_merge_record { + * on life times. */ +class access_record { public: int begin; int end; int reg; bool erase; - bool operator < (const register_merge_record& rhs) const { + bool operator < (const access_record& rhs) const { return begin < rhs.begin; } }; -class access_recorder { -public: - access_recorder(int _ntemps, int _narrays); - ~access_recorder(); - - void record_read(const st_src_reg& src, int line, prog_scope *scope); - void record_write(const st_dst_reg& src, int line, prog_scope *scope, - bool no_reswizzle); - - void get_required_live_ranges(register_live_range *register_live_ranges, - array_live_range *array_live_ranges); -private: - - int ntemps; - int narrays; - temp_access *temp_acc; - array_access *array_acc; -}; - -access_recorder::access_recorder(int _ntemps, int _narrays): - ntemps(_ntemps), - narrays(_narrays) -{ - temp_acc = new temp_access[ntemps]; - array_acc = new array_access[narrays]; -} - -access_recorder::~access_recorder() -{ - delete[] array_acc; - delete[] temp_acc; -} - -void access_recorder::record_read(const st_src_reg& src, int line, - prog_scope *scope) -{ - int readmask = 0; - for (int idx = 0; idx < 4; ++idx) { - int swz = GET_SWZ(src.swizzle, idx); - readmask |= (1 << swz) & 0xF; - } - - if (src.file == PROGRAM_TEMPORARY) - temp_acc[src.index].record_read(line, scope, readmask); - - if (src.file == PROGRAM_ARRAY) { - assert(src.array_id <= narrays); - array_acc[src.array_id - 1].record_access(line, scope, readmask); - } - - if (src.reladdr) - record_read(*src.reladdr, line, scope); - if (src.reladdr2) - record_read(*src.reladdr2, line, scope); -} - -void access_recorder::record_write(const st_dst_reg& dst, int line, - prog_scope *scope, bool can_reswizzle) -{ - if (dst.file == PROGRAM_TEMPORARY) - temp_acc[dst.index].record_write(line, scope, dst.writemask); - - if (dst.file == PROGRAM_ARRAY) { - assert(dst.array_id <= narrays); - - /* If the array is written as dst of a multi-dst operation, we must not - * reswizzle the access, because we would have to reswizzle also the - * other dst. For now just fill the mask to make interleaving impossible. - */ - array_acc[dst.array_id - 1].record_access(line, scope, - can_reswizzle ? dst.writemask: 0xF); - } - - if (dst.reladdr) - record_read(*dst.reladdr, line, scope); - if (dst.reladdr2) - record_read(*dst.reladdr2, line, scope); -} - -void access_recorder::get_required_live_ranges(struct register_live_range *register_live_ranges, - class array_live_range *array_live_ranges) -{ - RENAME_DEBUG(debug_log << "== register live ranges ==========\n"); - for(int i = 0; i < ntemps; ++i) { - RENAME_DEBUG(debug_log << setw(4) << i); - register_live_ranges[i] = temp_acc[i].get_required_live_range(); - RENAME_DEBUG(debug_log << ": [" << register_live_ranges[i].begin << ", " - << register_live_ranges[i].end << "]\n"); - } - RENAME_DEBUG(debug_log << "==================================\n\n"); - - RENAME_DEBUG(debug_log << "== array live ranges ==========\n"); - for(int i = 0; i < narrays; ++i) { - RENAME_DEBUG(debug_log<< setw(4) << i); - array_acc[i].get_required_live_range(array_live_ranges[i]); - RENAME_DEBUG(debug_log << ": [" <<array_live_ranges[i].begin() << ", " - << array_live_ranges[i].end() << "]\n"); - } - RENAME_DEBUG(debug_log << "==================================\n\n"); -} - } #ifndef NDEBUG /* Function used for debugging. */ -static void dump_instruction(ostream& os, int line, prog_scope *scope, +static void dump_instruction(int line, prog_scope *scope, const glsl_to_tgsi_instruction& inst); #endif -/* Scan the program and estimate the required register live ranges. - * The arraylive_ranges must be pre-allocated +/* Scan the program and estimate the required register life times. + * The array lifetimes must be pre-allocated */ bool -get_temp_registers_required_live_ranges(void *mem_ctx, exec_list *instructions, - int ntemps, struct register_live_range *register_live_ranges, - int narrays, class array_live_range *array_live_ranges) +get_temp_registers_required_lifetimes(void *mem_ctx, exec_list *instructions, + int ntemps, struct lifetime *lifetimes) { int line = 0; - int loop_id = 1; - int if_id = 1; + int loop_id = 0; + int if_id = 0; int switch_id = 0; bool is_at_end = false; + bool ok = true; int n_scopes = 1; /* Count scopes to allocate the needed space without the need for @@ -1146,12 +635,11 @@ get_temp_registers_required_live_ranges(void *mem_ctx, exec_list *instructions, } prog_scope_storage scopes(mem_ctx, n_scopes); - - access_recorder access(ntemps, narrays); + temp_access *acc = new temp_access[ntemps]; prog_scope *cur_scope = scopes.create(nullptr, outer_scope, 0, 0, line); - RENAME_DEBUG(debug_log << "========= Begin shader ============\n"); + RENAME_DEBUG(cerr << "========= Begin shader ============\n"); foreach_in_list(glsl_to_tgsi_instruction, inst, instructions) { if (is_at_end) { @@ -1159,7 +647,7 @@ get_temp_registers_required_live_ranges(void *mem_ctx, exec_list *instructions, break; } - RENAME_DEBUG(dump_instruction(debug_log, line, cur_scope, *inst)); + RENAME_DEBUG(dump_instruction(line, cur_scope, *inst)); switch (inst->op) { case TGSI_OPCODE_BGNLOOP: { @@ -1176,7 +664,9 @@ get_temp_registers_required_live_ranges(void *mem_ctx, exec_list *instructions, case TGSI_OPCODE_IF: case TGSI_OPCODE_UIF: { assert(num_inst_src_regs(inst) == 1); - access.record_read(inst->src[0], line, cur_scope); + const st_src_reg& src = inst->src[0]; + if (src.file == PROGRAM_TEMPORARY) + acc[src.index].record_read(line, cur_scope, src.swizzle); cur_scope = scopes.create(cur_scope, if_branch, if_id++, cur_scope->nesting_depth() + 1, line + 1); break; @@ -1202,12 +692,14 @@ get_temp_registers_required_live_ranges(void *mem_ctx, exec_list *instructions, } case TGSI_OPCODE_SWITCH: { assert(num_inst_src_regs(inst) == 1); + const st_src_reg& src = inst->src[0]; prog_scope *scope = scopes.create(cur_scope, switch_body, switch_id++, cur_scope->nesting_depth() + 1, line); /* We record the read only for the SWITCH statement itself, like it * is used by the only consumer of TGSI_OPCODE_SWITCH in tgsi_exec.c. */ - access.record_read(inst->src[0], line, cur_scope); + if (src.file == PROGRAM_TEMPORARY) + acc[src.index].record_read(line, cur_scope, src.swizzle); cur_scope = scope; break; } @@ -1229,9 +721,11 @@ get_temp_registers_required_live_ranges(void *mem_ctx, exec_list *instructions, cur_scope : cur_scope->parent(); assert(num_inst_src_regs(inst) == 1); - access.record_read(inst->src[0], line, switch_scope); + const st_src_reg& src = inst->src[0]; + if (src.file == PROGRAM_TEMPORARY) + acc[src.index].record_read(line, switch_scope, src.swizzle); - FALLTHROUGH; /* To allocate the scope. */ + /* Fall through to allocate the scope. */ } case TGSI_OPCODE_DEFAULT: { prog_scope_type t = inst->op == TGSI_OPCODE_CASE ? switch_case_branch @@ -1260,30 +754,35 @@ get_temp_registers_required_live_ranges(void *mem_ctx, exec_list *instructions, case TGSI_OPCODE_CAL: case TGSI_OPCODE_RET: /* These opcodes are not supported and if a subroutine would - * be called in a shader, then the live_range tracking would have + * be called in a shader, then the lifetime tracking would have * to follow that call to see which registers are used there. * Since this is not done, we have to bail out here and signal * that no register merge will take place. */ - return false; + ok = false; + goto out; default: { for (unsigned j = 0; j < num_inst_src_regs(inst); j++) { - access.record_read(inst->src[j], line, cur_scope); + const st_src_reg& src = inst->src[j]; + if (src.file == PROGRAM_TEMPORARY) + acc[src.index].record_read(line, cur_scope, src.swizzle); } for (unsigned j = 0; j < inst->tex_offset_num_offset; j++) { - access.record_read(inst->tex_offsets[j], line, cur_scope); + const st_src_reg& src = inst->tex_offsets[j]; + if (src.file == PROGRAM_TEMPORARY) + acc[src.index].record_read(line, cur_scope, src.swizzle); } - unsigned ndst = num_inst_dst_regs(inst); - for (unsigned j = 0; j < ndst; j++) { - access.record_write(inst->dst[j], line, cur_scope, ndst == 1); + for (unsigned j = 0; j < num_inst_dst_regs(inst); j++) { + const st_dst_reg& dst = inst->dst[j]; + if (dst.file == PROGRAM_TEMPORARY) + acc[dst.index].record_write(line, cur_scope, dst.writemask); } - access.record_read(inst->resource, line, cur_scope); } } ++line; } - RENAME_DEBUG(debug_log << "==================================\n\n"); + RENAME_DEBUG(cerr << "==================================\n\n"); /* Make sure last scope is closed, even though no * TGSI_OPCODE_END was given. @@ -1291,24 +790,34 @@ get_temp_registers_required_live_ranges(void *mem_ctx, exec_list *instructions, if (cur_scope->end() < 0) cur_scope->set_end(line - 1); - access.get_required_live_ranges(register_live_ranges, array_live_ranges); - return true; + RENAME_DEBUG(cerr << "========= lifetimes ==============\n"); + for(int i = 0; i < ntemps; ++i) { + RENAME_DEBUG(cerr << setw(4) << i); + lifetimes[i] = acc[i].get_required_lifetime(); + RENAME_DEBUG(cerr << ": [" << lifetimes[i].begin << ", " + << lifetimes[i].end << "]\n"); + } + RENAME_DEBUG(cerr << "==================================\n\n"); + +out: + delete[] acc; + return ok; } -/* Find the next register between [start, end) that has a live range starting +/* Find the next register between [start, end) that has a life time starting * at or after bound by using a binary search. * start points at the beginning of the search range, * end points at the element past the end of the search range, and * the array comprising [start, end) must be sorted in ascending order. */ -static register_merge_record* -find_next_rename(register_merge_record* start, register_merge_record* end, int bound) +static access_record* +find_next_rename(access_record* start, access_record* end, int bound) { int delta = (end - start); while (delta > 0) { int half = delta >> 1; - register_merge_record* middle = start + half; + access_record* middle = start + half; if (bound <= middle->begin) { delta = half; @@ -1323,9 +832,9 @@ find_next_rename(register_merge_record* start, register_merge_record* end, int b } #ifndef USE_STL_SORT -static int register_merge_record_compare (const void *a, const void *b) { - const register_merge_record *aa = static_cast<const register_merge_record*>(a); - const register_merge_record *bb = static_cast<const register_merge_record*>(b); +static int access_record_compare (const void *a, const void *b) { + const access_record *aa = static_cast<const access_record*>(a); + const access_record *bb = static_cast<const access_record*>(b); return aa->begin < bb->begin ? -1 : (aa->begin > bb->begin ? 1 : 0); } #endif @@ -1333,16 +842,16 @@ static int register_merge_record_compare (const void *a, const void *b) { /* This functions evaluates the register merges by using a binary * search to find suitable merge candidates. */ void get_temp_registers_remapping(void *mem_ctx, int ntemps, - const struct register_live_range *live_ranges, - struct rename_reg_pair *result) + const struct lifetime* lifetimes, + struct rename_reg_pair *result) { - register_merge_record *reg_access = ralloc_array(mem_ctx, register_merge_record, ntemps); + access_record *reg_access = ralloc_array(mem_ctx, access_record, ntemps); int used_temps = 0; for (int i = 0; i < ntemps; ++i) { - if (live_ranges[i].begin >= 0) { - reg_access[used_temps].begin =live_ranges[i].begin; - reg_access[used_temps].end =live_ranges[i].end; + if (lifetimes[i].begin >= 0) { + reg_access[used_temps].begin = lifetimes[i].begin; + reg_access[used_temps].end = lifetimes[i].end; reg_access[used_temps].reg = i; reg_access[used_temps].erase = false; ++used_temps; @@ -1352,17 +861,16 @@ void get_temp_registers_remapping(void *mem_ctx, int ntemps, #ifdef USE_STL_SORT std::sort(reg_access, reg_access + used_temps); #else - std::qsort(reg_access, used_temps, sizeof(register_merge_record), - register_merge_record_compare); + std::qsort(reg_access, used_temps, sizeof(access_record), access_record_compare); #endif - register_merge_record *trgt = reg_access; - register_merge_record *reg_access_end = reg_access + used_temps; - register_merge_record *first_erase = reg_access_end; - register_merge_record *search_start = trgt + 1; + access_record *trgt = reg_access; + access_record *reg_access_end = reg_access + used_temps; + access_record *first_erase = reg_access_end; + access_record *search_start = trgt + 1; while (trgt != reg_access_end) { - register_merge_record *src = find_next_rename(search_start, reg_access_end, + access_record *src = find_next_rename(search_start, reg_access_end, trgt->end); if (src != reg_access_end) { result[src->reg].new_reg = trgt->reg; @@ -1381,8 +889,8 @@ void get_temp_registers_remapping(void *mem_ctx, int ntemps, /* Moving to the next target register it is time to remove * the already merged registers from the search range */ if (first_erase != reg_access_end) { - register_merge_record *outp = first_erase; - register_merge_record *inp = first_erase + 1; + access_record *outp = first_erase; + access_record *inp = first_erase + 1; while (inp != reg_access_end) { if (!inp->erase) @@ -1402,11 +910,20 @@ void get_temp_registers_remapping(void *mem_ctx, int ntemps, /* Code below used for debugging */ #ifndef NDEBUG +static const char swizzle_txt[] = "xyzw"; + +static const char *tgsi_file_names[PROGRAM_FILE_MAX] = { + "TEMP", "ARRAY", "IN", "OUT", "STATE", "CONST", + "UNIFORM", "WO", "ADDR", "SAMPLER", "SV", "UNDEF", + "IMM", "BUF", "MEM", "IMAGE" +}; + static -void dump_instruction(ostream& os, int line, prog_scope *scope, +void dump_instruction(int line, prog_scope *scope, const glsl_to_tgsi_instruction& inst) { - const struct tgsi_opcode_info *info = inst.info; + const struct tgsi_opcode_info *info = tgsi_get_opcode_info(inst.op); + int indent = scope->nesting_depth(); if ((scope->type() == switch_case_branch || scope->type() == switch_default_branch) && @@ -1420,8 +937,74 @@ void dump_instruction(ostream& os, int line, prog_scope *scope, info->opcode == TGSI_OPCODE_ENDSWITCH) --indent; - os << setw(4) << line << ": "; - os << setw(indent * 4) << " "; - os << inst << "\n"; + cerr << setw(4) << line << ": "; + for (int i = 0; i < indent; ++i) + cerr << " "; + cerr << tgsi_get_opcode_name(info->opcode) << " "; + + bool has_operators = false; + for (unsigned j = 0; j < num_inst_dst_regs(&inst); j++) { + has_operators = true; + if (j > 0) + cerr << ", "; + + const st_dst_reg& dst = inst.dst[j]; + cerr << tgsi_file_names[dst.file]; + + if (dst.file == PROGRAM_ARRAY) + cerr << "(" << dst.array_id << ")"; + + cerr << "[" << dst.index << "]"; + + if (dst.writemask != TGSI_WRITEMASK_XYZW) { + cerr << "."; + if (dst.writemask & TGSI_WRITEMASK_X) cerr << "x"; + if (dst.writemask & TGSI_WRITEMASK_Y) cerr << "y"; + if (dst.writemask & TGSI_WRITEMASK_Z) cerr << "z"; + if (dst.writemask & TGSI_WRITEMASK_W) cerr << "w"; + } + } + if (has_operators) + cerr << " := "; + + for (unsigned j = 0; j < num_inst_src_regs(&inst); j++) { + if (j > 0) + cerr << ", "; + + const st_src_reg& src = inst.src[j]; + cerr << tgsi_file_names[src.file] + << "[" << src.index << "]"; + if (src.swizzle != SWIZZLE_XYZW) { + cerr << "."; + for (int idx = 0; idx < 4; ++idx) { + int swz = GET_SWZ(src.swizzle, idx); + if (swz < 4) { + cerr << swizzle_txt[swz]; + } + } + } + } + + if (inst.tex_offset_num_offset > 0) { + cerr << ", TEXOFS: "; + for (unsigned j = 0; j < inst.tex_offset_num_offset; j++) { + if (j > 0) + cerr << ", "; + + const st_src_reg& src = inst.tex_offsets[j]; + cerr << tgsi_file_names[src.file] + << "[" << src.index << "]"; + if (src.swizzle != SWIZZLE_XYZW) { + cerr << "."; + for (int idx = 0; idx < 4; ++idx) { + int swz = GET_SWZ(src.swizzle, idx); + if (swz < 4) { + cerr << swizzle_txt[swz]; + } + } + } + } + } + cerr << "\n"; } #endif diff --git a/lib/mesa/src/mesa/state_tracker/st_glsl_to_tgsi_temprename.h b/lib/mesa/src/mesa/state_tracker/st_glsl_to_tgsi_temprename.h index c70cd8881..3f21b1317 100644 --- a/lib/mesa/src/mesa/state_tracker/st_glsl_to_tgsi_temprename.h +++ b/lib/mesa/src/mesa/state_tracker/st_glsl_to_tgsi_temprename.h @@ -24,57 +24,48 @@ #ifndef MESA_GLSL_TO_TGSI_TEMPRENAME_H #define MESA_GLSL_TO_TGSI_TEMPRENAME_H -#include "st_glsl_to_tgsi_array_merge.h" +#include "st_glsl_to_tgsi_private.h" -/** Storage to record the required live range of a temporary register +/** Storage to record the required life time of a temporary register * begin == end == -1 indicates that the register can be reused without * limitations. Otherwise, "begin" indicates the first instruction in which * a write operation may target this temporary, and end indicates the * last instruction in which a value can be read from this temporary. * Hence, a register R2 can be merged with a register R1 if R1.end <= R2.begin. */ -struct register_live_range { +struct lifetime { int begin; int end; }; -/** Evaluates the required live ranges of temporary registers in a shader. - * The live range estimation can only be run sucessfully if the shader doesn't +/** Evaluates the required life times of temporary registers in a shader. + * The life time estimation can only be run sucessfully if the shader doesn't * call a subroutine. - * @param[in] mem_ctx a memory context that can be used with the ralloc_* - * functions + * @param[in] mem_ctx a memory context that can be used with the ralloc_* functions * @param[in] instructions the shader to be anlzyed * @param[in] ntemps number of temporaries reserved for this shader - * @param[in,out] reg_live_ranges memory location to store the estimated - * required live ranges for each temporary register. The parameter must - * point to allocated memory that can hold ntemps register_live_range - * structures. On output the live ranges contains the live ranges for - * the registers with the exception of TEMP[0] - * @param[in] narrays number of array sreserved for this shader - * @param[in,out] arr_live_ranges memory location to store the estimated required - * live ranges for each array. The parameter must point to allocated memory - * that can hold narrays array_live_range structures. On output the live - * ranges contains the live ranges for the registers with the exception of - * ARRAY[0]. + * @param[in,out] lifetimes memory location to store the estimated required + * life times for each temporary register. The parameter must point to + * allocated memory that can hold ntemps lifetime structures. On output + * the life times contains the life times for the registers with the + * exception of TEMP[0]. * @returns: true if the lifetimes were estimated, false if not (i.e. if a * subroutine was called). */ bool -get_temp_registers_required_live_ranges(void *mem_ctx, exec_list *instructions, - int ntemps, struct register_live_range *register_live_ranges, - int narrays, array_live_range *array_live_ranges); - +get_temp_registers_required_lifetimes(void *mem_ctx, exec_list *instructions, + int ntemps, struct lifetime *lifetimes); /** Estimate the merge remapping of the registers. - * @param[in] mem_ctx a memory context that can be used with the ralloc_* - * functions + * @param[in] mem_ctx a memory context that can be used with the ralloc_* functions * @param[in] ntemps number of temporaries reserved for this shader - * @param[in] reg_live_ranges required live range for each temporary register. + * @param[in] lifetimes required life time for each temporary register. * @param[in,out] result memory location to store the register remapping table. * On input the parameter must point to allocated memory that can hold the * renaming information for ntemps registers, on output the mapping is stored. * Note that TEMP[0] is not considered for register renaming. */ void get_temp_registers_remapping(void *mem_ctx, int ntemps, - const struct register_live_range* reg_live_ranges, - struct rename_reg_pair *result); + const struct lifetime* lifetimes, + struct rename_reg_pair *result); + #endif
\ No newline at end of file diff --git a/lib/mesa/src/mesa/state_tracker/tests/test_glsl_to_tgsi_lifetime.cpp b/lib/mesa/src/mesa/state_tracker/tests/test_glsl_to_tgsi_lifetime.cpp index 4b78ccb35..93f4020eb 100644 --- a/lib/mesa/src/mesa/state_tracker/tests/test_glsl_to_tgsi_lifetime.cpp +++ b/lib/mesa/src/mesa/state_tracker/tests/test_glsl_to_tgsi_lifetime.cpp @@ -21,43 +21,155 @@ * DEALINGS IN THE SOFTWARE. */ -#include "tgsi/tgsi_ureg.h" -#include "tgsi/tgsi_info.h" -#include "mesa/program/prog_instruction.h" +#include <state_tracker/st_glsl_to_tgsi_temprename.h> +#include <tgsi/tgsi_ureg.h> +#include <tgsi/tgsi_info.h> +#include <compiler/glsl/list.h> +#include <mesa/program/prog_instruction.h> -#include <gtest/gtest.h> #include <utility> -#include <algorithm> -#include <iostream> - -#include "st_tests_common.h" +#include <gtest/gtest.h> using std::vector; using std::pair; using std::make_pair; -using std::transform; -using std::copy; +/* A line to describe a TGSI instruction for building mock shaders. */ +struct MockCodeline { + MockCodeline(unsigned _op): op(_op) {} + MockCodeline(unsigned _op, const vector<int>& _dst, const vector<int>& _src, const vector<int>&_to): + op(_op), dst(_dst), src(_src), tex_offsets(_to){} + unsigned op; + vector<int> dst; + vector<int> src; + vector<int> tex_offsets; +}; + +/* A line to describe a TGSI instruction with swizzeling and write makss + * for building mock shaders. + */ +struct MockCodelineWithSwizzle { + MockCodelineWithSwizzle(unsigned _op): op(_op) {} + MockCodelineWithSwizzle(unsigned _op, const vector<pair<int,int>>& _dst, + const vector<pair<int, const char *>>& _src, + const vector<pair<int, const char *>>&_to): + op(_op), dst(_dst), src(_src), tex_offsets(_to){} + unsigned op; + vector<pair<int,int>> dst; + vector<pair<int, const char *>> src; + vector<pair<int, const char *>> tex_offsets; +}; + +/* A few constants that will notbe tracked as temporary registers by the + * mock shader. + */ +const int in0 = -1; +const int in1 = -2; +const int in2 = -3; + +const int out0 = -1; +const int out1 = -2; + +class MockShader { +public: + MockShader(const vector<MockCodeline>& source); + MockShader(const vector<MockCodelineWithSwizzle>& source); + ~MockShader(); + + void free(); + + exec_list* get_program() const; + int get_num_temps() const; +private: + st_src_reg create_src_register(int src_idx); + st_dst_reg create_dst_register(int dst_idx); + st_src_reg create_src_register(int src_idx, const char *swizzle); + st_dst_reg create_dst_register(int dst_idx,int writemask); + exec_list* program; + int num_temps; + void *mem_ctx; +}; + +using expectation = vector<vector<int>>; + +class MesaTestWithMemCtx : public testing::Test { + void SetUp(); + void TearDown(); +protected: + void *mem_ctx; +}; + +class LifetimeEvaluatorTest : public MesaTestWithMemCtx { +protected: + void run(const vector<MockCodeline>& code, const expectation& e); + void run(const vector<MockCodelineWithSwizzle>& code, const expectation& e); +private: + virtual void check(const vector<lifetime>& result, const expectation& e) = 0; +}; + +/* This is a test class to check the exact life times of + * registers. */ +class LifetimeEvaluatorExactTest : public LifetimeEvaluatorTest { +protected: + void check(const vector<lifetime>& result, const expectation& e); +}; + +/* This test class checks that the life time covers at least + * in the expected range. It is used for cases where we know that + * a the implementation could be improved on estimating the minimal + * life time. + */ +class LifetimeEvaluatorAtLeastTest : public LifetimeEvaluatorTest { +protected: + void check(const vector<lifetime>& result, const expectation& e); +}; + +/* With this test class the renaming mapping estimation is tested */ +class RegisterRemappingTest : public MesaTestWithMemCtx { +protected: + void run(const vector<lifetime>& lt, const vector<int>& expect); +}; + +/* With this test class the combined lifetime estimation and renaming + * mepping estimation is tested + */ +class RegisterLifetimeAndRemappingTest : public RegisterRemappingTest { +protected: + using RegisterRemappingTest::run; + template <typename CodeLine> + void run(const vector<CodeLine>& code, const vector<int>& expect); +}; + +template <typename CodeLine> +void RegisterLifetimeAndRemappingTest::run(const vector<CodeLine>& code, + const vector<int>& expect) +{ + MockShader shader(code); + std::vector<lifetime> lt(shader.get_num_temps()); + get_temp_registers_required_lifetimes(mem_ctx, shader.get_program(), + shader.get_num_temps(), <[0]); + this->run(lt, expect); +} TEST_F(LifetimeEvaluatorExactTest, SimpleMoveAdd) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_UADD, {out0}, {1,in0}, {}}, { TGSI_OPCODE_END} }; - run(code, temp_lt_expect({{-1,-1}, {0,1}})); + run(code, expectation({{-1,-1}, {0,1}})); } TEST_F(LifetimeEvaluatorExactTest, SimpleMoveAddMove) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_UADD, {2}, {1,in0}, {}}, { TGSI_OPCODE_MOV, {out0}, {2}, {}}, { TGSI_OPCODE_END} }; - run(code, temp_lt_expect({{-1, -1}, {0,1}, {1,2}})); + run(code, expectation({{-1, -1}, {0,1}, {1,2}})); } /* Test whether the texoffst are actually visited by the @@ -68,13 +180,13 @@ TEST_F(LifetimeEvaluatorExactTest, SimpleMoveAddMove) */ TEST_F(LifetimeEvaluatorExactTest, SimpleOpWithTexoffset) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_MOV, {2}, {in1}, {}}, { TGSI_OPCODE_TEX, {out0}, {in0}, {1,2}}, { TGSI_OPCODE_END} }; - run(code, temp_lt_expect({{-1, -1}, {0,2}, {1,2}})); + run(code, expectation({{-1, -1}, {0,2}, {1,2}})); } /* Simple register access involving a loop @@ -84,7 +196,7 @@ TEST_F(LifetimeEvaluatorExactTest, SimpleOpWithTexoffset) */ TEST_F(LifetimeEvaluatorExactTest, SimpleMoveInLoop) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_UADD, {2}, {1,in0}, {}}, @@ -94,7 +206,7 @@ TEST_F(LifetimeEvaluatorExactTest, SimpleMoveInLoop) { TGSI_OPCODE_MOV, {out0}, {3}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,5}, {2,3}, {3,6}})); + run (code, expectation({{-1,-1}, {0,5}, {2,3}, {3,6}})); } /* In loop if/else value written only in one path, and read later @@ -102,7 +214,7 @@ TEST_F(LifetimeEvaluatorExactTest, SimpleMoveInLoop) */ TEST_F(LifetimeEvaluatorExactTest, MoveInIfInLoop) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_IF, {}, {in1}, {}}, @@ -114,7 +226,7 @@ TEST_F(LifetimeEvaluatorExactTest, MoveInIfInLoop) { TGSI_OPCODE_MOV, {out0}, {3}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,7}, {1,7}, {5,8}})); + run (code, expectation({{-1,-1}, {0,7}, {1,7}, {5,8}})); } /* A non-dominant write within an IF can be ignored (if it is read @@ -122,7 +234,7 @@ TEST_F(LifetimeEvaluatorExactTest, MoveInIfInLoop) */ TEST_F(LifetimeEvaluatorExactTest, NonDominantWriteinIfInLoop) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_IF, {}, {in1}, {}}, @@ -136,7 +248,7 @@ TEST_F(LifetimeEvaluatorExactTest, NonDominantWriteinIfInLoop) { TGSI_OPCODE_MOV, {out0}, {2}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {1,5}, {5,10}})); + run (code, expectation({{-1,-1}, {1,5}, {5,10}})); } /* In Nested loop if/else value written only in one path, and read later @@ -144,7 +256,7 @@ TEST_F(LifetimeEvaluatorExactTest, NonDominantWriteinIfInLoop) */ TEST_F(LifetimeEvaluatorExactTest, MoveInIfInNestedLoop) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_BGNLOOP }, @@ -157,16 +269,16 @@ TEST_F(LifetimeEvaluatorExactTest, MoveInIfInNestedLoop) { TGSI_OPCODE_MOV, {out0}, {3}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,8}, {1,8}, {6,9}})); + run (code, expectation({{-1,-1}, {0,8}, {1,8}, {6,9}})); } /* In loop if/else value written in both path, and read later * - value must survive from first write to last read in loop * for now we only check that the minimum life time is correct. */ -TEST_F(LifetimeEvaluatorExactTest, WriteInIfAndElseInLoop) +TEST_F(LifetimeEvaluatorAtLeastTest, WriteInIfAndElseInLoop) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_IF, {}, {1}, {}}, @@ -180,16 +292,16 @@ TEST_F(LifetimeEvaluatorExactTest, WriteInIfAndElseInLoop) { TGSI_OPCODE_MOV, {out0}, {3}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,9}, {3,7}, {7,10}})); + run (code, expectation({{-1,-1}, {0,9}, {3,7}, {7,10}})); } -/* Test that read before write in ELSE path is properly tracked: - * In loop if/else value written in both path but read in else path - * before write and also read later - value must survive the whole loop. +/* In loop if/else value written in both path, read in else path + * before write and also read later + * - value must survive the whole loop */ TEST_F(LifetimeEvaluatorExactTest, WriteInIfAndElseReadInElseInLoop) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_IF, {}, {1}, {}}, @@ -203,138 +315,7 @@ TEST_F(LifetimeEvaluatorExactTest, WriteInIfAndElseReadInElseInLoop) { TGSI_OPCODE_MOV, {out0}, {3}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,9}, {1,9}, {7,10}})); -} - - -/* Test that a write in ELSE path only in loop is properly tracked: - * In loop if/else value written in else path and read outside - * - value must survive the whole loop. - */ -TEST_F(LifetimeEvaluatorExactTest, WriteInElseReadInLoop) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {1}, {}}, - { TGSI_OPCODE_UADD, {2}, {1,in0}, {}}, - { TGSI_OPCODE_ELSE }, - { TGSI_OPCODE_ADD, {3}, {1,2}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_UADD, {1}, {3,in1}, {}}, - { TGSI_OPCODE_ENDLOOP }, - { TGSI_OPCODE_MOV, {out0}, {1}, {}}, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {0,9}, {1,8}, {1,8}})); -} - -/* Test that tracking a second write in an ELSE path is not attributed - * to the IF path: In loop if/else value written in else path twice and - * read outside - value must survive the whole loop - */ -TEST_F(LifetimeEvaluatorExactTest, WriteInElseTwiceReadInLoop) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {1}, {}}, - { TGSI_OPCODE_UADD, {2}, {1,in0}, {}}, - { TGSI_OPCODE_ELSE }, - { TGSI_OPCODE_ADD, {3}, {1,2}, {}}, - { TGSI_OPCODE_ADD, {3}, {1,3}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_UADD, {1}, {3,in1}, {}}, - { TGSI_OPCODE_ENDLOOP }, - { TGSI_OPCODE_MOV, {out0}, {1}, {}}, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {0,10}, {1,9}, {1,9}})); -} - -/* Test that the IF and ELSE scopes from different IF/ELSE pairs are not - * merged: In loop if/else value written in if, and then in different else path - * and read outside - value must survive the whole loop - */ -TEST_F(LifetimeEvaluatorExactTest, WriteInOneIfandInAnotherElseInLoop) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {1}, {}}, - { TGSI_OPCODE_UADD, {2}, {1,in0}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_IF, {}, {1}, {}}, - { TGSI_OPCODE_ELSE }, - { TGSI_OPCODE_ADD, {2}, {1,1}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_UADD, {1}, {2,in1}, {}}, - { TGSI_OPCODE_ENDLOOP }, - { TGSI_OPCODE_MOV, {out0}, {1}, {}}, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {0,11}, {1,10}})); -} - -/* Test that with a new loop the resolution of the IF/ELSE write conditionality - * is restarted: In first loop value is written in both if and else, in second - * loop value is written only in if - must survive the second loop. - * However, the tracking is currently not able to restrict the lifetime - * in the first loop, hence the "AtLeast" test. - */ -TEST_F(LifetimeEvaluatorAtLeastTest, UnconditionalInFirstLoopConditionalInSecond) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {1}, {}}, - { TGSI_OPCODE_UADD, {2}, {1,in0}, {}}, - { TGSI_OPCODE_ELSE }, - { TGSI_OPCODE_UADD, {2}, {1,in1}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ENDLOOP }, - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {1}, {}}, - { TGSI_OPCODE_ADD, {2}, {in0,1}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_UADD, {1}, {2,in1}, {}}, - { TGSI_OPCODE_ENDLOOP }, - { TGSI_OPCODE_MOV, {out0}, {1}, {}}, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {0,14}, {3,13}})); -} - -/* Test that with a new loop the resolution of the IF/ELSE write conditionality - * is restarted, and also takes care of write before read in else scope: - * In first loop value is written in both if and else, in second loop value is - * also written in both, but first read in if - must survive the second loop. - * However, the tracking is currently not able to restrict the lifetime - * in the first loop, hence the "AtLeast" test. - */ -TEST_F(LifetimeEvaluatorAtLeastTest, UnconditionalInFirstLoopConditionalInSecond2) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {1}, {}}, - { TGSI_OPCODE_UADD, {2}, {1,in0}, {}}, - { TGSI_OPCODE_ELSE }, - { TGSI_OPCODE_UADD, {2}, {1,in1}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ENDLOOP }, - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {in1}, {}}, - { TGSI_OPCODE_ADD, {2}, {2,1}, {}}, - { TGSI_OPCODE_ELSE }, - { TGSI_OPCODE_MOV, {2}, {1}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_UADD, {1}, {2,in1}, {}}, - { TGSI_OPCODE_ENDLOOP }, - { TGSI_OPCODE_MOV, {out0}, {1}, {}}, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {0,16}, {3,15}})); + run (code, expectation({{-1,-1}, {0,9}, {1,9}, {7,10}})); } /* In loop if/else read in one path before written in the same loop @@ -342,7 +323,7 @@ TEST_F(LifetimeEvaluatorAtLeastTest, UnconditionalInFirstLoopConditionalInSecond */ TEST_F(LifetimeEvaluatorExactTest, ReadInIfInLoopBeforeWrite) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_IF, {}, {in0}, {}}, @@ -354,7 +335,7 @@ TEST_F(LifetimeEvaluatorExactTest, ReadInIfInLoopBeforeWrite) { TGSI_OPCODE_MOV, {out0}, {3}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,7}, {1,7}, {1,8}})); + run (code, expectation({{-1,-1}, {0,7}, {1,7}, {1,8}})); } /* In loop if/else read in one path before written in the same loop @@ -363,7 +344,7 @@ TEST_F(LifetimeEvaluatorExactTest, ReadInIfInLoopBeforeWrite) */ TEST_F(LifetimeEvaluatorExactTest, ReadInLoopInIfBeforeWriteAndLifeToTheEnd) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_IF, {}, {in0}, {}}, { TGSI_OPCODE_MUL, {1}, {1,in1}, {}}, @@ -373,16 +354,16 @@ TEST_F(LifetimeEvaluatorExactTest, ReadInLoopInIfBeforeWriteAndLifeToTheEnd) { TGSI_OPCODE_MOV, {out0}, {1}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,6}})); + run (code, expectation({{-1,-1}, {0,6}})); } -/* In loop read before written in the same loop read after the loop, - * value must survive the whole loop and to the read. - * This is kind of undefined behaviour though ... +/* In loop if/else read in one path before written in the same loop + * read after the loop, value must survivethe whole loop and + * to the read. */ TEST_F(LifetimeEvaluatorExactTest, ReadInLoopBeforeWriteAndLifeToTheEnd) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_MUL, {1}, {1,in1}, {}}, { TGSI_OPCODE_UADD, {1}, {1,in1}, {}}, @@ -390,17 +371,17 @@ TEST_F(LifetimeEvaluatorExactTest, ReadInLoopBeforeWriteAndLifeToTheEnd) { TGSI_OPCODE_MOV, {out0}, {1}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,4}})); + run (code, expectation({{-1,-1}, {0,4}})); } -/* Test whether nesting IF/ELSE pairs within a loop is resolved: - * Write in all conditional branches if the inner nesting level and - * read after the outer IF/ELSE pair is closed. The lifetime doesn't have - * to be extended to the full loop. + +/* Write in nested ifs in loop, for now we do test whether the + * life time is at least what is required, but we know that the + * implementation doesn't do a full check and sets larger boundaries */ -TEST_F(LifetimeEvaluatorExactTest, NestedIfInLoopAlwaysWriteButNotPropagated) +TEST_F(LifetimeEvaluatorAtLeastTest, NestedIfInLoopAlwaysWriteButNotPropagated) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_IF, {}, {in0}, {}}, { TGSI_OPCODE_IF, {}, {in0}, {}}, @@ -419,323 +400,24 @@ TEST_F(LifetimeEvaluatorExactTest, NestedIfInLoopAlwaysWriteButNotPropagated) { TGSI_OPCODE_ENDLOOP }, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {3,14}})); -} - -/* Test that nested chaining of IF/ELSE scopes is resolved: - * Write in each IF branch, and open another IF/ELSE scope pair in the ELSE - * branch. At the last nesting level, the temporary is also written in the - * ELSE branch, hence the full constrict results in an unconditional write. - */ -TEST_F(LifetimeEvaluatorExactTest, DeeplyNestedIfElseInLoopResolved) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ADD, {2}, {1, in1}, {}}, - { TGSI_OPCODE_ENDLOOP }, - { TGSI_OPCODE_MOV, {out0}, {2}, {}}, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {2,18}, {18, 20}})); + run (code, expectation({{-1,-1}, {3,14}})); } -/* The complementary case of the above: Open deeply nested IF/ELSE clauses - * and only at the deepest nesting level the temporary is written in the IF - * branch, but for all ELSE scopes the value is also written. Like above, when - * the full construct has been executed, the temporary has been written - * unconditionally. - */ -TEST_F(LifetimeEvaluatorExactTest, DeeplyNestedIfElseInLoopResolved2) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ADD, {2}, {1, in1}, {}}, - { TGSI_OPCODE_ENDLOOP }, - { TGSI_OPCODE_MOV, {out0}, {2}, {}}, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {5,18}, {18, 20}})); -} - -/* Test that a write in an IF scope within IF scope where the temporary already - * can be ignored. - */ -TEST_F(LifetimeEvaluatorExactTest, NestedIfElseInLoopResolvedInOuterScope) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ADD, {2}, {1, in1}, {}}, - { TGSI_OPCODE_ENDLOOP }, - { TGSI_OPCODE_MOV, {out0}, {2}, {}}, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {2,9}, {9, 11}})); -} - -/* Here the read before write in the nested if is of no consequence to the - * life time because the variable was already written in the enclosing if-branch. - */ -TEST_F(LifetimeEvaluatorExactTest, NestedIfElseInLoopWithReadResolvedInOuterScope) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_ADD, {1}, {in0, 1}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ADD, {2}, {1, in1}, {}}, - { TGSI_OPCODE_ENDLOOP }, - { TGSI_OPCODE_MOV, {out0}, {2}, {}}, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {2,9}, {9, 11}})); -} - -/* Here the nested if condition is of no consequence to the life time - * because the variable was already written in the enclosing else-branch. - */ -TEST_F(LifetimeEvaluatorExactTest, NestedIfElseInLoopResolvedInOuterScope2) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ADD, {2}, {1, in1}, {}}, - { TGSI_OPCODE_ENDLOOP }, - { TGSI_OPCODE_MOV, {out0}, {2}, {}}, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {2,9}, {9, 11}})); -} - -/* Test that tracking of IF/ELSE scopes does not unnessesarily cross loops, - * i.e. if the inner IF/ELSE pair is enclosed by a loop which is enclosed - * by another IF statement: The resolution of unconditionality of the write - * within the loop is not changed by the fact that the loop is enclosed by - * an IF scope. - */ -TEST_F(LifetimeEvaluatorExactTest, NestedIfInLoopAlwaysWriteParentIfOutsideLoop) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_MOV, {2}, {1}, {}}, - { TGSI_OPCODE_ENDLOOP }, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_MOV, {2}, {in1}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_MOV, {out0}, {2}, {}}, - - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {3,12}, {12, 17}})); -} - -/* The value is written in a loop and in a nested IF, but +/* The value is written in a loop and in a nested if, but * not in all code paths, hence the value must survive the loop. */ TEST_F(LifetimeEvaluatorExactTest, NestedIfInLoopWriteNotAlways) { - const vector<FakeCodeline> code = { - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_MOV, {out0}, {1}, {}}, - { TGSI_OPCODE_ENDLOOP }, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {0,13}})); -} - -/* Test that reading in an ELSE branach after writing is ignored: - * The value is written in a loop in both branches of if-else but also - * read in the else after writing, should have no effect on lifetime. - */ -TEST_F(LifetimeEvaluatorExactTest, IfElseWriteInLoopAlsoReadInElse) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_MOV, {1}, {in1}, {}}, - { TGSI_OPCODE_MUL, {1}, {in0, 1}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_MOV, {out0}, {1}, {}}, - { TGSI_OPCODE_ENDLOOP }, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {2,7}})); -} - -/* Test that a write in an inner IF/ELSE pair is propagated to the outer - * ELSE branch: The value is written in a loop in both branches of a nested - * IF/ELSE pair, but only within the outer else, hence in summary the write is - * conditional within the loop. - */ -TEST_F(LifetimeEvaluatorExactTest, WriteInNestedIfElseOuterElseOnly) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_ADD, {1}, {in1, in0}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_MOV, {out0}, {1}, {}}, - { TGSI_OPCODE_ENDLOOP }, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {0,10}})); -} - -/* Test that reads in an inner ELSE after write within the enclosing IF branch - * is of no consequence (i.e. check that the read in the ELSE branch is not - * attributed as read before write when the outer ELSE branch is scanned: - * Nested if-else in loop. The value is written in the outer if and else and - * read in one inner else, should limit lifetime. - */ -TEST_F(LifetimeEvaluatorExactTest, WriteUnconditionallyReadInNestedElse) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_MOV, {out1}, {1}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_MOV, {out0}, {1}, {}}, - { TGSI_OPCODE_ENDLOOP }, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {2,10}})); -} - - -/* Nested if-else in loop. The value is written in a loop in both branches - * of if-else but also read in the second nested else before writing. - * Is conditional. - */ -TEST_F(LifetimeEvaluatorExactTest, NestedIfelseReadFirstInInnerElseInLoop) -{ - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_IF, {}, {in0}, {}}, { TGSI_OPCODE_IF, {}, {in0}, {}}, { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_MOV, {1}, {in1}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_ADD, {1}, {in1, 1}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_MOV, {out0}, {1}, {}}, - { TGSI_OPCODE_ENDLOOP }, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {0,15}})); -} - -/* Test that read before write is properly tracked for nested IF branches. - * The value is written in a loop in both branches of IF/ELSE but also read in - * the second nested IF before writing - is conditional. - */ -TEST_F(LifetimeEvaluatorExactTest, NestedIfelseReadFirstInInnerIfInLoop) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_IF, {}, {in0}, {}}, { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_MOV, {1}, {in1}, {}}, { TGSI_OPCODE_ENDIF}, { TGSI_OPCODE_ELSE}, { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_ADD, {1}, {in1, 1}, {}}, - { TGSI_OPCODE_ELSE}, { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_ENDIF}, { TGSI_OPCODE_ENDIF}, @@ -743,111 +425,13 @@ TEST_F(LifetimeEvaluatorExactTest, NestedIfelseReadFirstInInnerIfInLoop) { TGSI_OPCODE_ENDLOOP }, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,15}})); -} - -/* Same as above, but for the secondary ELSE branch: - * The value is written in a loop in both branches of IF/ELSE but also read in - * the second nested ELSE branch before writing - is conditional. - */ -TEST_F(LifetimeEvaluatorExactTest, WriteInOneElseBranchReadFirstInOtherInLoop) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_MOV, {1}, {in1}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_ADD, {1}, {in1, 1}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_MOV, {out0}, {1}, {}}, - { TGSI_OPCODE_ENDLOOP }, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {2,11}})); -} - -/* Test that the "write is unconditional" resolution is not overwritten within - * a loop: The value is written in a loop in both branches of an IF/ELSE clause, - * hence the second IF doesn't make it conditional. - */ -TEST_F(LifetimeEvaluatorExactTest, WriteInIfElseBranchSecondIfInLoop) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_MOV, {1}, {in1}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_IF, {}, {in0}, {}}, - { TGSI_OPCODE_MOV, {1}, {in0}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_MOV, {out0}, {1}, {}}, - { TGSI_OPCODE_ENDLOOP }, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {2,9}})); -} - -/* Within an IF clause within a loop test that if a write occured in both - * branches of a nested IF/ELSE clause, followed by the last read within the - * enclosing IF or ELSE clause, the combined read is registered as unconditional, - * i.e.that it doesn't extend its live range beyond that enclosing IF or ELSE - * clause. - */ -TEST_F(LifetimeEvaluatorExactTest, DeeplyNestedinLoop) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_UIF, {}, {in0}, {}}, - { TGSI_OPCODE_FSEQ, {1}, {in1,in2}, {}}, - { TGSI_OPCODE_UIF, {}, {1}, {}}, - { TGSI_OPCODE_MOV, {2}, {in1}, {}}, - { TGSI_OPCODE_ELSE }, - { TGSI_OPCODE_MOV, {2}, {in2}, {}}, - { TGSI_OPCODE_ENDIF }, - { TGSI_OPCODE_MOV, {3}, {2}, {}}, - { TGSI_OPCODE_ENDIF }, - { TGSI_OPCODE_ADD, {out0}, {3, in1}, {}}, - { TGSI_OPCODE_ENDLOOP } - }; - run (code, temp_lt_expect({{-1,-1}, {2,3}, {4, 8}, {0,11}})); -} - -/** Regression test for bug #104803, - * Read and write in if/else path outside loop and later read in conditional - * within a loop. The first write is to be considered the dominant write. - */ -TEST_F(LifetimeEvaluatorExactTest, IfElseWriteInBothOutsideLoopReadInElseInLoop) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_IF, {}, {in0}, {} }, - { TGSI_OPCODE_MOV, {1}, {in0}, {} }, - { TGSI_OPCODE_ELSE, {}, {}, {} }, - { TGSI_OPCODE_MOV, {1}, {in1}, {} }, - { TGSI_OPCODE_ENDIF, {}, {}, {} }, - { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {in0}, {} }, - { TGSI_OPCODE_MOV, {2}, {in1}, {} }, - { TGSI_OPCODE_ELSE, {}, {}, {} }, - { TGSI_OPCODE_MOV, {2}, {1}, {} }, - { TGSI_OPCODE_ENDIF, {}, {}, {} }, - { TGSI_OPCODE_ENDLOOP }, - { TGSI_OPCODE_MOV, {out0}, {2}, {}}, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {1,11}, {7, 12}})); + run (code, expectation({{-1,-1}, {0,13}})); } /* A continue in the loop is not relevant */ TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterContinue) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_IF, {}, {in0}, {}}, { TGSI_OPCODE_CONT}, @@ -857,7 +441,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterContinue) { TGSI_OPCODE_MOV, {out0}, {1}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {4,6}})); + run (code, expectation({{-1,-1}, {4,6}})); } /* Temporary used to in case must live up to the case @@ -867,7 +451,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterContinue) */ TEST_F(LifetimeEvaluatorExactTest, UseSwitchCase) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_MOV, {2}, {in1}, {}}, { TGSI_OPCODE_MOV, {3}, {in2}, {}}, @@ -879,7 +463,7 @@ TEST_F(LifetimeEvaluatorExactTest, UseSwitchCase) { TGSI_OPCODE_ENDSWITCH}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,5}, {1,4}, {2,3}})); + run (code, expectation({{-1,-1}, {0,5}, {1,4}, {2,3}})); } /* With two destinations, if one result is thrown away, the @@ -887,14 +471,14 @@ TEST_F(LifetimeEvaluatorExactTest, UseSwitchCase) */ TEST_F(LifetimeEvaluatorExactTest, WriteTwoOnlyUseOne) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_DFRACEXP , {1,2}, {in0}, {}}, { TGSI_OPCODE_ADD , {3}, {2,in0}, {}}, { TGSI_OPCODE_MOV, {out1}, {3}, {}}, { TGSI_OPCODE_END}, }; - run (code, temp_lt_expect({{-1,-1}, {0,1}, {0,1}, {1,2}})); + run (code, expectation({{-1,-1}, {0,1}, {0,1}, {1,2}})); } /* If a break is in the loop, all variables written after the @@ -903,7 +487,7 @@ TEST_F(LifetimeEvaluatorExactTest, WriteTwoOnlyUseOne) */ TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterBreak) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_IF, {}, {in0}, {}}, { TGSI_OPCODE_BRK}, @@ -913,7 +497,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterBreak) { TGSI_OPCODE_MOV, {out0}, {1}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,6}})); + run (code, expectation({{-1,-1}, {0,6}})); } /* If a break is in the loop, all variables written after the @@ -922,7 +506,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterBreak) */ TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterBreak2Breaks) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_IF, {}, {in0}, {}}, { TGSI_OPCODE_BRK}, @@ -933,7 +517,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterBreak2Breaks) { TGSI_OPCODE_MOV, {out0}, {1}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,7}})); + run (code, expectation({{-1,-1}, {0,7}})); } /* Loop with a break at the beginning and read/write in the post @@ -945,7 +529,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterBreak2Breaks) */ TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAndReadAfterBreak) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_IF, {}, {in0}, {}}, { TGSI_OPCODE_BRK}, @@ -956,7 +540,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAndReadAfterBreak) { TGSI_OPCODE_MOV, {out0}, {2}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {4,5}, {0,7}})); + run (code, expectation({{-1,-1}, {4,5}, {0,7}})); } /* Same as above, just make sure that the life time of the local variable @@ -964,7 +548,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAndReadAfterBreak) */ TEST_F(LifetimeEvaluatorExactTest, NestedLoopWithWriteAndReadAfterBreak) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_IF, {}, {in1}, {}}, { TGSI_OPCODE_BRK}, @@ -982,7 +566,7 @@ TEST_F(LifetimeEvaluatorExactTest, NestedLoopWithWriteAndReadAfterBreak) { TGSI_OPCODE_MOV, {out0}, {4}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {8,9}, {0,13}, {11,12}, {0,14}})); + run (code, expectation({{-1,-1}, {8,9}, {0,13}, {11,12}, {0,14}})); } /* If a break is in the loop inside a switch case, make sure it is @@ -991,7 +575,7 @@ TEST_F(LifetimeEvaluatorExactTest, NestedLoopWithWriteAndReadAfterBreak) */ TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterBreakInSwitchInLoop) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_SWITCH, {}, {in1}, {}}, { TGSI_OPCODE_CASE, {}, {in1}, {}}, { TGSI_OPCODE_BGNLOOP }, @@ -1005,7 +589,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterBreakInSwitchInLoop) { TGSI_OPCODE_MOV, {out0}, {1}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {2,10}})); + run (code, expectation({{-1,-1}, {2,10}})); } /* Value written conditionally in one loop and read in another loop, @@ -1014,7 +598,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterBreakInSwitchInLoop) */ TEST_F(LifetimeEvaluatorExactTest, LoopsWithDifferntScopesConditionalWrite) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_IF, {}, {in0}, {}}, { TGSI_OPCODE_MOV, {1}, {in0}, {}}, @@ -1025,7 +609,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopsWithDifferntScopesConditionalWrite) { TGSI_OPCODE_ENDLOOP }, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,7}})); + run (code, expectation({{-1,-1}, {0,7}})); } /* Value written and read in one loop and last read in another loop, @@ -1033,7 +617,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopsWithDifferntScopesConditionalWrite) */ TEST_F(LifetimeEvaluatorExactTest, LoopsWithDifferntScopesFirstReadBeforeWrite) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_MUL, {1}, {1,in0}, {}}, { TGSI_OPCODE_ENDLOOP }, @@ -1042,7 +626,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopsWithDifferntScopesFirstReadBeforeWrite) { TGSI_OPCODE_ENDLOOP }, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,5}})); + run (code, expectation({{-1,-1}, {0,5}})); } @@ -1051,7 +635,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopsWithDifferntScopesFirstReadBeforeWrite) */ TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteInSwitch) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_SWITCH, {}, {in0}, {} }, { TGSI_OPCODE_CASE, {}, {in0}, {} }, @@ -1064,7 +648,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteInSwitch) { TGSI_OPCODE_ENDLOOP }, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,9}})); + run (code, expectation({{-1,-1}, {0,9}})); } /* Value written in one case, and read in other,in loop @@ -1072,7 +656,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteInSwitch) */ TEST_F(LifetimeEvaluatorExactTest, LoopWithReadWriteInSwitchDifferentCase) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_SWITCH, {}, {in0}, {} }, { TGSI_OPCODE_CASE, {}, {in0}, {} }, @@ -1085,7 +669,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopWithReadWriteInSwitchDifferentCase) { TGSI_OPCODE_ENDLOOP }, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,9}})); + run (code, expectation({{-1,-1}, {0,9}})); } /* Value written in one case, and read in other,in loop @@ -1093,7 +677,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopWithReadWriteInSwitchDifferentCase) */ TEST_F(LifetimeEvaluatorExactTest, LoopWithReadWriteInSwitchDifferentCaseFallThrough) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_SWITCH, {}, {in0}, {} }, { TGSI_OPCODE_CASE, {}, {in0}, {} }, @@ -1105,33 +689,34 @@ TEST_F(LifetimeEvaluatorExactTest, LoopWithReadWriteInSwitchDifferentCaseFallThr { TGSI_OPCODE_ENDLOOP }, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,8}})); + run (code, expectation({{-1,-1}, {0,8}})); } + /* Here we read and write from an to the same temp in the same instruction, * but the read is conditional (select operation), hence the lifetime must * start with the first write. */ TEST_F(LifetimeEvaluatorExactTest, WriteSelectFromSelf) { - const vector<FakeCodeline> code = { - { TGSI_OPCODE_USEQ, {5}, {in0,in1}, {}}, - { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}}, - { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}}, - { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}}, - { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}}, - { TGSI_OPCODE_FSLT, {2}, {1,in1}, {}}, - { TGSI_OPCODE_UIF, {}, {2}, {}}, - { TGSI_OPCODE_MOV, {3}, {in1}, {}}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_MOV, {4}, {in1}, {}}, - { TGSI_OPCODE_MOV, {4}, {4}, {}}, - { TGSI_OPCODE_MOV, {3}, {4}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_MOV, {out1}, {3}, {}}, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {1,5}, {5,6}, {7,13}, {9,11}, {0,4}})); + const vector<MockCodeline> code = { + {TGSI_OPCODE_USEQ, {5}, {in0,in1}, {}}, + {TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}}, + {TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}}, + {TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}}, + {TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}}, + {TGSI_OPCODE_FSLT, {2}, {1,in1}, {}}, + {TGSI_OPCODE_UIF, {}, {2}, {}}, + { TGSI_OPCODE_MOV, {3}, {in1}, {}}, + {TGSI_OPCODE_ELSE}, + { TGSI_OPCODE_MOV, {4}, {in1}, {}}, + { TGSI_OPCODE_MOV, {4}, {4}, {}}, + { TGSI_OPCODE_MOV, {3}, {4}, {}}, + {TGSI_OPCODE_ENDIF}, + {TGSI_OPCODE_MOV, {out1}, {3}, {}}, + {TGSI_OPCODE_END} + }; + run (code, expectation({{-1,-1}, {1,5}, {5,6}, {7,13}, {9,11}, {0,4}})); } /* This test checks wheter the ENDSWITCH is handled properly if the @@ -1139,7 +724,7 @@ TEST_F(LifetimeEvaluatorExactTest, WriteSelectFromSelf) */ TEST_F(LifetimeEvaluatorExactTest, LoopRWInSwitchCaseLastCaseWithoutBreak) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_SWITCH, {}, {in0}, {} }, { TGSI_OPCODE_CASE, {}, {in0}, {} }, @@ -1151,13 +736,13 @@ TEST_F(LifetimeEvaluatorExactTest, LoopRWInSwitchCaseLastCaseWithoutBreak) { TGSI_OPCODE_ENDLOOP }, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,8}})); + run (code, expectation({{-1,-1}, {0,8}})); } /* Value read/write in same case, stays there */ TEST_F(LifetimeEvaluatorExactTest, LoopWithReadWriteInSwitchSameCase) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_SWITCH, {}, {in0}, {} }, { TGSI_OPCODE_CASE, {}, {in0}, {} }, @@ -1170,7 +755,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopWithReadWriteInSwitchSameCase) { TGSI_OPCODE_ENDLOOP }, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {3,4}})); + run (code, expectation({{-1,-1}, {3,4}})); } /* Value read/write in all cases, should only live from first @@ -1178,7 +763,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopWithReadWriteInSwitchSameCase) */ TEST_F(LifetimeEvaluatorAtLeastTest, LoopWithReadWriteInSwitchSameCase) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_SWITCH, {}, {in0}, {}}, { TGSI_OPCODE_CASE, {}, {in0}, {} }, @@ -1192,13 +777,13 @@ TEST_F(LifetimeEvaluatorAtLeastTest, LoopWithReadWriteInSwitchSameCase) { TGSI_OPCODE_ENDLOOP }, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {3,9}})); + run (code, expectation({{-1,-1}, {3,9}})); } /* First read before first write with nested loops */ TEST_F(LifetimeEvaluatorExactTest, LoopsWithDifferentScopesCondReadBeforeWrite) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_IF, {}, {in0}, {}}, @@ -1211,7 +796,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopsWithDifferentScopesCondReadBeforeWrite) { TGSI_OPCODE_ENDLOOP }, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,9}})); + run (code, expectation({{-1,-1}, {0,9}})); } /* First read before first write wiredness with nested loops. @@ -1220,7 +805,7 @@ TEST_F(LifetimeEvaluatorExactTest, LoopsWithDifferentScopesCondReadBeforeWrite) */ TEST_F(LifetimeEvaluatorExactTest, FirstWriteAtferReadInNestedLoop) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_BGNLOOP }, @@ -1232,7 +817,7 @@ TEST_F(LifetimeEvaluatorExactTest, FirstWriteAtferReadInNestedLoop) { TGSI_OPCODE_MOV, {out0}, {3}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,7}, {1,7}, {4,8}})); + run (code, expectation({{-1,-1}, {0,7}, {1,7}, {4,8}})); } @@ -1246,83 +831,82 @@ TEST_F(LifetimeEvaluatorExactTest, FirstWriteAtferReadInNestedLoop) */ TEST_F(LifetimeEvaluatorExactTest, LoopWithConditionalComponentWrite_X) { - const vector<FakeCodeline> code = { - { TGSI_OPCODE_BGNLOOP}, - { TGSI_OPCODE_MOV, DST(1, WRITEMASK_Y), SRC(in1, "x"), {}, SWZ()}, - { TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}, SWZ()}, - { TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "y"), {}, SWZ()}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_MOV, DST(2, WRITEMASK_XY), SRC(1, "xy"), {}, SWZ()}, - { TGSI_OPCODE_ENDLOOP}, - { TGSI_OPCODE_MOV, DST(out0, WRITEMASK_XYZW), SRC(2, "xyxy"), {}, SWZ()}, - { TGSI_OPCODE_END} + const vector<MockCodelineWithSwizzle> code = { + MockCodelineWithSwizzle(TGSI_OPCODE_BGNLOOP), + MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(1, WRITEMASK_Y), SRC(in1, "x"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "y"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_ENDIF), + MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(2, WRITEMASK_XY), SRC(1, "xy"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_ENDLOOP), + MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(out0, WRITEMASK_XYZW), SRC(2, "xyxy"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_END) }; - run (code, temp_lt_expect({{-1,-1}, {0,6}, {5,7}})); + run (code, expectation({{-1,-1}, {0,6}, {5,7}})); } TEST_F(LifetimeEvaluatorExactTest, LoopWithConditionalComponentWrite_Y) { - const vector<FakeCodeline> code = { - { TGSI_OPCODE_BGNLOOP}, - { TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "x"), {}, SWZ()}, - { TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}, SWZ()}, - { TGSI_OPCODE_MOV, DST(1, WRITEMASK_Y), SRC(in1, "y"), {}, SWZ()}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_MOV, DST(2, WRITEMASK_XY), SRC(1, "xy"), {}, SWZ()}, - { TGSI_OPCODE_ENDLOOP}, - { TGSI_OPCODE_MOV, DST(out0, WRITEMASK_XYZW), SRC(2, "xyxy"), {}, SWZ()}, - { TGSI_OPCODE_END} + const vector<MockCodelineWithSwizzle> code = { + MockCodelineWithSwizzle(TGSI_OPCODE_BGNLOOP), + MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "x"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(1, WRITEMASK_Y), SRC(in1, "y"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_ENDIF), + MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(2, WRITEMASK_XY), SRC(1, "xy"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_ENDLOOP), + MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(out0, WRITEMASK_XYZW), SRC(2, "xyxy"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_END) }; - run (code, temp_lt_expect({{-1,-1}, {0,6}, {5,7}})); + run (code, expectation({{-1,-1}, {0,6}, {5,7}})); } TEST_F(LifetimeEvaluatorExactTest, LoopWithConditionalComponentWrite_Z) { - const vector<FakeCodeline> code = { - { TGSI_OPCODE_BGNLOOP}, - { TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "x"), {}, SWZ()}, - { TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}, SWZ()}, - { TGSI_OPCODE_MOV, DST(1, WRITEMASK_Z), SRC(in1, "y"), {}, SWZ()}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_MOV, DST(2, WRITEMASK_XY), SRC(1, "xz"), {}, SWZ()}, - { TGSI_OPCODE_ENDLOOP}, - { TGSI_OPCODE_MOV, DST(out0, WRITEMASK_XYZW), SRC(2, "xyxy"), {}, SWZ()}, - { TGSI_OPCODE_END} + const vector<MockCodelineWithSwizzle> code = { + MockCodelineWithSwizzle(TGSI_OPCODE_BGNLOOP), + MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "x"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(1, WRITEMASK_Z), SRC(in1, "y"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_ENDIF), + MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(2, WRITEMASK_XY), SRC(1, "xz"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_ENDLOOP), + MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(out0, WRITEMASK_XYZW), SRC(2, "xyxy"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_END) }; - run (code, temp_lt_expect({{-1,-1}, {0,6}, {5,7}})); + run (code, expectation({{-1,-1}, {0,6}, {5,7}})); } TEST_F(LifetimeEvaluatorExactTest, LoopWithConditionalComponentWrite_W) { - const vector<FakeCodeline> code = { - { TGSI_OPCODE_BGNLOOP}, - { TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "x"), {}, SWZ()}, - { TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}, SWZ()}, - { TGSI_OPCODE_MOV, DST(1, WRITEMASK_W), SRC(in1, "y"), {}, SWZ()}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_MOV, DST(2, WRITEMASK_XY), SRC(1, "xw"), {}, SWZ()}, - { TGSI_OPCODE_ENDLOOP}, - { TGSI_OPCODE_MOV, DST(out0, WRITEMASK_XYZW), SRC(2, "xyxy"), {}, SWZ()}, - { TGSI_OPCODE_END} + const vector<MockCodelineWithSwizzle> code = { + MockCodelineWithSwizzle(TGSI_OPCODE_BGNLOOP), + MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "x"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(1, WRITEMASK_W), SRC(in1, "y"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_ENDIF), + MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(2, WRITEMASK_XY), SRC(1, "xw"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_ENDLOOP), + MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(out0, WRITEMASK_XYZW), SRC(2, "xyxy"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_END) }; - run (code, temp_lt_expect({{-1,-1}, {0,6}, {5,7}})); + run (code, expectation({{-1,-1}, {0,6}, {5,7}})); } TEST_F(LifetimeEvaluatorExactTest, LoopWithConditionalComponentWrite_X_Read_Y_Before) { - const vector<FakeCodeline> code = { - { TGSI_OPCODE_BGNLOOP}, - { TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "x"), {}, SWZ()}, - { TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}, SWZ()}, - { TGSI_OPCODE_MOV, DST(2, WRITEMASK_XYZW), SRC(1, "yyyy"), {}, SWZ()}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_MOV, DST(1, WRITEMASK_YZW), SRC(2, "yyzw"), {}, SWZ()}, - { TGSI_OPCODE_ENDLOOP}, - { TGSI_OPCODE_ADD, DST(out0, WRITEMASK_XYZW), - SRC2(2, "yyzw", 1, "xyxy"), {}, SWZ()}, - { TGSI_OPCODE_END} + const vector<MockCodelineWithSwizzle> code = { + MockCodelineWithSwizzle(TGSI_OPCODE_BGNLOOP), + MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "x"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(2, WRITEMASK_XYZW), SRC(1, "yyyy"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_ENDIF), + MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(1, WRITEMASK_YZW), SRC(2, "yyzw"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_ENDLOOP), + MockCodelineWithSwizzle(TGSI_OPCODE_ADD, DST(out0, WRITEMASK_XYZW), SRC2(2, "yyzw", 1, "xyxy"), {}), + MockCodelineWithSwizzle(TGSI_OPCODE_END) }; - run (code, temp_lt_expect({{-1,-1}, {0,7}, {0,7}})); + run (code, expectation({{-1,-1}, {0,7}, {0,7}})); } /* The variable is conditionally read before first written, so @@ -1330,10 +914,10 @@ TEST_F(LifetimeEvaluatorExactTest, LoopWithConditionalComponentWrite_X_Read_Y_Be */ TEST_F(LifetimeEvaluatorExactTest, FRaWSameInstructionInLoopAndCondition) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_BGNLOOP }, - { TGSI_OPCODE_IF, {}, {in0}, {} }, + { TGSI_OPCODE_IF, {0}, {in0}, {} }, { TGSI_OPCODE_ADD, {1}, {1,in0}, {}}, { TGSI_OPCODE_ENDIF}, { TGSI_OPCODE_MOV, {1}, {in1}, {}}, @@ -1342,7 +926,7 @@ TEST_F(LifetimeEvaluatorExactTest, FRaWSameInstructionInLoopAndCondition) { TGSI_OPCODE_END}, }; - run (code, temp_lt_expect({{-1,-1}, {0,7}})); + run (code, expectation({{-1,-1}, {0,7}})); } /* If unconditionally first written and read in the same @@ -1351,12 +935,12 @@ TEST_F(LifetimeEvaluatorExactTest, FRaWSameInstructionInLoopAndCondition) */ TEST_F(LifetimeEvaluatorExactTest, FRaWSameInstruction) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_ADD, {1}, {1,in0}, {}}, { TGSI_OPCODE_END}, }; - run (code, temp_lt_expect({{-1,-1}, {0,1}})); + run (code, expectation({{-1,-1}, {0,1}})); } /* If unconditionally written and read in the same @@ -1365,14 +949,14 @@ TEST_F(LifetimeEvaluatorExactTest, FRaWSameInstruction) */ TEST_F(LifetimeEvaluatorExactTest, FRaWSameInstructionMoreThenOnce) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_ADD, {1}, {1,in0}, {}}, { TGSI_OPCODE_ADD, {1}, {1,in0}, {}}, { TGSI_OPCODE_MOV, {out0}, {in0}, {}}, { TGSI_OPCODE_END}, }; - run (code, temp_lt_expect({{-1,-1}, {0,2}})); + run (code, expectation({{-1,-1}, {0,2}})); } /* Register is only written. This should not happen, @@ -1381,51 +965,52 @@ TEST_F(LifetimeEvaluatorExactTest, FRaWSameInstructionMoreThenOnce) */ TEST_F(LifetimeEvaluatorExactTest, WriteOnly) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,1}})); + run (code, expectation({{-1,-1}, {0,1}})); } /* Register is read in IF. */ TEST_F(LifetimeEvaluatorExactTest, SimpleReadForIf) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_ADD, {out0}, {in0,in1}, {}}, { TGSI_OPCODE_IF, {}, {1}, {}}, { TGSI_OPCODE_ENDIF} }; - run (code, temp_lt_expect({{-1,-1}, {0,2}})); + run (code, expectation({{-1,-1}, {0,2}})); } TEST_F(LifetimeEvaluatorExactTest, WriteTwoReadOne) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_DFRACEXP , {1,2}, {in0}, {}}, { TGSI_OPCODE_ADD , {3}, {2,in0}, {}}, { TGSI_OPCODE_MOV, {out1}, {3}, {}}, { TGSI_OPCODE_END}, }; - run (code, temp_lt_expect({{-1,-1}, {0,1}, {0,1}, {1,2}})); + run (code, expectation({{-1,-1}, {0,1}, {0,1}, {1,2}})); } TEST_F(LifetimeEvaluatorExactTest, ReadOnly) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_MOV, {out0}, {1}, {}}, { TGSI_OPCODE_END}, }; - run (code, temp_lt_expect({{-1,-1}, {-1,-1}})); + run (code, expectation({{-1,-1}, {-1,-1}})); } + /* Test handling of missing END marker */ TEST_F(LifetimeEvaluatorExactTest, SomeScopesAndNoEndProgramId) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_IF, {}, {1}, {}}, { TGSI_OPCODE_MOV, {2}, {1}, {}}, @@ -1434,30 +1019,30 @@ TEST_F(LifetimeEvaluatorExactTest, SomeScopesAndNoEndProgramId) { TGSI_OPCODE_MOV, {out0}, {2}, {}}, { TGSI_OPCODE_ENDIF}, }; - run (code, temp_lt_expect({{-1,-1}, {0,4}, {2,5}})); + run (code, expectation({{-1,-1}, {0,4}, {2,5}})); } TEST_F(LifetimeEvaluatorExactTest, SerialReadWrite) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_MOV, {2}, {1}, {}}, { TGSI_OPCODE_MOV, {3}, {2}, {}}, { TGSI_OPCODE_MOV, {out0}, {3}, {}}, { TGSI_OPCODE_END}, }; - run (code, temp_lt_expect({{-1,-1}, {0,1}, {1,2}, {2,3}})); + run (code, expectation({{-1,-1}, {0,1}, {1,2}, {2,3}})); } /* Check that two destination registers are used */ TEST_F(LifetimeEvaluatorExactTest, TwoDestRegisters) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_DFRACEXP , {1,2}, {in0}, {}}, { TGSI_OPCODE_ADD, {out0}, {1,2}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,1}, {0,1}})); + run (code, expectation({{-1,-1}, {0,1}, {0,1}})); } /* Check that writing within a loop in a conditional is propagated @@ -1465,7 +1050,7 @@ TEST_F(LifetimeEvaluatorExactTest, TwoDestRegisters) */ TEST_F(LifetimeEvaluatorExactTest, WriteInLoopInConditionalReadOutside) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP}, { TGSI_OPCODE_IF, {}, {in0}, {}}, { TGSI_OPCODE_BGNLOOP}, @@ -1477,7 +1062,7 @@ TEST_F(LifetimeEvaluatorExactTest, WriteInLoopInConditionalReadOutside) { TGSI_OPCODE_MOV, {out0}, {2}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,7}, {6,8}})); + run (code, expectation({{-1,-1}, {0,7}, {6,8}})); } /* Check that a register written in a loop that is inside a conditional @@ -1486,7 +1071,7 @@ TEST_F(LifetimeEvaluatorExactTest, WriteInLoopInConditionalReadOutside) */ TEST_F(LifetimeEvaluatorExactTest, WriteInLoopInCondReadInCondOutsideLoop) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP}, { TGSI_OPCODE_IF, {}, {in0}, {}}, { TGSI_OPCODE_BGNLOOP}, @@ -1498,7 +1083,7 @@ TEST_F(LifetimeEvaluatorExactTest, WriteInLoopInCondReadInCondOutsideLoop) { TGSI_OPCODE_MOV, {out0}, {2}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {3,5}, {0,8}})); + run (code, expectation({{-1,-1}, {3,5}, {0,8}})); } /* Check that a register read before written in a loop that is @@ -1506,7 +1091,7 @@ TEST_F(LifetimeEvaluatorExactTest, WriteInLoopInCondReadInCondOutsideLoop) */ TEST_F(LifetimeEvaluatorExactTest, ReadWriteInLoopInCondReadInCondOutsideLoop) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP}, { TGSI_OPCODE_IF, {}, {in0}, {}}, { TGSI_OPCODE_BGNLOOP}, @@ -1518,7 +1103,7 @@ TEST_F(LifetimeEvaluatorExactTest, ReadWriteInLoopInCondReadInCondOutsideLoop) { TGSI_OPCODE_MOV, {out0}, {2}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,7}, {0,8}})); + run (code, expectation({{-1,-1}, {0,7}, {0,8}})); } /* With two destinations if one value is thrown away, we must @@ -1529,7 +1114,7 @@ TEST_F(LifetimeEvaluatorExactTest, ReadWriteInLoopInCondReadInCondOutsideLoop) */ TEST_F(LifetimeEvaluatorExactTest, WritePastLastRead2) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_MOV, {2}, {in0}, {}}, { TGSI_OPCODE_ADD, {3}, {1,2}, {}}, @@ -1537,30 +1122,30 @@ TEST_F(LifetimeEvaluatorExactTest, WritePastLastRead2) { TGSI_OPCODE_MOV, {out1}, {4}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,2}, {1,4}, {2,3}, {3,4}})); + run (code, expectation({{-1,-1}, {0,2}, {1,4}, {2,3}, {3,4}})); } /* Check that three source registers are used */ TEST_F(LifetimeEvaluatorExactTest, ThreeSourceRegisters) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_DFRACEXP , {1,2}, {in0}, {}}, { TGSI_OPCODE_ADD , {3}, {in0,in1}, {}}, { TGSI_OPCODE_MAD, {out0}, {1,2,3}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,2}, {0,2}, {1,2}})); + run (code, expectation({{-1,-1}, {0,2}, {0,2}, {1,2}})); } /* Check minimal lifetime for registers only written to */ TEST_F(LifetimeEvaluatorExactTest, OverwriteWrittenOnlyTemps) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_MOV , {1}, {in0}, {}}, { TGSI_OPCODE_MOV , {2}, {in1}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,1}, {1,2}})); + run (code, expectation({{-1,-1}, {0,1}, {1,2}})); } /* Same register is only written twice. This should not happen, @@ -1569,12 +1154,12 @@ TEST_F(LifetimeEvaluatorExactTest, OverwriteWrittenOnlyTemps) */ TEST_F(LifetimeEvaluatorExactTest, WriteOnlyTwiceSame) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,2}})); + run (code, expectation({{-1,-1}, {0,2}})); } /* Dead code elimination should catch and remove the case @@ -1586,14 +1171,14 @@ TEST_F(LifetimeEvaluatorExactTest, WriteOnlyTwiceSame) */ TEST_F(LifetimeEvaluatorExactTest, WritePastLastRead) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_MOV, {1}, {in0}, {}}, { TGSI_OPCODE_MOV, {2}, {1}, {}}, { TGSI_OPCODE_MOV, {1}, {2}, {}}, { TGSI_OPCODE_END}, }; - run (code, temp_lt_expect({{-1,-1}, {0,3}, {1,2}})); + run (code, expectation({{-1,-1}, {0,3}, {1,2}})); } /* If a break is in the loop, all variables written after the @@ -1602,7 +1187,7 @@ TEST_F(LifetimeEvaluatorExactTest, WritePastLastRead) */ TEST_F(LifetimeEvaluatorExactTest, NestedLoopWithWriteAfterBreak) { - const vector<FakeCodeline> code = { + const vector<MockCodeline> code = { { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_BGNLOOP }, { TGSI_OPCODE_IF, {}, {in0}, {}}, @@ -1614,93 +1199,7 @@ TEST_F(LifetimeEvaluatorExactTest, NestedLoopWithWriteAfterBreak) { TGSI_OPCODE_ENDLOOP }, { TGSI_OPCODE_END} }; - run (code, temp_lt_expect({{-1,-1}, {0,8}})); -} - - -#define MT(X,Y,Z) std::make_tuple(X,Y,Z) -/* Check lifetime estimation with a relative addressing in src. - * Note, since the lifetime estimation always extends the lifetime - * at to at least one instruction after the last write, for the - * test the last read must be at least two instructions after the - * last write to obtain a proper test. - */ - -TEST_F(LifetimeEvaluatorExactTest, ReadIndirectReladdr1) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_MOV, {1}, {in1}, {}}, - { TGSI_OPCODE_MOV, {2}, {in0}, {}}, - { TGSI_OPCODE_MOV, {MT(3,0,0)}, {MT(2,1,0)}, {}, RA()}, - { TGSI_OPCODE_MOV, {out0}, {3}, {}}, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {0,2}, {1,2}, {2,3}})); -} - -/* Check lifetime estimation with a relative addressing in src */ -TEST_F(LifetimeEvaluatorExactTest, ReadIndirectReladdr2) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_MOV , {1}, {in1}, {}}, - { TGSI_OPCODE_MOV , {2}, {in0}, {}}, - { TGSI_OPCODE_MOV , {MT(3,0,0)}, {MT(4,0,1)}, {}, RA()}, - { TGSI_OPCODE_MOV , {out0}, {3}, {}}, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {0,2}, {1,2},{2,3}})); -} - -/* Check lifetime estimation with a relative addressing in src */ -TEST_F(LifetimeEvaluatorExactTest, ReadIndirectTexOffsReladdr1) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_MOV , {1}, {in1}, {}}, - { TGSI_OPCODE_MOV , {2}, {in0}, {}}, - { TGSI_OPCODE_MOV , {MT(3,0,0)}, {MT(in2,0,0)}, {MT(5,1,0)}, RA()}, - { TGSI_OPCODE_MOV , {out0}, {3}, {}}, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {0,2}, {1,2}, {2,3}})); -} - -/* Check lifetime estimation with a relative addressing in src */ -TEST_F(LifetimeEvaluatorExactTest, ReadIndirectTexOffsReladdr2) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_MOV , {1}, {in1}, {}}, - { TGSI_OPCODE_MOV , {2}, {in0}, {}}, - { TGSI_OPCODE_MOV , {MT(3,0,0)}, {MT(in2,0,0)}, {MT(2,0,1)}, RA()}, - { TGSI_OPCODE_MOV , {out0}, {3}, {}}, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {0,2}, {1,2}, {2,3}})); -} - -/* Check lifetime estimation with a relative addressing in dst */ -TEST_F(LifetimeEvaluatorExactTest, WriteIndirectReladdr1) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_MOV , {1}, {in0}, {}}, - { TGSI_OPCODE_MOV , {1}, {in1}, {}}, - { TGSI_OPCODE_MOV , {MT(5,1,0)}, {MT(in1,0,0)}, {}, RA()}, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {0,2}})); -} - -/* Check lifetime estimation with a relative addressing in dst */ -TEST_F(LifetimeEvaluatorExactTest, WriteIndirectReladdr2) -{ - const vector<FakeCodeline> code = { - { TGSI_OPCODE_MOV , {1}, {in0}, {}}, - { TGSI_OPCODE_MOV , {2}, {in1}, {}}, - { TGSI_OPCODE_MOV , {MT(5,0,1)}, {MT(in1,0,0)}, {}, RA()}, - { TGSI_OPCODE_MOV , {out0}, {in0}, {}}, - { TGSI_OPCODE_MOV , {out1}, {2}, {}}, - { TGSI_OPCODE_END} - }; - run (code, temp_lt_expect({{-1,-1}, {0,2}, {1,4}})); + run (code, expectation({{-1,-1}, {0,8}})); } /* Test remapping table of registers. The tests don't assume @@ -1709,7 +1208,7 @@ TEST_F(LifetimeEvaluatorExactTest, WriteIndirectReladdr2) */ TEST_F(RegisterRemappingTest, RegisterRemapping1) { - vector<register_live_range> lt({{-1,-1}, + vector<lifetime> lt({{-1,-1}, {0,1}, {0,2}, {1,2}, @@ -1724,7 +1223,7 @@ TEST_F(RegisterRemappingTest, RegisterRemapping1) TEST_F(RegisterRemappingTest, RegisterRemapping2) { - vector<register_live_range> lt({{-1,-1}, + vector<lifetime> lt({{-1,-1}, {0,1}, {0,2}, {3,4}, @@ -1736,7 +1235,7 @@ TEST_F(RegisterRemappingTest, RegisterRemapping2) TEST_F(RegisterRemappingTest, RegisterRemappingMergeAllToOne) { - vector<register_live_range> lt({{-1,-1}, + vector<lifetime> lt({{-1,-1}, {0,1}, {1,2}, {2,3}, @@ -1748,7 +1247,7 @@ TEST_F(RegisterRemappingTest, RegisterRemappingMergeAllToOne) TEST_F(RegisterRemappingTest, RegisterRemappingIgnoreUnused) { - vector<register_live_range> lt({{-1,-1}, + vector<lifetime> lt({{-1,-1}, {0,1}, {1,2}, {2,3}, @@ -1761,7 +1260,7 @@ TEST_F(RegisterRemappingTest, RegisterRemappingIgnoreUnused) TEST_F(RegisterRemappingTest, RegisterRemappingMergeZeroLifetimeRegisters) { - vector<register_live_range> lt({{-1,-1}, + vector<lifetime> lt({{-1,-1}, {0,1}, {1,2}, {2,3}, @@ -1774,38 +1273,38 @@ TEST_F(RegisterRemappingTest, RegisterRemappingMergeZeroLifetimeRegisters) TEST_F(RegisterLifetimeAndRemappingTest, LifetimeAndRemapping) { - const vector<FakeCodeline> code = { - { TGSI_OPCODE_USEQ, {5}, {in0,in1}, {}}, - { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}}, - { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}}, - { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}}, - { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}}, - { TGSI_OPCODE_FSLT, {2}, {1,in1}, {}}, - { TGSI_OPCODE_UIF, {}, {2}, {}}, - { TGSI_OPCODE_MOV, {3}, {in1}, {}}, - { TGSI_OPCODE_ELSE}, - { TGSI_OPCODE_MOV, {4}, {in1}, {}}, - { TGSI_OPCODE_MOV, {4}, {4}, {}}, - { TGSI_OPCODE_MOV, {3}, {4}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_MOV, {out1}, {3}, {}}, - { TGSI_OPCODE_END} + const vector<MockCodeline> code = { + {TGSI_OPCODE_USEQ, {5}, {in0,in1}, {}}, + {TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}}, + {TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}}, + {TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}}, + {TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}}, + {TGSI_OPCODE_FSLT, {2}, {1,in1}, {}}, + {TGSI_OPCODE_UIF, {}, {2}, {}}, + { TGSI_OPCODE_MOV, {3}, {in1}, {}}, + {TGSI_OPCODE_ELSE}, + { TGSI_OPCODE_MOV, {4}, {in1}, {}}, + { TGSI_OPCODE_MOV, {4}, {4}, {}}, + { TGSI_OPCODE_MOV, {3}, {4}, {}}, + {TGSI_OPCODE_ENDIF}, + {TGSI_OPCODE_MOV, {out1}, {3}, {}}, + {TGSI_OPCODE_END} }; run (code, vector<int>({0,1,5,5,1,5})); } TEST_F(RegisterLifetimeAndRemappingTest, LifetimeAndRemappingWithUnusedReadOnlyIgnored) { - const vector<FakeCodeline> code = { - { TGSI_OPCODE_USEQ, {1}, {in0,in1}, {}}, - { TGSI_OPCODE_UCMP, {2}, {1,in1,2}, {}}, - { TGSI_OPCODE_UCMP, {4}, {2,in1,1}, {}}, - { TGSI_OPCODE_ADD, {5}, {2,4}, {}}, - { TGSI_OPCODE_UIF, {}, {7}, {}}, - { TGSI_OPCODE_ADD, {8}, {5,4}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_MOV, {out1}, {8}, {}}, - { TGSI_OPCODE_END} + const vector<MockCodeline> code = { + {TGSI_OPCODE_USEQ, {1}, {in0,in1}, {}}, + {TGSI_OPCODE_UCMP, {2}, {1,in1,2}, {}}, + {TGSI_OPCODE_UCMP, {4}, {2,in1,1}, {}}, + {TGSI_OPCODE_ADD, {5}, {2,4}, {}}, + {TGSI_OPCODE_UIF, {}, {7}, {}}, + { TGSI_OPCODE_ADD, {8}, {5,4}, {}}, + {TGSI_OPCODE_ENDIF}, + {TGSI_OPCODE_MOV, {out1}, {8}, {}}, + {TGSI_OPCODE_END} }; /* lt: 1: 0-2,2: 1-3 3: u 4: 2-5 5: 3-5 6: u 7: 0-(-1),8: 5-7 */ run (code, vector<int>({0,1,2,3,1,2,6,7,1})); @@ -1813,16 +1312,16 @@ TEST_F(RegisterLifetimeAndRemappingTest, LifetimeAndRemappingWithUnusedReadOnlyI TEST_F(RegisterLifetimeAndRemappingTest, LifetimeAndRemappingWithUnusedReadOnlyRemappedTo) { - const vector<FakeCodeline> code = { - { TGSI_OPCODE_USEQ, {1}, {in0,in1}, {}}, - { TGSI_OPCODE_UIF, {}, {7}, {}}, - { TGSI_OPCODE_UCMP, {2}, {1,in1,2}, {}}, - { TGSI_OPCODE_UCMP, {4}, {2,in1,1}, {}}, - { TGSI_OPCODE_ADD, {5}, {2,4}, {}}, - { TGSI_OPCODE_ADD, {8}, {5,4}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_MOV, {out1}, {8}, {}}, - { TGSI_OPCODE_END} + const vector<MockCodeline> code = { + {TGSI_OPCODE_USEQ, {1}, {in0,in1}, {}}, + {TGSI_OPCODE_UIF, {}, {7}, {}}, + { TGSI_OPCODE_UCMP, {2}, {1,in1,2}, {}}, + { TGSI_OPCODE_UCMP, {4}, {2,in1,1}, {}}, + { TGSI_OPCODE_ADD, {5}, {2,4}, {}}, + { TGSI_OPCODE_ADD, {8}, {5,4}, {}}, + {TGSI_OPCODE_ENDIF}, + {TGSI_OPCODE_MOV, {out1}, {8}, {}}, + {TGSI_OPCODE_END} }; /* lt: 1: 0-3,2: 2-4 3: u 4: 3-5 5: 4-5 6: u 7: 1-1,8: 5-7 */ run (code, vector<int>({0,1,2,3,1,2,6,7,1})); @@ -1830,17 +1329,272 @@ TEST_F(RegisterLifetimeAndRemappingTest, LifetimeAndRemappingWithUnusedReadOnlyR TEST_F(RegisterLifetimeAndRemappingTest, LifetimeAndRemappingWithUnusedReadOnlyRemapped) { - const vector<FakeCodeline> code = { - { TGSI_OPCODE_USEQ, {0}, {in0,in1}, {}}, - { TGSI_OPCODE_UCMP, {2}, {0,in1,2}, {}}, - { TGSI_OPCODE_UCMP, {4}, {2,in1,0}, {}}, - { TGSI_OPCODE_UIF, {}, {7}, {}}, - { TGSI_OPCODE_ADD, {5}, {4,4}, {}}, - { TGSI_OPCODE_ADD, {8}, {5,4}, {}}, - { TGSI_OPCODE_ENDIF}, - { TGSI_OPCODE_MOV, {out1}, {8}, {}}, - { TGSI_OPCODE_END} + const vector<MockCodeline> code = { + {TGSI_OPCODE_USEQ, {0}, {in0,in1}, {}}, + {TGSI_OPCODE_UCMP, {2}, {0,in1,2}, {}}, + {TGSI_OPCODE_UCMP, {4}, {2,in1,0}, {}}, + {TGSI_OPCODE_UIF, {}, {7}, {}}, + { TGSI_OPCODE_ADD, {5}, {4,4}, {}}, + { TGSI_OPCODE_ADD, {8}, {5,4}, {}}, + {TGSI_OPCODE_ENDIF}, + {TGSI_OPCODE_MOV, {out1}, {8}, {}}, + {TGSI_OPCODE_END} }; /* lt: 0: 0-2 1: u 2: 1-2 3: u 4: 2-5 5: 4-5 6: u 7:ro 8: 5-7 */ run (code, vector<int>({0,1,2,3,0,2,6,7,0})); } + +/* Implementation of helper and test classes */ +MockShader::~MockShader() +{ + free(); + ralloc_free(mem_ctx); +} + +MockShader::MockShader(const vector<MockCodelineWithSwizzle>& source): + num_temps(0) +{ + mem_ctx = ralloc_context(NULL); + + program = new(mem_ctx) exec_list(); + + for (MockCodelineWithSwizzle i: source) { + glsl_to_tgsi_instruction *next_instr = new(mem_ctx) glsl_to_tgsi_instruction(); + next_instr->op = i.op; + next_instr->info = tgsi_get_opcode_info(i.op); + + assert(i.src.size() < 4); + assert(i.dst.size() < 3); + assert(i.tex_offsets.size() < 3); + + for (unsigned k = 0; k < i.src.size(); ++k) { + next_instr->src[k] = create_src_register(i.src[k].first, i.src[k].second); + } + for (unsigned k = 0; k < i.dst.size(); ++k) { + next_instr->dst[k] = create_dst_register(i.dst[k].first, i.dst[k].second); + } + next_instr->tex_offset_num_offset = i.tex_offsets.size(); + next_instr->tex_offsets = new st_src_reg[i.tex_offsets.size()]; + for (unsigned k = 0; k < i.tex_offsets.size(); ++k) { + next_instr->tex_offsets[k] = create_src_register(i.tex_offsets[k].first, + i.tex_offsets[k].second); + } + program->push_tail(next_instr); + } + ++num_temps; +} + +MockShader::MockShader(const vector<MockCodeline>& source): + num_temps(0) +{ + mem_ctx = ralloc_context(NULL); + + program = new(mem_ctx) exec_list(); + + for (MockCodeline i: source) { + glsl_to_tgsi_instruction *next_instr = new(mem_ctx) glsl_to_tgsi_instruction(); + next_instr->op = i.op; + next_instr->info = tgsi_get_opcode_info(i.op); + + assert(i.src.size() < 4); + assert(i.dst.size() < 3); + assert(i.tex_offsets.size() < 3); + + for (unsigned k = 0; k < i.src.size(); ++k) { + next_instr->src[k] = create_src_register(i.src[k]); + } + for (unsigned k = 0; k < i.dst.size(); ++k) { + next_instr->dst[k] = create_dst_register(i.dst[k]); + } + next_instr->tex_offset_num_offset = i.tex_offsets.size(); + next_instr->tex_offsets = new st_src_reg[i.tex_offsets.size()]; + for (unsigned k = 0; k < i.tex_offsets.size(); ++k) { + next_instr->tex_offsets[k] = create_src_register(i.tex_offsets[k]); + } + program->push_tail(next_instr); + } + ++num_temps; +} + +int MockShader::get_num_temps() const +{ + return num_temps; +} + + +exec_list* MockShader::get_program() const +{ + return program; +} + +void MockShader::free() +{ + /* The list is not fully initialized, so + * tearing it down also must be done manually. */ + exec_node *p; + while ((p = program->pop_head())) { + glsl_to_tgsi_instruction * instr = static_cast<glsl_to_tgsi_instruction *>(p); + if (instr->tex_offset_num_offset > 0) + delete[] instr->tex_offsets; + delete p; + } + program = 0; + num_temps = 0; +} + +st_src_reg MockShader::create_src_register(int src_idx) +{ + gl_register_file file; + int idx = 0; + if (src_idx >= 0) { + file = PROGRAM_TEMPORARY; + idx = src_idx; + if (num_temps < idx) + num_temps = idx; + } else { + file = PROGRAM_INPUT; + idx = 1 - src_idx; + } + return st_src_reg(file, idx, GLSL_TYPE_INT); +} + +st_src_reg MockShader::create_src_register(int src_idx, const char *sw) +{ + uint16_t swizzle = 0; + for (int i = 0; i < 4; ++i) { + switch (sw[i]) { + case 'x': break; /* is zero */ + case 'y': swizzle |= SWIZZLE_Y << 3 * i; break; + case 'z': swizzle |= SWIZZLE_Z << 3 * i; break; + case 'w': swizzle |= SWIZZLE_W << 3 * i; break; + } + } + + gl_register_file file; + int idx = 0; + if (src_idx >= 0) { + file = PROGRAM_TEMPORARY; + idx = src_idx; + if (num_temps < idx) + num_temps = idx; + } else { + file = PROGRAM_INPUT; + idx = 1 - src_idx; + } + st_src_reg result(file, idx, GLSL_TYPE_INT); + result.swizzle = swizzle; + return result; +} + +st_dst_reg MockShader::create_dst_register(int dst_idx,int writemask) +{ + gl_register_file file; + int idx = 0; + if (dst_idx >= 0) { + file = PROGRAM_TEMPORARY; + idx = dst_idx; + if (num_temps < idx) + num_temps = idx; + } else { + file = PROGRAM_OUTPUT; + idx = 1 - dst_idx; + } + return st_dst_reg(file, writemask, GLSL_TYPE_INT, idx); +} + +st_dst_reg MockShader::create_dst_register(int dst_idx) +{ + gl_register_file file; + int idx = 0; + if (dst_idx >= 0) { + file = PROGRAM_TEMPORARY; + idx = dst_idx; + if (num_temps < idx) + num_temps = idx; + } else { + file = PROGRAM_OUTPUT; + idx = 1 - dst_idx; + } + return st_dst_reg(file,0xF, GLSL_TYPE_INT, idx); +} + + +void MesaTestWithMemCtx::SetUp() +{ + mem_ctx = ralloc_context(nullptr); +} + +void MesaTestWithMemCtx::TearDown() +{ + ralloc_free(mem_ctx); + mem_ctx = nullptr; +} + +void LifetimeEvaluatorTest::run(const vector<MockCodeline>& code, const expectation& e) +{ + MockShader shader(code); + std::vector<lifetime> result(shader.get_num_temps()); + + bool success = + get_temp_registers_required_lifetimes(mem_ctx, shader.get_program(), + shader.get_num_temps(), &result[0]); + + ASSERT_TRUE(success); + ASSERT_EQ(result.size(), e.size()); + check(result, e); +} + +void LifetimeEvaluatorTest::run(const vector<MockCodelineWithSwizzle>& code, + const expectation& e) +{ + MockShader shader(code); + std::vector<lifetime> result(shader.get_num_temps()); + + bool success = + get_temp_registers_required_lifetimes(mem_ctx, shader.get_program(), + shader.get_num_temps(), &result[0]); + ASSERT_TRUE(success); + ASSERT_EQ(result.size(), e.size()); + check(result, e); +} + +void LifetimeEvaluatorExactTest::check( const vector<lifetime>& lifetimes, + const expectation& e) +{ + for (unsigned i = 1; i < lifetimes.size(); ++i) { + EXPECT_EQ(lifetimes[i].begin, e[i][0]); + EXPECT_EQ(lifetimes[i].end, e[i][1]); + } +} + +void LifetimeEvaluatorAtLeastTest::check( const vector<lifetime>& lifetimes, + const expectation& e) +{ + for (unsigned i = 1; i < lifetimes.size(); ++i) { + EXPECT_LE(lifetimes[i].begin, e[i][0]); + EXPECT_GE(lifetimes[i].end, e[i][1]); + } +} + +void RegisterRemappingTest::run(const vector<lifetime>& lt, + const vector<int>& expect) +{ + rename_reg_pair proto{false,0}; + vector<rename_reg_pair> result(lt.size(), proto); + + get_temp_registers_remapping(mem_ctx, lt.size(), <[0], &result[0]); + + vector<int> remap(lt.size()); + for (unsigned i = 0; i < lt.size(); ++i) { + remap[i] = result[i].valid ? result[i].new_reg : i; + } + + std::transform(remap.begin(), remap.end(), result.begin(), remap.begin(), + [](int x, const rename_reg_pair& rn) { + return rn.valid ? rn.new_reg : x; + }); + + for(unsigned i = 1; i < remap.size(); ++i) { + EXPECT_EQ(remap[i], expect[i]); + } +} |