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