18267b333SNico Weber //===- CodeExtractor.cpp - Unit tests for CodeExtractor -------------------===//
28267b333SNico Weber //
3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68267b333SNico Weber //
78267b333SNico Weber //===----------------------------------------------------------------------===//
88267b333SNico Weber 
98267b333SNico Weber #include "llvm/Transforms/Utils/CodeExtractor.h"
108267b333SNico Weber #include "llvm/AsmParser/Parser.h"
118267b333SNico Weber #include "llvm/IR/BasicBlock.h"
128267b333SNico Weber #include "llvm/IR/Dominators.h"
13d129569eSVedant Kumar #include "llvm/IR/Instructions.h"
148267b333SNico Weber #include "llvm/IR/LLVMContext.h"
158267b333SNico Weber #include "llvm/IR/Module.h"
168267b333SNico Weber #include "llvm/IR/Verifier.h"
178267b333SNico Weber #include "llvm/IRReader/IRReader.h"
188267b333SNico Weber #include "llvm/Support/SourceMgr.h"
198267b333SNico Weber #include "gtest/gtest.h"
208267b333SNico Weber 
218267b333SNico Weber using namespace llvm;
228267b333SNico Weber 
238267b333SNico Weber namespace {
24d129569eSVedant Kumar BasicBlock *getBlockByName(Function *F, StringRef name) {
25d129569eSVedant Kumar   for (auto &BB : *F)
26d129569eSVedant Kumar     if (BB.getName() == name)
27d129569eSVedant Kumar       return &BB;
28d129569eSVedant Kumar   return nullptr;
29d129569eSVedant Kumar }
30d129569eSVedant Kumar 
31d129569eSVedant Kumar TEST(CodeExtractor, ExitStub) {
328267b333SNico Weber   LLVMContext Ctx;
338267b333SNico Weber   SMDiagnostic Err;
348267b333SNico Weber   std::unique_ptr<Module> M(parseAssemblyString(R"invalid(
358267b333SNico Weber     define i32 @foo(i32 %x, i32 %y, i32 %z) {
368267b333SNico Weber     header:
378267b333SNico Weber       %0 = icmp ugt i32 %x, %y
388267b333SNico Weber       br i1 %0, label %body1, label %body2
398267b333SNico Weber 
408267b333SNico Weber     body1:
418267b333SNico Weber       %1 = add i32 %z, 2
428267b333SNico Weber       br label %notExtracted
438267b333SNico Weber 
448267b333SNico Weber     body2:
458267b333SNico Weber       %2 = mul i32 %z, 7
468267b333SNico Weber       br label %notExtracted
478267b333SNico Weber 
488267b333SNico Weber     notExtracted:
498267b333SNico Weber       %3 = phi i32 [ %1, %body1 ], [ %2, %body2 ]
508267b333SNico Weber       %4 = add i32 %3, %x
518267b333SNico Weber       ret i32 %4
528267b333SNico Weber     }
538267b333SNico Weber   )invalid",
548267b333SNico Weber                                                 Err, Ctx));
558267b333SNico Weber 
568267b333SNico Weber   Function *Func = M->getFunction("foo");
57d129569eSVedant Kumar   SmallVector<BasicBlock *, 3> Candidates{ getBlockByName(Func, "header"),
58d129569eSVedant Kumar                                            getBlockByName(Func, "body1"),
59d129569eSVedant Kumar                                            getBlockByName(Func, "body2") };
608267b333SNico Weber 
618267b333SNico Weber   DominatorTree DT(*Func);
628267b333SNico Weber   CodeExtractor CE(Candidates, &DT);
638267b333SNico Weber   EXPECT_TRUE(CE.isEligible());
648267b333SNico Weber 
658267b333SNico Weber   Function *Outlined = CE.extractCodeRegion();
668267b333SNico Weber   EXPECT_TRUE(Outlined);
67d129569eSVedant Kumar   BasicBlock *Exit = getBlockByName(Func, "notExtracted");
68d129569eSVedant Kumar   BasicBlock *ExitSplit = getBlockByName(Outlined, "notExtracted.split");
69d129569eSVedant Kumar   // Ensure that PHI in exit block has only one incoming value (from code
70d129569eSVedant Kumar   // replacer block).
71d129569eSVedant Kumar   EXPECT_TRUE(Exit && cast<PHINode>(Exit->front()).getNumIncomingValues() == 1);
72d129569eSVedant Kumar   // Ensure that there is a PHI in outlined function with 2 incoming values.
73d129569eSVedant Kumar   EXPECT_TRUE(ExitSplit &&
74d129569eSVedant Kumar               cast<PHINode>(ExitSplit->front()).getNumIncomingValues() == 2);
758267b333SNico Weber   EXPECT_FALSE(verifyFunction(*Outlined));
76d129569eSVedant Kumar   EXPECT_FALSE(verifyFunction(*Func));
77d129569eSVedant Kumar }
78d129569eSVedant Kumar 
79d129569eSVedant Kumar TEST(CodeExtractor, ExitPHIOnePredFromRegion) {
80d129569eSVedant Kumar   LLVMContext Ctx;
81d129569eSVedant Kumar   SMDiagnostic Err;
82d129569eSVedant Kumar   std::unique_ptr<Module> M(parseAssemblyString(R"invalid(
83d129569eSVedant Kumar     define i32 @foo() {
84d129569eSVedant Kumar     header:
85d129569eSVedant Kumar       br i1 undef, label %extracted1, label %pred
86d129569eSVedant Kumar 
87d129569eSVedant Kumar     pred:
88d129569eSVedant Kumar       br i1 undef, label %exit1, label %exit2
89d129569eSVedant Kumar 
90d129569eSVedant Kumar     extracted1:
91d129569eSVedant Kumar       br i1 undef, label %extracted2, label %exit1
92d129569eSVedant Kumar 
93d129569eSVedant Kumar     extracted2:
94d129569eSVedant Kumar       br label %exit2
95d129569eSVedant Kumar 
96d129569eSVedant Kumar     exit1:
97d129569eSVedant Kumar       %0 = phi i32 [ 1, %extracted1 ], [ 2, %pred ]
98d129569eSVedant Kumar       ret i32 %0
99d129569eSVedant Kumar 
100d129569eSVedant Kumar     exit2:
101d129569eSVedant Kumar       %1 = phi i32 [ 3, %extracted2 ], [ 4, %pred ]
102d129569eSVedant Kumar       ret i32 %1
103d129569eSVedant Kumar     }
104d129569eSVedant Kumar   )invalid", Err, Ctx));
105d129569eSVedant Kumar 
106d129569eSVedant Kumar   Function *Func = M->getFunction("foo");
107d129569eSVedant Kumar   SmallVector<BasicBlock *, 2> ExtractedBlocks{
108d129569eSVedant Kumar     getBlockByName(Func, "extracted1"),
109d129569eSVedant Kumar     getBlockByName(Func, "extracted2")
110d129569eSVedant Kumar   };
111d129569eSVedant Kumar 
112d129569eSVedant Kumar   DominatorTree DT(*Func);
113d129569eSVedant Kumar   CodeExtractor CE(ExtractedBlocks, &DT);
114d129569eSVedant Kumar   EXPECT_TRUE(CE.isEligible());
115d129569eSVedant Kumar 
116d129569eSVedant Kumar   Function *Outlined = CE.extractCodeRegion();
117d129569eSVedant Kumar   EXPECT_TRUE(Outlined);
118d129569eSVedant Kumar   BasicBlock *Exit1 = getBlockByName(Func, "exit1");
119d129569eSVedant Kumar   BasicBlock *Exit2 = getBlockByName(Func, "exit2");
120d129569eSVedant Kumar   // Ensure that PHIs in exits are not splitted (since that they have only one
121d129569eSVedant Kumar   // incoming value from extracted region).
122d129569eSVedant Kumar   EXPECT_TRUE(Exit1 &&
123d129569eSVedant Kumar           cast<PHINode>(Exit1->front()).getNumIncomingValues() == 2);
124d129569eSVedant Kumar   EXPECT_TRUE(Exit2 &&
125d129569eSVedant Kumar           cast<PHINode>(Exit2->front()).getNumIncomingValues() == 2);
126d129569eSVedant Kumar   EXPECT_FALSE(verifyFunction(*Outlined));
127d129569eSVedant Kumar   EXPECT_FALSE(verifyFunction(*Func));
1288267b333SNico Weber }
129b2a6f8e5SVedant Kumar 
130b2a6f8e5SVedant Kumar TEST(CodeExtractor, StoreOutputInvokeResultAfterEHPad) {
131b2a6f8e5SVedant Kumar   LLVMContext Ctx;
132b2a6f8e5SVedant Kumar   SMDiagnostic Err;
133b2a6f8e5SVedant Kumar   std::unique_ptr<Module> M(parseAssemblyString(R"invalid(
134b2a6f8e5SVedant Kumar     declare i8 @hoge()
135b2a6f8e5SVedant Kumar 
136b2a6f8e5SVedant Kumar     define i32 @foo() personality i8* null {
137b2a6f8e5SVedant Kumar       entry:
138b2a6f8e5SVedant Kumar         %call = invoke i8 @hoge()
139b2a6f8e5SVedant Kumar                 to label %invoke.cont unwind label %lpad
140b2a6f8e5SVedant Kumar 
141b2a6f8e5SVedant Kumar       invoke.cont:                                      ; preds = %entry
142b2a6f8e5SVedant Kumar         unreachable
143b2a6f8e5SVedant Kumar 
144b2a6f8e5SVedant Kumar       lpad:                                             ; preds = %entry
145b2a6f8e5SVedant Kumar         %0 = landingpad { i8*, i32 }
146b2a6f8e5SVedant Kumar                 catch i8* null
147b2a6f8e5SVedant Kumar         br i1 undef, label %catch, label %finally.catchall
148b2a6f8e5SVedant Kumar 
149b2a6f8e5SVedant Kumar       catch:                                            ; preds = %lpad
150b2a6f8e5SVedant Kumar         %call2 = invoke i8 @hoge()
151b2a6f8e5SVedant Kumar                 to label %invoke.cont2 unwind label %lpad2
152b2a6f8e5SVedant Kumar 
153b2a6f8e5SVedant Kumar       invoke.cont2:                                    ; preds = %catch
154b2a6f8e5SVedant Kumar         %call3 = invoke i8 @hoge()
155b2a6f8e5SVedant Kumar                 to label %invoke.cont3 unwind label %lpad2
156b2a6f8e5SVedant Kumar 
157b2a6f8e5SVedant Kumar       invoke.cont3:                                    ; preds = %invoke.cont2
158b2a6f8e5SVedant Kumar         unreachable
159b2a6f8e5SVedant Kumar 
160b2a6f8e5SVedant Kumar       lpad2:                                           ; preds = %invoke.cont2, %catch
161b2a6f8e5SVedant Kumar         %ex.1 = phi i8* [ undef, %invoke.cont2 ], [ null, %catch ]
162b2a6f8e5SVedant Kumar         %1 = landingpad { i8*, i32 }
163b2a6f8e5SVedant Kumar                 catch i8* null
164b2a6f8e5SVedant Kumar         br label %finally.catchall
165b2a6f8e5SVedant Kumar 
166b2a6f8e5SVedant Kumar       finally.catchall:                                 ; preds = %lpad33, %lpad
167b2a6f8e5SVedant Kumar         %ex.2 = phi i8* [ %ex.1, %lpad2 ], [ null, %lpad ]
168b2a6f8e5SVedant Kumar         unreachable
169b2a6f8e5SVedant Kumar     }
170b2a6f8e5SVedant Kumar   )invalid", Err, Ctx));
171b2a6f8e5SVedant Kumar 
172b2a6f8e5SVedant Kumar 	if (!M) {
173b2a6f8e5SVedant Kumar     Err.print("unit", errs());
174b2a6f8e5SVedant Kumar     exit(1);
175b2a6f8e5SVedant Kumar   }
176b2a6f8e5SVedant Kumar 
177b2a6f8e5SVedant Kumar   Function *Func = M->getFunction("foo");
178b2a6f8e5SVedant Kumar   EXPECT_FALSE(verifyFunction(*Func, &errs()));
179b2a6f8e5SVedant Kumar 
180b2a6f8e5SVedant Kumar   SmallVector<BasicBlock *, 2> ExtractedBlocks{
181b2a6f8e5SVedant Kumar     getBlockByName(Func, "catch"),
182b2a6f8e5SVedant Kumar     getBlockByName(Func, "invoke.cont2"),
183b2a6f8e5SVedant Kumar     getBlockByName(Func, "invoke.cont3"),
184b2a6f8e5SVedant Kumar     getBlockByName(Func, "lpad2")
185b2a6f8e5SVedant Kumar   };
186b2a6f8e5SVedant Kumar 
187b2a6f8e5SVedant Kumar   DominatorTree DT(*Func);
188b2a6f8e5SVedant Kumar   CodeExtractor CE(ExtractedBlocks, &DT);
189b2a6f8e5SVedant Kumar   EXPECT_TRUE(CE.isEligible());
190b2a6f8e5SVedant Kumar 
191b2a6f8e5SVedant Kumar   Function *Outlined = CE.extractCodeRegion();
192b2a6f8e5SVedant Kumar   EXPECT_TRUE(Outlined);
193b2a6f8e5SVedant Kumar   EXPECT_FALSE(verifyFunction(*Outlined, &errs()));
194b2a6f8e5SVedant Kumar   EXPECT_FALSE(verifyFunction(*Func, &errs()));
195b2a6f8e5SVedant Kumar }
196b2a6f8e5SVedant Kumar 
1978267b333SNico Weber } // end anonymous namespace
198