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
26namespace spvtools {
27namespace opt {
28namespace {
29
30using ::testing::UnorderedElementsAre;
31using PassClassTest = PassTest<::testing::Test>;
32
33void 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/*
43Generated from the following GLSL
44
45#version 330
46in vec4 BaseColor;
47flat in int Count;
48void 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*/
61TEST_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/*
180Generated from the following GLSL
181#version 330
182in vec4 bigColor;
183in vec4 BaseColor;
184in float f;
185flat in int Count;
186flat in uvec4 v4;
187void 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*/
218TEST_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
1156TEST_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.
1282TEST_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