1/*
2 * Copyright © 2017 Gert Wollny
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24#ifndef mesa_st_tests_h
25#define mesa_st_tests_h
26
27#include "state_tracker/st_glsl_to_tgsi_temprename.h"
28#include "state_tracker/st_glsl_to_tgsi_array_merge.h"
29#include "gtest/gtest.h"
30
31#include <utility>
32
33#define MP(X, W) std::make_pair(X, W)
34#define MT(X,Y,Z) std::make_tuple(X,Y,Z)
35
36/* Use this to make the compiler pick the swizzle constructor below */
37struct SWZ {};
38
39/* Use this to make the compiler pick the constructor with reladdr below */
40struct RA {};
41
42/* Use this to make the compiler pick the constructor with array below */
43struct ARR {};
44
45/* A line to describe a TGSI instruction for building mock shaders. */
46struct FakeCodeline {
47   FakeCodeline(tgsi_opcode _op): op(_op), max_temp_id(0), max_array_id(0) {}
48   FakeCodeline(tgsi_opcode _op, const std::vector<int>& _dst, const std::vector<int>& _src,
49                const std::vector<int>&_to);
50
51   FakeCodeline(tgsi_opcode _op, const std::vector<std::pair<int,int>>& _dst,
52                const std::vector<std::pair<int, const char *>>& _src,
53                const std::vector<std::pair<int, const char *>>&_to, SWZ with_swizzle);
54
55   FakeCodeline(tgsi_opcode _op, const std::vector<std::tuple<int,int,int>>& _dst,
56                const std::vector<std::tuple<int,int,int>>& _src,
57                const std::vector<std::tuple<int,int,int>>&_to, RA with_reladdr);
58
59   FakeCodeline(tgsi_opcode _op, const std::vector<std::tuple<int, int, int> > &_dst,
60		const std::vector<std::tuple<int,int, const char*>>& _src,
61		const std::vector<std::tuple<int,int, const char*>>&_to, ARR with_array);
62
63   FakeCodeline(const glsl_to_tgsi_instruction& inst);
64
65   int get_max_reg_id() const { return max_temp_id;}
66   int get_max_array_id() const { return max_array_id;}
67
68   glsl_to_tgsi_instruction *get_codeline() const;
69
70   static void set_mem_ctx(void *ctx);
71
72   friend bool operator == (const FakeCodeline& lsh, const FakeCodeline& rhs);
73
74   void print(std::ostream& os) const;
75private:
76   st_src_reg create_src_register(int src_idx);
77   st_src_reg create_src_register(int src_idx, const char *swizzle);
78   st_src_reg create_src_register(int src_idx, gl_register_file file);
79   st_src_reg create_src_register(const std::tuple<int,int,int>& src);
80   st_src_reg *create_rel_src_register(int idx);
81   st_src_reg create_array_src_register(const std::tuple<int,int,const char*>& r);
82   st_dst_reg create_array_dst_register(const std::tuple<int,int,int>& r);
83
84   st_dst_reg create_dst_register(int dst_idx);
85   st_dst_reg create_dst_register(int dst_idx, int writemask);
86   st_dst_reg create_dst_register(int dst_idx, gl_register_file file);
87   st_dst_reg create_dst_register(const std::tuple<int,int,int>& dest);
88
89   template <typename st_reg>
90   void read_reg(const st_reg& s);
91
92   tgsi_opcode op;
93   std::vector<st_dst_reg> dst;
94   std::vector<st_src_reg> src;
95   std::vector<st_src_reg> tex_offsets;
96
97   int max_temp_id;
98   int max_array_id;
99   static void *mem_ctx;
100};
101
102inline std::ostream& operator << (std::ostream& os, const FakeCodeline& line)
103{
104   line.print(os);
105   return os;
106}
107
108/* A few constants that will not be tracked as temporary registers
109   by the fake shader.
110 */
111const int in0 = -1;
112const int in1 = -2;
113const int in2 = -3;
114
115const int out0 = -1;
116const int out1 = -2;
117const int out2 = -3;
118
119class FakeShader {
120public:
121   FakeShader(const std::vector<FakeCodeline>& source);
122   FakeShader(exec_list *tgsi_prog);
123
124   exec_list* get_program(void *ctx) const;
125   int get_num_temps() const;
126   int get_num_arrays() const;
127
128   size_t length() const;
129
130   const FakeCodeline& line(unsigned i) const;
131
132private:
133
134   std::vector<FakeCodeline> program;
135   int num_temps;
136   int num_arrays;
137};
138
139using temp_lt_expect = std::vector<std::vector<int>>;
140using array_lt_expect = std::vector<array_live_range>;
141
142class MesaTestWithMemCtx : public testing::Test {
143   void SetUp();
144   void TearDown();
145protected:
146   void *mem_ctx;
147};
148
149class LifetimeEvaluatorTest : public MesaTestWithMemCtx {
150protected:
151   void run(const std::vector<FakeCodeline>& code, const temp_lt_expect& e);
152   void run(const std::vector<FakeCodeline>& code, const array_lt_expect& e);
153private:
154   using life_range_result=std::pair<std::vector<register_live_range>,
155				   std::vector<array_live_range>>;
156   life_range_result run(const std::vector<FakeCodeline>& code, bool& success);
157
158   virtual void check(const std::vector<register_live_range>& result,
159		      const temp_lt_expect& e) = 0;
160   virtual void check(const std::vector<array_live_range>& lifetimes,
161		      const array_lt_expect& e) = 0;
162};
163
164/* This is a test class to check the exact life times of
165 * registers. */
166class LifetimeEvaluatorExactTest : public LifetimeEvaluatorTest {
167protected:
168   void check(const std::vector<register_live_range>& result,
169	      const temp_lt_expect& e);
170
171   void check(const std::vector<array_live_range>& result,
172	      const array_lt_expect& e);
173};
174
175/* This test class checks that the life time covers at least
176 * in the expected range. It is used for cases where we know that
177 * a the implementation could be improved on estimating the minimal
178 * life time.
179 */
180class LifetimeEvaluatorAtLeastTest : public LifetimeEvaluatorTest {
181protected:
182   void check(const std::vector<register_live_range>& result, const temp_lt_expect& e);
183   void check(const std::vector<array_live_range>& result,
184	      const array_lt_expect& e);
185};
186
187/* With this test class the renaming mapping estimation is tested */
188class RegisterRemappingTest : public MesaTestWithMemCtx {
189protected:
190   void run(const std::vector<register_live_range>& lt,
191	    const std::vector<int> &expect);
192};
193
194/* With this test class the combined lifetime estimation and renaming
195 * mepping estimation is tested
196 */
197class RegisterLifetimeAndRemappingTest : public RegisterRemappingTest  {
198protected:
199   using RegisterRemappingTest::run;
200   void run(const std::vector<FakeCodeline>& code, const std::vector<int> &expect);
201};
202
203#endif
204