acebfb829354a67fdd3c90efcab24d90fc9dbec6
[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 /** Regression test for bug #104803,
798 * Read and write in if/else path outside loop and later read in conditional
799 * within a loop. The first write is to be considered the dominant write.
800 */
801 TEST_F(LifetimeEvaluatorExactTest, IfElseWriteInBothOutsideLoopReadInElseInLoop)
802 {
803 const vector<FakeCodeline> code = {
804 { TGSI_OPCODE_IF, {}, {in0}, {} },
805 { TGSI_OPCODE_MOV, {1}, {in0}, {} },
806 { TGSI_OPCODE_ELSE, {}, {}, {} },
807 { TGSI_OPCODE_MOV, {1}, {in1}, {} },
808 { TGSI_OPCODE_ENDIF, {}, {}, {} },
809 { TGSI_OPCODE_BGNLOOP },
810 { TGSI_OPCODE_IF, {}, {in0}, {} },
811 { TGSI_OPCODE_MOV, {2}, {in1}, {} },
812 { TGSI_OPCODE_ELSE, {}, {}, {} },
813 { TGSI_OPCODE_MOV, {2}, {1}, {} },
814 { TGSI_OPCODE_ENDIF, {}, {}, {} },
815 { TGSI_OPCODE_ENDLOOP },
816 { TGSI_OPCODE_MOV, {out0}, {2}, {}},
817 { TGSI_OPCODE_END}
818 };
819 run (code, temp_lt_expect({{-1,-1}, {1,11}, {7, 12}}));
820 }
821
822 /* A continue in the loop is not relevant */
823 TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterContinue)
824 {
825 const vector<FakeCodeline> code = {
826 { TGSI_OPCODE_BGNLOOP },
827 { TGSI_OPCODE_IF, {}, {in0}, {}},
828 { TGSI_OPCODE_CONT},
829 { TGSI_OPCODE_ENDIF},
830 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
831 { TGSI_OPCODE_ENDLOOP },
832 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
833 { TGSI_OPCODE_END}
834 };
835 run (code, temp_lt_expect({{-1,-1}, {4,6}}));
836 }
837
838 /* Temporary used to in case must live up to the case
839 * statement where it is used, the switch we only keep
840 * for the actual SWITCH opcode like it is in tgsi_exec.c, the
841 * only current use case.
842 */
843 TEST_F(LifetimeEvaluatorExactTest, UseSwitchCase)
844 {
845 const vector<FakeCodeline> code = {
846 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
847 { TGSI_OPCODE_MOV, {2}, {in1}, {}},
848 { TGSI_OPCODE_MOV, {3}, {in2}, {}},
849 { TGSI_OPCODE_SWITCH, {}, {3}, {}},
850 { TGSI_OPCODE_CASE, {}, {2}, {}},
851 { TGSI_OPCODE_CASE, {}, {1}, {}},
852 { TGSI_OPCODE_BRK},
853 { TGSI_OPCODE_DEFAULT},
854 { TGSI_OPCODE_ENDSWITCH},
855 { TGSI_OPCODE_END}
856 };
857 run (code, temp_lt_expect({{-1,-1}, {0,5}, {1,4}, {2,3}}));
858 }
859
860 /* With two destinations, if one result is thrown away, the
861 * register must be kept past the writing instructions.
862 */
863 TEST_F(LifetimeEvaluatorExactTest, WriteTwoOnlyUseOne)
864 {
865 const vector<FakeCodeline> code = {
866 { TGSI_OPCODE_DFRACEXP , {1,2}, {in0}, {}},
867 { TGSI_OPCODE_ADD , {3}, {2,in0}, {}},
868 { TGSI_OPCODE_MOV, {out1}, {3}, {}},
869 { TGSI_OPCODE_END},
870
871 };
872 run (code, temp_lt_expect({{-1,-1}, {0,1}, {0,1}, {1,2}}));
873 }
874
875 /* If a break is in the loop, all variables written after the
876 * break and used outside the loop must be maintained for the
877 * whole loop
878 */
879 TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterBreak)
880 {
881 const vector<FakeCodeline> code = {
882 { TGSI_OPCODE_BGNLOOP },
883 { TGSI_OPCODE_IF, {}, {in0}, {}},
884 { TGSI_OPCODE_BRK},
885 { TGSI_OPCODE_ENDIF},
886 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
887 { TGSI_OPCODE_ENDLOOP },
888 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
889 { TGSI_OPCODE_END}
890 };
891 run (code, temp_lt_expect({{-1,-1}, {0,6}}));
892 }
893
894 /* If a break is in the loop, all variables written after the
895 * break and used outside the loop must be maintained for the
896 * whole loop. The first break in the loop is the defining one.
897 */
898 TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterBreak2Breaks)
899 {
900 const vector<FakeCodeline> code = {
901 { TGSI_OPCODE_BGNLOOP },
902 { TGSI_OPCODE_IF, {}, {in0}, {}},
903 { TGSI_OPCODE_BRK},
904 { TGSI_OPCODE_ENDIF},
905 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
906 { TGSI_OPCODE_BRK},
907 { TGSI_OPCODE_ENDLOOP },
908 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
909 { TGSI_OPCODE_END}
910 };
911 run (code, temp_lt_expect({{-1,-1}, {0,7}}));
912 }
913
914 /* Loop with a break at the beginning and read/write in the post
915 * break loop scope. The value written and read within the loop
916 * can be limited to [write, read], but the value read outside the
917 * loop must survive the whole loop. This is the typical code for
918 * while and for loops, where the breaking condition is tested at
919 * the beginning.
920 */
921 TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAndReadAfterBreak)
922 {
923 const vector<FakeCodeline> code = {
924 { TGSI_OPCODE_BGNLOOP },
925 { TGSI_OPCODE_IF, {}, {in0}, {}},
926 { TGSI_OPCODE_BRK},
927 { TGSI_OPCODE_ENDIF},
928 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
929 { TGSI_OPCODE_MOV, {2}, {1}, {}},
930 { TGSI_OPCODE_ENDLOOP },
931 { TGSI_OPCODE_MOV, {out0}, {2}, {}},
932 { TGSI_OPCODE_END}
933 };
934 run (code, temp_lt_expect({{-1,-1}, {4,5}, {0,7}}));
935 }
936
937 /* Same as above, just make sure that the life time of the local variable
938 * in the outer loop (3) is not accidently promoted to the whole loop.
939 */
940 TEST_F(LifetimeEvaluatorExactTest, NestedLoopWithWriteAndReadAfterBreak)
941 {
942 const vector<FakeCodeline> code = {
943 { TGSI_OPCODE_BGNLOOP },
944 { TGSI_OPCODE_IF, {}, {in1}, {}},
945 { TGSI_OPCODE_BRK},
946 { TGSI_OPCODE_ENDIF},
947 { TGSI_OPCODE_BGNLOOP},
948 { TGSI_OPCODE_IF, {}, {in0}, {}},
949 { TGSI_OPCODE_BRK},
950 { TGSI_OPCODE_ENDIF},
951 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
952 { TGSI_OPCODE_MOV, {2}, {1}, {}},
953 { TGSI_OPCODE_ENDLOOP },
954 { TGSI_OPCODE_ADD, {3}, {2,in0}, {}},
955 { TGSI_OPCODE_ADD, {4}, {3,in2}, {}},
956 { TGSI_OPCODE_ENDLOOP },
957 { TGSI_OPCODE_MOV, {out0}, {4}, {}},
958 { TGSI_OPCODE_END}
959 };
960 run (code, temp_lt_expect({{-1,-1}, {8,9}, {0,13}, {11,12}, {0,14}}));
961 }
962
963 /* If a break is in the loop inside a switch case, make sure it is
964 * interpreted as breaking that inner loop, i.e. the variable has to
965 * survive the loop.
966 */
967 TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteAfterBreakInSwitchInLoop)
968 {
969 const vector<FakeCodeline> code = {
970 { TGSI_OPCODE_SWITCH, {}, {in1}, {}},
971 { TGSI_OPCODE_CASE, {}, {in1}, {}},
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_ENDLOOP },
978 { TGSI_OPCODE_DEFAULT, {}, {}, {}},
979 { TGSI_OPCODE_ENDSWITCH, {}, {}, {}},
980 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
981 { TGSI_OPCODE_END}
982 };
983 run (code, temp_lt_expect({{-1,-1}, {2,10}}));
984 }
985
986 /* Value written conditionally in one loop and read in another loop,
987 * and both of these loops are within yet another loop. Here the value
988 * has to survive the outer loop.
989 */
990 TEST_F(LifetimeEvaluatorExactTest, LoopsWithDifferntScopesConditionalWrite)
991 {
992 const vector<FakeCodeline> code = {
993 { TGSI_OPCODE_BGNLOOP },
994 { TGSI_OPCODE_IF, {}, {in0}, {}},
995 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
996 { TGSI_OPCODE_ENDIF},
997 { TGSI_OPCODE_ENDLOOP },
998 { TGSI_OPCODE_BGNLOOP },
999 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1000 { TGSI_OPCODE_ENDLOOP },
1001 { TGSI_OPCODE_END}
1002 };
1003 run (code, temp_lt_expect({{-1,-1}, {0,7}}));
1004 }
1005
1006 /* Value written and read in one loop and last read in another loop,
1007 * Here the value has to survive both loops.
1008 */
1009 TEST_F(LifetimeEvaluatorExactTest, LoopsWithDifferntScopesFirstReadBeforeWrite)
1010 {
1011 const vector<FakeCodeline> code = {
1012 { TGSI_OPCODE_BGNLOOP },
1013 { TGSI_OPCODE_MUL, {1}, {1,in0}, {}},
1014 { TGSI_OPCODE_ENDLOOP },
1015 { TGSI_OPCODE_BGNLOOP },
1016 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1017 { TGSI_OPCODE_ENDLOOP },
1018 { TGSI_OPCODE_END}
1019 };
1020 run (code, temp_lt_expect({{-1,-1}, {0,5}}));
1021 }
1022
1023
1024 /* Value is written in one switch code path within a loop
1025 * must survive the full loop.
1026 */
1027 TEST_F(LifetimeEvaluatorExactTest, LoopWithWriteInSwitch)
1028 {
1029 const vector<FakeCodeline> code = {
1030 { TGSI_OPCODE_BGNLOOP },
1031 { TGSI_OPCODE_SWITCH, {}, {in0}, {} },
1032 { TGSI_OPCODE_CASE, {}, {in0}, {} },
1033 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1034 { TGSI_OPCODE_BRK },
1035 { TGSI_OPCODE_DEFAULT },
1036 { TGSI_OPCODE_BRK },
1037 { TGSI_OPCODE_ENDSWITCH },
1038 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1039 { TGSI_OPCODE_ENDLOOP },
1040 { TGSI_OPCODE_END}
1041 };
1042 run (code, temp_lt_expect({{-1,-1}, {0,9}}));
1043 }
1044
1045 /* Value written in one case, and read in other,in loop
1046 * - must survive the loop.
1047 */
1048 TEST_F(LifetimeEvaluatorExactTest, LoopWithReadWriteInSwitchDifferentCase)
1049 {
1050 const vector<FakeCodeline> code = {
1051 { TGSI_OPCODE_BGNLOOP },
1052 { TGSI_OPCODE_SWITCH, {}, {in0}, {} },
1053 { TGSI_OPCODE_CASE, {}, {in0}, {} },
1054 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1055 { TGSI_OPCODE_BRK },
1056 { TGSI_OPCODE_DEFAULT },
1057 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1058 { TGSI_OPCODE_BRK },
1059 { TGSI_OPCODE_ENDSWITCH },
1060 { TGSI_OPCODE_ENDLOOP },
1061 { TGSI_OPCODE_END}
1062 };
1063 run (code, temp_lt_expect({{-1,-1}, {0,9}}));
1064 }
1065
1066 /* Value written in one case, and read in other,in loop
1067 * - must survive the loop, even if the write case falls through.
1068 */
1069 TEST_F(LifetimeEvaluatorExactTest, LoopWithReadWriteInSwitchDifferentCaseFallThrough)
1070 {
1071 const vector<FakeCodeline> code = {
1072 { TGSI_OPCODE_BGNLOOP },
1073 { TGSI_OPCODE_SWITCH, {}, {in0}, {} },
1074 { TGSI_OPCODE_CASE, {}, {in0}, {} },
1075 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1076 { TGSI_OPCODE_DEFAULT },
1077 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1078 { TGSI_OPCODE_BRK },
1079 { TGSI_OPCODE_ENDSWITCH },
1080 { TGSI_OPCODE_ENDLOOP },
1081 { TGSI_OPCODE_END}
1082 };
1083 run (code, temp_lt_expect({{-1,-1}, {0,8}}));
1084 }
1085
1086 /* Here we read and write from an to the same temp in the same instruction,
1087 * but the read is conditional (select operation), hence the lifetime must
1088 * start with the first write.
1089 */
1090 TEST_F(LifetimeEvaluatorExactTest, WriteSelectFromSelf)
1091 {
1092 const vector<FakeCodeline> code = {
1093 { TGSI_OPCODE_USEQ, {5}, {in0,in1}, {}},
1094 { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
1095 { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
1096 { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
1097 { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
1098 { TGSI_OPCODE_FSLT, {2}, {1,in1}, {}},
1099 { TGSI_OPCODE_UIF, {}, {2}, {}},
1100 { TGSI_OPCODE_MOV, {3}, {in1}, {}},
1101 { TGSI_OPCODE_ELSE},
1102 { TGSI_OPCODE_MOV, {4}, {in1}, {}},
1103 { TGSI_OPCODE_MOV, {4}, {4}, {}},
1104 { TGSI_OPCODE_MOV, {3}, {4}, {}},
1105 { TGSI_OPCODE_ENDIF},
1106 { TGSI_OPCODE_MOV, {out1}, {3}, {}},
1107 { TGSI_OPCODE_END}
1108 };
1109 run (code, temp_lt_expect({{-1,-1}, {1,5}, {5,6}, {7,13}, {9,11}, {0,4}}));
1110 }
1111
1112 /* This test checks wheter the ENDSWITCH is handled properly if the
1113 * last switch case/default doesn't stop with a BRK.
1114 */
1115 TEST_F(LifetimeEvaluatorExactTest, LoopRWInSwitchCaseLastCaseWithoutBreak)
1116 {
1117 const vector<FakeCodeline> code = {
1118 { TGSI_OPCODE_BGNLOOP },
1119 { TGSI_OPCODE_SWITCH, {}, {in0}, {} },
1120 { TGSI_OPCODE_CASE, {}, {in0}, {} },
1121 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1122 { TGSI_OPCODE_BRK },
1123 { TGSI_OPCODE_DEFAULT },
1124 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1125 { TGSI_OPCODE_ENDSWITCH },
1126 { TGSI_OPCODE_ENDLOOP },
1127 { TGSI_OPCODE_END}
1128 };
1129 run (code, temp_lt_expect({{-1,-1}, {0,8}}));
1130 }
1131
1132 /* Value read/write in same case, stays there */
1133 TEST_F(LifetimeEvaluatorExactTest, LoopWithReadWriteInSwitchSameCase)
1134 {
1135 const vector<FakeCodeline> code = {
1136 { TGSI_OPCODE_BGNLOOP },
1137 { TGSI_OPCODE_SWITCH, {}, {in0}, {} },
1138 { TGSI_OPCODE_CASE, {}, {in0}, {} },
1139 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1140 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1141 { TGSI_OPCODE_BRK },
1142 { TGSI_OPCODE_DEFAULT },
1143 { TGSI_OPCODE_BRK },
1144 { TGSI_OPCODE_ENDSWITCH },
1145 { TGSI_OPCODE_ENDLOOP },
1146 { TGSI_OPCODE_END}
1147 };
1148 run (code, temp_lt_expect({{-1,-1}, {3,4}}));
1149 }
1150
1151 /* Value read/write in all cases, should only live from first
1152 * write to last read, but currently the whole loop is used.
1153 */
1154 TEST_F(LifetimeEvaluatorAtLeastTest, LoopWithReadWriteInSwitchSameCase)
1155 {
1156 const vector<FakeCodeline> code = {
1157 { TGSI_OPCODE_BGNLOOP },
1158 { TGSI_OPCODE_SWITCH, {}, {in0}, {}},
1159 { TGSI_OPCODE_CASE, {}, {in0}, {} },
1160 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1161 { TGSI_OPCODE_BRK },
1162 { TGSI_OPCODE_DEFAULT },
1163 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1164 { TGSI_OPCODE_BRK },
1165 { TGSI_OPCODE_ENDSWITCH },
1166 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1167 { TGSI_OPCODE_ENDLOOP },
1168 { TGSI_OPCODE_END}
1169 };
1170 run (code, temp_lt_expect({{-1,-1}, {3,9}}));
1171 }
1172
1173 /* First read before first write with nested loops */
1174 TEST_F(LifetimeEvaluatorExactTest, LoopsWithDifferentScopesCondReadBeforeWrite)
1175 {
1176 const vector<FakeCodeline> code = {
1177 { TGSI_OPCODE_BGNLOOP },
1178 { TGSI_OPCODE_BGNLOOP },
1179 { TGSI_OPCODE_IF, {}, {in0}, {}},
1180 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1181 { TGSI_OPCODE_ENDIF},
1182 { TGSI_OPCODE_ENDLOOP },
1183 { TGSI_OPCODE_BGNLOOP },
1184 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1185 { TGSI_OPCODE_ENDLOOP },
1186 { TGSI_OPCODE_ENDLOOP },
1187 { TGSI_OPCODE_END}
1188 };
1189 run (code, temp_lt_expect({{-1,-1}, {0,9}}));
1190 }
1191
1192 /* First read before first write wiredness with nested loops.
1193 * Here the first read of 2 is logically before the first, dominant
1194 * write, therfore, the 2 has to survive both loops.
1195 */
1196 TEST_F(LifetimeEvaluatorExactTest, FirstWriteAtferReadInNestedLoop)
1197 {
1198 const vector<FakeCodeline> code = {
1199 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1200 { TGSI_OPCODE_BGNLOOP },
1201 { TGSI_OPCODE_BGNLOOP },
1202 { TGSI_OPCODE_MUL, {2}, {2,1}, {}},
1203 { TGSI_OPCODE_MOV, {3}, {2}, {}},
1204 { TGSI_OPCODE_ENDLOOP },
1205 { TGSI_OPCODE_ADD, {1}, {1,in1}, {}},
1206 { TGSI_OPCODE_ENDLOOP },
1207 { TGSI_OPCODE_MOV, {out0}, {3}, {}},
1208 { TGSI_OPCODE_END}
1209 };
1210 run (code, temp_lt_expect({{-1,-1}, {0,7}, {1,7}, {4,8}}));
1211 }
1212
1213
1214 #define DST(X, W) vector<pair<int,int>>(1, make_pair(X, W))
1215 #define SRC(X, S) vector<pair<int, const char *>>(1, make_pair(X, S))
1216 #define SRC2(X, S, Y, T) vector<pair<int, const char *>>({make_pair(X, S), make_pair(Y, T)})
1217
1218 /* Partial write to components: one component was written unconditionally
1219 * but another conditionally, temporary must survive the whole loop.
1220 * Test series for all components.
1221 */
1222 TEST_F(LifetimeEvaluatorExactTest, LoopWithConditionalComponentWrite_X)
1223 {
1224 const vector<FakeCodeline> code = {
1225 { TGSI_OPCODE_BGNLOOP},
1226 { TGSI_OPCODE_MOV, DST(1, WRITEMASK_Y), SRC(in1, "x"), {}, SWZ()},
1227 { TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}, SWZ()},
1228 { TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "y"), {}, SWZ()},
1229 { TGSI_OPCODE_ENDIF},
1230 { TGSI_OPCODE_MOV, DST(2, WRITEMASK_XY), SRC(1, "xy"), {}, SWZ()},
1231 { TGSI_OPCODE_ENDLOOP},
1232 { TGSI_OPCODE_MOV, DST(out0, WRITEMASK_XYZW), SRC(2, "xyxy"), {}, SWZ()},
1233 { TGSI_OPCODE_END}
1234 };
1235 run (code, temp_lt_expect({{-1,-1}, {0,6}, {5,7}}));
1236 }
1237
1238 TEST_F(LifetimeEvaluatorExactTest, LoopWithConditionalComponentWrite_Y)
1239 {
1240 const vector<FakeCodeline> code = {
1241 { TGSI_OPCODE_BGNLOOP},
1242 { TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "x"), {}, SWZ()},
1243 { TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}, SWZ()},
1244 { TGSI_OPCODE_MOV, DST(1, WRITEMASK_Y), SRC(in1, "y"), {}, SWZ()},
1245 { TGSI_OPCODE_ENDIF},
1246 { TGSI_OPCODE_MOV, DST(2, WRITEMASK_XY), SRC(1, "xy"), {}, SWZ()},
1247 { TGSI_OPCODE_ENDLOOP},
1248 { TGSI_OPCODE_MOV, DST(out0, WRITEMASK_XYZW), SRC(2, "xyxy"), {}, SWZ()},
1249 { TGSI_OPCODE_END}
1250 };
1251 run (code, temp_lt_expect({{-1,-1}, {0,6}, {5,7}}));
1252 }
1253
1254 TEST_F(LifetimeEvaluatorExactTest, LoopWithConditionalComponentWrite_Z)
1255 {
1256 const vector<FakeCodeline> code = {
1257 { TGSI_OPCODE_BGNLOOP},
1258 { TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "x"), {}, SWZ()},
1259 { TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}, SWZ()},
1260 { TGSI_OPCODE_MOV, DST(1, WRITEMASK_Z), SRC(in1, "y"), {}, SWZ()},
1261 { TGSI_OPCODE_ENDIF},
1262 { TGSI_OPCODE_MOV, DST(2, WRITEMASK_XY), SRC(1, "xz"), {}, SWZ()},
1263 { TGSI_OPCODE_ENDLOOP},
1264 { TGSI_OPCODE_MOV, DST(out0, WRITEMASK_XYZW), SRC(2, "xyxy"), {}, SWZ()},
1265 { TGSI_OPCODE_END}
1266 };
1267 run (code, temp_lt_expect({{-1,-1}, {0,6}, {5,7}}));
1268 }
1269
1270 TEST_F(LifetimeEvaluatorExactTest, LoopWithConditionalComponentWrite_W)
1271 {
1272 const vector<FakeCodeline> code = {
1273 { TGSI_OPCODE_BGNLOOP},
1274 { TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "x"), {}, SWZ()},
1275 { TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}, SWZ()},
1276 { TGSI_OPCODE_MOV, DST(1, WRITEMASK_W), SRC(in1, "y"), {}, SWZ()},
1277 { TGSI_OPCODE_ENDIF},
1278 { TGSI_OPCODE_MOV, DST(2, WRITEMASK_XY), SRC(1, "xw"), {}, SWZ()},
1279 { TGSI_OPCODE_ENDLOOP},
1280 { TGSI_OPCODE_MOV, DST(out0, WRITEMASK_XYZW), SRC(2, "xyxy"), {}, SWZ()},
1281 { TGSI_OPCODE_END}
1282 };
1283 run (code, temp_lt_expect({{-1,-1}, {0,6}, {5,7}}));
1284 }
1285
1286 TEST_F(LifetimeEvaluatorExactTest, LoopWithConditionalComponentWrite_X_Read_Y_Before)
1287 {
1288 const vector<FakeCodeline> code = {
1289 { TGSI_OPCODE_BGNLOOP},
1290 { TGSI_OPCODE_MOV, DST(1, WRITEMASK_X), SRC(in1, "x"), {}, SWZ()},
1291 { TGSI_OPCODE_IF, {}, SRC(in0, "xxxx"), {}, SWZ()},
1292 { TGSI_OPCODE_MOV, DST(2, WRITEMASK_XYZW), SRC(1, "yyyy"), {}, SWZ()},
1293 { TGSI_OPCODE_ENDIF},
1294 { TGSI_OPCODE_MOV, DST(1, WRITEMASK_YZW), SRC(2, "yyzw"), {}, SWZ()},
1295 { TGSI_OPCODE_ENDLOOP},
1296 { TGSI_OPCODE_ADD, DST(out0, WRITEMASK_XYZW),
1297 SRC2(2, "yyzw", 1, "xyxy"), {}, SWZ()},
1298 { TGSI_OPCODE_END}
1299 };
1300 run (code, temp_lt_expect({{-1,-1}, {0,7}, {0,7}}));
1301 }
1302
1303 /* The variable is conditionally read before first written, so
1304 * it has to surive all the loops.
1305 */
1306 TEST_F(LifetimeEvaluatorExactTest, FRaWSameInstructionInLoopAndCondition)
1307 {
1308 const vector<FakeCodeline> code = {
1309 { TGSI_OPCODE_BGNLOOP },
1310 { TGSI_OPCODE_BGNLOOP },
1311 { TGSI_OPCODE_IF, {}, {in0}, {} },
1312 { TGSI_OPCODE_ADD, {1}, {1,in0}, {}},
1313 { TGSI_OPCODE_ENDIF},
1314 { TGSI_OPCODE_MOV, {1}, {in1}, {}},
1315 { TGSI_OPCODE_ENDLOOP },
1316 { TGSI_OPCODE_ENDLOOP },
1317 { TGSI_OPCODE_END},
1318
1319 };
1320 run (code, temp_lt_expect({{-1,-1}, {0,7}}));
1321 }
1322
1323 /* If unconditionally first written and read in the same
1324 * instruction, then the register must be kept for the
1325 * one write, but not more (undefined behaviour)
1326 */
1327 TEST_F(LifetimeEvaluatorExactTest, FRaWSameInstruction)
1328 {
1329 const vector<FakeCodeline> code = {
1330 { TGSI_OPCODE_ADD, {1}, {1,in0}, {}},
1331 { TGSI_OPCODE_END},
1332
1333 };
1334 run (code, temp_lt_expect({{-1,-1}, {0,1}}));
1335 }
1336
1337 /* If unconditionally written and read in the same
1338 * instruction, various times then the register must be
1339 * kept past the last write, but not longer (undefined behaviour)
1340 */
1341 TEST_F(LifetimeEvaluatorExactTest, FRaWSameInstructionMoreThenOnce)
1342 {
1343 const vector<FakeCodeline> code = {
1344 { TGSI_OPCODE_ADD, {1}, {1,in0}, {}},
1345 { TGSI_OPCODE_ADD, {1}, {1,in0}, {}},
1346 { TGSI_OPCODE_MOV, {out0}, {in0}, {}},
1347 { TGSI_OPCODE_END},
1348
1349 };
1350 run (code, temp_lt_expect({{-1,-1}, {0,2}}));
1351 }
1352
1353 /* Register is only written. This should not happen,
1354 * but to handle the case we want the register to life
1355 * at least one instruction
1356 */
1357 TEST_F(LifetimeEvaluatorExactTest, WriteOnly)
1358 {
1359 const vector<FakeCodeline> code = {
1360 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1361 { TGSI_OPCODE_END}
1362 };
1363 run (code, temp_lt_expect({{-1,-1}, {0,1}}));
1364 }
1365
1366 /* Register is read in IF.
1367 */
1368 TEST_F(LifetimeEvaluatorExactTest, SimpleReadForIf)
1369 {
1370 const vector<FakeCodeline> code = {
1371 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1372 { TGSI_OPCODE_ADD, {out0}, {in0,in1}, {}},
1373 { TGSI_OPCODE_IF, {}, {1}, {}},
1374 { TGSI_OPCODE_ENDIF}
1375 };
1376 run (code, temp_lt_expect({{-1,-1}, {0,2}}));
1377 }
1378
1379 TEST_F(LifetimeEvaluatorExactTest, WriteTwoReadOne)
1380 {
1381 const vector<FakeCodeline> code = {
1382 { TGSI_OPCODE_DFRACEXP , {1,2}, {in0}, {}},
1383 { TGSI_OPCODE_ADD , {3}, {2,in0}, {}},
1384 { TGSI_OPCODE_MOV, {out1}, {3}, {}},
1385 { TGSI_OPCODE_END},
1386 };
1387 run (code, temp_lt_expect({{-1,-1}, {0,1}, {0,1}, {1,2}}));
1388 }
1389
1390 TEST_F(LifetimeEvaluatorExactTest, ReadOnly)
1391 {
1392 const vector<FakeCodeline> code = {
1393 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1394 { TGSI_OPCODE_END},
1395 };
1396 run (code, temp_lt_expect({{-1,-1}, {-1,-1}}));
1397 }
1398
1399 /* Test handling of missing END marker
1400 */
1401 TEST_F(LifetimeEvaluatorExactTest, SomeScopesAndNoEndProgramId)
1402 {
1403 const vector<FakeCodeline> code = {
1404 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1405 { TGSI_OPCODE_IF, {}, {1}, {}},
1406 { TGSI_OPCODE_MOV, {2}, {1}, {}},
1407 { TGSI_OPCODE_ENDIF},
1408 { TGSI_OPCODE_IF, {}, {1}, {}},
1409 { TGSI_OPCODE_MOV, {out0}, {2}, {}},
1410 { TGSI_OPCODE_ENDIF},
1411 };
1412 run (code, temp_lt_expect({{-1,-1}, {0,4}, {2,5}}));
1413 }
1414
1415 TEST_F(LifetimeEvaluatorExactTest, SerialReadWrite)
1416 {
1417 const vector<FakeCodeline> code = {
1418 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1419 { TGSI_OPCODE_MOV, {2}, {1}, {}},
1420 { TGSI_OPCODE_MOV, {3}, {2}, {}},
1421 { TGSI_OPCODE_MOV, {out0}, {3}, {}},
1422 { TGSI_OPCODE_END},
1423 };
1424 run (code, temp_lt_expect({{-1,-1}, {0,1}, {1,2}, {2,3}}));
1425 }
1426
1427 /* Check that two destination registers are used */
1428 TEST_F(LifetimeEvaluatorExactTest, TwoDestRegisters)
1429 {
1430 const vector<FakeCodeline> code = {
1431 { TGSI_OPCODE_DFRACEXP , {1,2}, {in0}, {}},
1432 { TGSI_OPCODE_ADD, {out0}, {1,2}, {}},
1433 { TGSI_OPCODE_END}
1434 };
1435 run (code, temp_lt_expect({{-1,-1}, {0,1}, {0,1}}));
1436 }
1437
1438 /* Check that writing within a loop in a conditional is propagated
1439 * to the outer loop.
1440 */
1441 TEST_F(LifetimeEvaluatorExactTest, WriteInLoopInConditionalReadOutside)
1442 {
1443 const vector<FakeCodeline> code = {
1444 { TGSI_OPCODE_BGNLOOP},
1445 { TGSI_OPCODE_IF, {}, {in0}, {}},
1446 { TGSI_OPCODE_BGNLOOP},
1447 { TGSI_OPCODE_MOV, {1}, {in1}, {}},
1448 { TGSI_OPCODE_ENDLOOP},
1449 { TGSI_OPCODE_ENDIF},
1450 { TGSI_OPCODE_ADD, {2}, {1,in1}, {}},
1451 { TGSI_OPCODE_ENDLOOP},
1452 { TGSI_OPCODE_MOV, {out0}, {2}, {}},
1453 { TGSI_OPCODE_END}
1454 };
1455 run (code, temp_lt_expect({{-1,-1}, {0,7}, {6,8}}));
1456 }
1457
1458 /* Check that a register written in a loop that is inside a conditional
1459 * is not propagated past that loop if last read is also within the
1460 * conditional
1461 */
1462 TEST_F(LifetimeEvaluatorExactTest, WriteInLoopInCondReadInCondOutsideLoop)
1463 {
1464 const vector<FakeCodeline> code = {
1465 { TGSI_OPCODE_BGNLOOP},
1466 { TGSI_OPCODE_IF, {}, {in0}, {}},
1467 { TGSI_OPCODE_BGNLOOP},
1468 { TGSI_OPCODE_MUL, {1}, {in2,in1}, {}},
1469 { TGSI_OPCODE_ENDLOOP},
1470 { TGSI_OPCODE_ADD, {2}, {1,in1}, {}},
1471 { TGSI_OPCODE_ENDIF},
1472 { TGSI_OPCODE_ENDLOOP},
1473 { TGSI_OPCODE_MOV, {out0}, {2}, {}},
1474 { TGSI_OPCODE_END}
1475 };
1476 run (code, temp_lt_expect({{-1,-1}, {3,5}, {0,8}}));
1477 }
1478
1479 /* Check that a register read before written in a loop that is
1480 * inside a conditional is propagated to the outer loop.
1481 */
1482 TEST_F(LifetimeEvaluatorExactTest, ReadWriteInLoopInCondReadInCondOutsideLoop)
1483 {
1484 const vector<FakeCodeline> code = {
1485 { TGSI_OPCODE_BGNLOOP},
1486 { TGSI_OPCODE_IF, {}, {in0}, {}},
1487 { TGSI_OPCODE_BGNLOOP},
1488 { TGSI_OPCODE_MUL, {1}, {1,in1}, {}},
1489 { TGSI_OPCODE_ENDLOOP},
1490 { TGSI_OPCODE_ADD, {2}, {1,in1}, {}},
1491 { TGSI_OPCODE_ENDIF},
1492 { TGSI_OPCODE_ENDLOOP},
1493 { TGSI_OPCODE_MOV, {out0}, {2}, {}},
1494 { TGSI_OPCODE_END}
1495 };
1496 run (code, temp_lt_expect({{-1,-1}, {0,7}, {0,8}}));
1497 }
1498
1499 /* With two destinations if one value is thrown away, we must
1500 * ensure that the two output registers don't merge. In this test
1501 * case the last access for 2 and 3 is in line 4, but 4 can only
1502 * be merged with 3 because it is read,2 on the other hand is written
1503 * to, and merging it with 4 would result in a bug.
1504 */
1505 TEST_F(LifetimeEvaluatorExactTest, WritePastLastRead2)
1506 {
1507 const vector<FakeCodeline> code = {
1508 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1509 { TGSI_OPCODE_MOV, {2}, {in0}, {}},
1510 { TGSI_OPCODE_ADD, {3}, {1,2}, {}},
1511 { TGSI_OPCODE_DFRACEXP , {2,4}, {3}, {}},
1512 { TGSI_OPCODE_MOV, {out1}, {4}, {}},
1513 { TGSI_OPCODE_END}
1514 };
1515 run (code, temp_lt_expect({{-1,-1}, {0,2}, {1,4}, {2,3}, {3,4}}));
1516 }
1517
1518 /* Check that three source registers are used */
1519 TEST_F(LifetimeEvaluatorExactTest, ThreeSourceRegisters)
1520 {
1521 const vector<FakeCodeline> code = {
1522 { TGSI_OPCODE_DFRACEXP , {1,2}, {in0}, {}},
1523 { TGSI_OPCODE_ADD , {3}, {in0,in1}, {}},
1524 { TGSI_OPCODE_MAD, {out0}, {1,2,3}, {}},
1525 { TGSI_OPCODE_END}
1526 };
1527 run (code, temp_lt_expect({{-1,-1}, {0,2}, {0,2}, {1,2}}));
1528 }
1529
1530 /* Check minimal lifetime for registers only written to */
1531 TEST_F(LifetimeEvaluatorExactTest, OverwriteWrittenOnlyTemps)
1532 {
1533 const vector<FakeCodeline> code = {
1534 { TGSI_OPCODE_MOV , {1}, {in0}, {}},
1535 { TGSI_OPCODE_MOV , {2}, {in1}, {}},
1536 { TGSI_OPCODE_END}
1537 };
1538 run (code, temp_lt_expect({{-1,-1}, {0,1}, {1,2}}));
1539 }
1540
1541 /* Same register is only written twice. This should not happen,
1542 * but to handle the case we want the register to life
1543 * at least past the last write instruction
1544 */
1545 TEST_F(LifetimeEvaluatorExactTest, WriteOnlyTwiceSame)
1546 {
1547 const vector<FakeCodeline> code = {
1548 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1549 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1550 { TGSI_OPCODE_END}
1551 };
1552 run (code, temp_lt_expect({{-1,-1}, {0,2}}));
1553 }
1554
1555 /* Dead code elimination should catch and remove the case
1556 * when a variable is written after its last read, but
1557 * we want the code to be aware of this case.
1558 * The life time of this uselessly written variable is set
1559 * to the instruction after the write, because
1560 * otherwise it could be re-used too early.
1561 */
1562 TEST_F(LifetimeEvaluatorExactTest, WritePastLastRead)
1563 {
1564 const vector<FakeCodeline> code = {
1565 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1566 { TGSI_OPCODE_MOV, {2}, {1}, {}},
1567 { TGSI_OPCODE_MOV, {1}, {2}, {}},
1568 { TGSI_OPCODE_END},
1569
1570 };
1571 run (code, temp_lt_expect({{-1,-1}, {0,3}, {1,2}}));
1572 }
1573
1574 /* If a break is in the loop, all variables written after the
1575 * break and used outside the loop the variable must survive the
1576 * outer loop
1577 */
1578 TEST_F(LifetimeEvaluatorExactTest, NestedLoopWithWriteAfterBreak)
1579 {
1580 const vector<FakeCodeline> code = {
1581 { TGSI_OPCODE_BGNLOOP },
1582 { TGSI_OPCODE_BGNLOOP },
1583 { TGSI_OPCODE_IF, {}, {in0}, {}},
1584 { TGSI_OPCODE_BRK},
1585 { TGSI_OPCODE_ENDIF},
1586 { TGSI_OPCODE_MOV, {1}, {in0}, {}},
1587 { TGSI_OPCODE_ENDLOOP },
1588 { TGSI_OPCODE_MOV, {out0}, {1}, {}},
1589 { TGSI_OPCODE_ENDLOOP },
1590 { TGSI_OPCODE_END}
1591 };
1592 run (code, temp_lt_expect({{-1,-1}, {0,8}}));
1593 }
1594
1595
1596 #define MT(X,Y,Z) std::make_tuple(X,Y,Z)
1597 /* Check lifetime estimation with a relative addressing in src.
1598 * Note, since the lifetime estimation always extends the lifetime
1599 * at to at least one instruction after the last write, for the
1600 * test the last read must be at least two instructions after the
1601 * last write to obtain a proper test.
1602 */
1603
1604 TEST_F(LifetimeEvaluatorExactTest, ReadIndirectReladdr1)
1605 {
1606 const vector<FakeCodeline> code = {
1607 { TGSI_OPCODE_MOV, {1}, {in1}, {}},
1608 { TGSI_OPCODE_MOV, {2}, {in0}, {}},
1609 { TGSI_OPCODE_MOV, {MT(3,0,0)}, {MT(2,1,0)}, {}, RA()},
1610 { TGSI_OPCODE_MOV, {out0}, {3}, {}},
1611 { TGSI_OPCODE_END}
1612 };
1613 run (code, temp_lt_expect({{-1,-1}, {0,2}, {1,2}, {2,3}}));
1614 }
1615
1616 /* Check lifetime estimation with a relative addressing in src */
1617 TEST_F(LifetimeEvaluatorExactTest, ReadIndirectReladdr2)
1618 {
1619 const vector<FakeCodeline> code = {
1620 { TGSI_OPCODE_MOV , {1}, {in1}, {}},
1621 { TGSI_OPCODE_MOV , {2}, {in0}, {}},
1622 { TGSI_OPCODE_MOV , {MT(3,0,0)}, {MT(4,0,1)}, {}, RA()},
1623 { TGSI_OPCODE_MOV , {out0}, {3}, {}},
1624 { TGSI_OPCODE_END}
1625 };
1626 run (code, temp_lt_expect({{-1,-1}, {0,2}, {1,2},{2,3}}));
1627 }
1628
1629 /* Check lifetime estimation with a relative addressing in src */
1630 TEST_F(LifetimeEvaluatorExactTest, ReadIndirectTexOffsReladdr1)
1631 {
1632 const vector<FakeCodeline> code = {
1633 { TGSI_OPCODE_MOV , {1}, {in1}, {}},
1634 { TGSI_OPCODE_MOV , {2}, {in0}, {}},
1635 { TGSI_OPCODE_MOV , {MT(3,0,0)}, {MT(in2,0,0)}, {MT(5,1,0)}, RA()},
1636 { TGSI_OPCODE_MOV , {out0}, {3}, {}},
1637 { TGSI_OPCODE_END}
1638 };
1639 run (code, temp_lt_expect({{-1,-1}, {0,2}, {1,2}, {2,3}}));
1640 }
1641
1642 /* Check lifetime estimation with a relative addressing in src */
1643 TEST_F(LifetimeEvaluatorExactTest, ReadIndirectTexOffsReladdr2)
1644 {
1645 const vector<FakeCodeline> code = {
1646 { TGSI_OPCODE_MOV , {1}, {in1}, {}},
1647 { TGSI_OPCODE_MOV , {2}, {in0}, {}},
1648 { TGSI_OPCODE_MOV , {MT(3,0,0)}, {MT(in2,0,0)}, {MT(2,0,1)}, RA()},
1649 { TGSI_OPCODE_MOV , {out0}, {3}, {}},
1650 { TGSI_OPCODE_END}
1651 };
1652 run (code, temp_lt_expect({{-1,-1}, {0,2}, {1,2}, {2,3}}));
1653 }
1654
1655 /* Check lifetime estimation with a relative addressing in dst */
1656 TEST_F(LifetimeEvaluatorExactTest, WriteIndirectReladdr1)
1657 {
1658 const vector<FakeCodeline> code = {
1659 { TGSI_OPCODE_MOV , {1}, {in0}, {}},
1660 { TGSI_OPCODE_MOV , {1}, {in1}, {}},
1661 { TGSI_OPCODE_MOV , {MT(5,1,0)}, {MT(in1,0,0)}, {}, RA()},
1662 { TGSI_OPCODE_END}
1663 };
1664 run (code, temp_lt_expect({{-1,-1}, {0,2}}));
1665 }
1666
1667 /* Check lifetime estimation with a relative addressing in dst */
1668 TEST_F(LifetimeEvaluatorExactTest, WriteIndirectReladdr2)
1669 {
1670 const vector<FakeCodeline> code = {
1671 { TGSI_OPCODE_MOV , {1}, {in0}, {}},
1672 { TGSI_OPCODE_MOV , {2}, {in1}, {}},
1673 { TGSI_OPCODE_MOV , {MT(5,0,1)}, {MT(in1,0,0)}, {}, RA()},
1674 { TGSI_OPCODE_MOV , {out0}, {in0}, {}},
1675 { TGSI_OPCODE_MOV , {out1}, {2}, {}},
1676 { TGSI_OPCODE_END}
1677 };
1678 run (code, temp_lt_expect({{-1,-1}, {0,2}, {1,4}}));
1679 }
1680
1681 /* Test remapping table of registers. The tests don't assume
1682 * that the sorting algorithm used to sort the lifetimes
1683 * based on their 'begin' is stable.
1684 */
1685 TEST_F(RegisterRemappingTest, RegisterRemapping1)
1686 {
1687 vector<lifetime> lt({{-1,-1},
1688 {0,1},
1689 {0,2},
1690 {1,2},
1691 {2,10},
1692 {3,5},
1693 {5,10}
1694 });
1695
1696 vector<int> expect({0,1,2,1,1,2,2});
1697 run(lt, expect);
1698 }
1699
1700 TEST_F(RegisterRemappingTest, RegisterRemapping2)
1701 {
1702 vector<lifetime> lt({{-1,-1},
1703 {0,1},
1704 {0,2},
1705 {3,4},
1706 {4,5},
1707 });
1708 vector<int> expect({0,1,2,1,1});
1709 run(lt, expect);
1710 }
1711
1712 TEST_F(RegisterRemappingTest, RegisterRemappingMergeAllToOne)
1713 {
1714 vector<lifetime> lt({{-1,-1},
1715 {0,1},
1716 {1,2},
1717 {2,3},
1718 {3,4},
1719 });
1720 vector<int> expect({0,1,1,1,1});
1721 run(lt, expect);
1722 }
1723
1724 TEST_F(RegisterRemappingTest, RegisterRemappingIgnoreUnused)
1725 {
1726 vector<lifetime> lt({{-1,-1},
1727 {0,1},
1728 {1,2},
1729 {2,3},
1730 {-1,-1},
1731 {3,4},
1732 });
1733 vector<int> expect({0,1,1,1,4,1});
1734 run(lt, expect);
1735 }
1736
1737 TEST_F(RegisterRemappingTest, RegisterRemappingMergeZeroLifetimeRegisters)
1738 {
1739 vector<lifetime> lt({{-1,-1},
1740 {0,1},
1741 {1,2},
1742 {2,3},
1743 {3,3},
1744 {3,4},
1745 });
1746 vector<int> expect({0,1,1,1,1,1});
1747 run(lt, expect);
1748 }
1749
1750 TEST_F(RegisterLifetimeAndRemappingTest, LifetimeAndRemapping)
1751 {
1752 const vector<FakeCodeline> code = {
1753 { TGSI_OPCODE_USEQ, {5}, {in0,in1}, {}},
1754 { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
1755 { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
1756 { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
1757 { TGSI_OPCODE_UCMP, {1}, {5,in1,1}, {}},
1758 { TGSI_OPCODE_FSLT, {2}, {1,in1}, {}},
1759 { TGSI_OPCODE_UIF, {}, {2}, {}},
1760 { TGSI_OPCODE_MOV, {3}, {in1}, {}},
1761 { TGSI_OPCODE_ELSE},
1762 { TGSI_OPCODE_MOV, {4}, {in1}, {}},
1763 { TGSI_OPCODE_MOV, {4}, {4}, {}},
1764 { TGSI_OPCODE_MOV, {3}, {4}, {}},
1765 { TGSI_OPCODE_ENDIF},
1766 { TGSI_OPCODE_MOV, {out1}, {3}, {}},
1767 { TGSI_OPCODE_END}
1768 };
1769 run (code, vector<int>({0,1,5,5,1,5}));
1770 }
1771
1772 TEST_F(RegisterLifetimeAndRemappingTest, LifetimeAndRemappingWithUnusedReadOnlyIgnored)
1773 {
1774 const vector<FakeCodeline> code = {
1775 { TGSI_OPCODE_USEQ, {1}, {in0,in1}, {}},
1776 { TGSI_OPCODE_UCMP, {2}, {1,in1,2}, {}},
1777 { TGSI_OPCODE_UCMP, {4}, {2,in1,1}, {}},
1778 { TGSI_OPCODE_ADD, {5}, {2,4}, {}},
1779 { TGSI_OPCODE_UIF, {}, {7}, {}},
1780 { TGSI_OPCODE_ADD, {8}, {5,4}, {}},
1781 { TGSI_OPCODE_ENDIF},
1782 { TGSI_OPCODE_MOV, {out1}, {8}, {}},
1783 { TGSI_OPCODE_END}
1784 };
1785 /* lt: 1: 0-2,2: 1-3 3: u 4: 2-5 5: 3-5 6: u 7: 0-(-1),8: 5-7 */
1786 run (code, vector<int>({0,1,2,3,1,2,6,7,1}));
1787 }
1788
1789 TEST_F(RegisterLifetimeAndRemappingTest, LifetimeAndRemappingWithUnusedReadOnlyRemappedTo)
1790 {
1791 const vector<FakeCodeline> code = {
1792 { TGSI_OPCODE_USEQ, {1}, {in0,in1}, {}},
1793 { TGSI_OPCODE_UIF, {}, {7}, {}},
1794 { TGSI_OPCODE_UCMP, {2}, {1,in1,2}, {}},
1795 { TGSI_OPCODE_UCMP, {4}, {2,in1,1}, {}},
1796 { TGSI_OPCODE_ADD, {5}, {2,4}, {}},
1797 { TGSI_OPCODE_ADD, {8}, {5,4}, {}},
1798 { TGSI_OPCODE_ENDIF},
1799 { TGSI_OPCODE_MOV, {out1}, {8}, {}},
1800 { TGSI_OPCODE_END}
1801 };
1802 /* lt: 1: 0-3,2: 2-4 3: u 4: 3-5 5: 4-5 6: u 7: 1-1,8: 5-7 */
1803 run (code, vector<int>({0,1,2,3,1,2,6,7,1}));
1804 }
1805
1806 TEST_F(RegisterLifetimeAndRemappingTest, LifetimeAndRemappingWithUnusedReadOnlyRemapped)
1807 {
1808 const vector<FakeCodeline> code = {
1809 { TGSI_OPCODE_USEQ, {0}, {in0,in1}, {}},
1810 { TGSI_OPCODE_UCMP, {2}, {0,in1,2}, {}},
1811 { TGSI_OPCODE_UCMP, {4}, {2,in1,0}, {}},
1812 { TGSI_OPCODE_UIF, {}, {7}, {}},
1813 { TGSI_OPCODE_ADD, {5}, {4,4}, {}},
1814 { TGSI_OPCODE_ADD, {8}, {5,4}, {}},
1815 { TGSI_OPCODE_ENDIF},
1816 { TGSI_OPCODE_MOV, {out1}, {8}, {}},
1817 { TGSI_OPCODE_END}
1818 };
1819 /* lt: 0: 0-2 1: u 2: 1-2 3: u 4: 2-5 5: 4-5 6: u 7:ro 8: 5-7 */
1820 run (code, vector<int>({0,1,2,3,0,2,6,7,0}));
1821 }