Set the parent for basic blocks during inlining.
authorSteven Perron <stevenperron@google.com>
Mon, 11 Dec 2017 18:10:24 +0000 (13:10 -0500)
committerSteven Perron <stevenperron@google.com>
Tue, 12 Dec 2017 18:39:08 +0000 (13:39 -0500)
Inlining is not setting the parent (function) for each basic block.
This can cause problems for later optimizations.  The solution is to set
the parent for each new block just before it is linked into the
function.

source/opt/inline_exhaustive_pass.cpp
test/opt/inline_test.cpp

index c0ebe4b..77d7bd8 100644 (file)
@@ -40,6 +40,10 @@ bool InlineExhaustivePass::InlineExhaustive(ir::Function* func) {
         context()->KillNamesAndDecorates(&*ii);
 
         bi = bi.Erase();
+
+        for (auto& bb : newBlocks) {
+          bb->SetParent(func);
+        }
         bi = bi.InsertBefore(&newBlocks);
         // Insert new function variables.
         if (newVars.size() > 0)
index b9738b2..8f3675a 100644 (file)
@@ -2549,6 +2549,44 @@ OpFunctionEnd
   SinglePassRunAndCheck<opt::InlineExhaustivePass>(before, after, false, true);
 }
 
+TEST_F(InlineTest, SetParent) {
+  // Test that after inlining all basic blocks have the correct parent.
+  const std::string text =
+      R"(
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main"
+               OpName %main "main"
+               OpName %main_entry "main_entry"
+               OpName %foo_result "foo_result"
+               OpName %void_fn "void_fn"
+               OpName %foo "foo"
+               OpName %foo_entry "foo_entry"
+       %void = OpTypeVoid
+    %void_fn = OpTypeFunction %void
+        %foo = OpFunction %void None %void_fn
+  %foo_entry = OpLabel
+               OpReturn
+               OpFunctionEnd
+       %main = OpFunction %void None %void_fn
+ %main_entry = OpLabel
+ %foo_result = OpFunctionCall %void %foo
+               OpReturn
+               OpFunctionEnd
+)";
+
+  std::unique_ptr<ir::IRContext> context =
+      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
+  opt::InlineExhaustivePass pass;
+  pass.Run(context.get());
+
+  for (ir::Function& func : *context->module()) {
+    for (ir::BasicBlock& bb : func) {
+      EXPECT_TRUE(bb.GetParent() == &func);
+    }
+  }
+}
+
 // TODO(greg-lunarg): Add tests to verify handling of these cases:
 //
 //    Empty modules