2 * Copyright © 2017 Gert Wollny
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:
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
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.
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>
31 #include <gtest/gtest.h>
37 /* A line to describe a TGSI instruction for building mock shaders. */
39 MockCodeline(unsigned _op
): op(_op
) {}
40 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
){}
45 vector
<int> tex_offsets
;
48 /* A line to describe a TGSI instruction with swizzeling and write makss
49 * for building mock shaders.
51 struct MockCodelineWithSwizzle
{
52 MockCodelineWithSwizzle(unsigned _op
): op(_op
) {}
53 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
){}
58 vector
<pair
<int,int>> dst
;
59 vector
<pair
<int, const char *>> src
;
60 vector
<pair
<int, const char *>> tex_offsets
;
63 /* A few constants that will notbe tracked as temporary registers by the
75 MockShader(const vector
<MockCodeline
>& source
);
76 MockShader(const vector
<MockCodelineWithSwizzle
>& source
);
81 exec_list
* get_program() const;
82 int get_num_temps() const;
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
);
93 using expectation
= vector
<vector
<int>>;
95 class MesaTestWithMemCtx
: public testing::Test
{
102 class LifetimeEvaluatorTest
: public MesaTestWithMemCtx
{
104 void run(const vector
<MockCodeline
>& code
, const expectation
& e
);
105 void run(const vector
<MockCodelineWithSwizzle
>& code
, const expectation
& e
);
107 virtual void check(const vector
<lifetime
>& result
, const expectation
& e
) = 0;
110 /* This is a test class to check the exact life times of
112 class LifetimeEvaluatorExactTest
: public LifetimeEvaluatorTest
{
114 void check(const vector
<lifetime
>& result
, const expectation
& e
);
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
122 class LifetimeEvaluatorAtLeastTest
: public LifetimeEvaluatorTest
{
124 void check(const vector
<lifetime
>& result
, const expectation
& e
);
127 /* With this test class the renaming mapping estimation is tested */
128 class RegisterRemappingTest
: public MesaTestWithMemCtx
{
130 void run(const vector
<lifetime
>& lt
, const vector
<int>& expect
);
133 /* With this test class the combined lifetime estimation and renaming
134 * mepping estimation is tested
136 class RegisterLifetimeAndRemappingTest
: public RegisterRemappingTest
{
138 using RegisterRemappingTest::run
;
139 template <typename CodeLine
>
140 void run(const vector
<CodeLine
>& code
, const vector
<int>& expect
);
143 template <typename CodeLine
>
144 void RegisterLifetimeAndRemappingTest::run(const vector
<CodeLine
>& code
,
145 const vector
<int>& expect
)
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(), <
[0]);
151 this->run(lt
, expect
);
154 TEST_F(LifetimeEvaluatorExactTest
, SimpleMoveAdd
)
156 const vector
<MockCodeline
> code
= {
157 { TGSI_OPCODE_MOV
, {1}, {in0
}, {}},
158 { TGSI_OPCODE_UADD
, {out0
}, {1,in0
}, {}},
161 run(code
, expectation({{-1,-1}, {0,1}}));
164 TEST_F(LifetimeEvaluatorExactTest
, SimpleMoveAddMove
)
166 const vector
<MockCodeline
> code
= {
167 { TGSI_OPCODE_MOV
, {1}, {in0
}, {}},
168 { TGSI_OPCODE_UADD
, {2}, {1,in0
}, {}},
169 { TGSI_OPCODE_MOV
, {out0
}, {2}, {}},
172 run(code
, expectation({{-1, -1}, {0,1}, {1,2}}));
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.
181 TEST_F(LifetimeEvaluatorExactTest
, SimpleOpWithTexoffset
)
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}},
189 run(code
, expectation({{-1, -1}, {0,2}, {1,2}}));
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
197 TEST_F(LifetimeEvaluatorExactTest
, SimpleMoveInLoop
)
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}, {}},
209 run (code
, expectation({{-1,-1}, {0,5}, {2,3}, {3,6}}));
212 /* In loop if/else value written only in one path, and read later
213 * - value must survive the whole loop.
215 TEST_F(LifetimeEvaluatorExactTest
, MoveInIfInLoop
)
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}, {}},
229 run (code
, expectation({{-1,-1}, {0,7}, {1,7}, {5,8}}));
232 /* A non-dominant write within an IF can be ignored (if it is read
235 TEST_F(LifetimeEvaluatorExactTest
, NonDominantWriteinIfInLoop
)
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}, {}},
246 { TGSI_OPCODE_ENDIF
},
247 { TGSI_OPCODE_ENDLOOP
},
248 { TGSI_OPCODE_MOV
, {out0
}, {2}, {}},
251 run (code
, expectation({{-1,-1}, {1,5}, {5,10}}));
254 /* In Nested loop if/else value written only in one path, and read later
255 * - value must survive the outer loop.
257 TEST_F(LifetimeEvaluatorExactTest
, MoveInIfInNestedLoop
)
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}, {}},
272 run (code
, expectation({{-1,-1}, {0,8}, {1,8}, {6,9}}));
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.
279 TEST_F(LifetimeEvaluatorAtLeastTest
, WriteInIfAndElseInLoop
)
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}, {}},
295 run (code
, expectation({{-1,-1}, {0,9}, {3,7}, {7,10}}));
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
302 TEST_F(LifetimeEvaluatorExactTest
, WriteInIfAndElseReadInElseInLoop
)
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}, {}},
318 run (code
, expectation({{-1,-1}, {0,9}, {1,9}, {7,10}}));
321 /* In loop if/else read in one path before written in the same loop
322 * - value must survive the whole loop
324 TEST_F(LifetimeEvaluatorExactTest
, ReadInIfInLoopBeforeWrite
)
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}, {}},
338 run (code
, expectation({{-1,-1}, {0,7}, {1,7}, {1,8}}));
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
345 TEST_F(LifetimeEvaluatorExactTest
, ReadInLoopInIfBeforeWriteAndLifeToTheEnd
)
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}, {}},
357 run (code
, expectation({{-1,-1}, {0,6}}));
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
364 TEST_F(LifetimeEvaluatorExactTest
, ReadInLoopBeforeWriteAndLifeToTheEnd
)
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}, {}},
374 run (code
, expectation({{-1,-1}, {0,4}}));
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
382 TEST_F(LifetimeEvaluatorAtLeastTest
, NestedIfInLoopAlwaysWriteButNotPropagated
)
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
}, {}},
390 { TGSI_OPCODE_MOV
, {1}, {in0
}, {}},
391 { TGSI_OPCODE_ENDIF
},
393 { TGSI_OPCODE_IF
, {}, {in0
}, {}},
394 { TGSI_OPCODE_MOV
, {1}, {in0
}, {}},
396 { TGSI_OPCODE_MOV
, {1}, {in0
}, {}},
397 { TGSI_OPCODE_ENDIF
},
398 { TGSI_OPCODE_ENDIF
},
399 { TGSI_OPCODE_MOV
, {out0
}, {1}, {}},
400 { TGSI_OPCODE_ENDLOOP
},
403 run (code
, expectation({{-1,-1}, {3,14}}));
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.
409 TEST_F(LifetimeEvaluatorExactTest
, NestedIfInLoopWriteNotAlways
)
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
}, {}},
417 { TGSI_OPCODE_MOV
, {1}, {in0
}, {}},
418 { TGSI_OPCODE_ENDIF
},
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
},
428 run (code
, expectation({{-1,-1}, {0,13}}));
431 /* A continue in the loop is not relevant */
432 TEST_F(LifetimeEvaluatorExactTest
, LoopWithWriteAfterContinue
)
434 const vector
<MockCodeline
> code
= {
435 { TGSI_OPCODE_BGNLOOP
},
436 { TGSI_OPCODE_IF
, {}, {in0
}, {}},
438 { TGSI_OPCODE_ENDIF
},
439 { TGSI_OPCODE_MOV
, {1}, {in0
}, {}},
440 { TGSI_OPCODE_ENDLOOP
},
441 { TGSI_OPCODE_MOV
, {out0
}, {1}, {}},
444 run (code
, expectation({{-1,-1}, {4,6}}));
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.
452 TEST_F(LifetimeEvaluatorExactTest
, UseSwitchCase
)
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}, {}},
462 { TGSI_OPCODE_DEFAULT
},
463 { TGSI_OPCODE_ENDSWITCH
},
466 run (code
, expectation({{-1,-1}, {0,5}, {1,4}, {2,3}}));
469 /* With two destinations, if one result is thrown away, the
470 * register must be kept past the writing instructions.
472 TEST_F(LifetimeEvaluatorExactTest
, WriteTwoOnlyUseOne
)
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}, {}},
481 run (code
, expectation({{-1,-1}, {0,1}, {0,1}, {1,2}}));
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
488 TEST_F(LifetimeEvaluatorExactTest
, LoopWithWriteAfterBreak
)
490 const vector
<MockCodeline
> code
= {
491 { TGSI_OPCODE_BGNLOOP
},
492 { TGSI_OPCODE_IF
, {}, {in0
}, {}},
494 { TGSI_OPCODE_ENDIF
},
495 { TGSI_OPCODE_MOV
, {1}, {in0
}, {}},
496 { TGSI_OPCODE_ENDLOOP
},
497 { TGSI_OPCODE_MOV
, {out0
}, {1}, {}},
500 run (code
, expectation({{-1,-1}, {0,6}}));
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.
507 TEST_F(LifetimeEvaluatorExactTest
, LoopWithWriteAfterBreak2Breaks
)
509 const vector
<MockCodeline
> code
= {
510 { TGSI_OPCODE_BGNLOOP
},
511 { TGSI_OPCODE_IF
, {}, {in0
}, {}},
513 { TGSI_OPCODE_ENDIF
},
514 { TGSI_OPCODE_MOV
, {1}, {in0
}, {}},
516 { TGSI_OPCODE_ENDLOOP
},
517 { TGSI_OPCODE_MOV
, {out0
}, {1}, {}},
520 run (code
, expectation({{-1,-1}, {0,7}}));
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
530 TEST_F(LifetimeEvaluatorExactTest
, LoopWithWriteAndReadAfterBreak
)
532 const vector
<MockCodeline
> code
= {
533 { TGSI_OPCODE_BGNLOOP
},
534 { TGSI_OPCODE_IF
, {}, {in0
}, {}},
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}, {}},
543 run (code
, expectation({{-1,-1}, {4,5}, {0,7}}));
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.
549 TEST_F(LifetimeEvaluatorExactTest
, NestedLoopWithWriteAndReadAfterBreak
)
551 const vector
<MockCodeline
> code
= {
552 { TGSI_OPCODE_BGNLOOP
},
553 { TGSI_OPCODE_IF
, {}, {in1
}, {}},
555 { TGSI_OPCODE_ENDIF
},
556 { TGSI_OPCODE_BGNLOOP
},
557 { TGSI_OPCODE_IF
, {}, {in0
}, {}},
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}, {}},
569 run (code
, expectation({{-1,-1}, {8,9}, {0,13}, {11,12}, {0,14}}));
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
576 TEST_F(LifetimeEvaluatorExactTest
, LoopWithWriteAfterBreakInSwitchInLoop
)
578 const vector
<MockCodeline
> code
= {
579 { TGSI_OPCODE_SWITCH
, {}, {in1
}, {}},
580 { TGSI_OPCODE_CASE
, {}, {in1
}, {}},
581 { TGSI_OPCODE_BGNLOOP
},
582 { TGSI_OPCODE_IF
, {}, {in0
}, {}},
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}, {}},
592 run (code
, expectation({{-1,-1}, {2,10}}));
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.
599 TEST_F(LifetimeEvaluatorExactTest
, LoopsWithDifferntScopesConditionalWrite
)
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
},
612 run (code
, expectation({{-1,-1}, {0,7}}));
615 /* Value written and read in one loop and last read in another loop,
616 * Here the value has to survive both loops.
618 TEST_F(LifetimeEvaluatorExactTest
, LoopsWithDifferntScopesFirstReadBeforeWrite
)
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
},
629 run (code
, expectation({{-1,-1}, {0,5}}));
633 /* Value is written in one switch code path within a loop
634 * must survive the full loop.
636 TEST_F(LifetimeEvaluatorExactTest
, LoopWithWriteInSwitch
)
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
}, {}},
644 { TGSI_OPCODE_DEFAULT
},
646 { TGSI_OPCODE_ENDSWITCH
},
647 { TGSI_OPCODE_MOV
, {out0
}, {1}, {}},
648 { TGSI_OPCODE_ENDLOOP
},
651 run (code
, expectation({{-1,-1}, {0,9}}));
654 /* Value written in one case, and read in other,in loop
655 * - must survive the loop.
657 TEST_F(LifetimeEvaluatorExactTest
, LoopWithReadWriteInSwitchDifferentCase
)
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
}, {}},
665 { TGSI_OPCODE_DEFAULT
},
666 { TGSI_OPCODE_MOV
, {out0
}, {1}, {}},
668 { TGSI_OPCODE_ENDSWITCH
},
669 { TGSI_OPCODE_ENDLOOP
},
672 run (code
, expectation({{-1,-1}, {0,9}}));
675 /* Value written in one case, and read in other,in loop
676 * - must survive the loop, even if the write case falls through.
678 TEST_F(LifetimeEvaluatorExactTest
, LoopWithReadWriteInSwitchDifferentCaseFallThrough
)
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}, {}},
688 { TGSI_OPCODE_ENDSWITCH
},
689 { TGSI_OPCODE_ENDLOOP
},
692 run (code
, expectation({{-1,-1}, {0,8}}));
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.
700 TEST_F(LifetimeEvaluatorExactTest
, WriteSelectFromSelf
)
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
}, {}},
712 { TGSI_OPCODE_MOV
, {4}, {in1
}, {}},
713 { TGSI_OPCODE_MOV
, {4}, {4}, {}},
714 { TGSI_OPCODE_MOV
, {3}, {4}, {}},
716 {TGSI_OPCODE_MOV
, {out1
}, {3}, {}},
719 run (code
, expectation({{-1,-1}, {1,5}, {5,6}, {7,13}, {9,11}, {0,4}}));
722 /* This test checks wheter the ENDSWITCH is handled properly if the
723 * last switch case/default doesn't stop with a BRK.
725 TEST_F(LifetimeEvaluatorExactTest
, LoopRWInSwitchCaseLastCaseWithoutBreak
)
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
}, {}},
733 { TGSI_OPCODE_DEFAULT
},
734 { TGSI_OPCODE_MOV
, {out0
}, {1}, {}},
735 { TGSI_OPCODE_ENDSWITCH
},
736 { TGSI_OPCODE_ENDLOOP
},
739 run (code
, expectation({{-1,-1}, {0,8}}));
742 /* Value read/write in same case, stays there */
743 TEST_F(LifetimeEvaluatorExactTest
, LoopWithReadWriteInSwitchSameCase
)
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}, {}},
752 { TGSI_OPCODE_DEFAULT
},
754 { TGSI_OPCODE_ENDSWITCH
},
755 { TGSI_OPCODE_ENDLOOP
},
758 run (code
, expectation({{-1,-1}, {3,4}}));
761 /* Value read/write in all cases, should only live from first
762 * write to last read, but currently the whole loop is used.
764 TEST_F(LifetimeEvaluatorAtLeastTest
, LoopWithReadWriteInSwitchSameCase
)
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
}, {}},
772 { TGSI_OPCODE_DEFAULT
},
773 { TGSI_OPCODE_MOV
, {1}, {in0
}, {}},
775 { TGSI_OPCODE_ENDSWITCH
},
776 { TGSI_OPCODE_MOV
, {out0
}, {1}, {}},
777 { TGSI_OPCODE_ENDLOOP
},
780 run (code
, expectation({{-1,-1}, {3,9}}));
783 /* First read before first write with nested loops */
784 TEST_F(LifetimeEvaluatorExactTest
, LoopsWithDifferentScopesCondReadBeforeWrite
)
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
},
799 run (code
, expectation({{-1,-1}, {0,9}}));
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.
806 TEST_F(LifetimeEvaluatorExactTest
, FirstWriteAtferReadInNestedLoop
)
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}, {}},
820 run (code
, expectation({{-1,-1}, {0,7}, {1,7}, {4,8}}));
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)})
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.
832 TEST_F(LifetimeEvaluatorExactTest
, LoopWithConditionalComponentWrite_X
)
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
)
845 run (code
, expectation({{-1,-1}, {0,6}, {5,7}}));
848 TEST_F(LifetimeEvaluatorExactTest
, LoopWithConditionalComponentWrite_Y
)
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
)
861 run (code
, expectation({{-1,-1}, {0,6}, {5,7}}));
864 TEST_F(LifetimeEvaluatorExactTest
, LoopWithConditionalComponentWrite_Z
)
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
)
877 run (code
, expectation({{-1,-1}, {0,6}, {5,7}}));
880 TEST_F(LifetimeEvaluatorExactTest
, LoopWithConditionalComponentWrite_W
)
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
)
893 run (code
, expectation({{-1,-1}, {0,6}, {5,7}}));
896 TEST_F(LifetimeEvaluatorExactTest
, LoopWithConditionalComponentWrite_X_Read_Y_Before
)
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
)
909 run (code
, expectation({{-1,-1}, {0,7}, {0,7}}));
912 /* The variable is conditionally read before first written, so
913 * it has to surive all the loops.
915 TEST_F(LifetimeEvaluatorExactTest
, FRaWSameInstructionInLoopAndCondition
)
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
},
929 run (code
, expectation({{-1,-1}, {0,7}}));
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)
936 TEST_F(LifetimeEvaluatorExactTest
, FRaWSameInstruction
)
938 const vector
<MockCodeline
> code
= {
939 { TGSI_OPCODE_ADD
, {1}, {1,in0
}, {}},
943 run (code
, expectation({{-1,-1}, {0,1}}));
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)
950 TEST_F(LifetimeEvaluatorExactTest
, FRaWSameInstructionMoreThenOnce
)
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
}, {}},
959 run (code
, expectation({{-1,-1}, {0,2}}));
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
966 TEST_F(LifetimeEvaluatorExactTest
, WriteOnly
)
968 const vector
<MockCodeline
> code
= {
969 { TGSI_OPCODE_MOV
, {1}, {in0
}, {}},
972 run (code
, expectation({{-1,-1}, {0,1}}));
975 /* Register is read in IF.
977 TEST_F(LifetimeEvaluatorExactTest
, SimpleReadForIf
)
979 const vector
<MockCodeline
> code
= {
980 { TGSI_OPCODE_MOV
, {1}, {in0
}, {}},
981 { TGSI_OPCODE_ADD
, {out0
}, {in0
,in1
}, {}},
982 { TGSI_OPCODE_IF
, {}, {1}, {}},
985 run (code
, expectation({{-1,-1}, {0,2}}));
988 TEST_F(LifetimeEvaluatorExactTest
, WriteTwoReadOne
)
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}, {}},
996 run (code
, expectation({{-1,-1}, {0,1}, {0,1}, {1,2}}));
999 TEST_F(LifetimeEvaluatorExactTest
, ReadOnly
)
1001 const vector
<MockCodeline
> code
= {
1002 { TGSI_OPCODE_MOV
, {out0
}, {1}, {}},
1005 run (code
, expectation({{-1,-1}, {-1,-1}}));
1009 /* Test handling of missing END marker
1011 TEST_F(LifetimeEvaluatorExactTest
, SomeScopesAndNoEndProgramId
)
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
},
1022 run (code
, expectation({{-1,-1}, {0,4}, {2,5}}));
1025 TEST_F(LifetimeEvaluatorExactTest
, SerialReadWrite
)
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}, {}},
1034 run (code
, expectation({{-1,-1}, {0,1}, {1,2}, {2,3}}));
1037 /* Check that two destination registers are used */
1038 TEST_F(LifetimeEvaluatorExactTest
, TwoDestRegisters
)
1040 const vector
<MockCodeline
> code
= {
1041 { TGSI_OPCODE_DFRACEXP
, {1,2}, {in0
}, {}},
1042 { TGSI_OPCODE_ADD
, {out0
}, {1,2}, {}},
1045 run (code
, expectation({{-1,-1}, {0,1}, {0,1}}));
1048 /* Check that writing within a loop in a conditional is propagated
1049 * to the outer loop.
1051 TEST_F(LifetimeEvaluatorExactTest
, WriteInLoopInConditionalReadOutside
)
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}, {}},
1065 run (code
, expectation({{-1,-1}, {0,7}, {6,8}}));
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
1072 TEST_F(LifetimeEvaluatorExactTest
, WriteInLoopInCondReadInCondOutsideLoop
)
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}, {}},
1086 run (code
, expectation({{-1,-1}, {3,5}, {0,8}}));
1089 /* Check that a register read before written in a loop that is
1090 * inside a conditional is propagated to the outer loop.
1092 TEST_F(LifetimeEvaluatorExactTest
, ReadWriteInLoopInCondReadInCondOutsideLoop
)
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}, {}},
1106 run (code
, expectation({{-1,-1}, {0,7}, {0,8}}));
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.
1115 TEST_F(LifetimeEvaluatorExactTest
, WritePastLastRead2
)
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}, {}},
1125 run (code
, expectation({{-1,-1}, {0,2}, {1,4}, {2,3}, {3,4}}));
1128 /* Check that three source registers are used */
1129 TEST_F(LifetimeEvaluatorExactTest
, ThreeSourceRegisters
)
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}, {}},
1137 run (code
, expectation({{-1,-1}, {0,2}, {0,2}, {1,2}}));
1140 /* Check minimal lifetime for registers only written to */
1141 TEST_F(LifetimeEvaluatorExactTest
, OverwriteWrittenOnlyTemps
)
1143 const vector
<MockCodeline
> code
= {
1144 { TGSI_OPCODE_MOV
, {1}, {in0
}, {}},
1145 { TGSI_OPCODE_MOV
, {2}, {in1
}, {}},
1148 run (code
, expectation({{-1,-1}, {0,1}, {1,2}}));
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
1155 TEST_F(LifetimeEvaluatorExactTest
, WriteOnlyTwiceSame
)
1157 const vector
<MockCodeline
> code
= {
1158 { TGSI_OPCODE_MOV
, {1}, {in0
}, {}},
1159 { TGSI_OPCODE_MOV
, {1}, {in0
}, {}},
1162 run (code
, expectation({{-1,-1}, {0,2}}));
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.
1172 TEST_F(LifetimeEvaluatorExactTest
, WritePastLastRead
)
1174 const vector
<MockCodeline
> code
= {
1175 { TGSI_OPCODE_MOV
, {1}, {in0
}, {}},
1176 { TGSI_OPCODE_MOV
, {2}, {1}, {}},
1177 { TGSI_OPCODE_MOV
, {1}, {2}, {}},
1181 run (code
, expectation({{-1,-1}, {0,3}, {1,2}}));
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
1188 TEST_F(LifetimeEvaluatorExactTest
, NestedLoopWithWriteAfterBreak
)
1190 const vector
<MockCodeline
> code
= {
1191 { TGSI_OPCODE_BGNLOOP
},
1192 { TGSI_OPCODE_BGNLOOP
},
1193 { TGSI_OPCODE_IF
, {}, {in0
}, {}},
1195 { TGSI_OPCODE_ENDIF
},
1196 { TGSI_OPCODE_MOV
, {1}, {in0
}, {}},
1197 { TGSI_OPCODE_ENDLOOP
},
1198 { TGSI_OPCODE_MOV
, {out0
}, {1}, {}},
1199 { TGSI_OPCODE_ENDLOOP
},
1202 run (code
, expectation({{-1,-1}, {0,8}}));
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.
1209 TEST_F(RegisterRemappingTest
, RegisterRemapping1
)
1211 vector
<lifetime
> lt({{-1,-1},
1220 vector
<int> expect({0,1,2,1,1,2,2});
1224 TEST_F(RegisterRemappingTest
, RegisterRemapping2
)
1226 vector
<lifetime
> lt({{-1,-1},
1232 vector
<int> expect({0,1,2,1,1});
1236 TEST_F(RegisterRemappingTest
, RegisterRemappingMergeAllToOne
)
1238 vector
<lifetime
> lt({{-1,-1},
1244 vector
<int> expect({0,1,1,1,1});
1248 TEST_F(RegisterRemappingTest
, RegisterRemappingIgnoreUnused
)
1250 vector
<lifetime
> lt({{-1,-1},
1257 vector
<int> expect({0,1,1,1,4,1});
1261 TEST_F(RegisterRemappingTest
, RegisterRemappingMergeZeroLifetimeRegisters
)
1263 vector
<lifetime
> lt({{-1,-1},
1270 vector
<int> expect({0,1,1,1,1,1});
1274 TEST_F(RegisterLifetimeAndRemappingTest
, LifetimeAndRemapping
)
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
}, {}},
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}, {}},
1293 run (code
, vector
<int>({0,1,5,5,1,5}));
1296 TEST_F(RegisterLifetimeAndRemappingTest
, LifetimeAndRemappingWithUnusedReadOnlyIgnored
)
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}, {}},
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}));
1313 TEST_F(RegisterLifetimeAndRemappingTest
, LifetimeAndRemappingWithUnusedReadOnlyRemappedTo
)
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}, {}},
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}));
1330 TEST_F(RegisterLifetimeAndRemappingTest
, LifetimeAndRemappingWithUnusedReadOnlyRemapped
)
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}, {}},
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}));
1347 /* Implementation of helper and test classes */
1348 MockShader::~MockShader()
1351 ralloc_free(mem_ctx
);
1354 MockShader::MockShader(const vector
<MockCodelineWithSwizzle
>& source
):
1357 mem_ctx
= ralloc_context(NULL
);
1359 program
= new(mem_ctx
) exec_list();
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
);
1366 assert(i
.src
.size() < 4);
1367 assert(i
.dst
.size() < 3);
1368 assert(i
.tex_offsets
.size() < 3);
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
);
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
);
1376 next_instr
->tex_offset_num_offset
= i
.tex_offsets
.size();
1377 if (next_instr
->tex_offset_num_offset
> 0) {
1378 next_instr
->tex_offsets
= new st_src_reg
[i
.tex_offsets
.size()];
1379 for (unsigned k
= 0; k
< i
.tex_offsets
.size(); ++k
) {
1380 next_instr
->tex_offsets
[k
] = create_src_register(i
.tex_offsets
[k
].first
,
1381 i
.tex_offsets
[k
].second
);
1384 next_instr
->tex_offsets
= nullptr;
1386 program
->push_tail(next_instr
);
1391 MockShader::MockShader(const vector
<MockCodeline
>& source
):
1394 mem_ctx
= ralloc_context(NULL
);
1396 program
= new(mem_ctx
) exec_list();
1398 for (MockCodeline i
: source
) {
1399 glsl_to_tgsi_instruction
*next_instr
= new(mem_ctx
) glsl_to_tgsi_instruction();
1400 next_instr
->op
= i
.op
;
1401 next_instr
->info
= tgsi_get_opcode_info(i
.op
);
1403 assert(i
.src
.size() < 4);
1404 assert(i
.dst
.size() < 3);
1405 assert(i
.tex_offsets
.size() < 3);
1407 for (unsigned k
= 0; k
< i
.src
.size(); ++k
) {
1408 next_instr
->src
[k
] = create_src_register(i
.src
[k
]);
1410 for (unsigned k
= 0; k
< i
.dst
.size(); ++k
) {
1411 next_instr
->dst
[k
] = create_dst_register(i
.dst
[k
]);
1413 next_instr
->tex_offset_num_offset
= i
.tex_offsets
.size();
1414 if (next_instr
->tex_offset_num_offset
> 0) {
1415 next_instr
->tex_offsets
= new st_src_reg
[i
.tex_offsets
.size()];
1416 for (unsigned k
= 0; k
< i
.tex_offsets
.size(); ++k
) {
1417 next_instr
->tex_offsets
[k
] = create_src_register(i
.tex_offsets
[k
]);
1420 next_instr
->tex_offsets
= nullptr;
1422 program
->push_tail(next_instr
);
1427 int MockShader::get_num_temps() const
1433 exec_list
* MockShader::get_program() const
1438 void MockShader::free()
1440 /* The list is not fully initialized, so
1441 * tearing it down also must be done manually. */
1443 while ((p
= program
->pop_head())) {
1444 glsl_to_tgsi_instruction
* instr
= static_cast<glsl_to_tgsi_instruction
*>(p
);
1445 if (instr
->tex_offset_num_offset
> 0)
1446 delete[] instr
->tex_offsets
;
1453 st_src_reg
MockShader::create_src_register(int src_idx
)
1455 gl_register_file file
;
1458 file
= PROGRAM_TEMPORARY
;
1460 if (num_temps
< idx
)
1463 file
= PROGRAM_INPUT
;
1466 return st_src_reg(file
, idx
, GLSL_TYPE_INT
);
1469 st_src_reg
MockShader::create_src_register(int src_idx
, const char *sw
)
1471 uint16_t swizzle
= 0;
1472 for (int i
= 0; i
< 4; ++i
) {
1474 case 'x': break; /* is zero */
1475 case 'y': swizzle
|= SWIZZLE_Y
<< 3 * i
; break;
1476 case 'z': swizzle
|= SWIZZLE_Z
<< 3 * i
; break;
1477 case 'w': swizzle
|= SWIZZLE_W
<< 3 * i
; break;
1481 gl_register_file file
;
1484 file
= PROGRAM_TEMPORARY
;
1486 if (num_temps
< idx
)
1489 file
= PROGRAM_INPUT
;
1492 st_src_reg
result(file
, idx
, GLSL_TYPE_INT
);
1493 result
.swizzle
= swizzle
;
1497 st_dst_reg
MockShader::create_dst_register(int dst_idx
,int writemask
)
1499 gl_register_file file
;
1502 file
= PROGRAM_TEMPORARY
;
1504 if (num_temps
< idx
)
1507 file
= PROGRAM_OUTPUT
;
1510 return st_dst_reg(file
, writemask
, GLSL_TYPE_INT
, idx
);
1513 st_dst_reg
MockShader::create_dst_register(int dst_idx
)
1515 gl_register_file file
;
1518 file
= PROGRAM_TEMPORARY
;
1520 if (num_temps
< idx
)
1523 file
= PROGRAM_OUTPUT
;
1526 return st_dst_reg(file
,0xF, GLSL_TYPE_INT
, idx
);
1530 void MesaTestWithMemCtx::SetUp()
1532 mem_ctx
= ralloc_context(nullptr);
1535 void MesaTestWithMemCtx::TearDown()
1537 ralloc_free(mem_ctx
);
1541 void LifetimeEvaluatorTest::run(const vector
<MockCodeline
>& code
, const expectation
& e
)
1543 MockShader
shader(code
);
1544 std::vector
<lifetime
> result(shader
.get_num_temps());
1547 get_temp_registers_required_lifetimes(mem_ctx
, shader
.get_program(),
1548 shader
.get_num_temps(), &result
[0]);
1550 ASSERT_TRUE(success
);
1551 ASSERT_EQ(result
.size(), e
.size());
1555 void LifetimeEvaluatorTest::run(const vector
<MockCodelineWithSwizzle
>& code
,
1556 const expectation
& e
)
1558 MockShader
shader(code
);
1559 std::vector
<lifetime
> result(shader
.get_num_temps());
1562 get_temp_registers_required_lifetimes(mem_ctx
, shader
.get_program(),
1563 shader
.get_num_temps(), &result
[0]);
1564 ASSERT_TRUE(success
);
1565 ASSERT_EQ(result
.size(), e
.size());
1569 void LifetimeEvaluatorExactTest::check( const vector
<lifetime
>& lifetimes
,
1570 const expectation
& e
)
1572 for (unsigned i
= 1; i
< lifetimes
.size(); ++i
) {
1573 EXPECT_EQ(lifetimes
[i
].begin
, e
[i
][0]);
1574 EXPECT_EQ(lifetimes
[i
].end
, e
[i
][1]);
1578 void LifetimeEvaluatorAtLeastTest::check( const vector
<lifetime
>& lifetimes
,
1579 const expectation
& e
)
1581 for (unsigned i
= 1; i
< lifetimes
.size(); ++i
) {
1582 EXPECT_LE(lifetimes
[i
].begin
, e
[i
][0]);
1583 EXPECT_GE(lifetimes
[i
].end
, e
[i
][1]);
1587 void RegisterRemappingTest::run(const vector
<lifetime
>& lt
,
1588 const vector
<int>& expect
)
1590 rename_reg_pair proto
{false,0};
1591 vector
<rename_reg_pair
> result(lt
.size(), proto
);
1593 get_temp_registers_remapping(mem_ctx
, lt
.size(), <
[0], &result
[0]);
1595 vector
<int> remap(lt
.size());
1596 for (unsigned i
= 0; i
< lt
.size(); ++i
) {
1597 remap
[i
] = result
[i
].valid
? result
[i
].new_reg
: i
;
1600 std::transform(remap
.begin(), remap
.end(), result
.begin(), remap
.begin(),
1601 [](int x
, const rename_reg_pair
& rn
) {
1602 return rn
.valid
? rn
.new_reg
: x
;
1605 for(unsigned i
= 1; i
< remap
.size(); ++i
) {
1606 EXPECT_EQ(remap
[i
], expect
[i
]);