• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <state_tracker/st_glsl_to_tgsi_temprename.h>
25 #include <tgsi/tgsi_ureg.h>
26 #include <tgsi/tgsi_info.h>
27 #include <compiler/glsl/list.h>
28 #include <mesa/program/prog_instruction.h>
29 
30 #include <utility>
31 #include <gtest/gtest.h>
32 
33 using std::vector;
34 using std::pair;
35 using std::make_pair;
36 
37 /* A line to describe a TGSI instruction for building mock shaders. */
38 struct MockCodeline {
MockCodelineMockCodeline39    MockCodeline(unsigned _op): op(_op) {}
MockCodelineMockCodeline40    MockCodeline(unsigned _op, const vector<int>& _dst, const vector<int>& _src, const vector<int>&_to):
41       op(_op), dst(_dst), src(_src), tex_offsets(_to){}
42    unsigned op;
43    vector<int> dst;
44    vector<int> src;
45    vector<int> tex_offsets;
46 };
47 
48 /* A line to describe a TGSI instruction with swizzeling and write makss
49  * for building mock shaders.
50  */
51 struct MockCodelineWithSwizzle {
MockCodelineWithSwizzleMockCodelineWithSwizzle52    MockCodelineWithSwizzle(unsigned _op): op(_op) {}
MockCodelineWithSwizzleMockCodelineWithSwizzle53    MockCodelineWithSwizzle(unsigned _op, const vector<pair<int,int>>& _dst,
54                            const vector<pair<int, const char *>>& _src,
55                            const vector<pair<int, const char *>>&_to):
56       op(_op), dst(_dst), src(_src), tex_offsets(_to){}
57    unsigned op;
58    vector<pair<int,int>> dst;
59    vector<pair<int, const char *>> src;
60    vector<pair<int, const char *>> tex_offsets;
61 };
62 
63 /* A few constants that will notbe tracked as temporary registers by the
64  * mock shader.
65  */
66 const int in0 = -1;
67 const int in1 = -2;
68 const int in2 = -3;
69 
70 const int out0 = -1;
71 const int out1 = -2;
72 
73 class MockShader {
74 public:
75    MockShader(const vector<MockCodeline>& source);
76    MockShader(const vector<MockCodelineWithSwizzle>& source);
77    ~MockShader();
78 
79    void free();
80 
81    exec_list* get_program() const;
82    int get_num_temps() const;
83 private:
84    st_src_reg create_src_register(int src_idx);
85    st_dst_reg create_dst_register(int dst_idx);
86    st_src_reg create_src_register(int src_idx, const char *swizzle);
87    st_dst_reg create_dst_register(int dst_idx,int writemask);
88    exec_list* program;
89    int num_temps;
90    void *mem_ctx;
91 };
92 
93 using expectation = vector<vector<int>>;
94 
95 class MesaTestWithMemCtx : public testing::Test {
96    void SetUp();
97    void TearDown();
98 protected:
99    void *mem_ctx;
100 };
101 
102 class LifetimeEvaluatorTest : public MesaTestWithMemCtx {
103 protected:
104    void run(const vector<MockCodeline>& code, const expectation& e);
105    void run(const vector<MockCodelineWithSwizzle>& code, const expectation& e);
106 private:
107    virtual void check(const vector<lifetime>& result, const expectation& e) = 0;
108 };
109 
110 /* This is a test class to check the exact life times of
111  * registers. */
112 class LifetimeEvaluatorExactTest : public LifetimeEvaluatorTest {
113 protected:
114    void check(const vector<lifetime>& result, const expectation& e);
115 };
116 
117 /* This test class checks that the life time covers at least
118  * in the expected range. It is used for cases where we know that
119  * a the implementation could be improved on estimating the minimal
120  * life time.
121  */
122 class LifetimeEvaluatorAtLeastTest : public LifetimeEvaluatorTest {
123 protected:
124    void check(const vector<lifetime>& result, const expectation& e);
125 };
126 
127 /* With this test class the renaming mapping estimation is tested */
128 class RegisterRemappingTest : public MesaTestWithMemCtx {
129 protected:
130    void run(const vector<lifetime>& lt, const vector<int>& expect);
131 };
132 
133 /* With this test class the combined lifetime estimation and renaming
134  * mepping estimation is tested
135  */
136 class RegisterLifetimeAndRemappingTest : public RegisterRemappingTest  {
137 protected:
138    using RegisterRemappingTest::run;
139    template <typename CodeLine>
140    void run(const vector<CodeLine>& code, const vector<int>& expect);
141 };
142 
143 template <typename CodeLine>
run(const vector<CodeLine> & code,const vector<int> & expect)144 void RegisterLifetimeAndRemappingTest::run(const vector<CodeLine>& code,
145                                   const vector<int>& expect)
146 {
147      MockShader shader(code);
148      std::vector<lifetime> lt(shader.get_num_temps());
149      get_temp_registers_required_lifetimes(mem_ctx, shader.get_program(),
150                                            shader.get_num_temps(), &lt[0]);
151      this->run(lt, expect);
152 }
153 
TEST_F(LifetimeEvaluatorExactTest,SimpleMoveAdd)154 TEST_F(LifetimeEvaluatorExactTest, SimpleMoveAdd)
155 {
156    const vector<MockCodeline> code = {
157       { TGSI_OPCODE_MOV, {1}, {in0}, {}},
158       { TGSI_OPCODE_UADD, {out0}, {1,in0}, {}},
159       { TGSI_OPCODE_END}
160    };
161    run(code, expectation({{-1,-1}, {0,1}}));
162 }
163 
TEST_F(LifetimeEvaluatorExactTest,SimpleMoveAddMove)164 TEST_F(LifetimeEvaluatorExactTest, SimpleMoveAddMove)
165 {
166    const vector<MockCodeline> code = {
167       { TGSI_OPCODE_MOV, {1}, {in0}, {}},
168       { TGSI_OPCODE_UADD, {2}, {1,in0}, {}},
169       { TGSI_OPCODE_MOV, {out0}, {2}, {}},
170       { TGSI_OPCODE_END}
171    };
172    run(code, expectation({{-1, -1}, {0,1}, {1,2}}));
173 }
174 
175 /* Test whether the texoffst are actually visited by the
176  * merge algorithm. Note that it is of no importance
177  * what instruction is actually used, the MockShader class
178  * does not consider the details of the operation, only
179  * the number of arguments is of importance.
180  */
TEST_F(LifetimeEvaluatorExactTest,SimpleOpWithTexoffset)181 TEST_F(LifetimeEvaluatorExactTest, SimpleOpWithTexoffset)
182 {
183    const vector<MockCodeline> code = {
184       { TGSI_OPCODE_MOV, {1}, {in0}, {}},
185       { TGSI_OPCODE_MOV, {2}, {in1}, {}},
186       { TGSI_OPCODE_TEX, {out0}, {in0}, {1,2}},
187       { TGSI_OPCODE_END}
188    };
189    run(code, expectation({{-1, -1}, {0,2}, {1,2}}));
190 }
191 
192 /* Simple register access involving a loop
193  * 1: must life up to then end of the loop
194  * 2: only needs to life from write to read
195  * 3: only needs to life from write to read outside the loop
196  */
TEST_F(LifetimeEvaluatorExactTest,SimpleMoveInLoop)197 TEST_F(LifetimeEvaluatorExactTest, SimpleMoveInLoop)
198 {
199    const vector<MockCodeline> code = {
200       { TGSI_OPCODE_MOV, {1}, {in0}, {}},
201       { TGSI_OPCODE_BGNLOOP },
202       {   TGSI_OPCODE_UADD, {2}, {1,in0}, {}},
203       {   TGSI_OPCODE_UADD, {3}, {1,2}, {}},
204       {   TGSI_OPCODE_UADD, {3}, {3,in1}, {}},
205       { TGSI_OPCODE_ENDLOOP },
206       { TGSI_OPCODE_MOV, {out0}, {3}, {}},
207       { TGSI_OPCODE_END}
208    };
209    run (code, expectation({{-1,-1}, {0,5}, {2,3}, {3,6}}));
210 }
211 
212 /* In loop if/else value written only in one path, and read later
213  * - value must survive the whole loop.
214  */
TEST_F(LifetimeEvaluatorExactTest,MoveInIfInLoop)215 TEST_F(LifetimeEvaluatorExactTest, MoveInIfInLoop)
216 {
217    const vector<MockCodeline> code = {
218       { TGSI_OPCODE_MOV, {1}, {in0}, {}},
219       { TGSI_OPCODE_BGNLOOP },
220       {   TGSI_OPCODE_IF, {}, {in1}, {}},
221       {     TGSI_OPCODE_UADD, {2}, {1,in0}, {}},
222       {   TGSI_OPCODE_ENDIF},
223       {   TGSI_OPCODE_UADD, {3}, {1,2}, {}},
224       {   TGSI_OPCODE_UADD, {3}, {3,in1}, {}},
225       { TGSI_OPCODE_ENDLOOP },
226       { TGSI_OPCODE_MOV, {out0}, {3}, {}},
227       { TGSI_OPCODE_END}
228    };
229    run (code, expectation({{-1,-1}, {0,7}, {1,7}, {5,8}}));
230 }
231 
232 /* A non-dominant write within an IF can be ignored (if it is read
233  * later)
234  */
TEST_F(LifetimeEvaluatorExactTest,NonDominantWriteinIfInLoop)235 TEST_F(LifetimeEvaluatorExactTest, NonDominantWriteinIfInLoop)
236 {
237    const vector<MockCodeline> code = {
238       { TGSI_OPCODE_BGNLOOP },
239       {   TGSI_OPCODE_MOV, {1}, {in0}, {}},
240       {   TGSI_OPCODE_IF, {}, {in1}, {}},
241       {     TGSI_OPCODE_MOV, {1}, {in1}, {}},
242       {   TGSI_OPCODE_ENDIF},
243       {   TGSI_OPCODE_UADD, {2}, {1,in1}, {}},
244       {   TGSI_OPCODE_IF, {}, {2}, {}},
245       {     TGSI_OPCODE_BRK},
246       {   TGSI_OPCODE_ENDIF},
247       { TGSI_OPCODE_ENDLOOP },
248       { TGSI_OPCODE_MOV, {out0}, {2}, {}},
249       { TGSI_OPCODE_END}
250    };
251    run (code, expectation({{-1,-1}, {1,5}, {5,10}}));
252 }
253 
254 /* In Nested loop if/else value written only in one path, and read later
255  * - value must survive the outer loop.
256  */
TEST_F(LifetimeEvaluatorExactTest,MoveInIfInNestedLoop)257 TEST_F(LifetimeEvaluatorExactTest, MoveInIfInNestedLoop)
258 {
259    const vector<MockCodeline> code = {
260       { TGSI_OPCODE_MOV, {1}, {in0}, {}},
261       { TGSI_OPCODE_BGNLOOP },
262       {   TGSI_OPCODE_BGNLOOP },
263       {     TGSI_OPCODE_IF, {}, {in1}, {} },
264       {       TGSI_OPCODE_UADD, {2}, {1,in0}, {}},
265       {     TGSI_OPCODE_ENDIF},
266       {     TGSI_OPCODE_UADD, {3}, {1,2}, {}},
267       {   TGSI_OPCODE_ENDLOOP },
268       { TGSI_OPCODE_ENDLOOP },
269       { TGSI_OPCODE_MOV, {out0}, {3}, {}},
270       { TGSI_OPCODE_END}
271    };
272    run (code, expectation({{-1,-1}, {0,8}, {1,8}, {6,9}}));
273 }
274 
275 /* In loop if/else value written in both path, and read later
276  * - value must survive from first write to last read in loop
277  * for now we only check that the minimum life time is correct.
278  */
TEST_F(LifetimeEvaluatorAtLeastTest,WriteInIfAndElseInLoop)279 TEST_F(LifetimeEvaluatorAtLeastTest, WriteInIfAndElseInLoop)
280 {
281    const vector<MockCodeline> code = {
282       { TGSI_OPCODE_MOV, {1}, {in0}, {}},
283       { TGSI_OPCODE_BGNLOOP },
284       {   TGSI_OPCODE_IF, {}, {1}, {}},
285       {     TGSI_OPCODE_UADD, {2}, {1,in0}, {}},
286       {   TGSI_OPCODE_ELSE },
287       {     TGSI_OPCODE_MOV, {2}, {1}, {}},
288       {   TGSI_OPCODE_ENDIF},
289       {   TGSI_OPCODE_UADD, {3}, {1,2}, {}},
290       {   TGSI_OPCODE_UADD, {3}, {3,in1}, {}},
291       { TGSI_OPCODE_ENDLOOP },
292       { TGSI_OPCODE_MOV, {out0}, {3}, {}},
293       { TGSI_OPCODE_END}
294    };
295    run (code, expectation({{-1,-1}, {0,9}, {3,7}, {7,10}}));
296 }
297 
298 /* In loop if/else value written in both path, read in else path
299  * before write and also read later
300  * - value must survive the whole loop
301  */
TEST_F(LifetimeEvaluatorExactTest,WriteInIfAndElseReadInElseInLoop)302 TEST_F(LifetimeEvaluatorExactTest, WriteInIfAndElseReadInElseInLoop)
303 {
304    const vector<MockCodeline> code = {
305       { TGSI_OPCODE_MOV, {1}, {in0}, {}},
306       { TGSI_OPCODE_BGNLOOP },
307       {   TGSI_OPCODE_IF, {}, {1}, {}},
308       {     TGSI_OPCODE_UADD, {2}, {1,in0}, {}},
309       {   TGSI_OPCODE_ELSE },
310       {     TGSI_OPCODE_ADD, {2}, {1,2}, {}},
311       {   TGSI_OPCODE_ENDIF},
312       {   TGSI_OPCODE_UADD, {3}, {1,2}, {}},
313       {   TGSI_OPCODE_UADD, {3}, {3,in1}, {}},
314       { TGSI_OPCODE_ENDLOOP },
315       { TGSI_OPCODE_MOV, {out0}, {3}, {}},
316       { TGSI_OPCODE_END}
317    };
318    run (code, expectation({{-1,-1}, {0,9}, {1,9}, {7,10}}));
319 }
320 
321 /* In loop if/else read in one path before written in the same loop
322  * - value must survive the whole loop
323  */
TEST_F(LifetimeEvaluatorExactTest,ReadInIfInLoopBeforeWrite)324 TEST_F(LifetimeEvaluatorExactTest, ReadInIfInLoopBeforeWrite)
325 {
326    const vector<MockCodeline> code = {
327       { TGSI_OPCODE_MOV, {1}, {in0}, {}},
328       { TGSI_OPCODE_BGNLOOP },
329       {   TGSI_OPCODE_IF, {}, {in0}, {}},
330       {     TGSI_OPCODE_UADD, {2}, {1,3}, {}},
331       {   TGSI_OPCODE_ENDIF},
332       {   TGSI_OPCODE_UADD, {3}, {1,2}, {}},
333       {   TGSI_OPCODE_UADD, {3}, {3,in1}, {}},
334       { TGSI_OPCODE_ENDLOOP },
335       { TGSI_OPCODE_MOV, {out0}, {3}, {}},
336       { TGSI_OPCODE_END}
337    };
338    run (code, expectation({{-1,-1}, {0,7}, {1,7}, {1,8}}));
339 }
340 
341 /* In loop if/else read in one path before written in the same loop
342  * read after the loop, value must survivethe whole loop and
343  * to the read.
344  */
TEST_F(LifetimeEvaluatorExactTest,ReadInLoopInIfBeforeWriteAndLifeToTheEnd)345 TEST_F(LifetimeEvaluatorExactTest, ReadInLoopInIfBeforeWriteAndLifeToTheEnd)
346 {
347    const vector<MockCodeline> code = {
348       { TGSI_OPCODE_BGNLOOP },
349       {   TGSI_OPCODE_IF, {}, {in0}, {}},
350       {     TGSI_OPCODE_MUL, {1}, {1,in1}, {}},
351       {   TGSI_OPCODE_ENDIF},
352       {   TGSI_OPCODE_UADD, {1}, {1,in1}, {}},
353       { TGSI_OPCODE_ENDLOOP },
354       { TGSI_OPCODE_MOV, {out0}, {1}, {}},
355       { TGSI_OPCODE_END}
356    };
357    run (code, expectation({{-1,-1}, {0,6}}));
358 }
359 
360 /* In loop if/else read in one path before written in the same loop
361  * read after the loop, value must survivethe whole loop and
362  * to the read.
363  */
TEST_F(LifetimeEvaluatorExactTest,ReadInLoopBeforeWriteAndLifeToTheEnd)364 TEST_F(LifetimeEvaluatorExactTest, ReadInLoopBeforeWriteAndLifeToTheEnd)
365 {
366    const vector<MockCodeline> code = {
367       { TGSI_OPCODE_BGNLOOP },
368       {   TGSI_OPCODE_MUL, {1}, {1,in1}, {}},
369       {   TGSI_OPCODE_UADD, {1}, {1,in1}, {}},
370       { TGSI_OPCODE_ENDLOOP },
371       { TGSI_OPCODE_MOV, {out0}, {1}, {}},
372       { TGSI_OPCODE_END}
373    };
374    run (code, expectation({{-1,-1}, {0,4}}));
375 }
376 
377 
378 /* Write in nested ifs in loop, for now we do test whether the
379  * life time is at least what is required, but we know that the
380  * implementation doesn't do a full check and sets larger boundaries
381  */
TEST_F(LifetimeEvaluatorAtLeastTest,NestedIfInLoopAlwaysWriteButNotPropagated)382 TEST_F(LifetimeEvaluatorAtLeastTest, NestedIfInLoopAlwaysWriteButNotPropagated)
383 {
384    const vector<MockCodeline> code = {
385       { TGSI_OPCODE_BGNLOOP },
386       {   TGSI_OPCODE_IF, {}, {in0}, {}},
387       {     TGSI_OPCODE_IF, {}, {in0}, {}},
388       {       TGSI_OPCODE_MOV, {1}, {in0}, {}},
389       {     TGSI_OPCODE_ELSE},
390       {       TGSI_OPCODE_MOV, {1}, {in0}, {}},
391       {     TGSI_OPCODE_ENDIF},
392       {   TGSI_OPCODE_ELSE},
393       {     TGSI_OPCODE_IF, {}, {in0}, {}},
394       {       TGSI_OPCODE_MOV, {1}, {in0}, {}},
395       {     TGSI_OPCODE_ELSE},
396       {       TGSI_OPCODE_MOV, {1}, {in0}, {}},
397       {     TGSI_OPCODE_ENDIF},
398       {   TGSI_OPCODE_ENDIF},
399       {   TGSI_OPCODE_MOV, {out0}, {1}, {}},
400       { TGSI_OPCODE_ENDLOOP },
401       { TGSI_OPCODE_END}
402    };
403    run (code, expectation({{-1,-1}, {3,14}}));
404 }
405 
406 /* The value is written in a loop and in a nested if, but
407  * not in all code paths, hence the value must survive the loop.
408  */
TEST_F(LifetimeEvaluatorExactTest,NestedIfInLoopWriteNotAlways)409 TEST_F(LifetimeEvaluatorExactTest, NestedIfInLoopWriteNotAlways)
410 {
411    const vector<MockCodeline> code = {
412       { TGSI_OPCODE_BGNLOOP },
413       {   TGSI_OPCODE_IF, {}, {in0}, {}},
414       {     TGSI_OPCODE_IF, {}, {in0}, {}},
415       {       TGSI_OPCODE_MOV, {1}, {in0}, {}},
416       {     TGSI_OPCODE_ELSE},
417       {       TGSI_OPCODE_MOV, {1}, {in0}, {}},
418       {     TGSI_OPCODE_ENDIF},
419       {   TGSI_OPCODE_ELSE},
420       {     TGSI_OPCODE_IF, {}, {in0}, {}},
421       {       TGSI_OPCODE_MOV, {1}, {in0}, {}},
422       {     TGSI_OPCODE_ENDIF},
423       {   TGSI_OPCODE_ENDIF},
424       {   TGSI_OPCODE_MOV, {out0}, {1}, {}},
425       { TGSI_OPCODE_ENDLOOP },
426       { TGSI_OPCODE_END}
427    };
428    run (code, expectation({{-1,-1}, {0,13}}));
429 }
430 
431 /* A continue in the loop is not relevant */
TEST_F(LifetimeEvaluatorExactTest,LoopWithWriteAfterContinue)432 TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterContinue)
433 {
434    const vector<MockCodeline> code = {
435       { TGSI_OPCODE_BGNLOOP },
436       {   TGSI_OPCODE_IF, {}, {in0}, {}},
437       {     TGSI_OPCODE_CONT},
438       {   TGSI_OPCODE_ENDIF},
439       {   TGSI_OPCODE_MOV, {1}, {in0}, {}},
440       { TGSI_OPCODE_ENDLOOP },
441       { TGSI_OPCODE_MOV, {out0}, {1}, {}},
442       { TGSI_OPCODE_END}
443    };
444    run (code, expectation({{-1,-1}, {4,6}}));
445 }
446 
447 /* Temporary used to in case must live up to the case
448  * statement where it is used, the switch we only keep
449  * for the actual SWITCH opcode like it is in tgsi_exec.c, the
450  * only current use case.
451  */
TEST_F(LifetimeEvaluatorExactTest,UseSwitchCase)452 TEST_F(LifetimeEvaluatorExactTest, UseSwitchCase)
453 {
454    const vector<MockCodeline> code = {
455       { TGSI_OPCODE_MOV, {1}, {in0}, {}},
456       { TGSI_OPCODE_MOV, {2}, {in1}, {}},
457       { TGSI_OPCODE_MOV, {3}, {in2}, {}},
458       { TGSI_OPCODE_SWITCH, {}, {3}, {}},
459       {   TGSI_OPCODE_CASE, {}, {2}, {}},
460       {   TGSI_OPCODE_CASE, {}, {1}, {}},
461       {   TGSI_OPCODE_BRK},
462       {   TGSI_OPCODE_DEFAULT},
463       { TGSI_OPCODE_ENDSWITCH},
464       { TGSI_OPCODE_END}
465    };
466    run (code, expectation({{-1,-1}, {0,5}, {1,4}, {2,3}}));
467 }
468 
469 /* With two destinations, if one result is thrown away, the
470  * register must be kept past the writing instructions.
471  */
TEST_F(LifetimeEvaluatorExactTest,WriteTwoOnlyUseOne)472 TEST_F(LifetimeEvaluatorExactTest, WriteTwoOnlyUseOne)
473 {
474    const vector<MockCodeline> code = {
475       { TGSI_OPCODE_DFRACEXP , {1,2}, {in0}, {}},
476       { TGSI_OPCODE_ADD , {3}, {2,in0}, {}},
477       { TGSI_OPCODE_MOV, {out1}, {3}, {}},
478       { TGSI_OPCODE_END},
479 
480    };
481    run (code, expectation({{-1,-1}, {0,1}, {0,1}, {1,2}}));
482 }
483 
484 /* If a break is in the loop, all variables written after the
485  * break and used outside the loop must be maintained for the
486  * whole loop
487  */
TEST_F(LifetimeEvaluatorExactTest,LoopWithWriteAfterBreak)488 TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterBreak)
489 {
490    const vector<MockCodeline> code = {
491       { TGSI_OPCODE_BGNLOOP },
492       {   TGSI_OPCODE_IF, {}, {in0}, {}},
493       {     TGSI_OPCODE_BRK},
494       {   TGSI_OPCODE_ENDIF},
495       {   TGSI_OPCODE_MOV, {1}, {in0}, {}},
496       { TGSI_OPCODE_ENDLOOP },
497       { TGSI_OPCODE_MOV, {out0}, {1}, {}},
498       { TGSI_OPCODE_END}
499    };
500    run (code, expectation({{-1,-1}, {0,6}}));
501 }
502 
503 /* If a break is in the loop, all variables written after the
504  * break and used outside the loop must be maintained for the
505  * whole loop. The first break in the loop is the defining one.
506  */
TEST_F(LifetimeEvaluatorExactTest,LoopWithWriteAfterBreak2Breaks)507 TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterBreak2Breaks)
508 {
509    const vector<MockCodeline> code = {
510       { TGSI_OPCODE_BGNLOOP },
511       {   TGSI_OPCODE_IF, {}, {in0}, {}},
512       {     TGSI_OPCODE_BRK},
513       {   TGSI_OPCODE_ENDIF},
514       {   TGSI_OPCODE_MOV, {1}, {in0}, {}},
515       {   TGSI_OPCODE_BRK},
516       { TGSI_OPCODE_ENDLOOP },
517       { TGSI_OPCODE_MOV, {out0}, {1}, {}},
518       { TGSI_OPCODE_END}
519    };
520    run (code, expectation({{-1,-1}, {0,7}}));
521 }
522 
523 /* Loop with a break at the beginning and read/write in the post
524  * break loop scope. The value written and read within the loop
525  * can be limited to [write, read], but the value read outside the
526  * loop must survive the whole loop. This is the typical code for
527  * while and for loops, where the breaking condition is tested at
528  * the beginning.
529  */
TEST_F(LifetimeEvaluatorExactTest,LoopWithWriteAndReadAfterBreak)530 TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAndReadAfterBreak)
531 {
532    const vector<MockCodeline> code = {
533       { TGSI_OPCODE_BGNLOOP },
534       {   TGSI_OPCODE_IF, {}, {in0}, {}},
535       {     TGSI_OPCODE_BRK},
536       {   TGSI_OPCODE_ENDIF},
537       {   TGSI_OPCODE_MOV, {1}, {in0}, {}},
538       {   TGSI_OPCODE_MOV, {2}, {1}, {}},
539       { TGSI_OPCODE_ENDLOOP },
540       { TGSI_OPCODE_MOV, {out0}, {2}, {}},
541       { TGSI_OPCODE_END}
542    };
543    run (code, expectation({{-1,-1}, {4,5}, {0,7}}));
544 }
545 
546 /* Same as above, just make sure that the life time of the local variable
547  * in the outer loop (3) is not accidently promoted to the whole loop.
548  */
TEST_F(LifetimeEvaluatorExactTest,NestedLoopWithWriteAndReadAfterBreak)549 TEST_F(LifetimeEvaluatorExactTest, NestedLoopWithWriteAndReadAfterBreak)
550 {
551    const vector<MockCodeline> code = {
552       { TGSI_OPCODE_BGNLOOP },
553       {   TGSI_OPCODE_IF, {}, {in1}, {}},
554       {     TGSI_OPCODE_BRK},
555       {   TGSI_OPCODE_ENDIF},
556       {   TGSI_OPCODE_BGNLOOP},
557       {     TGSI_OPCODE_IF, {}, {in0}, {}},
558       {       TGSI_OPCODE_BRK},
559       {     TGSI_OPCODE_ENDIF},
560       {     TGSI_OPCODE_MOV, {1}, {in0}, {}},
561       {     TGSI_OPCODE_MOV, {2}, {1}, {}},
562       {   TGSI_OPCODE_ENDLOOP },
563       {   TGSI_OPCODE_ADD, {3}, {2,in0}, {}},
564       {   TGSI_OPCODE_ADD, {4}, {3,in2}, {}},
565       { TGSI_OPCODE_ENDLOOP },
566       { TGSI_OPCODE_MOV, {out0}, {4}, {}},
567       { TGSI_OPCODE_END}
568    };
569    run (code, expectation({{-1,-1}, {8,9}, {0,13}, {11,12}, {0,14}}));
570 }
571 
572 /* If a break is in the loop inside a switch case, make sure it is
573  * interpreted as breaking that inner loop, i.e. the variable has to
574  * survive the loop.
575  */
TEST_F(LifetimeEvaluatorExactTest,LoopWithWriteAfterBreakInSwitchInLoop)576 TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterBreakInSwitchInLoop)
577 {
578    const vector<MockCodeline> code = {
579       { TGSI_OPCODE_SWITCH, {}, {in1}, {}},
580       {  TGSI_OPCODE_CASE, {}, {in1}, {}},
581       {   TGSI_OPCODE_BGNLOOP },
582       {    TGSI_OPCODE_IF, {}, {in0}, {}},
583       {     TGSI_OPCODE_BRK},
584       {    TGSI_OPCODE_ENDIF},
585       {    TGSI_OPCODE_MOV, {1}, {in0}, {}},
586       {   TGSI_OPCODE_ENDLOOP },
587       {  TGSI_OPCODE_DEFAULT, {}, {}, {}},
588       { TGSI_OPCODE_ENDSWITCH, {}, {}, {}},
589       { TGSI_OPCODE_MOV, {out0}, {1}, {}},
590       { TGSI_OPCODE_END}
591    };
592    run (code, expectation({{-1,-1}, {2,10}}));
593 }
594 
595 /* Value written conditionally in one loop and read in another loop,
596  * and both of these loops are within yet another loop. Here the value
597  * has to survive the outer loop.
598  */
TEST_F(LifetimeEvaluatorExactTest,LoopsWithDifferntScopesConditionalWrite)599 TEST_F(LifetimeEvaluatorExactTest, LoopsWithDifferntScopesConditionalWrite)
600 {
601    const vector<MockCodeline> code = {
602       { TGSI_OPCODE_BGNLOOP },
603       {  TGSI_OPCODE_IF, {}, {in0}, {}},
604       {     TGSI_OPCODE_MOV, {1}, {in0}, {}},
605       {   TGSI_OPCODE_ENDIF},
606       { TGSI_OPCODE_ENDLOOP },
607       { TGSI_OPCODE_BGNLOOP },
608       {     TGSI_OPCODE_MOV, {out0}, {1}, {}},
609       { TGSI_OPCODE_ENDLOOP },
610       { TGSI_OPCODE_END}
611    };
612    run (code, expectation({{-1,-1}, {0,7}}));
613 }
614 
615 /* Value written and read in one loop and last read in another loop,
616  * Here the value has to survive both loops.
617  */
TEST_F(LifetimeEvaluatorExactTest,LoopsWithDifferntScopesFirstReadBeforeWrite)618 TEST_F(LifetimeEvaluatorExactTest, LoopsWithDifferntScopesFirstReadBeforeWrite)
619 {
620    const vector<MockCodeline> code = {
621       { TGSI_OPCODE_BGNLOOP },
622       {   TGSI_OPCODE_MUL, {1}, {1,in0}, {}},
623       { TGSI_OPCODE_ENDLOOP },
624       { TGSI_OPCODE_BGNLOOP },
625       {   TGSI_OPCODE_MOV, {out0}, {1}, {}},
626       { TGSI_OPCODE_ENDLOOP },
627       { TGSI_OPCODE_END}
628    };
629    run (code, expectation({{-1,-1}, {0,5}}));
630 }
631 
632 
633 /* Value is written in one switch code path within a loop
634  * must survive the full loop.
635  */
TEST_F(LifetimeEvaluatorExactTest,LoopWithWriteInSwitch)636 TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteInSwitch)
637 {
638    const vector<MockCodeline> code = {
639       { TGSI_OPCODE_BGNLOOP },
640       {   TGSI_OPCODE_SWITCH, {}, {in0}, {} },
641       {    TGSI_OPCODE_CASE, {}, {in0}, {} },
642       {     TGSI_OPCODE_MOV, {1}, {in0}, {}},
643       {    TGSI_OPCODE_BRK },
644       {   TGSI_OPCODE_DEFAULT },
645       {   TGSI_OPCODE_BRK },
646       {   TGSI_OPCODE_ENDSWITCH },
647       {   TGSI_OPCODE_MOV, {out0}, {1}, {}},
648       { TGSI_OPCODE_ENDLOOP },
649       { TGSI_OPCODE_END}
650    };
651    run (code, expectation({{-1,-1}, {0,9}}));
652 }
653 
654 /* Value written in one case, and read in other,in loop
655  * - must survive the loop.
656  */
TEST_F(LifetimeEvaluatorExactTest,LoopWithReadWriteInSwitchDifferentCase)657 TEST_F(LifetimeEvaluatorExactTest, LoopWithReadWriteInSwitchDifferentCase)
658 {
659    const vector<MockCodeline> code = {
660       { TGSI_OPCODE_BGNLOOP },
661       {   TGSI_OPCODE_SWITCH, {}, {in0}, {} },
662       {    TGSI_OPCODE_CASE, {}, {in0}, {} },
663       {     TGSI_OPCODE_MOV, {1}, {in0}, {}},
664       {    TGSI_OPCODE_BRK },
665       {   TGSI_OPCODE_DEFAULT },
666       {     TGSI_OPCODE_MOV, {out0}, {1}, {}},
667       {   TGSI_OPCODE_BRK },
668       {   TGSI_OPCODE_ENDSWITCH },
669       { TGSI_OPCODE_ENDLOOP },
670       { TGSI_OPCODE_END}
671    };
672    run (code, expectation({{-1,-1}, {0,9}}));
673 }
674 
675 /* Value written in one case, and read in other,in loop
676  * - must survive the loop, even if the write case falls through.
677  */
TEST_F(LifetimeEvaluatorExactTest,LoopWithReadWriteInSwitchDifferentCaseFallThrough)678 TEST_F(LifetimeEvaluatorExactTest, LoopWithReadWriteInSwitchDifferentCaseFallThrough)
679 {
680    const vector<MockCodeline> code = {
681       { TGSI_OPCODE_BGNLOOP },
682       {   TGSI_OPCODE_SWITCH, {}, {in0}, {} },
683       {    TGSI_OPCODE_CASE, {}, {in0}, {} },
684       {     TGSI_OPCODE_MOV, {1}, {in0}, {}},
685       {   TGSI_OPCODE_DEFAULT },
686       {     TGSI_OPCODE_MOV, {out0}, {1}, {}},
687       {   TGSI_OPCODE_BRK },
688       {   TGSI_OPCODE_ENDSWITCH },
689       { TGSI_OPCODE_ENDLOOP },
690       { TGSI_OPCODE_END}
691    };
692    run (code, expectation({{-1,-1}, {0,8}}));
693 }
694 
695 
696 /* Here we read and write from an to the same temp in the same instruction,
697  * but the read is conditional (select operation), hence the lifetime must
698  * start with the first write.
699  */
TEST_F(LifetimeEvaluatorExactTest,WriteSelectFromSelf)700 TEST_F(LifetimeEvaluatorExactTest, WriteSelectFromSelf)
701 {
702    const vector<MockCodeline> code = {
703       {TGSI_OPCODE_USEQ, {5}, {in0,in1}, {}},
704       {TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
705       {TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
706       {TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
707       {TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
708       {TGSI_OPCODE_FSLT, {2}, {1,in1}, {}},
709       {TGSI_OPCODE_UIF, {}, {2}, {}},
710       {  TGSI_OPCODE_MOV, {3}, {in1}, {}},
711       {TGSI_OPCODE_ELSE},
712       {  TGSI_OPCODE_MOV, {4}, {in1}, {}},
713       {  TGSI_OPCODE_MOV, {4}, {4}, {}},
714       {  TGSI_OPCODE_MOV, {3}, {4}, {}},
715       {TGSI_OPCODE_ENDIF},
716       {TGSI_OPCODE_MOV, {out1}, {3}, {}},
717       {TGSI_OPCODE_END}
718    };
719    run (code, expectation({{-1,-1}, {1,5}, {5,6}, {7,13}, {9,11}, {0,4}}));
720 }
721 
722 /* This test checks wheter the ENDSWITCH is handled properly if the
723  * last switch case/default doesn't stop with a BRK.
724  */
TEST_F(LifetimeEvaluatorExactTest,LoopRWInSwitchCaseLastCaseWithoutBreak)725 TEST_F(LifetimeEvaluatorExactTest, LoopRWInSwitchCaseLastCaseWithoutBreak)
726 {
727    const vector<MockCodeline> code = {
728       { TGSI_OPCODE_BGNLOOP },
729       {   TGSI_OPCODE_SWITCH, {}, {in0}, {} },
730       {    TGSI_OPCODE_CASE, {}, {in0}, {} },
731       {     TGSI_OPCODE_MOV, {1}, {in0}, {}},
732       {    TGSI_OPCODE_BRK },
733       {   TGSI_OPCODE_DEFAULT },
734       {     TGSI_OPCODE_MOV, {out0}, {1}, {}},
735       {   TGSI_OPCODE_ENDSWITCH },
736       { TGSI_OPCODE_ENDLOOP },
737       { TGSI_OPCODE_END}
738    };
739    run (code, expectation({{-1,-1}, {0,8}}));
740 }
741 
742 /* Value read/write in same case, stays there */
TEST_F(LifetimeEvaluatorExactTest,LoopWithReadWriteInSwitchSameCase)743 TEST_F(LifetimeEvaluatorExactTest, LoopWithReadWriteInSwitchSameCase)
744 {
745    const vector<MockCodeline> code = {
746       { TGSI_OPCODE_BGNLOOP },
747       {   TGSI_OPCODE_SWITCH, {}, {in0}, {} },
748       {    TGSI_OPCODE_CASE, {}, {in0}, {} },
749       {     TGSI_OPCODE_MOV, {1}, {in0}, {}},
750       {     TGSI_OPCODE_MOV, {out0}, {1}, {}},
751       {    TGSI_OPCODE_BRK },
752       {   TGSI_OPCODE_DEFAULT },
753       {   TGSI_OPCODE_BRK },
754       {   TGSI_OPCODE_ENDSWITCH },
755       { TGSI_OPCODE_ENDLOOP },
756       { TGSI_OPCODE_END}
757    };
758    run (code, expectation({{-1,-1}, {3,4}}));
759 }
760 
761 /* Value read/write in all cases, should only live from first
762  * write to last read, but currently the whole loop is used.
763  */
TEST_F(LifetimeEvaluatorAtLeastTest,LoopWithReadWriteInSwitchSameCase)764 TEST_F(LifetimeEvaluatorAtLeastTest, LoopWithReadWriteInSwitchSameCase)
765 {
766    const vector<MockCodeline> code = {
767       { TGSI_OPCODE_BGNLOOP },
768       {   TGSI_OPCODE_SWITCH, {}, {in0}, {}},
769       {    TGSI_OPCODE_CASE, {}, {in0}, {} },
770       {     TGSI_OPCODE_MOV, {1}, {in0}, {}},
771       {    TGSI_OPCODE_BRK },
772       {   TGSI_OPCODE_DEFAULT },
773       {     TGSI_OPCODE_MOV, {1}, {in0}, {}},
774       {   TGSI_OPCODE_BRK },
775       {   TGSI_OPCODE_ENDSWITCH },
776       {   TGSI_OPCODE_MOV, {out0}, {1}, {}},
777       { TGSI_OPCODE_ENDLOOP },
778       { TGSI_OPCODE_END}
779    };
780    run (code, expectation({{-1,-1}, {3,9}}));
781 }
782 
783 /* First read before first write with nested loops */
TEST_F(LifetimeEvaluatorExactTest,LoopsWithDifferentScopesCondReadBeforeWrite)784 TEST_F(LifetimeEvaluatorExactTest, LoopsWithDifferentScopesCondReadBeforeWrite)
785 {
786    const vector<MockCodeline> code = {
787       { TGSI_OPCODE_BGNLOOP },
788       {   TGSI_OPCODE_BGNLOOP },
789       {    TGSI_OPCODE_IF, {}, {in0}, {}},
790       {     TGSI_OPCODE_MOV, {out0}, {1}, {}},
791       {    TGSI_OPCODE_ENDIF},
792       {   TGSI_OPCODE_ENDLOOP },
793       {   TGSI_OPCODE_BGNLOOP },
794       {     TGSI_OPCODE_MOV, {1}, {in0}, {}},
795       {   TGSI_OPCODE_ENDLOOP },
796       { TGSI_OPCODE_ENDLOOP },
797       { TGSI_OPCODE_END}
798    };
799    run (code, expectation({{-1,-1}, {0,9}}));
800 }
801 
802 /* First read before first write wiredness with nested loops.
803  * Here the first read of 2 is logically before the first, dominant
804  * write, therfore, the 2 has to survive both loops.
805  */
TEST_F(LifetimeEvaluatorExactTest,FirstWriteAtferReadInNestedLoop)806 TEST_F(LifetimeEvaluatorExactTest, FirstWriteAtferReadInNestedLoop)
807 {
808    const vector<MockCodeline> code = {
809       { TGSI_OPCODE_MOV, {1}, {in0}, {}},
810       { TGSI_OPCODE_BGNLOOP },
811       {   TGSI_OPCODE_BGNLOOP },
812       {     TGSI_OPCODE_MUL, {2}, {2,1}, {}},
813       {     TGSI_OPCODE_MOV, {3}, {2}, {}},
814       {   TGSI_OPCODE_ENDLOOP },
815       { TGSI_OPCODE_ADD, {1}, {1,in1}, {}},
816       { TGSI_OPCODE_ENDLOOP },
817       { TGSI_OPCODE_MOV, {out0}, {3}, {}},
818       { TGSI_OPCODE_END}
819    };
820    run (code, expectation({{-1,-1}, {0,7}, {1,7}, {4,8}}));
821 }
822 
823 
824 #define DST(X, W) vector<pair<int,int>>(1, make_pair(X, W))
825 #define SRC(X, S) vector<pair<int, const char *>>(1, make_pair(X, S))
826 #define SRC2(X, S, Y, T) vector<pair<int, const char *>>({make_pair(X, S), make_pair(Y, T)})
827 
828 /* Partial write to components: one component was written unconditionally
829  * but another conditionally, temporary must survive the whole loop.
830  * Test series for all components.
831  */
TEST_F(LifetimeEvaluatorExactTest,LoopWithConditionalComponentWrite_X)832 TEST_F(LifetimeEvaluatorExactTest, LoopWithConditionalComponentWrite_X)
833 {
834    const vector<MockCodelineWithSwizzle> code = {
835       MockCodelineWithSwizzle(TGSI_OPCODE_BGNLOOP),
836       MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(1, WRITEMASK_Y), SRC(in1, "x"), {}),
837       MockCodelineWithSwizzle(TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}),
838       MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "y"), {}),
839       MockCodelineWithSwizzle(TGSI_OPCODE_ENDIF),
840       MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(2, WRITEMASK_XY), SRC(1, "xy"), {}),
841       MockCodelineWithSwizzle(TGSI_OPCODE_ENDLOOP),
842       MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(out0, WRITEMASK_XYZW), SRC(2, "xyxy"), {}),
843       MockCodelineWithSwizzle(TGSI_OPCODE_END)
844    };
845    run (code, expectation({{-1,-1}, {0,6}, {5,7}}));
846 }
847 
TEST_F(LifetimeEvaluatorExactTest,LoopWithConditionalComponentWrite_Y)848 TEST_F(LifetimeEvaluatorExactTest, LoopWithConditionalComponentWrite_Y)
849 {
850    const vector<MockCodelineWithSwizzle> code = {
851       MockCodelineWithSwizzle(TGSI_OPCODE_BGNLOOP),
852       MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "x"), {}),
853       MockCodelineWithSwizzle(TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}),
854       MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(1, WRITEMASK_Y), SRC(in1, "y"), {}),
855       MockCodelineWithSwizzle(TGSI_OPCODE_ENDIF),
856       MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(2, WRITEMASK_XY), SRC(1, "xy"), {}),
857       MockCodelineWithSwizzle(TGSI_OPCODE_ENDLOOP),
858       MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(out0, WRITEMASK_XYZW), SRC(2, "xyxy"), {}),
859       MockCodelineWithSwizzle(TGSI_OPCODE_END)
860    };
861    run (code, expectation({{-1,-1}, {0,6}, {5,7}}));
862 }
863 
TEST_F(LifetimeEvaluatorExactTest,LoopWithConditionalComponentWrite_Z)864 TEST_F(LifetimeEvaluatorExactTest, LoopWithConditionalComponentWrite_Z)
865 {
866    const vector<MockCodelineWithSwizzle> code = {
867       MockCodelineWithSwizzle(TGSI_OPCODE_BGNLOOP),
868       MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "x"), {}),
869       MockCodelineWithSwizzle(TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}),
870       MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(1, WRITEMASK_Z), SRC(in1, "y"), {}),
871       MockCodelineWithSwizzle(TGSI_OPCODE_ENDIF),
872       MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(2, WRITEMASK_XY), SRC(1, "xz"), {}),
873       MockCodelineWithSwizzle(TGSI_OPCODE_ENDLOOP),
874       MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(out0, WRITEMASK_XYZW), SRC(2, "xyxy"), {}),
875       MockCodelineWithSwizzle(TGSI_OPCODE_END)
876    };
877    run (code, expectation({{-1,-1}, {0,6}, {5,7}}));
878 }
879 
TEST_F(LifetimeEvaluatorExactTest,LoopWithConditionalComponentWrite_W)880 TEST_F(LifetimeEvaluatorExactTest, LoopWithConditionalComponentWrite_W)
881 {
882    const vector<MockCodelineWithSwizzle> code = {
883       MockCodelineWithSwizzle(TGSI_OPCODE_BGNLOOP),
884       MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "x"), {}),
885       MockCodelineWithSwizzle(TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}),
886       MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(1, WRITEMASK_W), SRC(in1, "y"), {}),
887       MockCodelineWithSwizzle(TGSI_OPCODE_ENDIF),
888       MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(2, WRITEMASK_XY), SRC(1, "xw"), {}),
889       MockCodelineWithSwizzle(TGSI_OPCODE_ENDLOOP),
890       MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(out0, WRITEMASK_XYZW), SRC(2, "xyxy"), {}),
891       MockCodelineWithSwizzle(TGSI_OPCODE_END)
892    };
893    run (code, expectation({{-1,-1}, {0,6}, {5,7}}));
894 }
895 
TEST_F(LifetimeEvaluatorExactTest,LoopWithConditionalComponentWrite_X_Read_Y_Before)896 TEST_F(LifetimeEvaluatorExactTest, LoopWithConditionalComponentWrite_X_Read_Y_Before)
897 {
898    const vector<MockCodelineWithSwizzle> code = {
899       MockCodelineWithSwizzle(TGSI_OPCODE_BGNLOOP),
900       MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "x"), {}),
901       MockCodelineWithSwizzle(TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}),
902       MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(2, WRITEMASK_XYZW), SRC(1, "yyyy"), {}),
903       MockCodelineWithSwizzle(TGSI_OPCODE_ENDIF),
904       MockCodelineWithSwizzle(TGSI_OPCODE_MOV, DST(1, WRITEMASK_YZW), SRC(2, "yyzw"), {}),
905       MockCodelineWithSwizzle(TGSI_OPCODE_ENDLOOP),
906       MockCodelineWithSwizzle(TGSI_OPCODE_ADD, DST(out0, WRITEMASK_XYZW), SRC2(2, "yyzw", 1, "xyxy"), {}),
907       MockCodelineWithSwizzle(TGSI_OPCODE_END)
908    };
909    run (code, expectation({{-1,-1}, {0,7}, {0,7}}));
910 }
911 
912 /* The variable is conditionally read before first written, so
913  * it has to surive all the loops.
914  */
TEST_F(LifetimeEvaluatorExactTest,FRaWSameInstructionInLoopAndCondition)915 TEST_F(LifetimeEvaluatorExactTest, FRaWSameInstructionInLoopAndCondition)
916 {
917    const vector<MockCodeline> code = {
918       { TGSI_OPCODE_BGNLOOP },
919       {   TGSI_OPCODE_BGNLOOP },
920       {     TGSI_OPCODE_IF, {0}, {in0}, {} },
921       {       TGSI_OPCODE_ADD, {1}, {1,in0}, {}},
922       {     TGSI_OPCODE_ENDIF},
923       {     TGSI_OPCODE_MOV, {1}, {in1}, {}},
924       {  TGSI_OPCODE_ENDLOOP },
925       { TGSI_OPCODE_ENDLOOP },
926       { TGSI_OPCODE_END},
927 
928    };
929    run (code, expectation({{-1,-1}, {0,7}}));
930 }
931 
932 /* If unconditionally first written and read in the same
933  * instruction, then the register must be kept for the
934  * one write, but not more (undefined behaviour)
935  */
TEST_F(LifetimeEvaluatorExactTest,FRaWSameInstruction)936 TEST_F(LifetimeEvaluatorExactTest, FRaWSameInstruction)
937 {
938    const vector<MockCodeline> code = {
939       { TGSI_OPCODE_ADD, {1}, {1,in0}, {}},
940       { TGSI_OPCODE_END},
941 
942    };
943    run (code, expectation({{-1,-1}, {0,1}}));
944 }
945 
946 /* If unconditionally written and read in the same
947  * instruction, various times then the register must be
948  * kept past the last write, but not longer (undefined behaviour)
949  */
TEST_F(LifetimeEvaluatorExactTest,FRaWSameInstructionMoreThenOnce)950 TEST_F(LifetimeEvaluatorExactTest, FRaWSameInstructionMoreThenOnce)
951 {
952    const vector<MockCodeline> code = {
953       { TGSI_OPCODE_ADD, {1}, {1,in0}, {}},
954       { TGSI_OPCODE_ADD, {1}, {1,in0}, {}},
955       { TGSI_OPCODE_MOV, {out0}, {in0}, {}},
956       { TGSI_OPCODE_END},
957 
958    };
959    run (code, expectation({{-1,-1}, {0,2}}));
960 }
961 
962 /* Register is only written. This should not happen,
963  * but to handle the case we want the register to life
964  * at least one instruction
965  */
TEST_F(LifetimeEvaluatorExactTest,WriteOnly)966 TEST_F(LifetimeEvaluatorExactTest, WriteOnly)
967 {
968    const vector<MockCodeline> code = {
969       { TGSI_OPCODE_MOV, {1}, {in0}, {}},
970       { TGSI_OPCODE_END}
971    };
972    run (code, expectation({{-1,-1}, {0,1}}));
973 }
974 
975 /* Register is read in IF.
976  */
TEST_F(LifetimeEvaluatorExactTest,SimpleReadForIf)977 TEST_F(LifetimeEvaluatorExactTest, SimpleReadForIf)
978 {
979    const vector<MockCodeline> code = {
980       { TGSI_OPCODE_MOV, {1}, {in0}, {}},
981       { TGSI_OPCODE_ADD, {out0}, {in0,in1}, {}},
982       { TGSI_OPCODE_IF, {}, {1}, {}},
983       { TGSI_OPCODE_ENDIF}
984    };
985    run (code, expectation({{-1,-1}, {0,2}}));
986 }
987 
TEST_F(LifetimeEvaluatorExactTest,WriteTwoReadOne)988 TEST_F(LifetimeEvaluatorExactTest, WriteTwoReadOne)
989 {
990    const vector<MockCodeline> code = {
991       { TGSI_OPCODE_DFRACEXP , {1,2}, {in0}, {}},
992       { TGSI_OPCODE_ADD , {3}, {2,in0}, {}},
993       { TGSI_OPCODE_MOV, {out1}, {3}, {}},
994       { TGSI_OPCODE_END},
995    };
996    run (code, expectation({{-1,-1}, {0,1}, {0,1}, {1,2}}));
997 }
998 
TEST_F(LifetimeEvaluatorExactTest,ReadOnly)999 TEST_F(LifetimeEvaluatorExactTest, ReadOnly)
1000 {
1001    const vector<MockCodeline> code = {
1002       { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1003       { TGSI_OPCODE_END},
1004    };
1005    run (code, expectation({{-1,-1}, {-1,-1}}));
1006 }
1007 
1008 
1009 /* Test handling of missing END marker
1010 */
TEST_F(LifetimeEvaluatorExactTest,SomeScopesAndNoEndProgramId)1011 TEST_F(LifetimeEvaluatorExactTest, SomeScopesAndNoEndProgramId)
1012 {
1013    const vector<MockCodeline> code = {
1014       { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1015       { TGSI_OPCODE_IF, {}, {1}, {}},
1016       { TGSI_OPCODE_MOV, {2}, {1}, {}},
1017       { TGSI_OPCODE_ENDIF},
1018       { TGSI_OPCODE_IF, {}, {1}, {}},
1019       { TGSI_OPCODE_MOV, {out0}, {2}, {}},
1020       { TGSI_OPCODE_ENDIF},
1021    };
1022    run (code, expectation({{-1,-1}, {0,4}, {2,5}}));
1023 }
1024 
TEST_F(LifetimeEvaluatorExactTest,SerialReadWrite)1025 TEST_F(LifetimeEvaluatorExactTest, SerialReadWrite)
1026 {
1027    const vector<MockCodeline> code = {
1028       { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1029       { TGSI_OPCODE_MOV, {2}, {1}, {}},
1030       { TGSI_OPCODE_MOV, {3}, {2}, {}},
1031       { TGSI_OPCODE_MOV, {out0}, {3}, {}},
1032       { TGSI_OPCODE_END},
1033    };
1034    run (code, expectation({{-1,-1}, {0,1}, {1,2}, {2,3}}));
1035 }
1036 
1037 /* Check that two destination registers are used */
TEST_F(LifetimeEvaluatorExactTest,TwoDestRegisters)1038 TEST_F(LifetimeEvaluatorExactTest, TwoDestRegisters)
1039 {
1040    const vector<MockCodeline> code = {
1041       { TGSI_OPCODE_DFRACEXP , {1,2}, {in0}, {}},
1042       { TGSI_OPCODE_ADD, {out0}, {1,2}, {}},
1043       { TGSI_OPCODE_END}
1044    };
1045    run (code, expectation({{-1,-1}, {0,1}, {0,1}}));
1046 }
1047 
1048 /* Check that writing within a loop in a conditional is propagated
1049  * to the outer loop.
1050  */
TEST_F(LifetimeEvaluatorExactTest,WriteInLoopInConditionalReadOutside)1051 TEST_F(LifetimeEvaluatorExactTest, WriteInLoopInConditionalReadOutside)
1052 {
1053    const vector<MockCodeline> code = {
1054       { TGSI_OPCODE_BGNLOOP},
1055       {   TGSI_OPCODE_IF, {}, {in0}, {}},
1056       {     TGSI_OPCODE_BGNLOOP},
1057       {       TGSI_OPCODE_MOV, {1}, {in1}, {}},
1058       {     TGSI_OPCODE_ENDLOOP},
1059       {   TGSI_OPCODE_ENDIF},
1060       {   TGSI_OPCODE_ADD, {2}, {1,in1}, {}},
1061       { TGSI_OPCODE_ENDLOOP},
1062       { TGSI_OPCODE_MOV, {out0}, {2}, {}},
1063       { TGSI_OPCODE_END}
1064    };
1065    run (code, expectation({{-1,-1}, {0,7}, {6,8}}));
1066 }
1067 
1068 /* Check that a register written in a loop that is inside a conditional
1069  * is not propagated past that loop if last read is also within the
1070  * conditional
1071 */
TEST_F(LifetimeEvaluatorExactTest,WriteInLoopInCondReadInCondOutsideLoop)1072 TEST_F(LifetimeEvaluatorExactTest, WriteInLoopInCondReadInCondOutsideLoop)
1073 {
1074    const vector<MockCodeline> code = {
1075       { TGSI_OPCODE_BGNLOOP},
1076       {   TGSI_OPCODE_IF, {}, {in0}, {}},
1077       {     TGSI_OPCODE_BGNLOOP},
1078       {       TGSI_OPCODE_MUL, {1}, {in2,in1}, {}},
1079       {     TGSI_OPCODE_ENDLOOP},
1080       {     TGSI_OPCODE_ADD, {2}, {1,in1}, {}},
1081       {   TGSI_OPCODE_ENDIF},
1082       { TGSI_OPCODE_ENDLOOP},
1083       { TGSI_OPCODE_MOV, {out0}, {2}, {}},
1084       { TGSI_OPCODE_END}
1085    };
1086    run (code, expectation({{-1,-1}, {3,5}, {0,8}}));
1087 }
1088 
1089 /* Check that a register read before written in a loop that is
1090  * inside a conditional is propagated to the outer loop.
1091  */
TEST_F(LifetimeEvaluatorExactTest,ReadWriteInLoopInCondReadInCondOutsideLoop)1092 TEST_F(LifetimeEvaluatorExactTest, ReadWriteInLoopInCondReadInCondOutsideLoop)
1093 {
1094    const vector<MockCodeline> code = {
1095       { TGSI_OPCODE_BGNLOOP},
1096       {   TGSI_OPCODE_IF, {}, {in0}, {}},
1097       {     TGSI_OPCODE_BGNLOOP},
1098       {       TGSI_OPCODE_MUL, {1}, {1,in1}, {}},
1099       {     TGSI_OPCODE_ENDLOOP},
1100       {     TGSI_OPCODE_ADD, {2}, {1,in1}, {}},
1101       {   TGSI_OPCODE_ENDIF},
1102       { TGSI_OPCODE_ENDLOOP},
1103       { TGSI_OPCODE_MOV, {out0}, {2}, {}},
1104       { TGSI_OPCODE_END}
1105    };
1106    run (code, expectation({{-1,-1}, {0,7}, {0,8}}));
1107 }
1108 
1109 /* With two destinations if one value is thrown away, we must
1110  * ensure that the two output registers don't merge. In this test
1111  * case the last access for 2 and 3 is in line 4, but 4 can only
1112  * be merged with 3 because it is read,2 on the other hand is written
1113  * to, and merging it with 4 would result in a bug.
1114  */
TEST_F(LifetimeEvaluatorExactTest,WritePastLastRead2)1115 TEST_F(LifetimeEvaluatorExactTest, WritePastLastRead2)
1116 {
1117    const vector<MockCodeline> code = {
1118       { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1119       { TGSI_OPCODE_MOV, {2}, {in0}, {}},
1120       { TGSI_OPCODE_ADD, {3}, {1,2}, {}},
1121       { TGSI_OPCODE_DFRACEXP , {2,4}, {3}, {}},
1122       { TGSI_OPCODE_MOV, {out1}, {4}, {}},
1123       { TGSI_OPCODE_END}
1124    };
1125    run (code, expectation({{-1,-1}, {0,2}, {1,4}, {2,3}, {3,4}}));
1126 }
1127 
1128 /* Check that three source registers are used */
TEST_F(LifetimeEvaluatorExactTest,ThreeSourceRegisters)1129 TEST_F(LifetimeEvaluatorExactTest, ThreeSourceRegisters)
1130 {
1131    const vector<MockCodeline> code = {
1132       { TGSI_OPCODE_DFRACEXP , {1,2}, {in0}, {}},
1133       { TGSI_OPCODE_ADD , {3}, {in0,in1}, {}},
1134       { TGSI_OPCODE_MAD, {out0}, {1,2,3}, {}},
1135       { TGSI_OPCODE_END}
1136    };
1137    run (code, expectation({{-1,-1}, {0,2}, {0,2}, {1,2}}));
1138 }
1139 
1140 /* Check minimal lifetime for registers only written to */
TEST_F(LifetimeEvaluatorExactTest,OverwriteWrittenOnlyTemps)1141 TEST_F(LifetimeEvaluatorExactTest, OverwriteWrittenOnlyTemps)
1142 {
1143    const vector<MockCodeline> code = {
1144       { TGSI_OPCODE_MOV , {1}, {in0}, {}},
1145       { TGSI_OPCODE_MOV , {2}, {in1}, {}},
1146       { TGSI_OPCODE_END}
1147    };
1148    run (code, expectation({{-1,-1}, {0,1}, {1,2}}));
1149 }
1150 
1151 /* Same register is only written twice. This should not happen,
1152  * but to handle the case we want the register to life
1153  * at least past the last write instruction
1154  */
TEST_F(LifetimeEvaluatorExactTest,WriteOnlyTwiceSame)1155 TEST_F(LifetimeEvaluatorExactTest, WriteOnlyTwiceSame)
1156 {
1157    const vector<MockCodeline> code = {
1158       { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1159       { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1160       { TGSI_OPCODE_END}
1161    };
1162    run (code, expectation({{-1,-1}, {0,2}}));
1163 }
1164 
1165 /* Dead code elimination should catch and remove the case
1166  * when a variable is written after its last read, but
1167  * we want the code to be aware of this case.
1168  * The life time of this uselessly written variable is set
1169  * to the instruction after the write, because
1170  * otherwise it could be re-used too early.
1171  */
TEST_F(LifetimeEvaluatorExactTest,WritePastLastRead)1172 TEST_F(LifetimeEvaluatorExactTest, WritePastLastRead)
1173 {
1174    const vector<MockCodeline> code = {
1175       { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1176       { TGSI_OPCODE_MOV, {2}, {1}, {}},
1177       { TGSI_OPCODE_MOV, {1}, {2}, {}},
1178       { TGSI_OPCODE_END},
1179 
1180    };
1181    run (code, expectation({{-1,-1}, {0,3}, {1,2}}));
1182 }
1183 
1184 /* If a break is in the loop, all variables written after the
1185  * break and used outside the loop the variable must survive the
1186  * outer loop
1187  */
TEST_F(LifetimeEvaluatorExactTest,NestedLoopWithWriteAfterBreak)1188 TEST_F(LifetimeEvaluatorExactTest, NestedLoopWithWriteAfterBreak)
1189 {
1190    const vector<MockCodeline> code = {
1191       { TGSI_OPCODE_BGNLOOP },
1192       {   TGSI_OPCODE_BGNLOOP },
1193       {     TGSI_OPCODE_IF, {}, {in0}, {}},
1194       {       TGSI_OPCODE_BRK},
1195       {     TGSI_OPCODE_ENDIF},
1196       {     TGSI_OPCODE_MOV, {1}, {in0}, {}},
1197       {   TGSI_OPCODE_ENDLOOP },
1198       {   TGSI_OPCODE_MOV, {out0}, {1}, {}},
1199       { TGSI_OPCODE_ENDLOOP },
1200       { TGSI_OPCODE_END}
1201    };
1202    run (code, expectation({{-1,-1}, {0,8}}));
1203 }
1204 
1205 /* Test remapping table of registers. The tests don't assume
1206  * that the sorting algorithm used to sort the lifetimes
1207  * based on their 'begin' is stable.
1208  */
TEST_F(RegisterRemappingTest,RegisterRemapping1)1209 TEST_F(RegisterRemappingTest, RegisterRemapping1)
1210 {
1211    vector<lifetime> lt({{-1,-1},
1212                         {0,1},
1213                         {0,2},
1214                         {1,2},
1215                         {2,10},
1216                         {3,5},
1217                         {5,10}
1218                        });
1219 
1220    vector<int> expect({0,1,2,1,1,2,2});
1221    run(lt, expect);
1222 }
1223 
TEST_F(RegisterRemappingTest,RegisterRemapping2)1224 TEST_F(RegisterRemappingTest, RegisterRemapping2)
1225 {
1226    vector<lifetime> lt({{-1,-1},
1227                         {0,1},
1228                         {0,2},
1229                         {3,4},
1230                         {4,5},
1231                        });
1232    vector<int> expect({0,1,2,1,1});
1233    run(lt, expect);
1234 }
1235 
TEST_F(RegisterRemappingTest,RegisterRemappingMergeAllToOne)1236 TEST_F(RegisterRemappingTest, RegisterRemappingMergeAllToOne)
1237 {
1238    vector<lifetime> lt({{-1,-1},
1239                         {0,1},
1240                         {1,2},
1241                         {2,3},
1242                         {3,4},
1243                        });
1244    vector<int> expect({0,1,1,1,1});
1245    run(lt, expect);
1246 }
1247 
TEST_F(RegisterRemappingTest,RegisterRemappingIgnoreUnused)1248 TEST_F(RegisterRemappingTest, RegisterRemappingIgnoreUnused)
1249 {
1250    vector<lifetime> lt({{-1,-1},
1251                         {0,1},
1252                         {1,2},
1253                         {2,3},
1254                         {-1,-1},
1255                         {3,4},
1256                        });
1257    vector<int> expect({0,1,1,1,4,1});
1258    run(lt, expect);
1259 }
1260 
TEST_F(RegisterRemappingTest,RegisterRemappingMergeZeroLifetimeRegisters)1261 TEST_F(RegisterRemappingTest, RegisterRemappingMergeZeroLifetimeRegisters)
1262 {
1263    vector<lifetime> lt({{-1,-1},
1264                         {0,1},
1265                         {1,2},
1266                         {2,3},
1267                         {3,3},
1268                         {3,4},
1269                        });
1270    vector<int> expect({0,1,1,1,1,1});
1271    run(lt, expect);
1272 }
1273 
TEST_F(RegisterLifetimeAndRemappingTest,LifetimeAndRemapping)1274 TEST_F(RegisterLifetimeAndRemappingTest, LifetimeAndRemapping)
1275 {
1276    const vector<MockCodeline> code = {
1277       {TGSI_OPCODE_USEQ, {5}, {in0,in1}, {}},
1278       {TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
1279       {TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
1280       {TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
1281       {TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
1282       {TGSI_OPCODE_FSLT, {2}, {1,in1}, {}},
1283       {TGSI_OPCODE_UIF, {}, {2}, {}},
1284       {  TGSI_OPCODE_MOV, {3}, {in1}, {}},
1285       {TGSI_OPCODE_ELSE},
1286       {  TGSI_OPCODE_MOV, {4}, {in1}, {}},
1287       {  TGSI_OPCODE_MOV, {4}, {4}, {}},
1288       {  TGSI_OPCODE_MOV, {3}, {4}, {}},
1289       {TGSI_OPCODE_ENDIF},
1290       {TGSI_OPCODE_MOV, {out1}, {3}, {}},
1291       {TGSI_OPCODE_END}
1292    };
1293    run (code, vector<int>({0,1,5,5,1,5}));
1294 }
1295 
TEST_F(RegisterLifetimeAndRemappingTest,LifetimeAndRemappingWithUnusedReadOnlyIgnored)1296 TEST_F(RegisterLifetimeAndRemappingTest, LifetimeAndRemappingWithUnusedReadOnlyIgnored)
1297 {
1298    const vector<MockCodeline> code = {
1299       {TGSI_OPCODE_USEQ, {1}, {in0,in1}, {}},
1300       {TGSI_OPCODE_UCMP, {2}, {1,in1,2}, {}},
1301       {TGSI_OPCODE_UCMP, {4}, {2,in1,1}, {}},
1302       {TGSI_OPCODE_ADD, {5}, {2,4}, {}},
1303       {TGSI_OPCODE_UIF, {}, {7}, {}},
1304       {  TGSI_OPCODE_ADD, {8}, {5,4}, {}},
1305       {TGSI_OPCODE_ENDIF},
1306       {TGSI_OPCODE_MOV, {out1}, {8}, {}},
1307       {TGSI_OPCODE_END}
1308    };
1309    /* lt: 1: 0-2,2: 1-3 3: u 4: 2-5 5: 3-5 6: u 7: 0-(-1),8: 5-7 */
1310    run (code, vector<int>({0,1,2,3,1,2,6,7,1}));
1311 }
1312 
TEST_F(RegisterLifetimeAndRemappingTest,LifetimeAndRemappingWithUnusedReadOnlyRemappedTo)1313 TEST_F(RegisterLifetimeAndRemappingTest, LifetimeAndRemappingWithUnusedReadOnlyRemappedTo)
1314 {
1315    const vector<MockCodeline> code = {
1316       {TGSI_OPCODE_USEQ, {1}, {in0,in1}, {}},
1317       {TGSI_OPCODE_UIF, {}, {7}, {}},
1318       {  TGSI_OPCODE_UCMP, {2}, {1,in1,2}, {}},
1319       {  TGSI_OPCODE_UCMP, {4}, {2,in1,1}, {}},
1320       {  TGSI_OPCODE_ADD, {5}, {2,4}, {}},
1321       {  TGSI_OPCODE_ADD, {8}, {5,4}, {}},
1322       {TGSI_OPCODE_ENDIF},
1323       {TGSI_OPCODE_MOV, {out1}, {8}, {}},
1324       {TGSI_OPCODE_END}
1325    };
1326    /* lt: 1: 0-3,2: 2-4 3: u 4: 3-5 5: 4-5 6: u 7: 1-1,8: 5-7 */
1327    run (code, vector<int>({0,1,2,3,1,2,6,7,1}));
1328 }
1329 
TEST_F(RegisterLifetimeAndRemappingTest,LifetimeAndRemappingWithUnusedReadOnlyRemapped)1330 TEST_F(RegisterLifetimeAndRemappingTest, LifetimeAndRemappingWithUnusedReadOnlyRemapped)
1331 {
1332    const vector<MockCodeline> code = {
1333       {TGSI_OPCODE_USEQ, {0}, {in0,in1}, {}},
1334       {TGSI_OPCODE_UCMP, {2}, {0,in1,2}, {}},
1335       {TGSI_OPCODE_UCMP, {4}, {2,in1,0}, {}},
1336       {TGSI_OPCODE_UIF, {}, {7}, {}},
1337       {  TGSI_OPCODE_ADD, {5}, {4,4}, {}},
1338       {  TGSI_OPCODE_ADD, {8}, {5,4}, {}},
1339       {TGSI_OPCODE_ENDIF},
1340       {TGSI_OPCODE_MOV, {out1}, {8}, {}},
1341       {TGSI_OPCODE_END}
1342    };
1343    /* lt: 0: 0-2 1: u 2: 1-2 3: u 4: 2-5 5: 4-5 6: u 7:ro 8: 5-7 */
1344    run (code, vector<int>({0,1,2,3,0,2,6,7,0}));
1345 }
1346 
1347 /* Implementation of helper and test classes */
~MockShader()1348 MockShader::~MockShader()
1349 {
1350    free();
1351    ralloc_free(mem_ctx);
1352 }
1353 
MockShader(const vector<MockCodelineWithSwizzle> & source)1354 MockShader::MockShader(const vector<MockCodelineWithSwizzle>& source):
1355    num_temps(0)
1356 {
1357    mem_ctx = ralloc_context(NULL);
1358 
1359    program = new(mem_ctx) exec_list();
1360 
1361    for (MockCodelineWithSwizzle i: source) {
1362       glsl_to_tgsi_instruction *next_instr = new(mem_ctx) glsl_to_tgsi_instruction();
1363       next_instr->op = i.op;
1364       next_instr->info = tgsi_get_opcode_info(i.op);
1365 
1366       assert(i.src.size() < 4);
1367       assert(i.dst.size() < 3);
1368       assert(i.tex_offsets.size() < 3);
1369 
1370       for (unsigned k = 0; k < i.src.size(); ++k) {
1371          next_instr->src[k] = create_src_register(i.src[k].first, i.src[k].second);
1372       }
1373       for (unsigned k = 0; k < i.dst.size(); ++k) {
1374          next_instr->dst[k] = create_dst_register(i.dst[k].first, i.dst[k].second);
1375       }
1376       next_instr->tex_offset_num_offset = i.tex_offsets.size();
1377       next_instr->tex_offsets = new st_src_reg[i.tex_offsets.size()];
1378       for (unsigned k = 0; k < i.tex_offsets.size(); ++k) {
1379          next_instr->tex_offsets[k] = create_src_register(i.tex_offsets[k].first,
1380                                                           i.tex_offsets[k].second);
1381       }
1382       program->push_tail(next_instr);
1383    }
1384    ++num_temps;
1385 }
1386 
MockShader(const vector<MockCodeline> & source)1387 MockShader::MockShader(const vector<MockCodeline>& source):
1388    num_temps(0)
1389 {
1390    mem_ctx = ralloc_context(NULL);
1391 
1392    program = new(mem_ctx) exec_list();
1393 
1394    for (MockCodeline i: source) {
1395       glsl_to_tgsi_instruction *next_instr = new(mem_ctx) glsl_to_tgsi_instruction();
1396       next_instr->op = i.op;
1397       next_instr->info = tgsi_get_opcode_info(i.op);
1398 
1399       assert(i.src.size() < 4);
1400       assert(i.dst.size() < 3);
1401       assert(i.tex_offsets.size() < 3);
1402 
1403       for (unsigned k = 0; k < i.src.size(); ++k) {
1404          next_instr->src[k] = create_src_register(i.src[k]);
1405       }
1406       for (unsigned k = 0; k < i.dst.size(); ++k) {
1407          next_instr->dst[k] = create_dst_register(i.dst[k]);
1408       }
1409       next_instr->tex_offset_num_offset = i.tex_offsets.size();
1410       next_instr->tex_offsets = new st_src_reg[i.tex_offsets.size()];
1411       for (unsigned k = 0; k < i.tex_offsets.size(); ++k) {
1412          next_instr->tex_offsets[k] = create_src_register(i.tex_offsets[k]);
1413       }
1414       program->push_tail(next_instr);
1415    }
1416    ++num_temps;
1417 }
1418 
get_num_temps() const1419 int MockShader::get_num_temps() const
1420 {
1421    return num_temps;
1422 }
1423 
1424 
get_program() const1425 exec_list* MockShader::get_program() const
1426 {
1427    return program;
1428 }
1429 
free()1430 void MockShader::free()
1431 {
1432    /* The list is not fully initialized, so
1433     * tearing it down also must be done manually. */
1434    exec_node *p;
1435    while ((p = program->pop_head())) {
1436       glsl_to_tgsi_instruction * instr = static_cast<glsl_to_tgsi_instruction *>(p);
1437       if (instr->tex_offset_num_offset > 0)
1438          delete[] instr->tex_offsets;
1439       delete p;
1440    }
1441    program = 0;
1442    num_temps = 0;
1443 }
1444 
create_src_register(int src_idx)1445 st_src_reg MockShader::create_src_register(int src_idx)
1446 {
1447    gl_register_file file;
1448    int idx = 0;
1449    if (src_idx >= 0) {
1450       file = PROGRAM_TEMPORARY;
1451       idx = src_idx;
1452       if (num_temps < idx)
1453          num_temps = idx;
1454    } else {
1455       file = PROGRAM_INPUT;
1456       idx = 1 - src_idx;
1457    }
1458    return st_src_reg(file, idx, GLSL_TYPE_INT);
1459 }
1460 
create_src_register(int src_idx,const char * sw)1461 st_src_reg MockShader::create_src_register(int src_idx, const char *sw)
1462 {
1463    uint16_t swizzle = 0;
1464    for (int i = 0; i < 4; ++i) {
1465       switch (sw[i]) {
1466       case 'x': break; /* is zero */
1467       case 'y': swizzle |= SWIZZLE_Y << 3 * i; break;
1468       case 'z': swizzle |= SWIZZLE_Z << 3 * i; break;
1469       case 'w': swizzle |= SWIZZLE_W << 3 * i; break;
1470       }
1471    }
1472 
1473    gl_register_file file;
1474    int idx = 0;
1475    if (src_idx >= 0) {
1476       file = PROGRAM_TEMPORARY;
1477       idx = src_idx;
1478       if (num_temps < idx)
1479          num_temps = idx;
1480    } else {
1481       file = PROGRAM_INPUT;
1482       idx = 1 - src_idx;
1483    }
1484    st_src_reg result(file, idx, GLSL_TYPE_INT);
1485    result.swizzle = swizzle;
1486    return result;
1487 }
1488 
create_dst_register(int dst_idx,int writemask)1489 st_dst_reg MockShader::create_dst_register(int dst_idx,int writemask)
1490 {
1491    gl_register_file file;
1492    int idx = 0;
1493    if (dst_idx >= 0) {
1494       file = PROGRAM_TEMPORARY;
1495       idx = dst_idx;
1496       if (num_temps < idx)
1497          num_temps = idx;
1498    } else {
1499       file = PROGRAM_OUTPUT;
1500       idx = 1 - dst_idx;
1501    }
1502    return st_dst_reg(file, writemask, GLSL_TYPE_INT, idx);
1503 }
1504 
create_dst_register(int dst_idx)1505 st_dst_reg MockShader::create_dst_register(int dst_idx)
1506 {
1507    gl_register_file file;
1508    int idx = 0;
1509    if (dst_idx >= 0) {
1510       file = PROGRAM_TEMPORARY;
1511       idx = dst_idx;
1512       if (num_temps < idx)
1513          num_temps = idx;
1514    } else {
1515       file = PROGRAM_OUTPUT;
1516       idx = 1 - dst_idx;
1517    }
1518    return st_dst_reg(file,0xF, GLSL_TYPE_INT, idx);
1519 }
1520 
1521 
SetUp()1522 void MesaTestWithMemCtx::SetUp()
1523 {
1524    mem_ctx = ralloc_context(nullptr);
1525 }
1526 
TearDown()1527 void MesaTestWithMemCtx::TearDown()
1528 {
1529    ralloc_free(mem_ctx);
1530    mem_ctx = nullptr;
1531 }
1532 
run(const vector<MockCodeline> & code,const expectation & e)1533 void LifetimeEvaluatorTest::run(const vector<MockCodeline>& code, const expectation& e)
1534 {
1535    MockShader shader(code);
1536    std::vector<lifetime> result(shader.get_num_temps());
1537 
1538    bool success =
1539          get_temp_registers_required_lifetimes(mem_ctx, shader.get_program(),
1540                                                shader.get_num_temps(), &result[0]);
1541 
1542    ASSERT_TRUE(success);
1543    ASSERT_EQ(result.size(), e.size());
1544    check(result, e);
1545 }
1546 
run(const vector<MockCodelineWithSwizzle> & code,const expectation & e)1547 void LifetimeEvaluatorTest::run(const vector<MockCodelineWithSwizzle>& code,
1548                                 const expectation& e)
1549 {
1550    MockShader shader(code);
1551    std::vector<lifetime> result(shader.get_num_temps());
1552 
1553    bool success =
1554          get_temp_registers_required_lifetimes(mem_ctx, shader.get_program(),
1555                                                shader.get_num_temps(), &result[0]);
1556    ASSERT_TRUE(success);
1557    ASSERT_EQ(result.size(), e.size());
1558    check(result, e);
1559 }
1560 
check(const vector<lifetime> & lifetimes,const expectation & e)1561 void LifetimeEvaluatorExactTest::check( const vector<lifetime>& lifetimes,
1562                                         const expectation& e)
1563 {
1564    for (unsigned i = 1; i < lifetimes.size(); ++i) {
1565       EXPECT_EQ(lifetimes[i].begin, e[i][0]);
1566       EXPECT_EQ(lifetimes[i].end, e[i][1]);
1567    }
1568 }
1569 
check(const vector<lifetime> & lifetimes,const expectation & e)1570 void LifetimeEvaluatorAtLeastTest::check( const vector<lifetime>& lifetimes,
1571                                           const expectation& e)
1572 {
1573    for (unsigned i = 1; i < lifetimes.size(); ++i) {
1574       EXPECT_LE(lifetimes[i].begin, e[i][0]);
1575       EXPECT_GE(lifetimes[i].end, e[i][1]);
1576    }
1577 }
1578 
run(const vector<lifetime> & lt,const vector<int> & expect)1579 void RegisterRemappingTest::run(const vector<lifetime>& lt,
1580                             const vector<int>& expect)
1581 {
1582    rename_reg_pair proto{false,0};
1583    vector<rename_reg_pair> result(lt.size(), proto);
1584 
1585    get_temp_registers_remapping(mem_ctx, lt.size(), &lt[0], &result[0]);
1586 
1587    vector<int> remap(lt.size());
1588    for (unsigned i = 0; i < lt.size(); ++i) {
1589       remap[i] = result[i].valid ? result[i].new_reg : i;
1590    }
1591 
1592    std::transform(remap.begin(), remap.end(), result.begin(), remap.begin(),
1593                   [](int x, const rename_reg_pair& rn) {
1594                      return rn.valid ? rn.new_reg : x;
1595                   });
1596 
1597    for(unsigned i = 1; i < remap.size(); ++i) {
1598       EXPECT_EQ(remap[i], expect[i]);
1599    }
1600 }
1601