18267b333SNico Weber //===- CodeExtractor.cpp - Unit tests for CodeExtractor -------------------===//
28267b333SNico Weber //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler 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"
11*50afaa9dSAditya Kumar #include "llvm/Analysis/AssumptionCache.h"
128267b333SNico Weber #include "llvm/IR/BasicBlock.h"
138267b333SNico Weber #include "llvm/IR/Dominators.h"
14d129569eSVedant Kumar #include "llvm/IR/Instructions.h"
158267b333SNico Weber #include "llvm/IR/LLVMContext.h"
168267b333SNico Weber #include "llvm/IR/Module.h"
178267b333SNico Weber #include "llvm/IR/Verifier.h"
188267b333SNico Weber #include "llvm/IRReader/IRReader.h"
198267b333SNico Weber #include "llvm/Support/SourceMgr.h"
208267b333SNico Weber #include "gtest/gtest.h"
218267b333SNico Weber 
228267b333SNico Weber using namespace llvm;
238267b333SNico Weber 
248267b333SNico Weber namespace {
25d129569eSVedant Kumar BasicBlock *getBlockByName(Function *F, StringRef name) {
26d129569eSVedant Kumar   for (auto &BB : *F)
27d129569eSVedant Kumar     if (BB.getName() == name)
28d129569eSVedant Kumar       return &BB;
29d129569eSVedant Kumar   return nullptr;
30d129569eSVedant Kumar }
31d129569eSVedant Kumar 
32d129569eSVedant Kumar TEST(CodeExtractor, ExitStub) {
338267b333SNico Weber   LLVMContext Ctx;
348267b333SNico Weber   SMDiagnostic Err;
358267b333SNico Weber   std::unique_ptr<Module> M(parseAssemblyString(R"invalid(
368267b333SNico Weber     define i32 @foo(i32 %x, i32 %y, i32 %z) {
378267b333SNico Weber     header:
388267b333SNico Weber       %0 = icmp ugt i32 %x, %y
398267b333SNico Weber       br i1 %0, label %body1, label %body2
408267b333SNico Weber 
418267b333SNico Weber     body1:
428267b333SNico Weber       %1 = add i32 %z, 2
438267b333SNico Weber       br label %notExtracted
448267b333SNico Weber 
458267b333SNico Weber     body2:
468267b333SNico Weber       %2 = mul i32 %z, 7
478267b333SNico Weber       br label %notExtracted
488267b333SNico Weber 
498267b333SNico Weber     notExtracted:
508267b333SNico Weber       %3 = phi i32 [ %1, %body1 ], [ %2, %body2 ]
518267b333SNico Weber       %4 = add i32 %3, %x
528267b333SNico Weber       ret i32 %4
538267b333SNico Weber     }
548267b333SNico Weber   )invalid",
558267b333SNico Weber                                                 Err, Ctx));
568267b333SNico Weber 
578267b333SNico Weber   Function *Func = M->getFunction("foo");
58d129569eSVedant Kumar   SmallVector<BasicBlock *, 3> Candidates{ getBlockByName(Func, "header"),
59d129569eSVedant Kumar                                            getBlockByName(Func, "body1"),
60d129569eSVedant Kumar                                            getBlockByName(Func, "body2") };
618267b333SNico Weber 
620e5dd512SVedant Kumar   CodeExtractor CE(Candidates);
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 
1120e5dd512SVedant Kumar   CodeExtractor CE(ExtractedBlocks);
113d129569eSVedant Kumar   EXPECT_TRUE(CE.isEligible());
114d129569eSVedant Kumar 
115d129569eSVedant Kumar   Function *Outlined = CE.extractCodeRegion();
116d129569eSVedant Kumar   EXPECT_TRUE(Outlined);
117d129569eSVedant Kumar   BasicBlock *Exit1 = getBlockByName(Func, "exit1");
118d129569eSVedant Kumar   BasicBlock *Exit2 = getBlockByName(Func, "exit2");
119d129569eSVedant Kumar   // Ensure that PHIs in exits are not splitted (since that they have only one
120d129569eSVedant Kumar   // incoming value from extracted region).
121d129569eSVedant Kumar   EXPECT_TRUE(Exit1 &&
122d129569eSVedant Kumar           cast<PHINode>(Exit1->front()).getNumIncomingValues() == 2);
123d129569eSVedant Kumar   EXPECT_TRUE(Exit2 &&
124d129569eSVedant Kumar           cast<PHINode>(Exit2->front()).getNumIncomingValues() == 2);
125d129569eSVedant Kumar   EXPECT_FALSE(verifyFunction(*Outlined));
126d129569eSVedant Kumar   EXPECT_FALSE(verifyFunction(*Func));
1278267b333SNico Weber }
128b2a6f8e5SVedant Kumar 
129b2a6f8e5SVedant Kumar TEST(CodeExtractor, StoreOutputInvokeResultAfterEHPad) {
130b2a6f8e5SVedant Kumar   LLVMContext Ctx;
131b2a6f8e5SVedant Kumar   SMDiagnostic Err;
132b2a6f8e5SVedant Kumar   std::unique_ptr<Module> M(parseAssemblyString(R"invalid(
133b2a6f8e5SVedant Kumar     declare i8 @hoge()
134b2a6f8e5SVedant Kumar 
135b2a6f8e5SVedant Kumar     define i32 @foo() personality i8* null {
136b2a6f8e5SVedant Kumar       entry:
137b2a6f8e5SVedant Kumar         %call = invoke i8 @hoge()
138b2a6f8e5SVedant Kumar                 to label %invoke.cont unwind label %lpad
139b2a6f8e5SVedant Kumar 
140b2a6f8e5SVedant Kumar       invoke.cont:                                      ; preds = %entry
141b2a6f8e5SVedant Kumar         unreachable
142b2a6f8e5SVedant Kumar 
143b2a6f8e5SVedant Kumar       lpad:                                             ; preds = %entry
144b2a6f8e5SVedant Kumar         %0 = landingpad { i8*, i32 }
145b2a6f8e5SVedant Kumar                 catch i8* null
146b2a6f8e5SVedant Kumar         br i1 undef, label %catch, label %finally.catchall
147b2a6f8e5SVedant Kumar 
148b2a6f8e5SVedant Kumar       catch:                                            ; preds = %lpad
149b2a6f8e5SVedant Kumar         %call2 = invoke i8 @hoge()
150b2a6f8e5SVedant Kumar                 to label %invoke.cont2 unwind label %lpad2
151b2a6f8e5SVedant Kumar 
152b2a6f8e5SVedant Kumar       invoke.cont2:                                    ; preds = %catch
153b2a6f8e5SVedant Kumar         %call3 = invoke i8 @hoge()
154b2a6f8e5SVedant Kumar                 to label %invoke.cont3 unwind label %lpad2
155b2a6f8e5SVedant Kumar 
156b2a6f8e5SVedant Kumar       invoke.cont3:                                    ; preds = %invoke.cont2
157b2a6f8e5SVedant Kumar         unreachable
158b2a6f8e5SVedant Kumar 
159b2a6f8e5SVedant Kumar       lpad2:                                           ; preds = %invoke.cont2, %catch
160b2a6f8e5SVedant Kumar         %ex.1 = phi i8* [ undef, %invoke.cont2 ], [ null, %catch ]
161b2a6f8e5SVedant Kumar         %1 = landingpad { i8*, i32 }
162b2a6f8e5SVedant Kumar                 catch i8* null
163b2a6f8e5SVedant Kumar         br label %finally.catchall
164b2a6f8e5SVedant Kumar 
165b2a6f8e5SVedant Kumar       finally.catchall:                                 ; preds = %lpad33, %lpad
166b2a6f8e5SVedant Kumar         %ex.2 = phi i8* [ %ex.1, %lpad2 ], [ null, %lpad ]
167b2a6f8e5SVedant Kumar         unreachable
168b2a6f8e5SVedant Kumar     }
169b2a6f8e5SVedant Kumar   )invalid", Err, Ctx));
170b2a6f8e5SVedant Kumar 
171b2a6f8e5SVedant Kumar 	if (!M) {
172b2a6f8e5SVedant Kumar     Err.print("unit", errs());
173b2a6f8e5SVedant Kumar     exit(1);
174b2a6f8e5SVedant Kumar   }
175b2a6f8e5SVedant Kumar 
176b2a6f8e5SVedant Kumar   Function *Func = M->getFunction("foo");
177b2a6f8e5SVedant Kumar   EXPECT_FALSE(verifyFunction(*Func, &errs()));
178b2a6f8e5SVedant Kumar 
179b2a6f8e5SVedant Kumar   SmallVector<BasicBlock *, 2> ExtractedBlocks{
180b2a6f8e5SVedant Kumar     getBlockByName(Func, "catch"),
181b2a6f8e5SVedant Kumar     getBlockByName(Func, "invoke.cont2"),
182b2a6f8e5SVedant Kumar     getBlockByName(Func, "invoke.cont3"),
183b2a6f8e5SVedant Kumar     getBlockByName(Func, "lpad2")
184b2a6f8e5SVedant Kumar   };
185b2a6f8e5SVedant Kumar 
1860e5dd512SVedant Kumar   CodeExtractor CE(ExtractedBlocks);
187b2a6f8e5SVedant Kumar   EXPECT_TRUE(CE.isEligible());
188b2a6f8e5SVedant Kumar 
189b2a6f8e5SVedant Kumar   Function *Outlined = CE.extractCodeRegion();
190b2a6f8e5SVedant Kumar   EXPECT_TRUE(Outlined);
191b2a6f8e5SVedant Kumar   EXPECT_FALSE(verifyFunction(*Outlined, &errs()));
192b2a6f8e5SVedant Kumar   EXPECT_FALSE(verifyFunction(*Func, &errs()));
193b2a6f8e5SVedant Kumar }
194b2a6f8e5SVedant Kumar 
1950e5dd512SVedant Kumar TEST(CodeExtractor, StoreOutputInvokeResultInExitStub) {
1960e5dd512SVedant Kumar   LLVMContext Ctx;
1970e5dd512SVedant Kumar   SMDiagnostic Err;
1980e5dd512SVedant Kumar   std::unique_ptr<Module> M(parseAssemblyString(R"invalid(
1990e5dd512SVedant Kumar     declare i32 @bar()
2000e5dd512SVedant Kumar 
2010e5dd512SVedant Kumar     define i32 @foo() personality i8* null {
2020e5dd512SVedant Kumar     entry:
2030e5dd512SVedant Kumar       %0 = invoke i32 @bar() to label %exit unwind label %lpad
2040e5dd512SVedant Kumar 
2050e5dd512SVedant Kumar     exit:
2060e5dd512SVedant Kumar       ret i32 %0
2070e5dd512SVedant Kumar 
2080e5dd512SVedant Kumar     lpad:
2090e5dd512SVedant Kumar       %1 = landingpad { i8*, i32 }
2100e5dd512SVedant Kumar               cleanup
2110e5dd512SVedant Kumar       resume { i8*, i32 } %1
2120e5dd512SVedant Kumar     }
2130e5dd512SVedant Kumar   )invalid",
2140e5dd512SVedant Kumar                                                 Err, Ctx));
2150e5dd512SVedant Kumar 
2160e5dd512SVedant Kumar   Function *Func = M->getFunction("foo");
2170e5dd512SVedant Kumar   SmallVector<BasicBlock *, 1> Blocks{ getBlockByName(Func, "entry"),
2180e5dd512SVedant Kumar                                        getBlockByName(Func, "lpad") };
2190e5dd512SVedant Kumar 
2200e5dd512SVedant Kumar   CodeExtractor CE(Blocks);
2210e5dd512SVedant Kumar   EXPECT_TRUE(CE.isEligible());
2220e5dd512SVedant Kumar 
2230e5dd512SVedant Kumar   Function *Outlined = CE.extractCodeRegion();
2240e5dd512SVedant Kumar   EXPECT_TRUE(Outlined);
2250e5dd512SVedant Kumar   EXPECT_FALSE(verifyFunction(*Outlined));
2260e5dd512SVedant Kumar   EXPECT_FALSE(verifyFunction(*Func));
2270e5dd512SVedant Kumar }
2280e5dd512SVedant Kumar 
229*50afaa9dSAditya Kumar TEST(CodeExtractor, ExtractAndInvalidateAssumptionCache) {
230*50afaa9dSAditya Kumar   LLVMContext Ctx;
231*50afaa9dSAditya Kumar   SMDiagnostic Err;
232*50afaa9dSAditya Kumar   std::unique_ptr<Module> M(parseAssemblyString(R"ir(
233*50afaa9dSAditya Kumar         target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
234*50afaa9dSAditya Kumar         target triple = "aarch64"
235*50afaa9dSAditya Kumar 
236*50afaa9dSAditya Kumar         %b = type { i64 }
237*50afaa9dSAditya Kumar         declare void @g(i8*)
238*50afaa9dSAditya Kumar 
239*50afaa9dSAditya Kumar         declare void @llvm.assume(i1) #0
240*50afaa9dSAditya Kumar 
241*50afaa9dSAditya Kumar         define void @test() {
242*50afaa9dSAditya Kumar         entry:
243*50afaa9dSAditya Kumar           br label %label
244*50afaa9dSAditya Kumar 
245*50afaa9dSAditya Kumar         label:
246*50afaa9dSAditya Kumar           %0 = load %b*, %b** inttoptr (i64 8 to %b**), align 8
247*50afaa9dSAditya Kumar           %1 = getelementptr inbounds %b, %b* %0, i64 undef, i32 0
248*50afaa9dSAditya Kumar           %2 = load i64, i64* %1, align 8
249*50afaa9dSAditya Kumar           %3 = icmp ugt i64 %2, 1
250*50afaa9dSAditya Kumar           br i1 %3, label %if.then, label %if.else
251*50afaa9dSAditya Kumar 
252*50afaa9dSAditya Kumar         if.then:
253*50afaa9dSAditya Kumar           unreachable
254*50afaa9dSAditya Kumar 
255*50afaa9dSAditya Kumar         if.else:
256*50afaa9dSAditya Kumar           call void @g(i8* undef)
257*50afaa9dSAditya Kumar           store i64 undef, i64* null, align 536870912
258*50afaa9dSAditya Kumar           %4 = icmp eq i64 %2, 0
259*50afaa9dSAditya Kumar           call void @llvm.assume(i1 %4)
260*50afaa9dSAditya Kumar           unreachable
261*50afaa9dSAditya Kumar         }
262*50afaa9dSAditya Kumar 
263*50afaa9dSAditya Kumar         attributes #0 = { nounwind willreturn }
264*50afaa9dSAditya Kumar   )ir",
265*50afaa9dSAditya Kumar                                                 Err, Ctx));
266*50afaa9dSAditya Kumar 
267*50afaa9dSAditya Kumar   assert(M && "Could not parse module?");
268*50afaa9dSAditya Kumar   Function *Func = M->getFunction("test");
269*50afaa9dSAditya Kumar   SmallVector<BasicBlock *, 1> Blocks{ getBlockByName(Func, "if.else") };
270*50afaa9dSAditya Kumar   AssumptionCache AC(*Func);
271*50afaa9dSAditya Kumar   CodeExtractor CE(Blocks, nullptr, false, nullptr, nullptr, &AC);
272*50afaa9dSAditya Kumar   EXPECT_TRUE(CE.isEligible());
273*50afaa9dSAditya Kumar 
274*50afaa9dSAditya Kumar   Function *Outlined = CE.extractCodeRegion();
275*50afaa9dSAditya Kumar   EXPECT_TRUE(Outlined);
276*50afaa9dSAditya Kumar   EXPECT_FALSE(verifyFunction(*Outlined));
277*50afaa9dSAditya Kumar   EXPECT_FALSE(verifyFunction(*Func));
278*50afaa9dSAditya Kumar   EXPECT_FALSE(CE.verifyAssumptionCache(*Func, &AC));
279*50afaa9dSAditya Kumar }
2808267b333SNico Weber } // end anonymous namespace
281