• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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