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