be42dff4ca83aa664084ee17e43e4f9aeb4de3e8
[platform/upstream/SPIRV-Tools.git] / test / opt / loop_optimizations / nested_loops.cpp
1 // Copyright (c) 2017 Google Inc.
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 <gmock/gmock.h>
16
17 #include <memory>
18 #include <string>
19 #include <unordered_set>
20 #include <vector>
21
22 #include "../assembly_builder.h"
23 #include "../function_utils.h"
24 #include "../pass_fixture.h"
25 #include "../pass_utils.h"
26
27 #include "opt/iterator.h"
28 #include "opt/loop_descriptor.h"
29 #include "opt/pass.h"
30 #include "opt/tree_iterator.h"
31
32 namespace {
33
34 using namespace spvtools;
35 using ::testing::UnorderedElementsAre;
36
37 using PassClassTest = PassTest<::testing::Test>;
38
39 /*
40 Generated from the following GLSL
41 #version 330 core
42 layout(location = 0) out vec4 c;
43 void main() {
44   int i = 0;
45   for (; i < 10; ++i) {
46     int j = 0;
47     int k = 0;
48     for (; j < 11; ++j) {}
49     for (; k < 12; ++k) {}
50   }
51 }
52 */
53 TEST_F(PassClassTest, BasicVisitFromEntryPoint) {
54   const std::string text = R"(
55                OpCapability Shader
56           %1 = OpExtInstImport "GLSL.std.450"
57                OpMemoryModel Logical GLSL450
58                OpEntryPoint Fragment %2 "main" %3
59                OpExecutionMode %2 OriginUpperLeft
60                OpSource GLSL 330
61                OpName %2 "main"
62                OpName %4 "i"
63                OpName %5 "j"
64                OpName %6 "k"
65                OpName %3 "c"
66                OpDecorate %3 Location 0
67           %7 = OpTypeVoid
68           %8 = OpTypeFunction %7
69           %9 = OpTypeInt 32 1
70          %10 = OpTypePointer Function %9
71          %11 = OpConstant %9 0
72          %12 = OpConstant %9 10
73          %13 = OpTypeBool
74          %14 = OpConstant %9 11
75          %15 = OpConstant %9 1
76          %16 = OpConstant %9 12
77          %17 = OpTypeFloat 32
78          %18 = OpTypeVector %17 4
79          %19 = OpTypePointer Output %18
80           %3 = OpVariable %19 Output
81           %2 = OpFunction %7 None %8
82          %20 = OpLabel
83           %4 = OpVariable %10 Function
84           %5 = OpVariable %10 Function
85           %6 = OpVariable %10 Function
86                OpStore %4 %11
87                OpBranch %21
88          %21 = OpLabel
89                OpLoopMerge %22 %23 None
90                OpBranch %24
91          %24 = OpLabel
92          %25 = OpLoad %9 %4
93          %26 = OpSLessThan %13 %25 %12
94                OpBranchConditional %26 %27 %22
95          %27 = OpLabel
96                OpStore %5 %11
97                OpStore %6 %11
98                OpBranch %28
99          %28 = OpLabel
100                OpLoopMerge %29 %30 None
101                OpBranch %31
102          %31 = OpLabel
103          %32 = OpLoad %9 %5
104          %33 = OpSLessThan %13 %32 %14
105                OpBranchConditional %33 %34 %29
106          %34 = OpLabel
107                OpBranch %30
108          %30 = OpLabel
109          %35 = OpLoad %9 %5
110          %36 = OpIAdd %9 %35 %15
111                OpStore %5 %36
112                OpBranch %28
113          %29 = OpLabel
114                OpBranch %37
115          %37 = OpLabel
116                OpLoopMerge %38 %39 None
117                OpBranch %40
118          %40 = OpLabel
119          %41 = OpLoad %9 %6
120          %42 = OpSLessThan %13 %41 %16
121                OpBranchConditional %42 %43 %38
122          %43 = OpLabel
123                OpBranch %39
124          %39 = OpLabel
125          %44 = OpLoad %9 %6
126          %45 = OpIAdd %9 %44 %15
127                OpStore %6 %45
128                OpBranch %37
129          %38 = OpLabel
130                OpBranch %23
131          %23 = OpLabel
132          %46 = OpLoad %9 %4
133          %47 = OpIAdd %9 %46 %15
134                OpStore %4 %47
135                OpBranch %21
136          %22 = OpLabel
137                OpReturn
138                OpFunctionEnd
139   )";
140   // clang-format on
141   std::unique_ptr<ir::IRContext> context =
142       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
143                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
144   ir::Module* module = context->module();
145   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
146                              << text << std::endl;
147   const ir::Function* f = spvtest::GetFunction(module, 2);
148   ir::LoopDescriptor& ld = *context->GetLoopDescriptor(f);
149
150   EXPECT_EQ(ld.NumLoops(), 3u);
151
152   // Invalid basic block id.
153   EXPECT_EQ(ld[0u], nullptr);
154   // Not a loop header.
155   EXPECT_EQ(ld[20], nullptr);
156
157   ir::Loop& parent_loop = *ld[21];
158   EXPECT_TRUE(parent_loop.HasNestedLoops());
159   EXPECT_FALSE(parent_loop.IsNested());
160   EXPECT_EQ(parent_loop.GetDepth(), 1u);
161   EXPECT_EQ(std::distance(parent_loop.begin(), parent_loop.end()), 2u);
162   EXPECT_EQ(parent_loop.GetHeaderBlock(), spvtest::GetBasicBlock(f, 21));
163   EXPECT_EQ(parent_loop.GetLatchBlock(), spvtest::GetBasicBlock(f, 23));
164   EXPECT_EQ(parent_loop.GetMergeBlock(), spvtest::GetBasicBlock(f, 22));
165
166   ir::Loop& child_loop_1 = *ld[28];
167   EXPECT_FALSE(child_loop_1.HasNestedLoops());
168   EXPECT_TRUE(child_loop_1.IsNested());
169   EXPECT_EQ(child_loop_1.GetDepth(), 2u);
170   EXPECT_EQ(std::distance(child_loop_1.begin(), child_loop_1.end()), 0u);
171   EXPECT_EQ(child_loop_1.GetHeaderBlock(), spvtest::GetBasicBlock(f, 28));
172   EXPECT_EQ(child_loop_1.GetLatchBlock(), spvtest::GetBasicBlock(f, 30));
173   EXPECT_EQ(child_loop_1.GetMergeBlock(), spvtest::GetBasicBlock(f, 29));
174
175   ir::Loop& child_loop_2 = *ld[37];
176   EXPECT_FALSE(child_loop_2.HasNestedLoops());
177   EXPECT_TRUE(child_loop_2.IsNested());
178   EXPECT_EQ(child_loop_2.GetDepth(), 2u);
179   EXPECT_EQ(std::distance(child_loop_2.begin(), child_loop_2.end()), 0u);
180   EXPECT_EQ(child_loop_2.GetHeaderBlock(), spvtest::GetBasicBlock(f, 37));
181   EXPECT_EQ(child_loop_2.GetLatchBlock(), spvtest::GetBasicBlock(f, 39));
182   EXPECT_EQ(child_loop_2.GetMergeBlock(), spvtest::GetBasicBlock(f, 38));
183 }
184
185 static void CheckLoopBlocks(ir::Loop* loop,
186                             std::unordered_set<uint32_t>* expected_ids) {
187   SCOPED_TRACE("Check loop " + std::to_string(loop->GetHeaderBlock()->id()));
188   for (uint32_t bb_id : loop->GetBlocks()) {
189     EXPECT_EQ(expected_ids->count(bb_id), 1u);
190     expected_ids->erase(bb_id);
191   }
192   EXPECT_FALSE(loop->IsInsideLoop(loop->GetMergeBlock()));
193   EXPECT_EQ(expected_ids->size(), 0u);
194 }
195
196 /*
197 Generated from the following GLSL
198 #version 330 core
199 layout(location = 0) out vec4 c;
200 void main() {
201   int i = 0;
202   for (; i < 10; ++i) {
203     for (int j = 0; j < 11; ++j) {
204       if (j < 5) {
205         for (int k = 0; k < 12; ++k) {}
206       }
207       else {}
208       for (int k = 0; k < 12; ++k) {}
209     }
210   }
211 }*/
212 TEST_F(PassClassTest, TripleNestedLoop) {
213   const std::string text = R"(
214                OpCapability Shader
215           %1 = OpExtInstImport "GLSL.std.450"
216                OpMemoryModel Logical GLSL450
217                OpEntryPoint Fragment %2 "main" %3
218                OpExecutionMode %2 OriginUpperLeft
219                OpSource GLSL 330
220                OpName %2 "main"
221                OpName %4 "i"
222                OpName %5 "j"
223                OpName %6 "k"
224                OpName %7 "k"
225                OpName %3 "c"
226                OpDecorate %3 Location 0
227           %8 = OpTypeVoid
228           %9 = OpTypeFunction %8
229          %10 = OpTypeInt 32 1
230          %11 = OpTypePointer Function %10
231          %12 = OpConstant %10 0
232          %13 = OpConstant %10 10
233          %14 = OpTypeBool
234          %15 = OpConstant %10 11
235          %16 = OpConstant %10 5
236          %17 = OpConstant %10 12
237          %18 = OpConstant %10 1
238          %19 = OpTypeFloat 32
239          %20 = OpTypeVector %19 4
240          %21 = OpTypePointer Output %20
241           %3 = OpVariable %21 Output
242           %2 = OpFunction %8 None %9
243          %22 = OpLabel
244           %4 = OpVariable %11 Function
245           %5 = OpVariable %11 Function
246           %6 = OpVariable %11 Function
247           %7 = OpVariable %11 Function
248                OpStore %4 %12
249                OpBranch %23
250          %23 = OpLabel
251                OpLoopMerge %24 %25 None
252                OpBranch %26
253          %26 = OpLabel
254          %27 = OpLoad %10 %4
255          %28 = OpSLessThan %14 %27 %13
256                OpBranchConditional %28 %29 %24
257          %29 = OpLabel
258                OpStore %5 %12
259                OpBranch %30
260          %30 = OpLabel
261                OpLoopMerge %31 %32 None
262                OpBranch %33
263          %33 = OpLabel
264          %34 = OpLoad %10 %5
265          %35 = OpSLessThan %14 %34 %15
266                OpBranchConditional %35 %36 %31
267          %36 = OpLabel
268          %37 = OpLoad %10 %5
269          %38 = OpSLessThan %14 %37 %16
270                OpSelectionMerge %39 None
271                OpBranchConditional %38 %40 %39
272          %40 = OpLabel
273                OpStore %6 %12
274                OpBranch %41
275          %41 = OpLabel
276                OpLoopMerge %42 %43 None
277                OpBranch %44
278          %44 = OpLabel
279          %45 = OpLoad %10 %6
280          %46 = OpSLessThan %14 %45 %17
281                OpBranchConditional %46 %47 %42
282          %47 = OpLabel
283                OpBranch %43
284          %43 = OpLabel
285          %48 = OpLoad %10 %6
286          %49 = OpIAdd %10 %48 %18
287                OpStore %6 %49
288                OpBranch %41
289          %42 = OpLabel
290                OpBranch %39
291          %39 = OpLabel
292                OpStore %7 %12
293                OpBranch %50
294          %50 = OpLabel
295                OpLoopMerge %51 %52 None
296                OpBranch %53
297          %53 = OpLabel
298          %54 = OpLoad %10 %7
299          %55 = OpSLessThan %14 %54 %17
300                OpBranchConditional %55 %56 %51
301          %56 = OpLabel
302                OpBranch %52
303          %52 = OpLabel
304          %57 = OpLoad %10 %7
305          %58 = OpIAdd %10 %57 %18
306                OpStore %7 %58
307                OpBranch %50
308          %51 = OpLabel
309                OpBranch %32
310          %32 = OpLabel
311          %59 = OpLoad %10 %5
312          %60 = OpIAdd %10 %59 %18
313                OpStore %5 %60
314                OpBranch %30
315          %31 = OpLabel
316                OpBranch %25
317          %25 = OpLabel
318          %61 = OpLoad %10 %4
319          %62 = OpIAdd %10 %61 %18
320                OpStore %4 %62
321                OpBranch %23
322          %24 = OpLabel
323                OpReturn
324                OpFunctionEnd
325   )";
326   // clang-format on
327   std::unique_ptr<ir::IRContext> context =
328       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
329                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
330   ir::Module* module = context->module();
331   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
332                              << text << std::endl;
333   const ir::Function* f = spvtest::GetFunction(module, 2);
334   ir::LoopDescriptor& ld = *context->GetLoopDescriptor(f);
335
336   EXPECT_EQ(ld.NumLoops(), 4u);
337
338   // Invalid basic block id.
339   EXPECT_EQ(ld[0u], nullptr);
340   // Not in a loop.
341   EXPECT_EQ(ld[22], nullptr);
342
343   // Check that we can map basic block to the correct loop.
344   // The following block ids do not belong to a loop.
345   for (uint32_t bb_id : {22, 24}) EXPECT_EQ(ld[bb_id], nullptr);
346
347   {
348     std::unordered_set<uint32_t> basic_block_in_loop = {
349         {23, 26, 29, 30, 33, 36, 40, 41, 44, 47, 43,
350          42, 39, 50, 53, 56, 52, 51, 32, 31, 25}};
351     ir::Loop* loop = ld[23];
352     CheckLoopBlocks(loop, &basic_block_in_loop);
353
354     EXPECT_TRUE(loop->HasNestedLoops());
355     EXPECT_FALSE(loop->IsNested());
356     EXPECT_EQ(loop->GetDepth(), 1u);
357     EXPECT_EQ(std::distance(loop->begin(), loop->end()), 1u);
358     EXPECT_EQ(loop->GetPreHeaderBlock(), spvtest::GetBasicBlock(f, 22));
359     EXPECT_EQ(loop->GetHeaderBlock(), spvtest::GetBasicBlock(f, 23));
360     EXPECT_EQ(loop->GetLatchBlock(), spvtest::GetBasicBlock(f, 25));
361     EXPECT_EQ(loop->GetMergeBlock(), spvtest::GetBasicBlock(f, 24));
362     EXPECT_FALSE(loop->IsInsideLoop(loop->GetMergeBlock()));
363     EXPECT_FALSE(loop->IsInsideLoop(loop->GetPreHeaderBlock()));
364   }
365
366   {
367     std::unordered_set<uint32_t> basic_block_in_loop = {
368         {30, 33, 36, 40, 41, 44, 47, 43, 42, 39, 50, 53, 56, 52, 51, 32}};
369     ir::Loop* loop = ld[30];
370     CheckLoopBlocks(loop, &basic_block_in_loop);
371
372     EXPECT_TRUE(loop->HasNestedLoops());
373     EXPECT_TRUE(loop->IsNested());
374     EXPECT_EQ(loop->GetDepth(), 2u);
375     EXPECT_EQ(std::distance(loop->begin(), loop->end()), 2u);
376     EXPECT_EQ(loop->GetPreHeaderBlock(), spvtest::GetBasicBlock(f, 29));
377     EXPECT_EQ(loop->GetHeaderBlock(), spvtest::GetBasicBlock(f, 30));
378     EXPECT_EQ(loop->GetLatchBlock(), spvtest::GetBasicBlock(f, 32));
379     EXPECT_EQ(loop->GetMergeBlock(), spvtest::GetBasicBlock(f, 31));
380     EXPECT_FALSE(loop->IsInsideLoop(loop->GetMergeBlock()));
381     EXPECT_FALSE(loop->IsInsideLoop(loop->GetPreHeaderBlock()));
382   }
383
384   {
385     std::unordered_set<uint32_t> basic_block_in_loop = {{41, 44, 47, 43}};
386     ir::Loop* loop = ld[41];
387     CheckLoopBlocks(loop, &basic_block_in_loop);
388
389     EXPECT_FALSE(loop->HasNestedLoops());
390     EXPECT_TRUE(loop->IsNested());
391     EXPECT_EQ(loop->GetDepth(), 3u);
392     EXPECT_EQ(std::distance(loop->begin(), loop->end()), 0u);
393     EXPECT_EQ(loop->GetPreHeaderBlock(), spvtest::GetBasicBlock(f, 40));
394     EXPECT_EQ(loop->GetHeaderBlock(), spvtest::GetBasicBlock(f, 41));
395     EXPECT_EQ(loop->GetLatchBlock(), spvtest::GetBasicBlock(f, 43));
396     EXPECT_EQ(loop->GetMergeBlock(), spvtest::GetBasicBlock(f, 42));
397     EXPECT_FALSE(loop->IsInsideLoop(loop->GetMergeBlock()));
398     EXPECT_FALSE(loop->IsInsideLoop(loop->GetPreHeaderBlock()));
399   }
400
401   {
402     std::unordered_set<uint32_t> basic_block_in_loop = {{50, 53, 56, 52}};
403     ir::Loop* loop = ld[50];
404     CheckLoopBlocks(loop, &basic_block_in_loop);
405
406     EXPECT_FALSE(loop->HasNestedLoops());
407     EXPECT_TRUE(loop->IsNested());
408     EXPECT_EQ(loop->GetDepth(), 3u);
409     EXPECT_EQ(std::distance(loop->begin(), loop->end()), 0u);
410     EXPECT_EQ(loop->GetPreHeaderBlock(), spvtest::GetBasicBlock(f, 39));
411     EXPECT_EQ(loop->GetHeaderBlock(), spvtest::GetBasicBlock(f, 50));
412     EXPECT_EQ(loop->GetLatchBlock(), spvtest::GetBasicBlock(f, 52));
413     EXPECT_EQ(loop->GetMergeBlock(), spvtest::GetBasicBlock(f, 51));
414     EXPECT_FALSE(loop->IsInsideLoop(loop->GetMergeBlock()));
415     EXPECT_FALSE(loop->IsInsideLoop(loop->GetPreHeaderBlock()));
416   }
417
418   // Make sure LoopDescriptor gives us the inner most loop when we query for
419   // loops.
420   for (const ir::BasicBlock& bb : *f) {
421     if (ir::Loop* loop = ld[&bb]) {
422       for (ir::Loop& sub_loop :
423            ir::make_range(++opt::TreeDFIterator<ir::Loop>(loop),
424                           opt::TreeDFIterator<ir::Loop>())) {
425         EXPECT_FALSE(sub_loop.IsInsideLoop(bb.id()));
426       }
427     }
428   }
429 }
430
431 /*
432 Generated from the following GLSL
433 #version 330 core
434 layout(location = 0) out vec4 c;
435 void main() {
436   for (int i = 0; i < 10; ++i) {
437     for (int j = 0; j < 11; ++j) {
438       for (int k = 0; k < 11; ++k) {}
439     }
440     for (int k = 0; k < 12; ++k) {}
441   }
442 }
443 */
444 TEST_F(PassClassTest, LoopParentTest) {
445   const std::string text = R"(
446                OpCapability Shader
447           %1 = OpExtInstImport "GLSL.std.450"
448                OpMemoryModel Logical GLSL450
449                OpEntryPoint Fragment %2 "main" %3
450                OpExecutionMode %2 OriginUpperLeft
451                OpSource GLSL 330
452                OpName %2 "main"
453                OpName %4 "i"
454                OpName %5 "j"
455                OpName %6 "k"
456                OpName %7 "k"
457                OpName %3 "c"
458                OpDecorate %3 Location 0
459           %8 = OpTypeVoid
460           %9 = OpTypeFunction %8
461          %10 = OpTypeInt 32 1
462          %11 = OpTypePointer Function %10
463          %12 = OpConstant %10 0
464          %13 = OpConstant %10 10
465          %14 = OpTypeBool
466          %15 = OpConstant %10 11
467          %16 = OpConstant %10 1
468          %17 = OpConstant %10 12
469          %18 = OpTypeFloat 32
470          %19 = OpTypeVector %18 4
471          %20 = OpTypePointer Output %19
472           %3 = OpVariable %20 Output
473           %2 = OpFunction %8 None %9
474          %21 = OpLabel
475           %4 = OpVariable %11 Function
476           %5 = OpVariable %11 Function
477           %6 = OpVariable %11 Function
478           %7 = OpVariable %11 Function
479                OpStore %4 %12
480                OpBranch %22
481          %22 = OpLabel
482                OpLoopMerge %23 %24 None
483                OpBranch %25
484          %25 = OpLabel
485          %26 = OpLoad %10 %4
486          %27 = OpSLessThan %14 %26 %13
487                OpBranchConditional %27 %28 %23
488          %28 = OpLabel
489                OpStore %5 %12
490                OpBranch %29
491          %29 = OpLabel
492                OpLoopMerge %30 %31 None
493                OpBranch %32
494          %32 = OpLabel
495          %33 = OpLoad %10 %5
496          %34 = OpSLessThan %14 %33 %15
497                OpBranchConditional %34 %35 %30
498          %35 = OpLabel
499                OpStore %6 %12
500                OpBranch %36
501          %36 = OpLabel
502                OpLoopMerge %37 %38 None
503                OpBranch %39
504          %39 = OpLabel
505          %40 = OpLoad %10 %6
506          %41 = OpSLessThan %14 %40 %15
507                OpBranchConditional %41 %42 %37
508          %42 = OpLabel
509                OpBranch %38
510          %38 = OpLabel
511          %43 = OpLoad %10 %6
512          %44 = OpIAdd %10 %43 %16
513                OpStore %6 %44
514                OpBranch %36
515          %37 = OpLabel
516                OpBranch %31
517          %31 = OpLabel
518          %45 = OpLoad %10 %5
519          %46 = OpIAdd %10 %45 %16
520                OpStore %5 %46
521                OpBranch %29
522          %30 = OpLabel
523                OpStore %7 %12
524                OpBranch %47
525          %47 = OpLabel
526                OpLoopMerge %48 %49 None
527                OpBranch %50
528          %50 = OpLabel
529          %51 = OpLoad %10 %7
530          %52 = OpSLessThan %14 %51 %17
531                OpBranchConditional %52 %53 %48
532          %53 = OpLabel
533                OpBranch %49
534          %49 = OpLabel
535          %54 = OpLoad %10 %7
536          %55 = OpIAdd %10 %54 %16
537                OpStore %7 %55
538                OpBranch %47
539          %48 = OpLabel
540                OpBranch %24
541          %24 = OpLabel
542          %56 = OpLoad %10 %4
543          %57 = OpIAdd %10 %56 %16
544                OpStore %4 %57
545                OpBranch %22
546          %23 = OpLabel
547                OpReturn
548                OpFunctionEnd
549   )";
550   // clang-format on
551   std::unique_ptr<ir::IRContext> context =
552       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
553                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
554   ir::Module* module = context->module();
555   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
556                              << text << std::endl;
557   const ir::Function* f = spvtest::GetFunction(module, 2);
558   ir::LoopDescriptor& ld = *context->GetLoopDescriptor(f);
559
560   EXPECT_EQ(ld.NumLoops(), 4u);
561
562   {
563     ir::Loop& loop = *ld[22];
564     EXPECT_TRUE(loop.HasNestedLoops());
565     EXPECT_FALSE(loop.IsNested());
566     EXPECT_EQ(loop.GetDepth(), 1u);
567     EXPECT_EQ(loop.GetParent(), nullptr);
568   }
569
570   {
571     ir::Loop& loop = *ld[29];
572     EXPECT_TRUE(loop.HasNestedLoops());
573     EXPECT_TRUE(loop.IsNested());
574     EXPECT_EQ(loop.GetDepth(), 2u);
575     EXPECT_EQ(loop.GetParent(), ld[22]);
576   }
577
578   {
579     ir::Loop& loop = *ld[36];
580     EXPECT_FALSE(loop.HasNestedLoops());
581     EXPECT_TRUE(loop.IsNested());
582     EXPECT_EQ(loop.GetDepth(), 3u);
583     EXPECT_EQ(loop.GetParent(), ld[29]);
584   }
585
586   {
587     ir::Loop& loop = *ld[47];
588     EXPECT_FALSE(loop.HasNestedLoops());
589     EXPECT_TRUE(loop.IsNested());
590     EXPECT_EQ(loop.GetDepth(), 2u);
591     EXPECT_EQ(loop.GetParent(), ld[22]);
592   }
593 }
594
595 }  // namespace