mesa/st/glsl_to_tgsi: Properly resolve life times simple if/else + use constructs
[mesa.git] / src / mesa / state_tracker / tests / test_glsl_to_tgsi_lifetime.cpp
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 <tgsi/tgsi_ureg.h>
25 #include <tgsi/tgsi_info.h>
26 #include <mesa/program/prog_instruction.h>
27
28 #include <gtest/gtest.h>
29 #include <utility>
30 #include <algorithm>
31 #include <iostream>
32
33 #include "st_tests_common.h"
34
35 using std::vector;
36 using std::pair;
37 using std::make_pair;
38 using std::transform;
39 using std::copy;
40
41
42 TEST_F(LifetimeEvaluatorExactTest, SimpleMoveAdd)
43 {
44 const vector<FakeCodeline> code = {
45 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
46 { TGSI_OPCODE_UADD, {out0}, {1,in0}, {}},
47 { TGSI_OPCODE_END}
48 };
49 run(code, temp_lt_expect({{-1,-1}, {0,1}}));
50 }
51
52 TEST_F(LifetimeEvaluatorExactTest, SimpleMoveAddMove)
53 {
54 const vector<FakeCodeline> code = {
55 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
56 { TGSI_OPCODE_UADD, {2}, {1,in0}, {}},
57 { TGSI_OPCODE_MOV, {out0}, {2}, {}},
58 { TGSI_OPCODE_END}
59 };
60 run(code, temp_lt_expect({{-1, -1}, {0,1}, {1,2}}));
61 }
62
63 /* Test whether the texoffst are actually visited by the
64 * merge algorithm. Note that it is of no importance
65 * what instruction is actually used, the MockShader class
66 * does not consider the details of the operation, only
67 * the number of arguments is of importance.
68 */
69 TEST_F(LifetimeEvaluatorExactTest, SimpleOpWithTexoffset)
70 {
71 const vector<FakeCodeline> code = {
72 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
73 { TGSI_OPCODE_MOV, {2}, {in1}, {}},
74 { TGSI_OPCODE_TEX, {out0}, {in0}, {1,2}},
75 { TGSI_OPCODE_END}
76 };
77 run(code, temp_lt_expect({{-1, -1}, {0,2}, {1,2}}));
78 }
79
80 /* Simple register access involving a loop
81 * 1: must life up to then end of the loop
82 * 2: only needs to life from write to read
83 * 3: only needs to life from write to read outside the loop
84 */
85 TEST_F(LifetimeEvaluatorExactTest, SimpleMoveInLoop)
86 {
87 const vector<FakeCodeline> code = {
88 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
89 { TGSI_OPCODE_BGNLOOP },
90 { TGSI_OPCODE_UADD, {2}, {1,in0}, {}},
91 { TGSI_OPCODE_UADD, {3}, {1,2}, {}},
92 { TGSI_OPCODE_UADD, {3}, {3,in1}, {}},
93 { TGSI_OPCODE_ENDLOOP },
94 { TGSI_OPCODE_MOV, {out0}, {3}, {}},
95 { TGSI_OPCODE_END}
96 };
97 run (code, temp_lt_expect({{-1,-1}, {0,5}, {2,3}, {3,6}}));
98 }
99
100 /* In loop if/else value written only in one path, and read later
101 * - value must survive the whole loop.
102 */
103 TEST_F(LifetimeEvaluatorExactTest, MoveInIfInLoop)
104 {
105 const vector<FakeCodeline> code = {
106 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
107 { TGSI_OPCODE_BGNLOOP },
108 { TGSI_OPCODE_IF, {}, {in1}, {}},
109 { TGSI_OPCODE_UADD, {2}, {1,in0}, {}},
110 { TGSI_OPCODE_ENDIF},
111 { TGSI_OPCODE_UADD, {3}, {1,2}, {}},
112 { TGSI_OPCODE_UADD, {3}, {3,in1}, {}},
113 { TGSI_OPCODE_ENDLOOP },
114 { TGSI_OPCODE_MOV, {out0}, {3}, {}},
115 { TGSI_OPCODE_END}
116 };
117 run (code, temp_lt_expect({{-1,-1}, {0,7}, {1,7}, {5,8}}));
118 }
119
120 /* A non-dominant write within an IF can be ignored (if it is read
121 * later)
122 */
123 TEST_F(LifetimeEvaluatorExactTest, NonDominantWriteinIfInLoop)
124 {
125 const vector<FakeCodeline> code = {
126 { TGSI_OPCODE_BGNLOOP },
127 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
128 { TGSI_OPCODE_IF, {}, {in1}, {}},
129 { TGSI_OPCODE_MOV, {1}, {in1}, {}},
130 { TGSI_OPCODE_ENDIF},
131 { TGSI_OPCODE_UADD, {2}, {1,in1}, {}},
132 { TGSI_OPCODE_IF, {}, {2}, {}},
133 { TGSI_OPCODE_BRK},
134 { TGSI_OPCODE_ENDIF},
135 { TGSI_OPCODE_ENDLOOP },
136 { TGSI_OPCODE_MOV, {out0}, {2}, {}},
137 { TGSI_OPCODE_END}
138 };
139 run (code, temp_lt_expect({{-1,-1}, {1,5}, {5,10}}));
140 }
141
142 /* In Nested loop if/else value written only in one path, and read later
143 * - value must survive the outer loop.
144 */
145 TEST_F(LifetimeEvaluatorExactTest, MoveInIfInNestedLoop)
146 {
147 const vector<FakeCodeline> code = {
148 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
149 { TGSI_OPCODE_BGNLOOP },
150 { TGSI_OPCODE_BGNLOOP },
151 { TGSI_OPCODE_IF, {}, {in1}, {} },
152 { TGSI_OPCODE_UADD, {2}, {1,in0}, {}},
153 { TGSI_OPCODE_ENDIF},
154 { TGSI_OPCODE_UADD, {3}, {1,2}, {}},
155 { TGSI_OPCODE_ENDLOOP },
156 { TGSI_OPCODE_ENDLOOP },
157 { TGSI_OPCODE_MOV, {out0}, {3}, {}},
158 { TGSI_OPCODE_END}
159 };
160 run (code, temp_lt_expect({{-1,-1}, {0,8}, {1,8}, {6,9}}));
161 }
162
163 /* In loop if/else value written in both path, and read later
164 * - value must survive from first write to last read in loop
165 * for now we only check that the minimum life time is correct.
166 */
167 TEST_F(LifetimeEvaluatorExactTest, WriteInIfAndElseInLoop)
168 {
169 const vector<FakeCodeline> code = {
170 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
171 { TGSI_OPCODE_BGNLOOP },
172 { TGSI_OPCODE_IF, {}, {1}, {}},
173 { TGSI_OPCODE_UADD, {2}, {1,in0}, {}},
174 { TGSI_OPCODE_ELSE },
175 { TGSI_OPCODE_MOV, {2}, {1}, {}},
176 { TGSI_OPCODE_ENDIF},
177 { TGSI_OPCODE_UADD, {3}, {1,2}, {}},
178 { TGSI_OPCODE_UADD, {3}, {3,in1}, {}},
179 { TGSI_OPCODE_ENDLOOP },
180 { TGSI_OPCODE_MOV, {out0}, {3}, {}},
181 { TGSI_OPCODE_END}
182 };
183 run (code, temp_lt_expect({{-1,-1}, {0,9}, {3,7}, {7,10}}));
184 }
185
186 /* Test that read before write in ELSE path is properly tracked:
187 * In loop if/else value written in both path but read in else path
188 * before write and also read later - value must survive the whole loop.
189 */
190 TEST_F(LifetimeEvaluatorExactTest, WriteInIfAndElseReadInElseInLoop)
191 {
192 const vector<FakeCodeline> code = {
193 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
194 { TGSI_OPCODE_BGNLOOP },
195 { TGSI_OPCODE_IF, {}, {1}, {}},
196 { TGSI_OPCODE_UADD, {2}, {1,in0}, {}},
197 { TGSI_OPCODE_ELSE },
198 { TGSI_OPCODE_ADD, {2}, {1,2}, {}},
199 { TGSI_OPCODE_ENDIF},
200 { TGSI_OPCODE_UADD, {3}, {1,2}, {}},
201 { TGSI_OPCODE_UADD, {3}, {3,in1}, {}},
202 { TGSI_OPCODE_ENDLOOP },
203 { TGSI_OPCODE_MOV, {out0}, {3}, {}},
204 { TGSI_OPCODE_END}
205 };
206 run (code, temp_lt_expect({{-1,-1}, {0,9}, {1,9}, {7,10}}));
207 }
208
209
210 /* Test that a write in ELSE path only in loop is properly tracked:
211 * In loop if/else value written in else path and read outside
212 * - value must survive the whole loop.
213 */
214 TEST_F(LifetimeEvaluatorExactTest, WriteInElseReadInLoop)
215 {
216 const vector<FakeCodeline> code = {
217 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
218 { TGSI_OPCODE_BGNLOOP },
219 { TGSI_OPCODE_IF, {}, {1}, {}},
220 { TGSI_OPCODE_UADD, {2}, {1,in0}, {}},
221 { TGSI_OPCODE_ELSE },
222 { TGSI_OPCODE_ADD, {3}, {1,2}, {}},
223 { TGSI_OPCODE_ENDIF},
224 { TGSI_OPCODE_UADD, {1}, {3,in1}, {}},
225 { TGSI_OPCODE_ENDLOOP },
226 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
227 { TGSI_OPCODE_END}
228 };
229 run (code, temp_lt_expect({{-1,-1}, {0,9}, {1,8}, {1,8}}));
230 }
231
232 /* Test that tracking a second write in an ELSE path is not attributed
233 * to the IF path: In loop if/else value written in else path twice and
234 * read outside - value must survive the whole loop
235 */
236 TEST_F(LifetimeEvaluatorExactTest, WriteInElseTwiceReadInLoop)
237 {
238 const vector<FakeCodeline> code = {
239 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
240 { TGSI_OPCODE_BGNLOOP },
241 { TGSI_OPCODE_IF, {}, {1}, {}},
242 { TGSI_OPCODE_UADD, {2}, {1,in0}, {}},
243 { TGSI_OPCODE_ELSE },
244 { TGSI_OPCODE_ADD, {3}, {1,2}, {}},
245 { TGSI_OPCODE_ADD, {3}, {1,3}, {}},
246 { TGSI_OPCODE_ENDIF},
247 { TGSI_OPCODE_UADD, {1}, {3,in1}, {}},
248 { TGSI_OPCODE_ENDLOOP },
249 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
250 { TGSI_OPCODE_END}
251 };
252 run (code, temp_lt_expect({{-1,-1}, {0,10}, {1,9}, {1,9}}));
253 }
254
255 /* Test that the IF and ELSE scopes from different IF/ELSE pairs are not
256 * merged: In loop if/else value written in if, and then in different else path
257 * and read outside - value must survive the whole loop
258 */
259 TEST_F(LifetimeEvaluatorExactTest, WriteInOneIfandInAnotherElseInLoop)
260 {
261 const vector<FakeCodeline> code = {
262 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
263 { TGSI_OPCODE_BGNLOOP },
264 { TGSI_OPCODE_IF, {}, {1}, {}},
265 { TGSI_OPCODE_UADD, {2}, {1,in0}, {}},
266 { TGSI_OPCODE_ENDIF},
267 { TGSI_OPCODE_IF, {}, {1}, {}},
268 { TGSI_OPCODE_ELSE },
269 { TGSI_OPCODE_ADD, {2}, {1,1}, {}},
270 { TGSI_OPCODE_ENDIF},
271 { TGSI_OPCODE_UADD, {1}, {2,in1}, {}},
272 { TGSI_OPCODE_ENDLOOP },
273 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
274 { TGSI_OPCODE_END}
275 };
276 run (code, temp_lt_expect({{-1,-1}, {0,11}, {1,10}}));
277 }
278
279 /* Test that with a new loop the resolution of the IF/ELSE write conditionality
280 * is restarted: In first loop value is written in both if and else, in second
281 * loop value is written only in if - must survive the second loop.
282 * However, the tracking is currently not able to restrict the lifetime
283 * in the first loop, hence the "AtLeast" test.
284 */
285 TEST_F(LifetimeEvaluatorAtLeastTest, UnconditionalInFirstLoopConditionalInSecond)
286 {
287 const vector<FakeCodeline> code = {
288 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
289 { TGSI_OPCODE_BGNLOOP },
290 { TGSI_OPCODE_IF, {}, {1}, {}},
291 { TGSI_OPCODE_UADD, {2}, {1,in0}, {}},
292 { TGSI_OPCODE_ELSE },
293 { TGSI_OPCODE_UADD, {2}, {1,in1}, {}},
294 { TGSI_OPCODE_ENDIF},
295 { TGSI_OPCODE_ENDLOOP },
296 { TGSI_OPCODE_BGNLOOP },
297 { TGSI_OPCODE_IF, {}, {1}, {}},
298 { TGSI_OPCODE_ADD, {2}, {in0,1}, {}},
299 { TGSI_OPCODE_ENDIF},
300 { TGSI_OPCODE_UADD, {1}, {2,in1}, {}},
301 { TGSI_OPCODE_ENDLOOP },
302 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
303 { TGSI_OPCODE_END}
304 };
305 run (code, temp_lt_expect({{-1,-1}, {0,14}, {3,13}}));
306 }
307
308 /* Test that with a new loop the resolution of the IF/ELSE write conditionality
309 * is restarted, and also takes care of write before read in else scope:
310 * In first loop value is written in both if and else, in second loop value is
311 * also written in both, but first read in if - must survive the second loop.
312 * However, the tracking is currently not able to restrict the lifetime
313 * in the first loop, hence the "AtLeast" test.
314 */
315 TEST_F(LifetimeEvaluatorAtLeastTest, UnconditionalInFirstLoopConditionalInSecond2)
316 {
317 const vector<FakeCodeline> code = {
318 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
319 { TGSI_OPCODE_BGNLOOP },
320 { TGSI_OPCODE_IF, {}, {1}, {}},
321 { TGSI_OPCODE_UADD, {2}, {1,in0}, {}},
322 { TGSI_OPCODE_ELSE },
323 { TGSI_OPCODE_UADD, {2}, {1,in1}, {}},
324 { TGSI_OPCODE_ENDIF},
325 { TGSI_OPCODE_ENDLOOP },
326 { TGSI_OPCODE_BGNLOOP },
327 { TGSI_OPCODE_IF, {}, {in1}, {}},
328 { TGSI_OPCODE_ADD, {2}, {2,1}, {}},
329 { TGSI_OPCODE_ELSE },
330 { TGSI_OPCODE_MOV, {2}, {1}, {}},
331 { TGSI_OPCODE_ENDIF},
332 { TGSI_OPCODE_UADD, {1}, {2,in1}, {}},
333 { TGSI_OPCODE_ENDLOOP },
334 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
335 { TGSI_OPCODE_END}
336 };
337 run (code, temp_lt_expect({{-1,-1}, {0,16}, {3,15}}));
338 }
339
340 /* In loop if/else read in one path before written in the same loop
341 * - value must survive the whole loop
342 */
343 TEST_F(LifetimeEvaluatorExactTest, ReadInIfInLoopBeforeWrite)
344 {
345 const vector<FakeCodeline> code = {
346 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
347 { TGSI_OPCODE_BGNLOOP },
348 { TGSI_OPCODE_IF, {}, {in0}, {}},
349 { TGSI_OPCODE_UADD, {2}, {1,3}, {}},
350 { TGSI_OPCODE_ENDIF},
351 { TGSI_OPCODE_UADD, {3}, {1,2}, {}},
352 { TGSI_OPCODE_UADD, {3}, {3,in1}, {}},
353 { TGSI_OPCODE_ENDLOOP },
354 { TGSI_OPCODE_MOV, {out0}, {3}, {}},
355 { TGSI_OPCODE_END}
356 };
357 run (code, temp_lt_expect({{-1,-1}, {0,7}, {1,7}, {1,8}}));
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 */
364 TEST_F(LifetimeEvaluatorExactTest, ReadInLoopInIfBeforeWriteAndLifeToTheEnd)
365 {
366 const vector<FakeCodeline> code = {
367 { TGSI_OPCODE_BGNLOOP },
368 { TGSI_OPCODE_IF, {}, {in0}, {}},
369 { TGSI_OPCODE_MUL, {1}, {1,in1}, {}},
370 { TGSI_OPCODE_ENDIF},
371 { TGSI_OPCODE_UADD, {1}, {1,in1}, {}},
372 { TGSI_OPCODE_ENDLOOP },
373 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
374 { TGSI_OPCODE_END}
375 };
376 run (code, temp_lt_expect({{-1,-1}, {0,6}}));
377 }
378
379 /* In loop read before written in the same loop read after the loop,
380 * value must survive the whole loop and to the read.
381 * This is kind of undefined behaviour though ...
382 */
383 TEST_F(LifetimeEvaluatorExactTest, ReadInLoopBeforeWriteAndLifeToTheEnd)
384 {
385 const vector<FakeCodeline> code = {
386 { TGSI_OPCODE_BGNLOOP },
387 { TGSI_OPCODE_MUL, {1}, {1,in1}, {}},
388 { TGSI_OPCODE_UADD, {1}, {1,in1}, {}},
389 { TGSI_OPCODE_ENDLOOP },
390 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
391 { TGSI_OPCODE_END}
392 };
393 run (code, temp_lt_expect({{-1,-1}, {0,4}}));
394 }
395
396 /* Test whether nesting IF/ELSE pairs within a loop is resolved:
397 * Write in all conditional branches if the inner nesting level and
398 * read after the outer IF/ELSE pair is closed. The lifetime doesn't have
399 * to be extended to the full loop.
400 */
401 TEST_F(LifetimeEvaluatorExactTest, NestedIfInLoopAlwaysWriteButNotPropagated)
402 {
403 const vector<FakeCodeline> code = {
404 { TGSI_OPCODE_BGNLOOP },
405 { TGSI_OPCODE_IF, {}, {in0}, {}},
406 { TGSI_OPCODE_IF, {}, {in0}, {}},
407 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
408 { TGSI_OPCODE_ELSE},
409 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
410 { TGSI_OPCODE_ENDIF},
411 { TGSI_OPCODE_ELSE},
412 { TGSI_OPCODE_IF, {}, {in0}, {}},
413 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
414 { TGSI_OPCODE_ELSE},
415 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
416 { TGSI_OPCODE_ENDIF},
417 { TGSI_OPCODE_ENDIF},
418 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
419 { TGSI_OPCODE_ENDLOOP },
420 { TGSI_OPCODE_END}
421 };
422 run (code, temp_lt_expect({{-1,-1}, {3,14}}));
423 }
424
425 /* Test that nested chaining of IF/ELSE scopes is resolved:
426 * Write in each IF branch, and open another IF/ELSE scope pair in the ELSE
427 * branch. At the last nesting level, the temporary is also written in the
428 * ELSE branch, hence the full constrict results in an unconditional write.
429 */
430 TEST_F(LifetimeEvaluatorExactTest, DeeplyNestedIfElseInLoopResolved)
431 {
432 const vector<FakeCodeline> code = {
433 { TGSI_OPCODE_BGNLOOP },
434 { TGSI_OPCODE_IF, {}, {in0}, {}},
435 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
436 { TGSI_OPCODE_ELSE},
437 { TGSI_OPCODE_IF, {}, {in0}, {}},
438 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
439 { TGSI_OPCODE_ELSE},
440 { TGSI_OPCODE_IF, {}, {in0}, {}},
441 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
442 { TGSI_OPCODE_ELSE},
443 { TGSI_OPCODE_IF, {}, {in0}, {}},
444 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
445 { TGSI_OPCODE_ELSE},
446 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
447 { TGSI_OPCODE_ENDIF},
448 { TGSI_OPCODE_ENDIF},
449 { TGSI_OPCODE_ENDIF},
450 { TGSI_OPCODE_ENDIF},
451 { TGSI_OPCODE_ADD, {2}, {1, in1}, {}},
452 { TGSI_OPCODE_ENDLOOP },
453 { TGSI_OPCODE_MOV, {out0}, {2}, {}},
454 { TGSI_OPCODE_END}
455 };
456 run (code, temp_lt_expect({{-1,-1}, {2,18}, {18, 20}}));
457 }
458
459 /* The complementary case of the above: Open deeply nested IF/ELSE clauses
460 * and only at the deepest nesting level the temporary is written in the IF
461 * branch, but for all ELSE scopes the value is also written. Like above, when
462 * the full construct has been executed, the temporary has been written
463 * unconditionally.
464 */
465 TEST_F(LifetimeEvaluatorExactTest, DeeplyNestedIfElseInLoopResolved2)
466 {
467 const vector<FakeCodeline> code = {
468 { TGSI_OPCODE_BGNLOOP },
469 { TGSI_OPCODE_IF, {}, {in0}, {}},
470 { TGSI_OPCODE_IF, {}, {in0}, {}},
471 { TGSI_OPCODE_IF, {}, {in0}, {}},
472 { TGSI_OPCODE_IF, {}, {in0}, {}},
473 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
474 { TGSI_OPCODE_ELSE},
475 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
476 { TGSI_OPCODE_ENDIF},
477 { TGSI_OPCODE_ELSE},
478 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
479 { TGSI_OPCODE_ENDIF},
480 { TGSI_OPCODE_ELSE},
481 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
482 { TGSI_OPCODE_ENDIF},
483 { TGSI_OPCODE_ELSE},
484 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
485 { TGSI_OPCODE_ENDIF},
486 { TGSI_OPCODE_ADD, {2}, {1, in1}, {}},
487 { TGSI_OPCODE_ENDLOOP },
488 { TGSI_OPCODE_MOV, {out0}, {2}, {}},
489 { TGSI_OPCODE_END}
490 };
491 run (code, temp_lt_expect({{-1,-1}, {5,18}, {18, 20}}));
492 }
493
494 /* Test that a write in an IF scope within IF scope where the temporary already
495 * can be ignored.
496 */
497 TEST_F(LifetimeEvaluatorExactTest, NestedIfElseInLoopResolvedInOuterScope)
498 {
499 const vector<FakeCodeline> code = {
500 { TGSI_OPCODE_BGNLOOP },
501 { TGSI_OPCODE_IF, {}, {in0}, {}},
502 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
503 { TGSI_OPCODE_IF, {}, {in0}, {}},
504 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
505 { TGSI_OPCODE_ENDIF},
506 { TGSI_OPCODE_ELSE},
507 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
508 { TGSI_OPCODE_ENDIF},
509 { TGSI_OPCODE_ADD, {2}, {1, in1}, {}},
510 { TGSI_OPCODE_ENDLOOP },
511 { TGSI_OPCODE_MOV, {out0}, {2}, {}},
512 { TGSI_OPCODE_END}
513 };
514 run (code, temp_lt_expect({{-1,-1}, {2,9}, {9, 11}}));
515 }
516
517 /* Here the read before write in the nested if is of no consequence to the
518 * life time because the variable was already written in the enclosing if-branch.
519 */
520 TEST_F(LifetimeEvaluatorExactTest, NestedIfElseInLoopWithReadResolvedInOuterScope)
521 {
522 const vector<FakeCodeline> code = {
523 { TGSI_OPCODE_BGNLOOP },
524 { TGSI_OPCODE_IF, {}, {in0}, {}},
525 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
526 { TGSI_OPCODE_IF, {}, {in0}, {}},
527 { TGSI_OPCODE_ADD, {1}, {in0, 1}, {}},
528 { TGSI_OPCODE_ENDIF},
529 { TGSI_OPCODE_ELSE},
530 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
531 { TGSI_OPCODE_ENDIF},
532 { TGSI_OPCODE_ADD, {2}, {1, in1}, {}},
533 { TGSI_OPCODE_ENDLOOP },
534 { TGSI_OPCODE_MOV, {out0}, {2}, {}},
535 { TGSI_OPCODE_END}
536 };
537 run (code, temp_lt_expect({{-1,-1}, {2,9}, {9, 11}}));
538 }
539
540 /* Here the nested if condition is of no consequence to the life time
541 * because the variable was already written in the enclosing else-branch.
542 */
543 TEST_F(LifetimeEvaluatorExactTest, NestedIfElseInLoopResolvedInOuterScope2)
544 {
545 const vector<FakeCodeline> code = {
546 { TGSI_OPCODE_BGNLOOP },
547 { TGSI_OPCODE_IF, {}, {in0}, {}},
548 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
549 { TGSI_OPCODE_ELSE},
550 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
551 { TGSI_OPCODE_IF, {}, {in0}, {}},
552 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
553 { TGSI_OPCODE_ENDIF},
554 { TGSI_OPCODE_ENDIF},
555 { TGSI_OPCODE_ADD, {2}, {1, in1}, {}},
556 { TGSI_OPCODE_ENDLOOP },
557 { TGSI_OPCODE_MOV, {out0}, {2}, {}},
558 { TGSI_OPCODE_END}
559 };
560 run (code, temp_lt_expect({{-1,-1}, {2,9}, {9, 11}}));
561 }
562
563 /* Test that tracking of IF/ELSE scopes does not unnessesarily cross loops,
564 * i.e. if the inner IF/ELSE pair is enclosed by a loop which is enclosed
565 * by another IF statement: The resolution of unconditionality of the write
566 * within the loop is not changed by the fact that the loop is enclosed by
567 * an IF scope.
568 */
569 TEST_F(LifetimeEvaluatorExactTest, NestedIfInLoopAlwaysWriteParentIfOutsideLoop)
570 {
571 const vector<FakeCodeline> code = {
572 { TGSI_OPCODE_IF, {}, {in0}, {}},
573 { TGSI_OPCODE_BGNLOOP },
574 { TGSI_OPCODE_IF, {}, {in0}, {}},
575 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
576 { TGSI_OPCODE_ELSE},
577 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
578 { TGSI_OPCODE_ENDIF},
579 { TGSI_OPCODE_IF, {}, {in0}, {}},
580 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
581 { TGSI_OPCODE_ELSE},
582 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
583 { TGSI_OPCODE_ENDIF},
584 { TGSI_OPCODE_MOV, {2}, {1}, {}},
585 { TGSI_OPCODE_ENDLOOP },
586 { TGSI_OPCODE_ELSE},
587 { TGSI_OPCODE_MOV, {2}, {in1}, {}},
588 { TGSI_OPCODE_ENDIF},
589 { TGSI_OPCODE_MOV, {out0}, {2}, {}},
590
591 { TGSI_OPCODE_END}
592 };
593 run (code, temp_lt_expect({{-1,-1}, {3,12}, {12, 17}}));
594 }
595
596 /* The value is written in a loop and in a nested IF, but
597 * not in all code paths, hence the value must survive the loop.
598 */
599 TEST_F(LifetimeEvaluatorExactTest, NestedIfInLoopWriteNotAlways)
600 {
601 const vector<FakeCodeline> code = {
602 { TGSI_OPCODE_BGNLOOP },
603 { TGSI_OPCODE_IF, {}, {in0}, {}},
604 { TGSI_OPCODE_IF, {}, {in0}, {}},
605 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
606 { TGSI_OPCODE_ELSE},
607 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
608 { TGSI_OPCODE_ENDIF},
609 { TGSI_OPCODE_ELSE},
610 { TGSI_OPCODE_IF, {}, {in0}, {}},
611 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
612 { TGSI_OPCODE_ENDIF},
613 { TGSI_OPCODE_ENDIF},
614 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
615 { TGSI_OPCODE_ENDLOOP },
616 { TGSI_OPCODE_END}
617 };
618 run (code, temp_lt_expect({{-1,-1}, {0,13}}));
619 }
620
621 /* Test that reading in an ELSE branach after writing is ignored:
622 * The value is written in a loop in both branches of if-else but also
623 * read in the else after writing, should have no effect on lifetime.
624 */
625 TEST_F(LifetimeEvaluatorExactTest, IfElseWriteInLoopAlsoReadInElse)
626 {
627 const vector<FakeCodeline> code = {
628 { TGSI_OPCODE_BGNLOOP },
629 { TGSI_OPCODE_IF, {}, {in0}, {}},
630 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
631 { TGSI_OPCODE_ELSE},
632 { TGSI_OPCODE_MOV, {1}, {in1}, {}},
633 { TGSI_OPCODE_MUL, {1}, {in0, 1}, {}},
634 { TGSI_OPCODE_ENDIF},
635 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
636 { TGSI_OPCODE_ENDLOOP },
637 { TGSI_OPCODE_END}
638 };
639 run (code, temp_lt_expect({{-1,-1}, {2,7}}));
640 }
641
642 /* Test that a write in an inner IF/ELSE pair is propagated to the outer
643 * ELSE branch: The value is written in a loop in both branches of a nested
644 * IF/ELSE pair, but only within the outer else, hence in summary the write is
645 * conditional within the loop.
646 */
647 TEST_F(LifetimeEvaluatorExactTest, WriteInNestedIfElseOuterElseOnly)
648 {
649 const vector<FakeCodeline> code = {
650 { TGSI_OPCODE_BGNLOOP },
651 { TGSI_OPCODE_IF, {}, {in0}, {}},
652 { TGSI_OPCODE_ELSE},
653 { TGSI_OPCODE_IF, {}, {in0}, {}},
654 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
655 { TGSI_OPCODE_ELSE},
656 { TGSI_OPCODE_ADD, {1}, {in1, in0}, {}},
657 { TGSI_OPCODE_ENDIF},
658 { TGSI_OPCODE_ENDIF},
659 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
660 { TGSI_OPCODE_ENDLOOP },
661 { TGSI_OPCODE_END}
662 };
663 run (code, temp_lt_expect({{-1,-1}, {0,10}}));
664 }
665
666 /* Test that reads in an inner ELSE after write within the enclosing IF branch
667 * is of no consequence (i.e. check that the read in the ELSE branch is not
668 * attributed as read before write when the outer ELSE branch is scanned:
669 * Nested if-else in loop. The value is written in the outer if and else and
670 * read in one inner else, should limit lifetime.
671 */
672 TEST_F(LifetimeEvaluatorExactTest, WriteUnconditionallyReadInNestedElse)
673 {
674 const vector<FakeCodeline> code = {
675 { TGSI_OPCODE_BGNLOOP },
676 { TGSI_OPCODE_IF, {}, {in0}, {}},
677 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
678 { TGSI_OPCODE_IF, {}, {in0}, {}},
679 { TGSI_OPCODE_ELSE},
680 { TGSI_OPCODE_MOV, {out1}, {1}, {}},
681 { TGSI_OPCODE_ENDIF},
682 { TGSI_OPCODE_ELSE},
683 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
684 { TGSI_OPCODE_ENDIF},
685 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
686 { TGSI_OPCODE_ENDLOOP },
687 { TGSI_OPCODE_END}
688 };
689 run (code, temp_lt_expect({{-1,-1}, {2,10}}));
690 }
691
692
693 /* Nested if-else in loop. The value is written in a loop in both branches
694 * of if-else but also read in the second nested else before writing.
695 * Is conditional.
696 */
697 TEST_F(LifetimeEvaluatorExactTest, NestedIfelseReadFirstInInnerElseInLoop)
698 {
699 const vector<FakeCodeline> code = {
700 { TGSI_OPCODE_BGNLOOP },
701 { TGSI_OPCODE_IF, {}, {in0}, {}},
702 { TGSI_OPCODE_IF, {}, {in0}, {}},
703 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
704 { TGSI_OPCODE_ELSE},
705 { TGSI_OPCODE_MOV, {1}, {in1}, {}},
706 { TGSI_OPCODE_ENDIF},
707 { TGSI_OPCODE_ELSE},
708 { TGSI_OPCODE_IF, {}, {in0}, {}},
709 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
710 { TGSI_OPCODE_ELSE},
711 { TGSI_OPCODE_ADD, {1}, {in1, 1}, {}},
712 { TGSI_OPCODE_ENDIF},
713 { TGSI_OPCODE_ENDIF},
714 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
715 { TGSI_OPCODE_ENDLOOP },
716 { TGSI_OPCODE_END}
717 };
718 run (code, temp_lt_expect({{-1,-1}, {0,15}}));
719 }
720
721 /* Test that read before write is properly tracked for nested IF branches.
722 * The value is written in a loop in both branches of IF/ELSE but also read in
723 * the second nested IF before writing - is conditional.
724 */
725 TEST_F(LifetimeEvaluatorExactTest, NestedIfelseReadFirstInInnerIfInLoop)
726 {
727 const vector<FakeCodeline> code = {
728 { TGSI_OPCODE_BGNLOOP },
729 { TGSI_OPCODE_IF, {}, {in0}, {}},
730 { TGSI_OPCODE_IF, {}, {in0}, {}},
731 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
732 { TGSI_OPCODE_ELSE},
733 { TGSI_OPCODE_MOV, {1}, {in1}, {}},
734 { TGSI_OPCODE_ENDIF},
735 { TGSI_OPCODE_ELSE},
736 { TGSI_OPCODE_IF, {}, {in0}, {}},
737 { TGSI_OPCODE_ADD, {1}, {in1, 1}, {}},
738 { TGSI_OPCODE_ELSE},
739 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
740 { TGSI_OPCODE_ENDIF},
741 { TGSI_OPCODE_ENDIF},
742 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
743 { TGSI_OPCODE_ENDLOOP },
744 { TGSI_OPCODE_END}
745 };
746 run (code, temp_lt_expect({{-1,-1}, {0,15}}));
747 }
748
749 /* Same as above, but for the secondary ELSE branch:
750 * The value is written in a loop in both branches of IF/ELSE but also read in
751 * the second nested ELSE branch before writing - is conditional.
752 */
753 TEST_F(LifetimeEvaluatorExactTest, WriteInOneElseBranchReadFirstInOtherInLoop)
754 {
755 const vector<FakeCodeline> code = {
756 { TGSI_OPCODE_BGNLOOP },
757 { TGSI_OPCODE_IF, {}, {in0}, {}},
758 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
759 { TGSI_OPCODE_ELSE},
760 { TGSI_OPCODE_MOV, {1}, {in1}, {}},
761 { TGSI_OPCODE_ENDIF},
762 { TGSI_OPCODE_IF, {}, {in0}, {}},
763 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
764 { TGSI_OPCODE_ELSE},
765 { TGSI_OPCODE_ADD, {1}, {in1, 1}, {}},
766 { TGSI_OPCODE_ENDIF},
767 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
768 { TGSI_OPCODE_ENDLOOP },
769 { TGSI_OPCODE_END}
770 };
771 run (code, temp_lt_expect({{-1,-1}, {2,11}}));
772 }
773
774 /* Test that the "write is unconditional" resolution is not overwritten within
775 * a loop: The value is written in a loop in both branches of an IF/ELSE clause,
776 * hence the second IF doesn't make it conditional.
777 */
778 TEST_F(LifetimeEvaluatorExactTest, WriteInIfElseBranchSecondIfInLoop)
779 {
780 const vector<FakeCodeline> code = {
781 { TGSI_OPCODE_BGNLOOP },
782 { TGSI_OPCODE_IF, {}, {in0}, {}},
783 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
784 { TGSI_OPCODE_ELSE},
785 { TGSI_OPCODE_MOV, {1}, {in1}, {}},
786 { TGSI_OPCODE_ENDIF},
787 { TGSI_OPCODE_IF, {}, {in0}, {}},
788 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
789 { TGSI_OPCODE_ENDIF},
790 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
791 { TGSI_OPCODE_ENDLOOP },
792 { TGSI_OPCODE_END}
793 };
794 run (code, temp_lt_expect({{-1,-1}, {2,9}}));
795 }
796
797 /* Within an IF clause within a loop test that if a write occured in both
798 * branches of a nested IF/ELSE clause, followed by the last read within the
799 * enclosing IF or ELSE clause, the combined read is registered as unconditional,
800 * i.e.that it doesn't extend its live range beyond that enclosing IF or ELSE
801 * clause.
802 */
803 TEST_F(LifetimeEvaluatorExactTest, DeeplyNestedinLoop)
804 {
805 const vector<FakeCodeline> code = {
806 { TGSI_OPCODE_BGNLOOP },
807 { TGSI_OPCODE_UIF, {}, {in0}, {}},
808 { TGSI_OPCODE_FSEQ, {1}, {in1,in2}, {}},
809 { TGSI_OPCODE_UIF, {}, {1}, {}},
810 { TGSI_OPCODE_MOV, {2}, {in1}, {}},
811 { TGSI_OPCODE_ELSE },
812 { TGSI_OPCODE_MOV, {2}, {in2}, {}},
813 { TGSI_OPCODE_ENDIF },
814 { TGSI_OPCODE_MOV, {3}, {2}, {}},
815 { TGSI_OPCODE_ENDIF },
816 { TGSI_OPCODE_ADD, {out0}, {3, in1}, {}},
817 { TGSI_OPCODE_ENDLOOP }
818 };
819 run (code, temp_lt_expect({{-1,-1}, {2,3}, {4, 8}, {0,11}}));
820 }
821
822 /** Regression test for bug #104803,
823 * Read and write in if/else path outside loop and later read in conditional
824 * within a loop. The first write is to be considered the dominant write.
825 */
826 TEST_F(LifetimeEvaluatorExactTest, IfElseWriteInBothOutsideLoopReadInElseInLoop)
827 {
828 const vector<FakeCodeline> code = {
829 { TGSI_OPCODE_IF, {}, {in0}, {} },
830 { TGSI_OPCODE_MOV, {1}, {in0}, {} },
831 { TGSI_OPCODE_ELSE, {}, {}, {} },
832 { TGSI_OPCODE_MOV, {1}, {in1}, {} },
833 { TGSI_OPCODE_ENDIF, {}, {}, {} },
834 { TGSI_OPCODE_BGNLOOP },
835 { TGSI_OPCODE_IF, {}, {in0}, {} },
836 { TGSI_OPCODE_MOV, {2}, {in1}, {} },
837 { TGSI_OPCODE_ELSE, {}, {}, {} },
838 { TGSI_OPCODE_MOV, {2}, {1}, {} },
839 { TGSI_OPCODE_ENDIF, {}, {}, {} },
840 { TGSI_OPCODE_ENDLOOP },
841 { TGSI_OPCODE_MOV, {out0}, {2}, {}},
842 { TGSI_OPCODE_END}
843 };
844 run (code, temp_lt_expect({{-1,-1}, {1,11}, {7, 12}}));
845 }
846
847 /* A continue in the loop is not relevant */
848 TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterContinue)
849 {
850 const vector<FakeCodeline> code = {
851 { TGSI_OPCODE_BGNLOOP },
852 { TGSI_OPCODE_IF, {}, {in0}, {}},
853 { TGSI_OPCODE_CONT},
854 { TGSI_OPCODE_ENDIF},
855 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
856 { TGSI_OPCODE_ENDLOOP },
857 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
858 { TGSI_OPCODE_END}
859 };
860 run (code, temp_lt_expect({{-1,-1}, {4,6}}));
861 }
862
863 /* Temporary used to in case must live up to the case
864 * statement where it is used, the switch we only keep
865 * for the actual SWITCH opcode like it is in tgsi_exec.c, the
866 * only current use case.
867 */
868 TEST_F(LifetimeEvaluatorExactTest, UseSwitchCase)
869 {
870 const vector<FakeCodeline> code = {
871 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
872 { TGSI_OPCODE_MOV, {2}, {in1}, {}},
873 { TGSI_OPCODE_MOV, {3}, {in2}, {}},
874 { TGSI_OPCODE_SWITCH, {}, {3}, {}},
875 { TGSI_OPCODE_CASE, {}, {2}, {}},
876 { TGSI_OPCODE_CASE, {}, {1}, {}},
877 { TGSI_OPCODE_BRK},
878 { TGSI_OPCODE_DEFAULT},
879 { TGSI_OPCODE_ENDSWITCH},
880 { TGSI_OPCODE_END}
881 };
882 run (code, temp_lt_expect({{-1,-1}, {0,5}, {1,4}, {2,3}}));
883 }
884
885 /* With two destinations, if one result is thrown away, the
886 * register must be kept past the writing instructions.
887 */
888 TEST_F(LifetimeEvaluatorExactTest, WriteTwoOnlyUseOne)
889 {
890 const vector<FakeCodeline> code = {
891 { TGSI_OPCODE_DFRACEXP , {1,2}, {in0}, {}},
892 { TGSI_OPCODE_ADD , {3}, {2,in0}, {}},
893 { TGSI_OPCODE_MOV, {out1}, {3}, {}},
894 { TGSI_OPCODE_END},
895
896 };
897 run (code, temp_lt_expect({{-1,-1}, {0,1}, {0,1}, {1,2}}));
898 }
899
900 /* If a break is in the loop, all variables written after the
901 * break and used outside the loop must be maintained for the
902 * whole loop
903 */
904 TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterBreak)
905 {
906 const vector<FakeCodeline> code = {
907 { TGSI_OPCODE_BGNLOOP },
908 { TGSI_OPCODE_IF, {}, {in0}, {}},
909 { TGSI_OPCODE_BRK},
910 { TGSI_OPCODE_ENDIF},
911 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
912 { TGSI_OPCODE_ENDLOOP },
913 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
914 { TGSI_OPCODE_END}
915 };
916 run (code, temp_lt_expect({{-1,-1}, {0,6}}));
917 }
918
919 /* If a break is in the loop, all variables written after the
920 * break and used outside the loop must be maintained for the
921 * whole loop. The first break in the loop is the defining one.
922 */
923 TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterBreak2Breaks)
924 {
925 const vector<FakeCodeline> code = {
926 { TGSI_OPCODE_BGNLOOP },
927 { TGSI_OPCODE_IF, {}, {in0}, {}},
928 { TGSI_OPCODE_BRK},
929 { TGSI_OPCODE_ENDIF},
930 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
931 { TGSI_OPCODE_BRK},
932 { TGSI_OPCODE_ENDLOOP },
933 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
934 { TGSI_OPCODE_END}
935 };
936 run (code, temp_lt_expect({{-1,-1}, {0,7}}));
937 }
938
939 /* Loop with a break at the beginning and read/write in the post
940 * break loop scope. The value written and read within the loop
941 * can be limited to [write, read], but the value read outside the
942 * loop must survive the whole loop. This is the typical code for
943 * while and for loops, where the breaking condition is tested at
944 * the beginning.
945 */
946 TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAndReadAfterBreak)
947 {
948 const vector<FakeCodeline> code = {
949 { TGSI_OPCODE_BGNLOOP },
950 { TGSI_OPCODE_IF, {}, {in0}, {}},
951 { TGSI_OPCODE_BRK},
952 { TGSI_OPCODE_ENDIF},
953 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
954 { TGSI_OPCODE_MOV, {2}, {1}, {}},
955 { TGSI_OPCODE_ENDLOOP },
956 { TGSI_OPCODE_MOV, {out0}, {2}, {}},
957 { TGSI_OPCODE_END}
958 };
959 run (code, temp_lt_expect({{-1,-1}, {4,5}, {0,7}}));
960 }
961
962 /* Same as above, just make sure that the life time of the local variable
963 * in the outer loop (3) is not accidently promoted to the whole loop.
964 */
965 TEST_F(LifetimeEvaluatorExactTest, NestedLoopWithWriteAndReadAfterBreak)
966 {
967 const vector<FakeCodeline> code = {
968 { TGSI_OPCODE_BGNLOOP },
969 { TGSI_OPCODE_IF, {}, {in1}, {}},
970 { TGSI_OPCODE_BRK},
971 { TGSI_OPCODE_ENDIF},
972 { TGSI_OPCODE_BGNLOOP},
973 { TGSI_OPCODE_IF, {}, {in0}, {}},
974 { TGSI_OPCODE_BRK},
975 { TGSI_OPCODE_ENDIF},
976 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
977 { TGSI_OPCODE_MOV, {2}, {1}, {}},
978 { TGSI_OPCODE_ENDLOOP },
979 { TGSI_OPCODE_ADD, {3}, {2,in0}, {}},
980 { TGSI_OPCODE_ADD, {4}, {3,in2}, {}},
981 { TGSI_OPCODE_ENDLOOP },
982 { TGSI_OPCODE_MOV, {out0}, {4}, {}},
983 { TGSI_OPCODE_END}
984 };
985 run (code, temp_lt_expect({{-1,-1}, {8,9}, {0,13}, {11,12}, {0,14}}));
986 }
987
988 /* If a break is in the loop inside a switch case, make sure it is
989 * interpreted as breaking that inner loop, i.e. the variable has to
990 * survive the loop.
991 */
992 TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterBreakInSwitchInLoop)
993 {
994 const vector<FakeCodeline> code = {
995 { TGSI_OPCODE_SWITCH, {}, {in1}, {}},
996 { TGSI_OPCODE_CASE, {}, {in1}, {}},
997 { TGSI_OPCODE_BGNLOOP },
998 { TGSI_OPCODE_IF, {}, {in0}, {}},
999 { TGSI_OPCODE_BRK},
1000 { TGSI_OPCODE_ENDIF},
1001 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1002 { TGSI_OPCODE_ENDLOOP },
1003 { TGSI_OPCODE_DEFAULT, {}, {}, {}},
1004 { TGSI_OPCODE_ENDSWITCH, {}, {}, {}},
1005 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1006 { TGSI_OPCODE_END}
1007 };
1008 run (code, temp_lt_expect({{-1,-1}, {2,10}}));
1009 }
1010
1011 /* Value written conditionally in one loop and read in another loop,
1012 * and both of these loops are within yet another loop. Here the value
1013 * has to survive the outer loop.
1014 */
1015 TEST_F(LifetimeEvaluatorExactTest, LoopsWithDifferntScopesConditionalWrite)
1016 {
1017 const vector<FakeCodeline> code = {
1018 { TGSI_OPCODE_BGNLOOP },
1019 { TGSI_OPCODE_IF, {}, {in0}, {}},
1020 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1021 { TGSI_OPCODE_ENDIF},
1022 { TGSI_OPCODE_ENDLOOP },
1023 { TGSI_OPCODE_BGNLOOP },
1024 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1025 { TGSI_OPCODE_ENDLOOP },
1026 { TGSI_OPCODE_END}
1027 };
1028 run (code, temp_lt_expect({{-1,-1}, {0,7}}));
1029 }
1030
1031 /* Value written and read in one loop and last read in another loop,
1032 * Here the value has to survive both loops.
1033 */
1034 TEST_F(LifetimeEvaluatorExactTest, LoopsWithDifferntScopesFirstReadBeforeWrite)
1035 {
1036 const vector<FakeCodeline> code = {
1037 { TGSI_OPCODE_BGNLOOP },
1038 { TGSI_OPCODE_MUL, {1}, {1,in0}, {}},
1039 { TGSI_OPCODE_ENDLOOP },
1040 { TGSI_OPCODE_BGNLOOP },
1041 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1042 { TGSI_OPCODE_ENDLOOP },
1043 { TGSI_OPCODE_END}
1044 };
1045 run (code, temp_lt_expect({{-1,-1}, {0,5}}));
1046 }
1047
1048
1049 /* Value is written in one switch code path within a loop
1050 * must survive the full loop.
1051 */
1052 TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteInSwitch)
1053 {
1054 const vector<FakeCodeline> code = {
1055 { TGSI_OPCODE_BGNLOOP },
1056 { TGSI_OPCODE_SWITCH, {}, {in0}, {} },
1057 { TGSI_OPCODE_CASE, {}, {in0}, {} },
1058 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1059 { TGSI_OPCODE_BRK },
1060 { TGSI_OPCODE_DEFAULT },
1061 { TGSI_OPCODE_BRK },
1062 { TGSI_OPCODE_ENDSWITCH },
1063 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1064 { TGSI_OPCODE_ENDLOOP },
1065 { TGSI_OPCODE_END}
1066 };
1067 run (code, temp_lt_expect({{-1,-1}, {0,9}}));
1068 }
1069
1070 /* Value written in one case, and read in other,in loop
1071 * - must survive the loop.
1072 */
1073 TEST_F(LifetimeEvaluatorExactTest, LoopWithReadWriteInSwitchDifferentCase)
1074 {
1075 const vector<FakeCodeline> code = {
1076 { TGSI_OPCODE_BGNLOOP },
1077 { TGSI_OPCODE_SWITCH, {}, {in0}, {} },
1078 { TGSI_OPCODE_CASE, {}, {in0}, {} },
1079 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1080 { TGSI_OPCODE_BRK },
1081 { TGSI_OPCODE_DEFAULT },
1082 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1083 { TGSI_OPCODE_BRK },
1084 { TGSI_OPCODE_ENDSWITCH },
1085 { TGSI_OPCODE_ENDLOOP },
1086 { TGSI_OPCODE_END}
1087 };
1088 run (code, temp_lt_expect({{-1,-1}, {0,9}}));
1089 }
1090
1091 /* Value written in one case, and read in other,in loop
1092 * - must survive the loop, even if the write case falls through.
1093 */
1094 TEST_F(LifetimeEvaluatorExactTest, LoopWithReadWriteInSwitchDifferentCaseFallThrough)
1095 {
1096 const vector<FakeCodeline> code = {
1097 { TGSI_OPCODE_BGNLOOP },
1098 { TGSI_OPCODE_SWITCH, {}, {in0}, {} },
1099 { TGSI_OPCODE_CASE, {}, {in0}, {} },
1100 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1101 { TGSI_OPCODE_DEFAULT },
1102 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1103 { TGSI_OPCODE_BRK },
1104 { TGSI_OPCODE_ENDSWITCH },
1105 { TGSI_OPCODE_ENDLOOP },
1106 { TGSI_OPCODE_END}
1107 };
1108 run (code, temp_lt_expect({{-1,-1}, {0,8}}));
1109 }
1110
1111 /* Here we read and write from an to the same temp in the same instruction,
1112 * but the read is conditional (select operation), hence the lifetime must
1113 * start with the first write.
1114 */
1115 TEST_F(LifetimeEvaluatorExactTest, WriteSelectFromSelf)
1116 {
1117 const vector<FakeCodeline> code = {
1118 { TGSI_OPCODE_USEQ, {5}, {in0,in1}, {}},
1119 { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
1120 { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
1121 { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
1122 { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
1123 { TGSI_OPCODE_FSLT, {2}, {1,in1}, {}},
1124 { TGSI_OPCODE_UIF, {}, {2}, {}},
1125 { TGSI_OPCODE_MOV, {3}, {in1}, {}},
1126 { TGSI_OPCODE_ELSE},
1127 { TGSI_OPCODE_MOV, {4}, {in1}, {}},
1128 { TGSI_OPCODE_MOV, {4}, {4}, {}},
1129 { TGSI_OPCODE_MOV, {3}, {4}, {}},
1130 { TGSI_OPCODE_ENDIF},
1131 { TGSI_OPCODE_MOV, {out1}, {3}, {}},
1132 { TGSI_OPCODE_END}
1133 };
1134 run (code, temp_lt_expect({{-1,-1}, {1,5}, {5,6}, {7,13}, {9,11}, {0,4}}));
1135 }
1136
1137 /* This test checks wheter the ENDSWITCH is handled properly if the
1138 * last switch case/default doesn't stop with a BRK.
1139 */
1140 TEST_F(LifetimeEvaluatorExactTest, LoopRWInSwitchCaseLastCaseWithoutBreak)
1141 {
1142 const vector<FakeCodeline> code = {
1143 { TGSI_OPCODE_BGNLOOP },
1144 { TGSI_OPCODE_SWITCH, {}, {in0}, {} },
1145 { TGSI_OPCODE_CASE, {}, {in0}, {} },
1146 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1147 { TGSI_OPCODE_BRK },
1148 { TGSI_OPCODE_DEFAULT },
1149 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1150 { TGSI_OPCODE_ENDSWITCH },
1151 { TGSI_OPCODE_ENDLOOP },
1152 { TGSI_OPCODE_END}
1153 };
1154 run (code, temp_lt_expect({{-1,-1}, {0,8}}));
1155 }
1156
1157 /* Value read/write in same case, stays there */
1158 TEST_F(LifetimeEvaluatorExactTest, LoopWithReadWriteInSwitchSameCase)
1159 {
1160 const vector<FakeCodeline> code = {
1161 { TGSI_OPCODE_BGNLOOP },
1162 { TGSI_OPCODE_SWITCH, {}, {in0}, {} },
1163 { TGSI_OPCODE_CASE, {}, {in0}, {} },
1164 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1165 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1166 { TGSI_OPCODE_BRK },
1167 { TGSI_OPCODE_DEFAULT },
1168 { TGSI_OPCODE_BRK },
1169 { TGSI_OPCODE_ENDSWITCH },
1170 { TGSI_OPCODE_ENDLOOP },
1171 { TGSI_OPCODE_END}
1172 };
1173 run (code, temp_lt_expect({{-1,-1}, {3,4}}));
1174 }
1175
1176 /* Value read/write in all cases, should only live from first
1177 * write to last read, but currently the whole loop is used.
1178 */
1179 TEST_F(LifetimeEvaluatorAtLeastTest, LoopWithReadWriteInSwitchSameCase)
1180 {
1181 const vector<FakeCodeline> code = {
1182 { TGSI_OPCODE_BGNLOOP },
1183 { TGSI_OPCODE_SWITCH, {}, {in0}, {}},
1184 { TGSI_OPCODE_CASE, {}, {in0}, {} },
1185 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1186 { TGSI_OPCODE_BRK },
1187 { TGSI_OPCODE_DEFAULT },
1188 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1189 { TGSI_OPCODE_BRK },
1190 { TGSI_OPCODE_ENDSWITCH },
1191 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1192 { TGSI_OPCODE_ENDLOOP },
1193 { TGSI_OPCODE_END}
1194 };
1195 run (code, temp_lt_expect({{-1,-1}, {3,9}}));
1196 }
1197
1198 /* First read before first write with nested loops */
1199 TEST_F(LifetimeEvaluatorExactTest, LoopsWithDifferentScopesCondReadBeforeWrite)
1200 {
1201 const vector<FakeCodeline> code = {
1202 { TGSI_OPCODE_BGNLOOP },
1203 { TGSI_OPCODE_BGNLOOP },
1204 { TGSI_OPCODE_IF, {}, {in0}, {}},
1205 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1206 { TGSI_OPCODE_ENDIF},
1207 { TGSI_OPCODE_ENDLOOP },
1208 { TGSI_OPCODE_BGNLOOP },
1209 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1210 { TGSI_OPCODE_ENDLOOP },
1211 { TGSI_OPCODE_ENDLOOP },
1212 { TGSI_OPCODE_END}
1213 };
1214 run (code, temp_lt_expect({{-1,-1}, {0,9}}));
1215 }
1216
1217 /* First read before first write wiredness with nested loops.
1218 * Here the first read of 2 is logically before the first, dominant
1219 * write, therfore, the 2 has to survive both loops.
1220 */
1221 TEST_F(LifetimeEvaluatorExactTest, FirstWriteAtferReadInNestedLoop)
1222 {
1223 const vector<FakeCodeline> code = {
1224 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1225 { TGSI_OPCODE_BGNLOOP },
1226 { TGSI_OPCODE_BGNLOOP },
1227 { TGSI_OPCODE_MUL, {2}, {2,1}, {}},
1228 { TGSI_OPCODE_MOV, {3}, {2}, {}},
1229 { TGSI_OPCODE_ENDLOOP },
1230 { TGSI_OPCODE_ADD, {1}, {1,in1}, {}},
1231 { TGSI_OPCODE_ENDLOOP },
1232 { TGSI_OPCODE_MOV, {out0}, {3}, {}},
1233 { TGSI_OPCODE_END}
1234 };
1235 run (code, temp_lt_expect({{-1,-1}, {0,7}, {1,7}, {4,8}}));
1236 }
1237
1238
1239 #define DST(X, W) vector<pair<int,int>>(1, make_pair(X, W))
1240 #define SRC(X, S) vector<pair<int, const char *>>(1, make_pair(X, S))
1241 #define SRC2(X, S, Y, T) vector<pair<int, const char *>>({make_pair(X, S), make_pair(Y, T)})
1242
1243 /* Partial write to components: one component was written unconditionally
1244 * but another conditionally, temporary must survive the whole loop.
1245 * Test series for all components.
1246 */
1247 TEST_F(LifetimeEvaluatorExactTest, LoopWithConditionalComponentWrite_X)
1248 {
1249 const vector<FakeCodeline> code = {
1250 { TGSI_OPCODE_BGNLOOP},
1251 { TGSI_OPCODE_MOV, DST(1, WRITEMASK_Y), SRC(in1, "x"), {}, SWZ()},
1252 { TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}, SWZ()},
1253 { TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "y"), {}, SWZ()},
1254 { TGSI_OPCODE_ENDIF},
1255 { TGSI_OPCODE_MOV, DST(2, WRITEMASK_XY), SRC(1, "xy"), {}, SWZ()},
1256 { TGSI_OPCODE_ENDLOOP},
1257 { TGSI_OPCODE_MOV, DST(out0, WRITEMASK_XYZW), SRC(2, "xyxy"), {}, SWZ()},
1258 { TGSI_OPCODE_END}
1259 };
1260 run (code, temp_lt_expect({{-1,-1}, {0,6}, {5,7}}));
1261 }
1262
1263 TEST_F(LifetimeEvaluatorExactTest, LoopWithConditionalComponentWrite_Y)
1264 {
1265 const vector<FakeCodeline> code = {
1266 { TGSI_OPCODE_BGNLOOP},
1267 { TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "x"), {}, SWZ()},
1268 { TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}, SWZ()},
1269 { TGSI_OPCODE_MOV, DST(1, WRITEMASK_Y), SRC(in1, "y"), {}, SWZ()},
1270 { TGSI_OPCODE_ENDIF},
1271 { TGSI_OPCODE_MOV, DST(2, WRITEMASK_XY), SRC(1, "xy"), {}, SWZ()},
1272 { TGSI_OPCODE_ENDLOOP},
1273 { TGSI_OPCODE_MOV, DST(out0, WRITEMASK_XYZW), SRC(2, "xyxy"), {}, SWZ()},
1274 { TGSI_OPCODE_END}
1275 };
1276 run (code, temp_lt_expect({{-1,-1}, {0,6}, {5,7}}));
1277 }
1278
1279 TEST_F(LifetimeEvaluatorExactTest, LoopWithConditionalComponentWrite_Z)
1280 {
1281 const vector<FakeCodeline> code = {
1282 { TGSI_OPCODE_BGNLOOP},
1283 { TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "x"), {}, SWZ()},
1284 { TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}, SWZ()},
1285 { TGSI_OPCODE_MOV, DST(1, WRITEMASK_Z), SRC(in1, "y"), {}, SWZ()},
1286 { TGSI_OPCODE_ENDIF},
1287 { TGSI_OPCODE_MOV, DST(2, WRITEMASK_XY), SRC(1, "xz"), {}, SWZ()},
1288 { TGSI_OPCODE_ENDLOOP},
1289 { TGSI_OPCODE_MOV, DST(out0, WRITEMASK_XYZW), SRC(2, "xyxy"), {}, SWZ()},
1290 { TGSI_OPCODE_END}
1291 };
1292 run (code, temp_lt_expect({{-1,-1}, {0,6}, {5,7}}));
1293 }
1294
1295 TEST_F(LifetimeEvaluatorExactTest, LoopWithConditionalComponentWrite_W)
1296 {
1297 const vector<FakeCodeline> code = {
1298 { TGSI_OPCODE_BGNLOOP},
1299 { TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "x"), {}, SWZ()},
1300 { TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}, SWZ()},
1301 { TGSI_OPCODE_MOV, DST(1, WRITEMASK_W), SRC(in1, "y"), {}, SWZ()},
1302 { TGSI_OPCODE_ENDIF},
1303 { TGSI_OPCODE_MOV, DST(2, WRITEMASK_XY), SRC(1, "xw"), {}, SWZ()},
1304 { TGSI_OPCODE_ENDLOOP},
1305 { TGSI_OPCODE_MOV, DST(out0, WRITEMASK_XYZW), SRC(2, "xyxy"), {}, SWZ()},
1306 { TGSI_OPCODE_END}
1307 };
1308 run (code, temp_lt_expect({{-1,-1}, {0,6}, {5,7}}));
1309 }
1310
1311 TEST_F(LifetimeEvaluatorExactTest, LoopWithConditionalComponentWrite_X_Read_Y_Before)
1312 {
1313 const vector<FakeCodeline> code = {
1314 { TGSI_OPCODE_BGNLOOP},
1315 { TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "x"), {}, SWZ()},
1316 { TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}, SWZ()},
1317 { TGSI_OPCODE_MOV, DST(2, WRITEMASK_XYZW), SRC(1, "yyyy"), {}, SWZ()},
1318 { TGSI_OPCODE_ENDIF},
1319 { TGSI_OPCODE_MOV, DST(1, WRITEMASK_YZW), SRC(2, "yyzw"), {}, SWZ()},
1320 { TGSI_OPCODE_ENDLOOP},
1321 { TGSI_OPCODE_ADD, DST(out0, WRITEMASK_XYZW),
1322 SRC2(2, "yyzw", 1, "xyxy"), {}, SWZ()},
1323 { TGSI_OPCODE_END}
1324 };
1325 run (code, temp_lt_expect({{-1,-1}, {0,7}, {0,7}}));
1326 }
1327
1328 /* The variable is conditionally read before first written, so
1329 * it has to surive all the loops.
1330 */
1331 TEST_F(LifetimeEvaluatorExactTest, FRaWSameInstructionInLoopAndCondition)
1332 {
1333 const vector<FakeCodeline> code = {
1334 { TGSI_OPCODE_BGNLOOP },
1335 { TGSI_OPCODE_BGNLOOP },
1336 { TGSI_OPCODE_IF, {}, {in0}, {} },
1337 { TGSI_OPCODE_ADD, {1}, {1,in0}, {}},
1338 { TGSI_OPCODE_ENDIF},
1339 { TGSI_OPCODE_MOV, {1}, {in1}, {}},
1340 { TGSI_OPCODE_ENDLOOP },
1341 { TGSI_OPCODE_ENDLOOP },
1342 { TGSI_OPCODE_END},
1343
1344 };
1345 run (code, temp_lt_expect({{-1,-1}, {0,7}}));
1346 }
1347
1348 /* If unconditionally first written and read in the same
1349 * instruction, then the register must be kept for the
1350 * one write, but not more (undefined behaviour)
1351 */
1352 TEST_F(LifetimeEvaluatorExactTest, FRaWSameInstruction)
1353 {
1354 const vector<FakeCodeline> code = {
1355 { TGSI_OPCODE_ADD, {1}, {1,in0}, {}},
1356 { TGSI_OPCODE_END},
1357
1358 };
1359 run (code, temp_lt_expect({{-1,-1}, {0,1}}));
1360 }
1361
1362 /* If unconditionally written and read in the same
1363 * instruction, various times then the register must be
1364 * kept past the last write, but not longer (undefined behaviour)
1365 */
1366 TEST_F(LifetimeEvaluatorExactTest, FRaWSameInstructionMoreThenOnce)
1367 {
1368 const vector<FakeCodeline> code = {
1369 { TGSI_OPCODE_ADD, {1}, {1,in0}, {}},
1370 { TGSI_OPCODE_ADD, {1}, {1,in0}, {}},
1371 { TGSI_OPCODE_MOV, {out0}, {in0}, {}},
1372 { TGSI_OPCODE_END},
1373
1374 };
1375 run (code, temp_lt_expect({{-1,-1}, {0,2}}));
1376 }
1377
1378 /* Register is only written. This should not happen,
1379 * but to handle the case we want the register to life
1380 * at least one instruction
1381 */
1382 TEST_F(LifetimeEvaluatorExactTest, WriteOnly)
1383 {
1384 const vector<FakeCodeline> code = {
1385 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1386 { TGSI_OPCODE_END}
1387 };
1388 run (code, temp_lt_expect({{-1,-1}, {0,1}}));
1389 }
1390
1391 /* Register is read in IF.
1392 */
1393 TEST_F(LifetimeEvaluatorExactTest, SimpleReadForIf)
1394 {
1395 const vector<FakeCodeline> code = {
1396 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1397 { TGSI_OPCODE_ADD, {out0}, {in0,in1}, {}},
1398 { TGSI_OPCODE_IF, {}, {1}, {}},
1399 { TGSI_OPCODE_ENDIF}
1400 };
1401 run (code, temp_lt_expect({{-1,-1}, {0,2}}));
1402 }
1403
1404 TEST_F(LifetimeEvaluatorExactTest, WriteTwoReadOne)
1405 {
1406 const vector<FakeCodeline> code = {
1407 { TGSI_OPCODE_DFRACEXP , {1,2}, {in0}, {}},
1408 { TGSI_OPCODE_ADD , {3}, {2,in0}, {}},
1409 { TGSI_OPCODE_MOV, {out1}, {3}, {}},
1410 { TGSI_OPCODE_END},
1411 };
1412 run (code, temp_lt_expect({{-1,-1}, {0,1}, {0,1}, {1,2}}));
1413 }
1414
1415 TEST_F(LifetimeEvaluatorExactTest, ReadOnly)
1416 {
1417 const vector<FakeCodeline> code = {
1418 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1419 { TGSI_OPCODE_END},
1420 };
1421 run (code, temp_lt_expect({{-1,-1}, {-1,-1}}));
1422 }
1423
1424 /* Test handling of missing END marker
1425 */
1426 TEST_F(LifetimeEvaluatorExactTest, SomeScopesAndNoEndProgramId)
1427 {
1428 const vector<FakeCodeline> code = {
1429 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1430 { TGSI_OPCODE_IF, {}, {1}, {}},
1431 { TGSI_OPCODE_MOV, {2}, {1}, {}},
1432 { TGSI_OPCODE_ENDIF},
1433 { TGSI_OPCODE_IF, {}, {1}, {}},
1434 { TGSI_OPCODE_MOV, {out0}, {2}, {}},
1435 { TGSI_OPCODE_ENDIF},
1436 };
1437 run (code, temp_lt_expect({{-1,-1}, {0,4}, {2,5}}));
1438 }
1439
1440 TEST_F(LifetimeEvaluatorExactTest, SerialReadWrite)
1441 {
1442 const vector<FakeCodeline> code = {
1443 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1444 { TGSI_OPCODE_MOV, {2}, {1}, {}},
1445 { TGSI_OPCODE_MOV, {3}, {2}, {}},
1446 { TGSI_OPCODE_MOV, {out0}, {3}, {}},
1447 { TGSI_OPCODE_END},
1448 };
1449 run (code, temp_lt_expect({{-1,-1}, {0,1}, {1,2}, {2,3}}));
1450 }
1451
1452 /* Check that two destination registers are used */
1453 TEST_F(LifetimeEvaluatorExactTest, TwoDestRegisters)
1454 {
1455 const vector<FakeCodeline> code = {
1456 { TGSI_OPCODE_DFRACEXP , {1,2}, {in0}, {}},
1457 { TGSI_OPCODE_ADD, {out0}, {1,2}, {}},
1458 { TGSI_OPCODE_END}
1459 };
1460 run (code, temp_lt_expect({{-1,-1}, {0,1}, {0,1}}));
1461 }
1462
1463 /* Check that writing within a loop in a conditional is propagated
1464 * to the outer loop.
1465 */
1466 TEST_F(LifetimeEvaluatorExactTest, WriteInLoopInConditionalReadOutside)
1467 {
1468 const vector<FakeCodeline> code = {
1469 { TGSI_OPCODE_BGNLOOP},
1470 { TGSI_OPCODE_IF, {}, {in0}, {}},
1471 { TGSI_OPCODE_BGNLOOP},
1472 { TGSI_OPCODE_MOV, {1}, {in1}, {}},
1473 { TGSI_OPCODE_ENDLOOP},
1474 { TGSI_OPCODE_ENDIF},
1475 { TGSI_OPCODE_ADD, {2}, {1,in1}, {}},
1476 { TGSI_OPCODE_ENDLOOP},
1477 { TGSI_OPCODE_MOV, {out0}, {2}, {}},
1478 { TGSI_OPCODE_END}
1479 };
1480 run (code, temp_lt_expect({{-1,-1}, {0,7}, {6,8}}));
1481 }
1482
1483 /* Check that a register written in a loop that is inside a conditional
1484 * is not propagated past that loop if last read is also within the
1485 * conditional
1486 */
1487 TEST_F(LifetimeEvaluatorExactTest, WriteInLoopInCondReadInCondOutsideLoop)
1488 {
1489 const vector<FakeCodeline> code = {
1490 { TGSI_OPCODE_BGNLOOP},
1491 { TGSI_OPCODE_IF, {}, {in0}, {}},
1492 { TGSI_OPCODE_BGNLOOP},
1493 { TGSI_OPCODE_MUL, {1}, {in2,in1}, {}},
1494 { TGSI_OPCODE_ENDLOOP},
1495 { TGSI_OPCODE_ADD, {2}, {1,in1}, {}},
1496 { TGSI_OPCODE_ENDIF},
1497 { TGSI_OPCODE_ENDLOOP},
1498 { TGSI_OPCODE_MOV, {out0}, {2}, {}},
1499 { TGSI_OPCODE_END}
1500 };
1501 run (code, temp_lt_expect({{-1,-1}, {3,5}, {0,8}}));
1502 }
1503
1504 /* Check that a register read before written in a loop that is
1505 * inside a conditional is propagated to the outer loop.
1506 */
1507 TEST_F(LifetimeEvaluatorExactTest, ReadWriteInLoopInCondReadInCondOutsideLoop)
1508 {
1509 const vector<FakeCodeline> code = {
1510 { TGSI_OPCODE_BGNLOOP},
1511 { TGSI_OPCODE_IF, {}, {in0}, {}},
1512 { TGSI_OPCODE_BGNLOOP},
1513 { TGSI_OPCODE_MUL, {1}, {1,in1}, {}},
1514 { TGSI_OPCODE_ENDLOOP},
1515 { TGSI_OPCODE_ADD, {2}, {1,in1}, {}},
1516 { TGSI_OPCODE_ENDIF},
1517 { TGSI_OPCODE_ENDLOOP},
1518 { TGSI_OPCODE_MOV, {out0}, {2}, {}},
1519 { TGSI_OPCODE_END}
1520 };
1521 run (code, temp_lt_expect({{-1,-1}, {0,7}, {0,8}}));
1522 }
1523
1524 /* With two destinations if one value is thrown away, we must
1525 * ensure that the two output registers don't merge. In this test
1526 * case the last access for 2 and 3 is in line 4, but 4 can only
1527 * be merged with 3 because it is read,2 on the other hand is written
1528 * to, and merging it with 4 would result in a bug.
1529 */
1530 TEST_F(LifetimeEvaluatorExactTest, WritePastLastRead2)
1531 {
1532 const vector<FakeCodeline> code = {
1533 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1534 { TGSI_OPCODE_MOV, {2}, {in0}, {}},
1535 { TGSI_OPCODE_ADD, {3}, {1,2}, {}},
1536 { TGSI_OPCODE_DFRACEXP , {2,4}, {3}, {}},
1537 { TGSI_OPCODE_MOV, {out1}, {4}, {}},
1538 { TGSI_OPCODE_END}
1539 };
1540 run (code, temp_lt_expect({{-1,-1}, {0,2}, {1,4}, {2,3}, {3,4}}));
1541 }
1542
1543 /* Check that three source registers are used */
1544 TEST_F(LifetimeEvaluatorExactTest, ThreeSourceRegisters)
1545 {
1546 const vector<FakeCodeline> code = {
1547 { TGSI_OPCODE_DFRACEXP , {1,2}, {in0}, {}},
1548 { TGSI_OPCODE_ADD , {3}, {in0,in1}, {}},
1549 { TGSI_OPCODE_MAD, {out0}, {1,2,3}, {}},
1550 { TGSI_OPCODE_END}
1551 };
1552 run (code, temp_lt_expect({{-1,-1}, {0,2}, {0,2}, {1,2}}));
1553 }
1554
1555 /* Check minimal lifetime for registers only written to */
1556 TEST_F(LifetimeEvaluatorExactTest, OverwriteWrittenOnlyTemps)
1557 {
1558 const vector<FakeCodeline> code = {
1559 { TGSI_OPCODE_MOV , {1}, {in0}, {}},
1560 { TGSI_OPCODE_MOV , {2}, {in1}, {}},
1561 { TGSI_OPCODE_END}
1562 };
1563 run (code, temp_lt_expect({{-1,-1}, {0,1}, {1,2}}));
1564 }
1565
1566 /* Same register is only written twice. This should not happen,
1567 * but to handle the case we want the register to life
1568 * at least past the last write instruction
1569 */
1570 TEST_F(LifetimeEvaluatorExactTest, WriteOnlyTwiceSame)
1571 {
1572 const vector<FakeCodeline> code = {
1573 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1574 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1575 { TGSI_OPCODE_END}
1576 };
1577 run (code, temp_lt_expect({{-1,-1}, {0,2}}));
1578 }
1579
1580 /* Dead code elimination should catch and remove the case
1581 * when a variable is written after its last read, but
1582 * we want the code to be aware of this case.
1583 * The life time of this uselessly written variable is set
1584 * to the instruction after the write, because
1585 * otherwise it could be re-used too early.
1586 */
1587 TEST_F(LifetimeEvaluatorExactTest, WritePastLastRead)
1588 {
1589 const vector<FakeCodeline> code = {
1590 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1591 { TGSI_OPCODE_MOV, {2}, {1}, {}},
1592 { TGSI_OPCODE_MOV, {1}, {2}, {}},
1593 { TGSI_OPCODE_END},
1594
1595 };
1596 run (code, temp_lt_expect({{-1,-1}, {0,3}, {1,2}}));
1597 }
1598
1599 /* If a break is in the loop, all variables written after the
1600 * break and used outside the loop the variable must survive the
1601 * outer loop
1602 */
1603 TEST_F(LifetimeEvaluatorExactTest, NestedLoopWithWriteAfterBreak)
1604 {
1605 const vector<FakeCodeline> code = {
1606 { TGSI_OPCODE_BGNLOOP },
1607 { TGSI_OPCODE_BGNLOOP },
1608 { TGSI_OPCODE_IF, {}, {in0}, {}},
1609 { TGSI_OPCODE_BRK},
1610 { TGSI_OPCODE_ENDIF},
1611 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1612 { TGSI_OPCODE_ENDLOOP },
1613 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1614 { TGSI_OPCODE_ENDLOOP },
1615 { TGSI_OPCODE_END}
1616 };
1617 run (code, temp_lt_expect({{-1,-1}, {0,8}}));
1618 }
1619
1620
1621 #define MT(X,Y,Z) std::make_tuple(X,Y,Z)
1622 /* Check lifetime estimation with a relative addressing in src.
1623 * Note, since the lifetime estimation always extends the lifetime
1624 * at to at least one instruction after the last write, for the
1625 * test the last read must be at least two instructions after the
1626 * last write to obtain a proper test.
1627 */
1628
1629 TEST_F(LifetimeEvaluatorExactTest, ReadIndirectReladdr1)
1630 {
1631 const vector<FakeCodeline> code = {
1632 { TGSI_OPCODE_MOV, {1}, {in1}, {}},
1633 { TGSI_OPCODE_MOV, {2}, {in0}, {}},
1634 { TGSI_OPCODE_MOV, {MT(3,0,0)}, {MT(2,1,0)}, {}, RA()},
1635 { TGSI_OPCODE_MOV, {out0}, {3}, {}},
1636 { TGSI_OPCODE_END}
1637 };
1638 run (code, temp_lt_expect({{-1,-1}, {0,2}, {1,2}, {2,3}}));
1639 }
1640
1641 /* Check lifetime estimation with a relative addressing in src */
1642 TEST_F(LifetimeEvaluatorExactTest, ReadIndirectReladdr2)
1643 {
1644 const vector<FakeCodeline> code = {
1645 { TGSI_OPCODE_MOV , {1}, {in1}, {}},
1646 { TGSI_OPCODE_MOV , {2}, {in0}, {}},
1647 { TGSI_OPCODE_MOV , {MT(3,0,0)}, {MT(4,0,1)}, {}, RA()},
1648 { TGSI_OPCODE_MOV , {out0}, {3}, {}},
1649 { TGSI_OPCODE_END}
1650 };
1651 run (code, temp_lt_expect({{-1,-1}, {0,2}, {1,2},{2,3}}));
1652 }
1653
1654 /* Check lifetime estimation with a relative addressing in src */
1655 TEST_F(LifetimeEvaluatorExactTest, ReadIndirectTexOffsReladdr1)
1656 {
1657 const vector<FakeCodeline> code = {
1658 { TGSI_OPCODE_MOV , {1}, {in1}, {}},
1659 { TGSI_OPCODE_MOV , {2}, {in0}, {}},
1660 { TGSI_OPCODE_MOV , {MT(3,0,0)}, {MT(in2,0,0)}, {MT(5,1,0)}, RA()},
1661 { TGSI_OPCODE_MOV , {out0}, {3}, {}},
1662 { TGSI_OPCODE_END}
1663 };
1664 run (code, temp_lt_expect({{-1,-1}, {0,2}, {1,2}, {2,3}}));
1665 }
1666
1667 /* Check lifetime estimation with a relative addressing in src */
1668 TEST_F(LifetimeEvaluatorExactTest, ReadIndirectTexOffsReladdr2)
1669 {
1670 const vector<FakeCodeline> code = {
1671 { TGSI_OPCODE_MOV , {1}, {in1}, {}},
1672 { TGSI_OPCODE_MOV , {2}, {in0}, {}},
1673 { TGSI_OPCODE_MOV , {MT(3,0,0)}, {MT(in2,0,0)}, {MT(2,0,1)}, RA()},
1674 { TGSI_OPCODE_MOV , {out0}, {3}, {}},
1675 { TGSI_OPCODE_END}
1676 };
1677 run (code, temp_lt_expect({{-1,-1}, {0,2}, {1,2}, {2,3}}));
1678 }
1679
1680 /* Check lifetime estimation with a relative addressing in dst */
1681 TEST_F(LifetimeEvaluatorExactTest, WriteIndirectReladdr1)
1682 {
1683 const vector<FakeCodeline> code = {
1684 { TGSI_OPCODE_MOV , {1}, {in0}, {}},
1685 { TGSI_OPCODE_MOV , {1}, {in1}, {}},
1686 { TGSI_OPCODE_MOV , {MT(5,1,0)}, {MT(in1,0,0)}, {}, RA()},
1687 { TGSI_OPCODE_END}
1688 };
1689 run (code, temp_lt_expect({{-1,-1}, {0,2}}));
1690 }
1691
1692 /* Check lifetime estimation with a relative addressing in dst */
1693 TEST_F(LifetimeEvaluatorExactTest, WriteIndirectReladdr2)
1694 {
1695 const vector<FakeCodeline> code = {
1696 { TGSI_OPCODE_MOV , {1}, {in0}, {}},
1697 { TGSI_OPCODE_MOV , {2}, {in1}, {}},
1698 { TGSI_OPCODE_MOV , {MT(5,0,1)}, {MT(in1,0,0)}, {}, RA()},
1699 { TGSI_OPCODE_MOV , {out0}, {in0}, {}},
1700 { TGSI_OPCODE_MOV , {out1}, {2}, {}},
1701 { TGSI_OPCODE_END}
1702 };
1703 run (code, temp_lt_expect({{-1,-1}, {0,2}, {1,4}}));
1704 }
1705
1706 /* Test remapping table of registers. The tests don't assume
1707 * that the sorting algorithm used to sort the lifetimes
1708 * based on their 'begin' is stable.
1709 */
1710 TEST_F(RegisterRemappingTest, RegisterRemapping1)
1711 {
1712 vector<lifetime> lt({{-1,-1},
1713 {0,1},
1714 {0,2},
1715 {1,2},
1716 {2,10},
1717 {3,5},
1718 {5,10}
1719 });
1720
1721 vector<int> expect({0,1,2,1,1,2,2});
1722 run(lt, expect);
1723 }
1724
1725 TEST_F(RegisterRemappingTest, RegisterRemapping2)
1726 {
1727 vector<lifetime> lt({{-1,-1},
1728 {0,1},
1729 {0,2},
1730 {3,4},
1731 {4,5},
1732 });
1733 vector<int> expect({0,1,2,1,1});
1734 run(lt, expect);
1735 }
1736
1737 TEST_F(RegisterRemappingTest, RegisterRemappingMergeAllToOne)
1738 {
1739 vector<lifetime> lt({{-1,-1},
1740 {0,1},
1741 {1,2},
1742 {2,3},
1743 {3,4},
1744 });
1745 vector<int> expect({0,1,1,1,1});
1746 run(lt, expect);
1747 }
1748
1749 TEST_F(RegisterRemappingTest, RegisterRemappingIgnoreUnused)
1750 {
1751 vector<lifetime> lt({{-1,-1},
1752 {0,1},
1753 {1,2},
1754 {2,3},
1755 {-1,-1},
1756 {3,4},
1757 });
1758 vector<int> expect({0,1,1,1,4,1});
1759 run(lt, expect);
1760 }
1761
1762 TEST_F(RegisterRemappingTest, RegisterRemappingMergeZeroLifetimeRegisters)
1763 {
1764 vector<lifetime> lt({{-1,-1},
1765 {0,1},
1766 {1,2},
1767 {2,3},
1768 {3,3},
1769 {3,4},
1770 });
1771 vector<int> expect({0,1,1,1,1,1});
1772 run(lt, expect);
1773 }
1774
1775 TEST_F(RegisterLifetimeAndRemappingTest, LifetimeAndRemapping)
1776 {
1777 const vector<FakeCodeline> code = {
1778 { TGSI_OPCODE_USEQ, {5}, {in0,in1}, {}},
1779 { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
1780 { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
1781 { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
1782 { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
1783 { TGSI_OPCODE_FSLT, {2}, {1,in1}, {}},
1784 { TGSI_OPCODE_UIF, {}, {2}, {}},
1785 { TGSI_OPCODE_MOV, {3}, {in1}, {}},
1786 { TGSI_OPCODE_ELSE},
1787 { TGSI_OPCODE_MOV, {4}, {in1}, {}},
1788 { TGSI_OPCODE_MOV, {4}, {4}, {}},
1789 { TGSI_OPCODE_MOV, {3}, {4}, {}},
1790 { TGSI_OPCODE_ENDIF},
1791 { TGSI_OPCODE_MOV, {out1}, {3}, {}},
1792 { TGSI_OPCODE_END}
1793 };
1794 run (code, vector<int>({0,1,5,5,1,5}));
1795 }
1796
1797 TEST_F(RegisterLifetimeAndRemappingTest, LifetimeAndRemappingWithUnusedReadOnlyIgnored)
1798 {
1799 const vector<FakeCodeline> code = {
1800 { TGSI_OPCODE_USEQ, {1}, {in0,in1}, {}},
1801 { TGSI_OPCODE_UCMP, {2}, {1,in1,2}, {}},
1802 { TGSI_OPCODE_UCMP, {4}, {2,in1,1}, {}},
1803 { TGSI_OPCODE_ADD, {5}, {2,4}, {}},
1804 { TGSI_OPCODE_UIF, {}, {7}, {}},
1805 { TGSI_OPCODE_ADD, {8}, {5,4}, {}},
1806 { TGSI_OPCODE_ENDIF},
1807 { TGSI_OPCODE_MOV, {out1}, {8}, {}},
1808 { TGSI_OPCODE_END}
1809 };
1810 /* lt: 1: 0-2,2: 1-3 3: u 4: 2-5 5: 3-5 6: u 7: 0-(-1),8: 5-7 */
1811 run (code, vector<int>({0,1,2,3,1,2,6,7,1}));
1812 }
1813
1814 TEST_F(RegisterLifetimeAndRemappingTest, LifetimeAndRemappingWithUnusedReadOnlyRemappedTo)
1815 {
1816 const vector<FakeCodeline> code = {
1817 { TGSI_OPCODE_USEQ, {1}, {in0,in1}, {}},
1818 { TGSI_OPCODE_UIF, {}, {7}, {}},
1819 { TGSI_OPCODE_UCMP, {2}, {1,in1,2}, {}},
1820 { TGSI_OPCODE_UCMP, {4}, {2,in1,1}, {}},
1821 { TGSI_OPCODE_ADD, {5}, {2,4}, {}},
1822 { TGSI_OPCODE_ADD, {8}, {5,4}, {}},
1823 { TGSI_OPCODE_ENDIF},
1824 { TGSI_OPCODE_MOV, {out1}, {8}, {}},
1825 { TGSI_OPCODE_END}
1826 };
1827 /* lt: 1: 0-3,2: 2-4 3: u 4: 3-5 5: 4-5 6: u 7: 1-1,8: 5-7 */
1828 run (code, vector<int>({0,1,2,3,1,2,6,7,1}));
1829 }
1830
1831 TEST_F(RegisterLifetimeAndRemappingTest, LifetimeAndRemappingWithUnusedReadOnlyRemapped)
1832 {
1833 const vector<FakeCodeline> code = {
1834 { TGSI_OPCODE_USEQ, {0}, {in0,in1}, {}},
1835 { TGSI_OPCODE_UCMP, {2}, {0,in1,2}, {}},
1836 { TGSI_OPCODE_UCMP, {4}, {2,in1,0}, {}},
1837 { TGSI_OPCODE_UIF, {}, {7}, {}},
1838 { TGSI_OPCODE_ADD, {5}, {4,4}, {}},
1839 { TGSI_OPCODE_ADD, {8}, {5,4}, {}},
1840 { TGSI_OPCODE_ENDIF},
1841 { TGSI_OPCODE_MOV, {out1}, {8}, {}},
1842 { TGSI_OPCODE_END}
1843 };
1844 /* lt: 0: 0-2 1: u 2: 1-2 3: u 4: 2-5 5: 4-5 6: u 7:ro 8: 5-7 */
1845 run (code, vector<int>({0,1,2,3,0,2,6,7,0}));
1846 }