summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2018-10-23 05:51:41 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2018-10-23 05:51:41 +0000
commit6cb9ed16dbefce87ec66640575ee58997b0770ca (patch)
tree22e63481f9ba42bdfdc80bad6f89703d72069d0b
parent88a8b3efd937a485138a2493e90645d2cb79f1cc (diff)
Import Mesa 17.3.9
-rw-r--r--lib/mesa/src/mesa/state_tracker/st_glsl_to_tgsi_private.cpp177
-rw-r--r--lib/mesa/src/mesa/state_tracker/st_glsl_to_tgsi_private.h53
-rw-r--r--lib/mesa/src/mesa/state_tracker/st_glsl_to_tgsi_temprename.cpp819
-rw-r--r--lib/mesa/src/mesa/state_tracker/st_glsl_to_tgsi_temprename.h45
-rw-r--r--lib/mesa/src/mesa/state_tracker/tests/test_glsl_to_tgsi_lifetime.cpp1484
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 &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 &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 &reg);
void operator=(const st_src_reg &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(), &lt[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(), &lt[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]);
+ }
+}