1 // Copyright (c) 2018 Google LLC.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <memory>
16 #include <unordered_set>
17 #include <vector>
18
19 #include "gmock/gmock.h"
20 #include "source/opt/register_pressure.h"
21 #include "test/opt/assembly_builder.h"
22 #include "test/opt/function_utils.h"
23 #include "test/opt/pass_fixture.h"
24 #include "test/opt/pass_utils.h"
25
26 namespace spvtools {
27 namespace opt {
28 namespace {
29
30 using ::testing::UnorderedElementsAre;
31 using PassClassTest = PassTest<::testing::Test>;
32
CompareSets(const std::unordered_set<Instruction * > & computed,const std::unordered_set<uint32_t> & expected)33 void CompareSets(const std::unordered_set<Instruction*>& computed,
34 const std::unordered_set<uint32_t>& expected) {
35 for (Instruction* insn : computed) {
36 EXPECT_TRUE(expected.count(insn->result_id()))
37 << "Unexpected instruction in live set: " << *insn;
38 }
39 EXPECT_EQ(computed.size(), expected.size());
40 }
41
42 /*
43 Generated from the following GLSL
44
45 #version 330
46 in vec4 BaseColor;
47 flat in int Count;
48 void main()
49 {
50 vec4 color = BaseColor;
51 vec4 acc;
52 if (Count == 0) {
53 acc = color;
54 }
55 else {
56 acc = color + vec4(0,1,2,0);
57 }
58 gl_FragColor = acc + color;
59 }
60 */
TEST_F(PassClassTest,LivenessWithIf)61 TEST_F(PassClassTest, LivenessWithIf) {
62 const std::string text = R"(
63 OpCapability Shader
64 %1 = OpExtInstImport "GLSL.std.450"
65 OpMemoryModel Logical GLSL450
66 OpEntryPoint Fragment %4 "main" %11 %15 %32
67 OpExecutionMode %4 OriginLowerLeft
68 OpSource GLSL 330
69 OpName %4 "main"
70 OpName %11 "BaseColor"
71 OpName %15 "Count"
72 OpName %32 "gl_FragColor"
73 OpDecorate %11 Location 0
74 OpDecorate %15 Flat
75 OpDecorate %15 Location 0
76 OpDecorate %32 Location 0
77 %2 = OpTypeVoid
78 %3 = OpTypeFunction %2
79 %6 = OpTypeFloat 32
80 %7 = OpTypeVector %6 4
81 %10 = OpTypePointer Input %7
82 %11 = OpVariable %10 Input
83 %13 = OpTypeInt 32 1
84 %14 = OpTypePointer Input %13
85 %15 = OpVariable %14 Input
86 %17 = OpConstant %13 0
87 %18 = OpTypeBool
88 %26 = OpConstant %6 0
89 %27 = OpConstant %6 1
90 %28 = OpConstant %6 2
91 %29 = OpConstantComposite %7 %26 %27 %28 %26
92 %31 = OpTypePointer Output %7
93 %32 = OpVariable %31 Output
94 %4 = OpFunction %2 None %3
95 %5 = OpLabel
96 %12 = OpLoad %7 %11
97 %16 = OpLoad %13 %15
98 %19 = OpIEqual %18 %16 %17
99 OpSelectionMerge %21 None
100 OpBranchConditional %19 %20 %24
101 %20 = OpLabel
102 OpBranch %21
103 %24 = OpLabel
104 %30 = OpFAdd %7 %12 %29
105 OpBranch %21
106 %21 = OpLabel
107 %36 = OpPhi %7 %12 %20 %30 %24
108 %35 = OpFAdd %7 %36 %12
109 OpStore %32 %35
110 OpReturn
111 OpFunctionEnd
112 )";
113 std::unique_ptr<IRContext> context =
114 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
115 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
116 Module* module = context->module();
117 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
118 << text << std::endl;
119 Function* f = &*module->begin();
120 LivenessAnalysis* liveness_analysis = context->GetLivenessAnalysis();
121 const RegisterLiveness* register_liveness = liveness_analysis->Get(f);
122 {
123 SCOPED_TRACE("Block 5");
124 auto live_sets = register_liveness->Get(5);
125 std::unordered_set<uint32_t> live_in{
126 11, // %11 = OpVariable %10 Input
127 15, // %15 = OpVariable %14 Input
128 32, // %32 = OpVariable %31 Output
129 };
130 CompareSets(live_sets->live_in_, live_in);
131
132 std::unordered_set<uint32_t> live_out{
133 12, // %12 = OpLoad %7 %11
134 32, // %32 = OpVariable %31 Output
135 };
136 CompareSets(live_sets->live_out_, live_out);
137 }
138 {
139 SCOPED_TRACE("Block 20");
140 auto live_sets = register_liveness->Get(20);
141 std::unordered_set<uint32_t> live_inout{
142 12, // %12 = OpLoad %7 %11
143 32, // %32 = OpVariable %31 Output
144 };
145 CompareSets(live_sets->live_in_, live_inout);
146 CompareSets(live_sets->live_out_, live_inout);
147 }
148 {
149 SCOPED_TRACE("Block 24");
150 auto live_sets = register_liveness->Get(24);
151 std::unordered_set<uint32_t> live_in{
152 12, // %12 = OpLoad %7 %11
153 32, // %32 = OpVariable %31 Output
154 };
155 CompareSets(live_sets->live_in_, live_in);
156
157 std::unordered_set<uint32_t> live_out{
158 12, // %12 = OpLoad %7 %11
159 30, // %30 = OpFAdd %7 %12 %29
160 32, // %32 = OpVariable %31 Output
161 };
162 CompareSets(live_sets->live_out_, live_out);
163 }
164 {
165 SCOPED_TRACE("Block 21");
166 auto live_sets = register_liveness->Get(21);
167 std::unordered_set<uint32_t> live_in{
168 12, // %12 = OpLoad %7 %11
169 32, // %32 = OpVariable %31 Output
170 36, // %36 = OpPhi %7 %12 %20 %30 %24
171 };
172 CompareSets(live_sets->live_in_, live_in);
173
174 std::unordered_set<uint32_t> live_out{};
175 CompareSets(live_sets->live_out_, live_out);
176 }
177 }
178
179 /*
180 Generated from the following GLSL
181 #version 330
182 in vec4 bigColor;
183 in vec4 BaseColor;
184 in float f;
185 flat in int Count;
186 flat in uvec4 v4;
187 void main()
188 {
189 vec4 color = BaseColor;
190 for (int i = 0; i < Count; ++i)
191 color += bigColor;
192 float sum = 0.0;
193 for (int i = 0; i < 4; ++i) {
194 float acc = 0.0;
195 if (sum == 0.0) {
196 acc = v4[i];
197 }
198 else {
199 acc = BaseColor[i];
200 }
201 sum += acc + v4[i];
202 }
203 vec4 tv4;
204 for (int i = 0; i < 4; ++i)
205 tv4[i] = v4[i] * 4u;
206 color += vec4(sum) + tv4;
207 vec4 r;
208 r.xyz = BaseColor.xyz;
209 for (int i = 0; i < Count; ++i)
210 r.w = f;
211 color.xyz += r.xyz;
212 for (int i = 0; i < 16; i += 4)
213 for (int j = 0; j < 4; j++)
214 color *= f;
215 gl_FragColor = color + tv4;
216 }
217 */
TEST_F(PassClassTest,RegisterLiveness)218 TEST_F(PassClassTest, RegisterLiveness) {
219 const std::string text = R"(
220 OpCapability Shader
221 %1 = OpExtInstImport "GLSL.std.450"
222 OpMemoryModel Logical GLSL450
223 OpEntryPoint Fragment %4 "main" %11 %24 %28 %55 %124 %176
224 OpExecutionMode %4 OriginLowerLeft
225 OpSource GLSL 330
226 OpName %4 "main"
227 OpName %11 "BaseColor"
228 OpName %24 "Count"
229 OpName %28 "bigColor"
230 OpName %55 "v4"
231 OpName %84 "tv4"
232 OpName %124 "f"
233 OpName %176 "gl_FragColor"
234 OpDecorate %11 Location 0
235 OpDecorate %24 Flat
236 OpDecorate %24 Location 0
237 OpDecorate %28 Location 0
238 OpDecorate %55 Flat
239 OpDecorate %55 Location 0
240 OpDecorate %124 Location 0
241 OpDecorate %176 Location 0
242 %2 = OpTypeVoid
243 %3 = OpTypeFunction %2
244 %6 = OpTypeFloat 32
245 %7 = OpTypeVector %6 4
246 %8 = OpTypePointer Function %7
247 %10 = OpTypePointer Input %7
248 %11 = OpVariable %10 Input
249 %13 = OpTypeInt 32 1
250 %16 = OpConstant %13 0
251 %23 = OpTypePointer Input %13
252 %24 = OpVariable %23 Input
253 %26 = OpTypeBool
254 %28 = OpVariable %10 Input
255 %33 = OpConstant %13 1
256 %35 = OpTypePointer Function %6
257 %37 = OpConstant %6 0
258 %45 = OpConstant %13 4
259 %52 = OpTypeInt 32 0
260 %53 = OpTypeVector %52 4
261 %54 = OpTypePointer Input %53
262 %55 = OpVariable %54 Input
263 %57 = OpTypePointer Input %52
264 %63 = OpTypePointer Input %6
265 %89 = OpConstant %52 4
266 %102 = OpTypeVector %6 3
267 %124 = OpVariable %63 Input
268 %158 = OpConstant %13 16
269 %175 = OpTypePointer Output %7
270 %176 = OpVariable %175 Output
271 %195 = OpUndef %7
272 %4 = OpFunction %2 None %3
273 %5 = OpLabel
274 %84 = OpVariable %8 Function
275 %12 = OpLoad %7 %11
276 OpBranch %17
277 %17 = OpLabel
278 %191 = OpPhi %7 %12 %5 %31 %18
279 %184 = OpPhi %13 %16 %5 %34 %18
280 %25 = OpLoad %13 %24
281 %27 = OpSLessThan %26 %184 %25
282 OpLoopMerge %19 %18 None
283 OpBranchConditional %27 %18 %19
284 %18 = OpLabel
285 %29 = OpLoad %7 %28
286 %31 = OpFAdd %7 %191 %29
287 %34 = OpIAdd %13 %184 %33
288 OpBranch %17
289 %19 = OpLabel
290 OpBranch %39
291 %39 = OpLabel
292 %188 = OpPhi %6 %37 %19 %73 %51
293 %185 = OpPhi %13 %16 %19 %75 %51
294 %46 = OpSLessThan %26 %185 %45
295 OpLoopMerge %41 %51 None
296 OpBranchConditional %46 %40 %41
297 %40 = OpLabel
298 %49 = OpFOrdEqual %26 %188 %37
299 OpSelectionMerge %51 None
300 OpBranchConditional %49 %50 %61
301 %50 = OpLabel
302 %58 = OpAccessChain %57 %55 %185
303 %59 = OpLoad %52 %58
304 %60 = OpConvertUToF %6 %59
305 OpBranch %51
306 %61 = OpLabel
307 %64 = OpAccessChain %63 %11 %185
308 %65 = OpLoad %6 %64
309 OpBranch %51
310 %51 = OpLabel
311 %210 = OpPhi %6 %60 %50 %65 %61
312 %68 = OpAccessChain %57 %55 %185
313 %69 = OpLoad %52 %68
314 %70 = OpConvertUToF %6 %69
315 %71 = OpFAdd %6 %210 %70
316 %73 = OpFAdd %6 %188 %71
317 %75 = OpIAdd %13 %185 %33
318 OpBranch %39
319 %41 = OpLabel
320 OpBranch %77
321 %77 = OpLabel
322 %186 = OpPhi %13 %16 %41 %94 %78
323 %83 = OpSLessThan %26 %186 %45
324 OpLoopMerge %79 %78 None
325 OpBranchConditional %83 %78 %79
326 %78 = OpLabel
327 %87 = OpAccessChain %57 %55 %186
328 %88 = OpLoad %52 %87
329 %90 = OpIMul %52 %88 %89
330 %91 = OpConvertUToF %6 %90
331 %92 = OpAccessChain %35 %84 %186
332 OpStore %92 %91
333 %94 = OpIAdd %13 %186 %33
334 OpBranch %77
335 %79 = OpLabel
336 %96 = OpCompositeConstruct %7 %188 %188 %188 %188
337 %97 = OpLoad %7 %84
338 %98 = OpFAdd %7 %96 %97
339 %100 = OpFAdd %7 %191 %98
340 %104 = OpVectorShuffle %102 %12 %12 0 1 2
341 %106 = OpVectorShuffle %7 %195 %104 4 5 6 3
342 OpBranch %108
343 %108 = OpLabel
344 %197 = OpPhi %7 %106 %79 %208 %133
345 %196 = OpPhi %13 %16 %79 %143 %133
346 %115 = OpSLessThan %26 %196 %25
347 OpLoopMerge %110 %133 None
348 OpBranchConditional %115 %109 %110
349 %109 = OpLabel
350 OpBranch %117
351 %117 = OpLabel
352 %209 = OpPhi %7 %197 %109 %181 %118
353 %204 = OpPhi %13 %16 %109 %129 %118
354 %123 = OpSLessThan %26 %204 %45
355 OpLoopMerge %119 %118 None
356 OpBranchConditional %123 %118 %119
357 %118 = OpLabel
358 %125 = OpLoad %6 %124
359 %181 = OpCompositeInsert %7 %125 %209 3
360 %129 = OpIAdd %13 %204 %33
361 OpBranch %117
362 %119 = OpLabel
363 OpBranch %131
364 %131 = OpLabel
365 %208 = OpPhi %7 %209 %119 %183 %132
366 %205 = OpPhi %13 %16 %119 %141 %132
367 %137 = OpSLessThan %26 %205 %45
368 OpLoopMerge %133 %132 None
369 OpBranchConditional %137 %132 %133
370 %132 = OpLabel
371 %138 = OpLoad %6 %124
372 %183 = OpCompositeInsert %7 %138 %208 3
373 %141 = OpIAdd %13 %205 %33
374 OpBranch %131
375 %133 = OpLabel
376 %143 = OpIAdd %13 %196 %33
377 OpBranch %108
378 %110 = OpLabel
379 %145 = OpVectorShuffle %102 %197 %197 0 1 2
380 %147 = OpVectorShuffle %102 %100 %100 0 1 2
381 %148 = OpFAdd %102 %147 %145
382 %150 = OpVectorShuffle %7 %100 %148 4 5 6 3
383 OpBranch %152
384 %152 = OpLabel
385 %200 = OpPhi %7 %150 %110 %203 %163
386 %199 = OpPhi %13 %16 %110 %174 %163
387 %159 = OpSLessThan %26 %199 %158
388 OpLoopMerge %154 %163 None
389 OpBranchConditional %159 %153 %154
390 %153 = OpLabel
391 OpBranch %161
392 %161 = OpLabel
393 %203 = OpPhi %7 %200 %153 %170 %162
394 %201 = OpPhi %13 %16 %153 %172 %162
395 %167 = OpSLessThan %26 %201 %45
396 OpLoopMerge %163 %162 None
397 OpBranchConditional %167 %162 %163
398 %162 = OpLabel
399 %168 = OpLoad %6 %124
400 %170 = OpVectorTimesScalar %7 %203 %168
401 %172 = OpIAdd %13 %201 %33
402 OpBranch %161
403 %163 = OpLabel
404 %174 = OpIAdd %13 %199 %45
405 OpBranch %152
406 %154 = OpLabel
407 %178 = OpLoad %7 %84
408 %179 = OpFAdd %7 %200 %178
409 OpStore %176 %179
410 OpReturn
411 OpFunctionEnd
412 )";
413 std::unique_ptr<IRContext> context =
414 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
415 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
416 Module* module = context->module();
417 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
418 << text << std::endl;
419 Function* f = &*module->begin();
420 LivenessAnalysis* liveness_analysis = context->GetLivenessAnalysis();
421 const RegisterLiveness* register_liveness = liveness_analysis->Get(f);
422 LoopDescriptor& ld = *context->GetLoopDescriptor(f);
423
424 {
425 SCOPED_TRACE("Block 5");
426 auto live_sets = register_liveness->Get(5);
427 std::unordered_set<uint32_t> live_in{
428 11, // %11 = OpVariable %10 Input
429 24, // %24 = OpVariable %23 Input
430 28, // %28 = OpVariable %10 Input
431 55, // %55 = OpVariable %54 Input
432 124, // %124 = OpVariable %63 Input
433 176, // %176 = OpVariable %175 Output
434 };
435 CompareSets(live_sets->live_in_, live_in);
436
437 std::unordered_set<uint32_t> live_out{
438 11, // %11 = OpVariable %10 Input
439 12, // %12 = OpLoad %7 %11
440 24, // %24 = OpVariable %23 Input
441 28, // %28 = OpVariable %10 Input
442 55, // %55 = OpVariable %54 Input
443 84, // %84 = OpVariable %8 Function
444 124, // %124 = OpVariable %63 Input
445 176, // %176 = OpVariable %175 Output
446 };
447 CompareSets(live_sets->live_out_, live_out);
448
449 EXPECT_EQ(live_sets->used_registers_, 8u);
450 }
451 {
452 SCOPED_TRACE("Block 17");
453 auto live_sets = register_liveness->Get(17);
454 std::unordered_set<uint32_t> live_in{
455 11, // %11 = OpVariable %10 Input
456 12, // %12 = OpLoad %7 %11
457 24, // %24 = OpVariable %23 Input
458 28, // %28 = OpVariable %10 Input
459 55, // %55 = OpVariable %54 Input
460 84, // %84 = OpVariable %8 Function
461 124, // %124 = OpVariable %63 Input
462 176, // %176 = OpVariable %175 Output
463 184, // %184 = OpPhi %13 %16 %5 %34 %18
464 191, // %191 = OpPhi %7 %12 %5 %31 %18
465 };
466 CompareSets(live_sets->live_in_, live_in);
467
468 std::unordered_set<uint32_t> live_out{
469 11, // %11 = OpVariable %10 Input
470 12, // %12 = OpLoad %7 %11
471 25, // %25 = OpLoad %13 %24
472 28, // %28 = OpVariable %10 Input
473 55, // %55 = OpVariable %54 Input
474 84, // %84 = OpVariable %8 Function
475 124, // %124 = OpVariable %63 Input
476 176, // %176 = OpVariable %175 Output
477 184, // %184 = OpPhi %13 %16 %5 %34 %18
478 191, // %191 = OpPhi %7 %12 %5 %31 %18
479 };
480 CompareSets(live_sets->live_out_, live_out);
481
482 EXPECT_EQ(live_sets->used_registers_, 11u);
483 }
484 {
485 SCOPED_TRACE("Block 18");
486 auto live_sets = register_liveness->Get(18);
487 std::unordered_set<uint32_t> live_in{
488 11, // %11 = OpVariable %10 Input
489 12, // %12 = OpLoad %7 %11
490 24, // %24 = OpVariable %23 Input
491 28, // %28 = OpVariable %10 Input
492 55, // %55 = OpVariable %54 Input
493 84, // %84 = OpVariable %8 Function
494 124, // %124 = OpVariable %63 Input
495 176, // %176 = OpVariable %175 Output
496 184, // %184 = OpPhi %13 %16 %5 %34 %18
497 191, // %191 = OpPhi %7 %12 %5 %31 %18
498 };
499 CompareSets(live_sets->live_in_, live_in);
500
501 std::unordered_set<uint32_t> live_out{
502 11, // %11 = OpVariable %10 Input
503 12, // %12 = OpLoad %7 %11
504 24, // %24 = OpVariable %23 Input
505 28, // %28 = OpVariable %10 Input
506 31, // %31 = OpFAdd %7 %191 %29
507 34, // %34 = OpIAdd %13 %184 %33
508 55, // %55 = OpVariable %54 Input
509 84, // %84 = OpVariable %8 Function
510 124, // %124 = OpVariable %63 Input
511 176, // %176 = OpVariable %175 Output
512 };
513 CompareSets(live_sets->live_out_, live_out);
514
515 EXPECT_EQ(live_sets->used_registers_, 12u);
516 }
517 {
518 SCOPED_TRACE("Block 19");
519 auto live_sets = register_liveness->Get(19);
520 std::unordered_set<uint32_t> live_inout{
521 11, // %11 = OpVariable %10 Input
522 12, // %12 = OpLoad %7 %11
523 25, // %25 = OpLoad %13 %24
524 55, // %55 = OpVariable %54 Input
525 84, // %84 = OpVariable %8 Function
526 124, // %124 = OpVariable %63 Input
527 176, // %176 = OpVariable %175 Output
528 191, // %191 = OpPhi %7 %12 %5 %31 %18
529 };
530 CompareSets(live_sets->live_in_, live_inout);
531 CompareSets(live_sets->live_out_, live_inout);
532
533 EXPECT_EQ(live_sets->used_registers_, 8u);
534 }
535 {
536 SCOPED_TRACE("Block 39");
537 auto live_sets = register_liveness->Get(39);
538 std::unordered_set<uint32_t> live_inout{
539 11, // %11 = OpVariable %10 Input
540 12, // %12 = OpLoad %7 %11
541 25, // %25 = OpLoad %13 %24
542 55, // %55 = OpVariable %54 Input
543 84, // %84 = OpVariable %8 Function
544 124, // %124 = OpVariable %63 Input
545 176, // %176 = OpVariable %175 Output
546 185, // %185 = OpPhi %13 %16 %19 %75 %51
547 188, // %188 = OpPhi %6 %37 %19 %73 %51
548 191, // %191 = OpPhi %7 %12 %5 %31 %18
549 };
550 CompareSets(live_sets->live_in_, live_inout);
551 CompareSets(live_sets->live_out_, live_inout);
552
553 EXPECT_EQ(live_sets->used_registers_, 11u);
554 }
555 {
556 SCOPED_TRACE("Block 40");
557 auto live_sets = register_liveness->Get(40);
558 std::unordered_set<uint32_t> live_inout{
559 11, // %11 = OpVariable %10 Input
560 12, // %12 = OpLoad %7 %11
561 25, // %25 = OpLoad %13 %24
562 55, // %55 = OpVariable %54 Input
563 84, // %84 = OpVariable %8 Function
564 124, // %124 = OpVariable %63 Input
565 176, // %176 = OpVariable %175 Output
566 185, // %185 = OpPhi %13 %16 %19 %75 %51
567 188, // %188 = OpPhi %6 %37 %19 %73 %51
568 191, // %191 = OpPhi %7 %12 %5 %31 %18
569 };
570 CompareSets(live_sets->live_in_, live_inout);
571 CompareSets(live_sets->live_out_, live_inout);
572
573 EXPECT_EQ(live_sets->used_registers_, 11u);
574 }
575 {
576 SCOPED_TRACE("Block 50");
577 auto live_sets = register_liveness->Get(50);
578 std::unordered_set<uint32_t> live_in{
579 11, // %11 = OpVariable %10 Input
580 12, // %12 = OpLoad %7 %11
581 25, // %25 = OpLoad %13 %24
582 55, // %55 = OpVariable %54 Input
583 84, // %84 = OpVariable %8 Function
584 124, // %124 = OpVariable %63 Input
585 176, // %176 = OpVariable %175 Output
586 185, // %185 = OpPhi %13 %16 %19 %75 %51
587 188, // %188 = OpPhi %6 %37 %19 %73 %51
588 191, // %191 = OpPhi %7 %12 %5 %31 %18
589 };
590 CompareSets(live_sets->live_in_, live_in);
591
592 std::unordered_set<uint32_t> live_out{
593 11, // %11 = OpVariable %10 Input
594 12, // %12 = OpLoad %7 %11
595 25, // %25 = OpLoad %13 %24
596 55, // %55 = OpVariable %54 Input
597 60, // %60 = OpConvertUToF %6 %59
598 84, // %84 = OpVariable %8 Function
599 124, // %124 = OpVariable %63 Input
600 176, // %176 = OpVariable %175 Output
601 185, // %185 = OpPhi %13 %16 %19 %75 %51
602 188, // %188 = OpPhi %6 %37 %19 %73 %51
603 191, // %191 = OpPhi %7 %12 %5 %31 %18
604 };
605 CompareSets(live_sets->live_out_, live_out);
606
607 EXPECT_EQ(live_sets->used_registers_, 12u);
608 }
609 {
610 SCOPED_TRACE("Block 61");
611 auto live_sets = register_liveness->Get(61);
612 std::unordered_set<uint32_t> live_in{
613 11, // %11 = OpVariable %10 Input
614 12, // %12 = OpLoad %7 %11
615 25, // %25 = OpLoad %13 %24
616 55, // %55 = OpVariable %54 Input
617 84, // %84 = OpVariable %8 Function
618 124, // %124 = OpVariable %63 Input
619 176, // %176 = OpVariable %175 Output
620 185, // %185 = OpPhi %13 %16 %19 %75 %51
621 188, // %188 = OpPhi %6 %37 %19 %73 %51
622 191, // %191 = OpPhi %7 %12 %5 %31 %18
623 };
624 CompareSets(live_sets->live_in_, live_in);
625
626 std::unordered_set<uint32_t> live_out{
627 11, // %11 = OpVariable %10 Input
628 12, // %12 = OpLoad %7 %11
629 25, // %25 = OpLoad %13 %24
630 55, // %55 = OpVariable %54 Input
631 65, // %65 = OpLoad %6 %64
632 84, // %84 = OpVariable %8 Function
633 124, // %124 = OpVariable %63 Input
634 176, // %176 = OpVariable %175 Output
635 185, // %185 = OpPhi %13 %16 %19 %75 %51
636 188, // %188 = OpPhi %6 %37 %19 %73 %51
637 191, // %191 = OpPhi %7 %12 %5 %31 %18
638 };
639 CompareSets(live_sets->live_out_, live_out);
640
641 EXPECT_EQ(live_sets->used_registers_, 12u);
642 }
643 {
644 SCOPED_TRACE("Block 51");
645 auto live_sets = register_liveness->Get(51);
646 std::unordered_set<uint32_t> live_in{
647 11, // %11 = OpVariable %10 Input
648 12, // %12 = OpLoad %7 %11
649 25, // %25 = OpLoad %13 %24
650 55, // %55 = OpVariable %54 Input
651 84, // %84 = OpVariable %8 Function
652 124, // %124 = OpVariable %63 Input
653 176, // %176 = OpVariable %175 Output
654 185, // %185 = OpPhi %13 %16 %19 %75 %51
655 188, // %188 = OpPhi %6 %37 %19 %73 %51
656 191, // %191 = OpPhi %7 %12 %5 %31 %18
657 210, // %210 = OpPhi %6 %60 %50 %65 %61
658 };
659 CompareSets(live_sets->live_in_, live_in);
660
661 std::unordered_set<uint32_t> live_out{
662 11, // %11 = OpVariable %10 Input
663 12, // %12 = OpLoad %7 %11
664 25, // %25 = OpLoad %13 %24
665 55, // %55 = OpVariable %54 Input
666 73, // %73 = OpFAdd %6 %188 %71
667 75, // %75 = OpIAdd %13 %185 %33
668 84, // %84 = OpVariable %8 Function
669 124, // %124 = OpVariable %63 Input
670 176, // %176 = OpVariable %175 Output
671 191, // %191 = OpPhi %7 %12 %5 %31 %18
672 };
673 CompareSets(live_sets->live_out_, live_out);
674
675 EXPECT_EQ(live_sets->used_registers_, 13u);
676 }
677 {
678 SCOPED_TRACE("Block 41");
679 auto live_sets = register_liveness->Get(41);
680 std::unordered_set<uint32_t> live_inout{
681 12, // %12 = OpLoad %7 %11
682 25, // %25 = OpLoad %13 %24
683 55, // %55 = OpVariable %54 Input
684 84, // %84 = OpVariable %8 Function
685 124, // %124 = OpVariable %63 Input
686 176, // %176 = OpVariable %175 Output
687 188, // %188 = OpPhi %6 %37 %19 %73 %51
688 191, // %191 = OpPhi %7 %12 %5 %31 %18
689 };
690 CompareSets(live_sets->live_in_, live_inout);
691 CompareSets(live_sets->live_out_, live_inout);
692
693 EXPECT_EQ(live_sets->used_registers_, 8u);
694 }
695 {
696 SCOPED_TRACE("Block 77");
697 auto live_sets = register_liveness->Get(77);
698 std::unordered_set<uint32_t> live_inout{
699 12, // %12 = OpLoad %7 %11
700 25, // %25 = OpLoad %13 %24
701 55, // %55 = OpVariable %54 Input
702 84, // %84 = OpVariable %8 Function
703 124, // %124 = OpVariable %63 Input
704 176, // %176 = OpVariable %175 Output
705 186, // %186 = OpPhi %13 %16 %41 %94 %78
706 188, // %188 = OpPhi %6 %37 %19 %73 %51
707 191, // %191 = OpPhi %7 %12 %5 %31 %18
708 };
709 CompareSets(live_sets->live_in_, live_inout);
710 CompareSets(live_sets->live_out_, live_inout);
711
712 EXPECT_EQ(live_sets->used_registers_, 10u);
713 }
714 {
715 SCOPED_TRACE("Block 78");
716 auto live_sets = register_liveness->Get(78);
717 std::unordered_set<uint32_t> live_in{
718 12, // %12 = OpLoad %7 %11
719 25, // %25 = OpLoad %13 %24
720 55, // %55 = OpVariable %54 Input
721 84, // %84 = OpVariable %8 Function
722 124, // %124 = OpVariable %63 Input
723 176, // %176 = OpVariable %175 Output
724 186, // %186 = OpPhi %13 %16 %41 %94 %78
725 188, // %188 = OpPhi %6 %37 %19 %73 %51
726 191, // %191 = OpPhi %7 %12 %5 %31 %18
727 };
728 CompareSets(live_sets->live_in_, live_in);
729
730 std::unordered_set<uint32_t> live_out{
731 12, // %12 = OpLoad %7 %11
732 25, // %25 = OpLoad %13 %24
733 55, // %55 = OpVariable %54 Input
734 84, // %84 = OpVariable %8 Function
735 94, // %94 = OpIAdd %13 %186 %33
736 124, // %124 = OpVariable %63 Input
737 176, // %176 = OpVariable %175 Output
738 188, // %188 = OpPhi %6 %37 %19 %73 %51
739 191, // %191 = OpPhi %7 %12 %5 %31 %18
740 };
741 CompareSets(live_sets->live_out_, live_out);
742
743 EXPECT_EQ(live_sets->used_registers_, 11u);
744 }
745 {
746 SCOPED_TRACE("Block 79");
747 auto live_sets = register_liveness->Get(79);
748 std::unordered_set<uint32_t> live_in{
749 12, // %12 = OpLoad %7 %11
750 25, // %25 = OpLoad %13 %24
751 84, // %84 = OpVariable %8 Function
752 124, // %124 = OpVariable %63 Input
753 176, // %176 = OpVariable %175 Output
754 188, // %188 = OpPhi %6 %37 %19 %73 %51
755 191, // %191 = OpPhi %7 %12 %5 %31 %18
756 };
757 CompareSets(live_sets->live_in_, live_in);
758
759 std::unordered_set<uint32_t> live_out{
760 25, // %25 = OpLoad %13 %24
761 84, // %84 = OpVariable %8 Function
762 100, // %100 = OpFAdd %7 %191 %98
763 106, // %106 = OpVectorShuffle %7 %195 %104 4 5 6 3
764 124, // %124 = OpVariable %63 Input
765 176, // %176 = OpVariable %175 Output
766 };
767 CompareSets(live_sets->live_out_, live_out);
768
769 EXPECT_EQ(live_sets->used_registers_, 9u);
770 }
771 {
772 SCOPED_TRACE("Block 108");
773 auto live_sets = register_liveness->Get(108);
774 std::unordered_set<uint32_t> live_in{
775 25, // %25 = OpLoad %13 %24
776 84, // %84 = OpVariable %8 Function
777 100, // %100 = OpFAdd %7 %191 %98
778 124, // %124 = OpVariable %63 Input
779 176, // %176 = OpVariable %175 Output
780 196, // %196 = OpPhi %13 %16 %79 %143 %133
781 197, // %197 = OpPhi %7 %106 %79 %208 %133
782 };
783 CompareSets(live_sets->live_in_, live_in);
784
785 std::unordered_set<uint32_t> live_out{
786 84, // %84 = OpVariable %8 Function
787 100, // %100 = OpFAdd %7 %191 %98
788 124, // %124 = OpVariable %63 Input
789 176, // %176 = OpVariable %175 Output
790 196, // %196 = OpPhi %13 %16 %79 %143 %133
791 197, // %197 = OpPhi %7 %106 %79 %208 %133
792 };
793 CompareSets(live_sets->live_out_, live_out);
794
795 EXPECT_EQ(live_sets->used_registers_, 8u);
796 }
797 {
798 SCOPED_TRACE("Block 109");
799 auto live_sets = register_liveness->Get(109);
800 std::unordered_set<uint32_t> live_inout{
801 25, // %25 = OpLoad %13 %24
802 84, // %84 = OpVariable %8 Function
803 100, // %100 = OpFAdd %7 %191 %98
804 124, // %124 = OpVariable %63 Input
805 176, // %176 = OpVariable %175 Output
806 196, // %196 = OpPhi %13 %16 %79 %143 %133
807 197, // %197 = OpPhi %7 %106 %79 %208 %133
808 };
809 CompareSets(live_sets->live_in_, live_inout);
810 CompareSets(live_sets->live_out_, live_inout);
811
812 EXPECT_EQ(live_sets->used_registers_, 7u);
813 }
814 {
815 SCOPED_TRACE("Block 117");
816 auto live_sets = register_liveness->Get(117);
817 std::unordered_set<uint32_t> live_inout{
818 25, // %25 = OpLoad %13 %24
819 84, // %84 = OpVariable %8 Function
820 100, // %100 = OpFAdd %7 %191 %98
821 124, // %124 = OpVariable %63 Input
822 176, // %176 = OpVariable %175 Output
823 196, // %196 = OpPhi %13 %16 %79 %143 %133
824 204, // %204 = OpPhi %13 %16 %109 %129 %118
825 209, // %209 = OpPhi %7 %197 %109 %181 %118
826 };
827 CompareSets(live_sets->live_in_, live_inout);
828 CompareSets(live_sets->live_out_, live_inout);
829
830 EXPECT_EQ(live_sets->used_registers_, 9u);
831 }
832 {
833 SCOPED_TRACE("Block 118");
834 auto live_sets = register_liveness->Get(118);
835 std::unordered_set<uint32_t> live_in{
836 25, // %25 = OpLoad %13 %24
837 84, // %84 = OpVariable %8 Function
838 100, // %100 = OpFAdd %7 %191 %98
839 124, // %124 = OpVariable %63 Input
840 176, // %176 = OpVariable %175 Output
841 196, // %196 = OpPhi %13 %16 %79 %143 %133
842 204, // %204 = OpPhi %13 %16 %109 %129 %118
843 209, // %209 = OpPhi %7 %197 %109 %181 %118
844 };
845 CompareSets(live_sets->live_in_, live_in);
846
847 std::unordered_set<uint32_t> live_out{
848 25, // %25 = OpLoad %13 %24
849 84, // %84 = OpVariable %8 Function
850 100, // %100 = OpFAdd %7 %191 %98
851 124, // %124 = OpVariable %63 Input
852 129, // %129 = OpIAdd %13 %204 %33
853 176, // %176 = OpVariable %175 Output
854 181, // %181 = OpCompositeInsert %7 %125 %209 3
855 196, // %196 = OpPhi %13 %16 %79 %143 %133
856 };
857 CompareSets(live_sets->live_out_, live_out);
858
859 EXPECT_EQ(live_sets->used_registers_, 10u);
860 }
861 {
862 SCOPED_TRACE("Block 119");
863 auto live_sets = register_liveness->Get(119);
864 std::unordered_set<uint32_t> live_inout{
865 25, // %25 = OpLoad %13 %24
866 84, // %84 = OpVariable %8 Function
867 100, // %100 = OpFAdd %7 %191 %98
868 124, // %124 = OpVariable %63 Input
869 176, // %176 = OpVariable %175 Output
870 196, // %196 = OpPhi %13 %16 %79 %143 %133
871 209, // %209 = OpPhi %7 %197 %109 %181 %118
872 };
873 CompareSets(live_sets->live_in_, live_inout);
874 CompareSets(live_sets->live_out_, live_inout);
875
876 EXPECT_EQ(live_sets->used_registers_, 7u);
877 }
878 {
879 SCOPED_TRACE("Block 131");
880 auto live_sets = register_liveness->Get(131);
881 std::unordered_set<uint32_t> live_inout{
882 25, // %25 = OpLoad %13 %24
883 84, // %84 = OpVariable %8 Function
884 100, // %100 = OpFAdd %7 %191 %98
885 124, // %124 = OpVariable %63 Input
886 176, // %176 = OpVariable %175 Output
887 196, // %196 = OpPhi %13 %16 %79 %143 %133
888 205, // %205 = OpPhi %13 %16 %119 %141 %132
889 208, // %208 = OpPhi %7 %209 %119 %183 %132
890 };
891 CompareSets(live_sets->live_in_, live_inout);
892 CompareSets(live_sets->live_out_, live_inout);
893
894 EXPECT_EQ(live_sets->used_registers_, 9u);
895 }
896 {
897 SCOPED_TRACE("Block 132");
898 auto live_sets = register_liveness->Get(132);
899 std::unordered_set<uint32_t> live_in{
900 25, // %25 = OpLoad %13 %24
901 84, // %84 = OpVariable %8 Function
902 100, // %100 = OpFAdd %7 %191 %98
903 124, // %124 = OpVariable %63 Input
904 176, // %176 = OpVariable %175 Output
905 196, // %196 = OpPhi %13 %16 %79 %143 %133
906 205, // %205 = OpPhi %13 %16 %119 %141 %132
907 208, // %208 = OpPhi %7 %209 %119 %183 %132
908 };
909 CompareSets(live_sets->live_in_, live_in);
910
911 std::unordered_set<uint32_t> live_out{
912 25, // %25 = OpLoad %13 %24
913 84, // %84 = OpVariable %8 Function
914 100, // %100 = OpFAdd %7 %191 %98
915 124, // %124 = OpVariable %63 Input
916 141, // %141 = OpIAdd %13 %205 %33
917 176, // %176 = OpVariable %175 Output
918 183, // %183 = OpCompositeInsert %7 %138 %208 3
919 196, // %196 = OpPhi %13 %16 %79 %143 %133
920 };
921 CompareSets(live_sets->live_out_, live_out);
922
923 EXPECT_EQ(live_sets->used_registers_, 10u);
924 }
925 {
926 SCOPED_TRACE("Block 133");
927 auto live_sets = register_liveness->Get(133);
928 std::unordered_set<uint32_t> live_in{
929 25, // %25 = OpLoad %13 %24
930 84, // %84 = OpVariable %8 Function
931 100, // %100 = OpFAdd %7 %191 %98
932 124, // %124 = OpVariable %63 Input
933 176, // %176 = OpVariable %175 Output
934 196, // %196 = OpPhi %13 %16 %79 %143 %133
935 208, // %208 = OpPhi %7 %209 %119 %183 %132
936 };
937 CompareSets(live_sets->live_in_, live_in);
938
939 std::unordered_set<uint32_t> live_out{
940 25, // %25 = OpLoad %13 %24
941 84, // %84 = OpVariable %8 Function
942 100, // %100 = OpFAdd %7 %191 %98
943 124, // %124 = OpVariable %63 Input
944 143, // %143 = OpIAdd %13 %196 %33
945 176, // %176 = OpVariable %175 Output
946 208, // %208 = OpPhi %7 %209 %119 %183 %132
947 };
948 CompareSets(live_sets->live_out_, live_out);
949
950 EXPECT_EQ(live_sets->used_registers_, 8u);
951 }
952 {
953 SCOPED_TRACE("Block 110");
954 auto live_sets = register_liveness->Get(110);
955 std::unordered_set<uint32_t> live_in{
956 84, // %84 = OpVariable %8 Function
957 100, // %100 = OpFAdd %7 %191 %98
958 124, // %124 = OpVariable %63 Input
959 176, // %176 = OpVariable %175 Output
960 197, // %197 = OpPhi %7 %106 %79 %208 %133
961 };
962 CompareSets(live_sets->live_in_, live_in);
963
964 std::unordered_set<uint32_t> live_out{
965 84, // %84 = OpVariable %8 Function
966 124, // %124 = OpVariable %63 Input
967 150, // %150 = OpVectorShuffle %7 %100 %148 4 5 6 3
968 176, // %176 = OpVariable %175 Output
969 };
970 CompareSets(live_sets->live_out_, live_out);
971
972 EXPECT_EQ(live_sets->used_registers_, 7u);
973 }
974 {
975 SCOPED_TRACE("Block 152");
976 auto live_sets = register_liveness->Get(152);
977 std::unordered_set<uint32_t> live_inout{
978 84, // %84 = OpVariable %8 Function
979 124, // %124 = OpVariable %63 Input
980 176, // %176 = OpVariable %175 Output
981 199, // %199 = OpPhi %13 %16 %110 %174 %163
982 200, // %200 = OpPhi %7 %150 %110 %203 %163
983 };
984 CompareSets(live_sets->live_in_, live_inout);
985 CompareSets(live_sets->live_out_, live_inout);
986
987 EXPECT_EQ(live_sets->used_registers_, 6u);
988 }
989 {
990 SCOPED_TRACE("Block 153");
991 auto live_sets = register_liveness->Get(153);
992 std::unordered_set<uint32_t> live_inout{
993 84, // %84 = OpVariable %8 Function
994 124, // %124 = OpVariable %63 Input
995 176, // %176 = OpVariable %175 Output
996 199, // %199 = OpPhi %13 %16 %110 %174 %163
997 200, // %200 = OpPhi %7 %150 %110 %203 %163
998 };
999 CompareSets(live_sets->live_in_, live_inout);
1000 CompareSets(live_sets->live_out_, live_inout);
1001
1002 EXPECT_EQ(live_sets->used_registers_, 5u);
1003 }
1004 {
1005 SCOPED_TRACE("Block 161");
1006 auto live_sets = register_liveness->Get(161);
1007 std::unordered_set<uint32_t> live_inout{
1008 84, // %84 = OpVariable %8 Function
1009 124, // %124 = OpVariable %63 Input
1010 176, // %176 = OpVariable %175 Output
1011 199, // %199 = OpPhi %13 %16 %110 %174 %163
1012 201, // %201 = OpPhi %13 %16 %153 %172 %162
1013 203, // %203 = OpPhi %7 %200 %153 %170 %162
1014 };
1015 CompareSets(live_sets->live_in_, live_inout);
1016 CompareSets(live_sets->live_out_, live_inout);
1017
1018 EXPECT_EQ(live_sets->used_registers_, 7u);
1019 }
1020 {
1021 SCOPED_TRACE("Block 162");
1022 auto live_sets = register_liveness->Get(162);
1023 std::unordered_set<uint32_t> live_in{
1024 84, // %84 = OpVariable %8 Function
1025 124, // %124 = OpVariable %63 Input
1026 176, // %176 = OpVariable %175 Output
1027 199, // %199 = OpPhi %13 %16 %110 %174 %163
1028 201, // %201 = OpPhi %13 %16 %153 %172 %162
1029 203, // %203 = OpPhi %7 %200 %153 %170 %162
1030 };
1031 CompareSets(live_sets->live_in_, live_in);
1032
1033 std::unordered_set<uint32_t> live_out{
1034 84, // %84 = OpVariable %8 Function
1035 124, // %124 = OpVariable %63 Input
1036 170, // %170 = OpVectorTimesScalar %7 %203 %168
1037 172, // %172 = OpIAdd %13 %201 %33
1038 176, // %176 = OpVariable %175 Output
1039 199, // %199 = OpPhi %13 %16 %110 %174 %163
1040 };
1041 CompareSets(live_sets->live_out_, live_out);
1042
1043 EXPECT_EQ(live_sets->used_registers_, 8u);
1044 }
1045 {
1046 SCOPED_TRACE("Block 163");
1047 auto live_sets = register_liveness->Get(163);
1048 std::unordered_set<uint32_t> live_in{
1049 84, // %84 = OpVariable %8 Function
1050 124, // %124 = OpVariable %63 Input
1051 176, // %176 = OpVariable %175 Output
1052 199, // %199 = OpPhi %13 %16 %110 %174 %163
1053 203, // %203 = OpPhi %7 %200 %153 %170 %162
1054 };
1055 CompareSets(live_sets->live_in_, live_in);
1056
1057 std::unordered_set<uint32_t> live_out{
1058 84, // %84 = OpVariable %8 Function
1059 124, // %124 = OpVariable %63 Input
1060 174, // %174 = OpIAdd %13 %199 %45
1061 176, // %176 = OpVariable %175 Output
1062 203, // %203 = OpPhi %7 %200 %153 %170 %162
1063 };
1064 CompareSets(live_sets->live_out_, live_out);
1065
1066 EXPECT_EQ(live_sets->used_registers_, 6u);
1067 }
1068 {
1069 SCOPED_TRACE("Block 154");
1070 auto live_sets = register_liveness->Get(154);
1071 std::unordered_set<uint32_t> live_in{
1072 84, // %84 = OpVariable %8 Function
1073 176, // %176 = OpVariable %175 Output
1074 200, // %200 = OpPhi %7 %150 %110 %203 %163
1075 };
1076 CompareSets(live_sets->live_in_, live_in);
1077
1078 std::unordered_set<uint32_t> live_out{};
1079 CompareSets(live_sets->live_out_, live_out);
1080
1081 EXPECT_EQ(live_sets->used_registers_, 4u);
1082 }
1083
1084 {
1085 SCOPED_TRACE("Compute loop pressure");
1086 RegisterLiveness::RegionRegisterLiveness loop_reg_pressure;
1087 register_liveness->ComputeLoopRegisterPressure(*ld[39], &loop_reg_pressure);
1088 // Generate(*context->cfg()->block(39), &loop_reg_pressure);
1089 std::unordered_set<uint32_t> live_in{
1090 11, // %11 = OpVariable %10 Input
1091 12, // %12 = OpLoad %7 %11
1092 25, // %25 = OpLoad %13 %24
1093 55, // %55 = OpVariable %54 Input
1094 84, // %84 = OpVariable %8 Function
1095 124, // %124 = OpVariable %63 Input
1096 176, // %176 = OpVariable %175 Output
1097 185, // %185 = OpPhi %13 %16 %19 %75 %51
1098 188, // %188 = OpPhi %6 %37 %19 %73 %51
1099 191, // %191 = OpPhi %7 %12 %5 %31 %18
1100 };
1101 CompareSets(loop_reg_pressure.live_in_, live_in);
1102
1103 std::unordered_set<uint32_t> live_out{
1104 12, // %12 = OpLoad %7 %11
1105 25, // %25 = OpLoad %13 %24
1106 55, // %55 = OpVariable %54 Input
1107 84, // %84 = OpVariable %8 Function
1108 124, // %124 = OpVariable %63 Input
1109 176, // %176 = OpVariable %175 Output
1110 188, // %188 = OpPhi %6 %37 %19 %73 %51
1111 191, // %191 = OpPhi %7 %12 %5 %31 %18
1112 };
1113 CompareSets(loop_reg_pressure.live_out_, live_out);
1114
1115 EXPECT_EQ(loop_reg_pressure.used_registers_, 13u);
1116 }
1117
1118 {
1119 SCOPED_TRACE("Loop Fusion simulation");
1120 RegisterLiveness::RegionRegisterLiveness simulation_resut;
1121 register_liveness->SimulateFusion(*ld[17], *ld[39], &simulation_resut);
1122
1123 std::unordered_set<uint32_t> live_in{
1124 11, // %11 = OpVariable %10 Input
1125 12, // %12 = OpLoad %7 %11
1126 24, // %24 = OpVariable %23 Input
1127 25, // %25 = OpLoad %13 %24
1128 28, // %28 = OpVariable %10 Input
1129 55, // %55 = OpVariable %54 Input
1130 84, // %84 = OpVariable %8 Function
1131 124, // %124 = OpVariable %63 Input
1132 176, // %176 = OpVariable %175 Output
1133 184, // %184 = OpPhi %13 %16 %5 %34 %18
1134 185, // %185 = OpPhi %13 %16 %19 %75 %51
1135 188, // %188 = OpPhi %6 %37 %19 %73 %51
1136 191, // %191 = OpPhi %7 %12 %5 %31 %18
1137 };
1138 CompareSets(simulation_resut.live_in_, live_in);
1139
1140 std::unordered_set<uint32_t> live_out{
1141 12, // %12 = OpLoad %7 %11
1142 25, // %25 = OpLoad %13 %24
1143 55, // %55 = OpVariable %54 Input
1144 84, // %84 = OpVariable %8 Function
1145 124, // %124 = OpVariable %63 Input
1146 176, // %176 = OpVariable %175 Output
1147 188, // %188 = OpPhi %6 %37 %19 %73 %51
1148 191, // %191 = OpPhi %7 %12 %5 %31 %18
1149 };
1150 CompareSets(simulation_resut.live_out_, live_out);
1151
1152 EXPECT_EQ(simulation_resut.used_registers_, 17u);
1153 }
1154 }
1155
TEST_F(PassClassTest,FissionSimulation)1156 TEST_F(PassClassTest, FissionSimulation) {
1157 const std::string source = R"(
1158 OpCapability Shader
1159 %1 = OpExtInstImport "GLSL.std.450"
1160 OpMemoryModel Logical GLSL450
1161 OpEntryPoint Fragment %2 "main"
1162 OpExecutionMode %2 OriginUpperLeft
1163 OpSource GLSL 430
1164 OpName %2 "main"
1165 OpName %3 "i"
1166 OpName %4 "A"
1167 OpName %5 "B"
1168 %6 = OpTypeVoid
1169 %7 = OpTypeFunction %6
1170 %8 = OpTypeInt 32 1
1171 %9 = OpTypePointer Function %8
1172 %10 = OpConstant %8 0
1173 %11 = OpConstant %8 10
1174 %12 = OpTypeBool
1175 %13 = OpTypeFloat 32
1176 %14 = OpTypeInt 32 0
1177 %15 = OpConstant %14 10
1178 %16 = OpTypeArray %13 %15
1179 %17 = OpTypePointer Function %16
1180 %18 = OpTypePointer Function %13
1181 %19 = OpConstant %8 1
1182 %2 = OpFunction %6 None %7
1183 %20 = OpLabel
1184 %3 = OpVariable %9 Function
1185 %4 = OpVariable %17 Function
1186 %5 = OpVariable %17 Function
1187 OpBranch %21
1188 %21 = OpLabel
1189 %22 = OpPhi %8 %10 %20 %23 %24
1190 OpLoopMerge %25 %24 None
1191 OpBranch %26
1192 %26 = OpLabel
1193 %27 = OpSLessThan %12 %22 %11
1194 OpBranchConditional %27 %28 %25
1195 %28 = OpLabel
1196 %29 = OpAccessChain %18 %5 %22
1197 %30 = OpLoad %13 %29
1198 %31 = OpAccessChain %18 %4 %22
1199 OpStore %31 %30
1200 %32 = OpAccessChain %18 %4 %22
1201 %33 = OpLoad %13 %32
1202 %34 = OpAccessChain %18 %5 %22
1203 OpStore %34 %33
1204 OpBranch %24
1205 %24 = OpLabel
1206 %23 = OpIAdd %8 %22 %19
1207 OpBranch %21
1208 %25 = OpLabel
1209 OpStore %3 %22
1210 OpReturn
1211 OpFunctionEnd
1212 )";
1213 std::unique_ptr<IRContext> context =
1214 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
1215 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1216 Module* module = context->module();
1217 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1218 << source << std::endl;
1219 Function* f = &*module->begin();
1220 LivenessAnalysis* liveness_analysis = context->GetLivenessAnalysis();
1221 const RegisterLiveness* register_liveness = liveness_analysis->Get(f);
1222 LoopDescriptor& ld = *context->GetLoopDescriptor(f);
1223 analysis::DefUseManager& def_use_mgr = *context->get_def_use_mgr();
1224
1225 {
1226 RegisterLiveness::RegionRegisterLiveness l1_sim_resut;
1227 RegisterLiveness::RegionRegisterLiveness l2_sim_resut;
1228 std::unordered_set<Instruction*> moved_instructions{
1229 def_use_mgr.GetDef(29), def_use_mgr.GetDef(30), def_use_mgr.GetDef(31),
1230 def_use_mgr.GetDef(31)->NextNode()};
1231 std::unordered_set<Instruction*> copied_instructions{
1232 def_use_mgr.GetDef(22), def_use_mgr.GetDef(27),
1233 def_use_mgr.GetDef(27)->NextNode(), def_use_mgr.GetDef(23)};
1234
1235 register_liveness->SimulateFission(*ld[21], moved_instructions,
1236 copied_instructions, &l1_sim_resut,
1237 &l2_sim_resut);
1238 {
1239 SCOPED_TRACE("L1 simulation");
1240 std::unordered_set<uint32_t> live_in{
1241 3, // %3 = OpVariable %9 Function
1242 4, // %4 = OpVariable %17 Function
1243 5, // %5 = OpVariable %17 Function
1244 22, // %22 = OpPhi %8 %10 %20 %23 %24
1245 };
1246 CompareSets(l1_sim_resut.live_in_, live_in);
1247
1248 std::unordered_set<uint32_t> live_out{
1249 3, // %3 = OpVariable %9 Function
1250 4, // %4 = OpVariable %17 Function
1251 5, // %5 = OpVariable %17 Function
1252 22, // %22 = OpPhi %8 %10 %20 %23 %24
1253 };
1254 CompareSets(l1_sim_resut.live_out_, live_out);
1255
1256 EXPECT_EQ(l1_sim_resut.used_registers_, 6u);
1257 }
1258 {
1259 SCOPED_TRACE("L2 simulation");
1260 std::unordered_set<uint32_t> live_in{
1261 3, // %3 = OpVariable %9 Function
1262 4, // %4 = OpVariable %17 Function
1263 5, // %5 = OpVariable %17 Function
1264 22, // %22 = OpPhi %8 %10 %20 %23 %24
1265 };
1266 CompareSets(l2_sim_resut.live_in_, live_in);
1267
1268 std::unordered_set<uint32_t> live_out{
1269 3, // %3 = OpVariable %9 Function
1270 22, // %22 = OpPhi %8 %10 %20 %23 %24
1271 };
1272 CompareSets(l2_sim_resut.live_out_, live_out);
1273
1274 EXPECT_EQ(l2_sim_resut.used_registers_, 6u);
1275 }
1276 }
1277 }
1278
1279 // Test that register liveness does not fail when there is an unreachable block.
1280 // We are not testing if the liveness is computed correctly because the specific
1281 // results do not matter for unreachable blocks.
TEST_F(PassClassTest,RegisterLivenessWithUnreachableBlock)1282 TEST_F(PassClassTest, RegisterLivenessWithUnreachableBlock) {
1283 const std::string text = R"(
1284 OpCapability Shader
1285 %1 = OpExtInstImport "GLSL.std.450"
1286 OpMemoryModel Logical GLSL450
1287 OpEntryPoint Fragment %2 "main"
1288 OpExecutionMode %2 OriginLowerLeft
1289 OpSource GLSL 330
1290 OpSourceExtension "GL_ARB_shading_language_420pack"
1291 %void = OpTypeVoid
1292 %4 = OpTypeFunction %void
1293 %2 = OpFunction %void None %4
1294 %5 = OpLabel
1295 OpBranch %6
1296 %6 = OpLabel
1297 OpLoopMerge %7 %8 None
1298 OpBranch %9
1299 %9 = OpLabel
1300 OpBranch %7
1301 %8 = OpLabel
1302 OpBranch %6
1303 %7 = OpLabel
1304 OpReturn
1305 OpFunctionEnd
1306 )";
1307
1308 std::unique_ptr<IRContext> context =
1309 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1310 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1311 Module* module = context->module();
1312 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1313 << text << std::endl;
1314 Function* f = &*module->begin();
1315 LivenessAnalysis* liveness_analysis = context->GetLivenessAnalysis();
1316 liveness_analysis->Get(f);
1317 }
1318
1319 } // namespace
1320 } // namespace opt
1321 } // namespace spvtools
1322