818 lines · cpp
1//===- CodeExtractor.cpp - Unit tests for CodeExtractor -------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/Transforms/Utils/CodeExtractor.h"10#include "llvm/Analysis/AssumptionCache.h"11#include "llvm/AsmParser/Parser.h"12#include "llvm/IR/BasicBlock.h"13#include "llvm/IR/Constants.h"14#include "llvm/IR/DebugInfoMetadata.h"15#include "llvm/IR/Dominators.h"16#include "llvm/IR/InstIterator.h"17#include "llvm/IR/Instructions.h"18#include "llvm/IR/LLVMContext.h"19#include "llvm/IR/Module.h"20#include "llvm/IR/Verifier.h"21#include "llvm/IRReader/IRReader.h"22#include "llvm/Support/SourceMgr.h"23#include "gtest/gtest.h"24 25using namespace llvm;26 27namespace {28BasicBlock *getBlockByName(Function *F, StringRef name) {29 for (auto &BB : *F)30 if (BB.getName() == name)31 return &BB;32 return nullptr;33}34 35Instruction *getInstByName(Function *F, StringRef Name) {36 for (Instruction &I : instructions(F))37 if (I.getName() == Name)38 return &I;39 return nullptr;40}41 42TEST(CodeExtractor, ExitStub) {43 LLVMContext Ctx;44 SMDiagnostic Err;45 std::unique_ptr<Module> M(parseAssemblyString(R"invalid(46 define i32 @foo(i32 %x, i32 %y, i32 %z) {47 header:48 %0 = icmp ugt i32 %x, %y49 br i1 %0, label %body1, label %body250 51 body1:52 %1 = add i32 %z, 253 br label %notExtracted54 55 body2:56 %2 = mul i32 %z, 757 br label %notExtracted58 59 notExtracted:60 %3 = phi i32 [ %1, %body1 ], [ %2, %body2 ]61 %4 = add i32 %3, %x62 ret i32 %463 }64 )invalid",65 Err, Ctx));66 67 Function *Func = M->getFunction("foo");68 SmallVector<BasicBlock *, 3> Candidates{ getBlockByName(Func, "header"),69 getBlockByName(Func, "body1"),70 getBlockByName(Func, "body2") };71 72 CodeExtractor CE(Candidates);73 EXPECT_TRUE(CE.isEligible());74 75 CodeExtractorAnalysisCache CEAC(*Func);76 Function *Outlined = CE.extractCodeRegion(CEAC);77 EXPECT_TRUE(Outlined);78 BasicBlock *Exit = getBlockByName(Func, "notExtracted");79 BasicBlock *ExitSplit = getBlockByName(Outlined, "notExtracted.split");80 // Ensure that PHI in exit block has only one incoming value (from code81 // replacer block).82 EXPECT_TRUE(Exit && cast<PHINode>(Exit->front()).getNumIncomingValues() == 1);83 // Ensure that there is a PHI in outlined function with 2 incoming values.84 EXPECT_TRUE(ExitSplit &&85 cast<PHINode>(ExitSplit->front()).getNumIncomingValues() == 2);86 EXPECT_FALSE(verifyFunction(*Outlined));87 EXPECT_FALSE(verifyFunction(*Func));88}89 90TEST(CodeExtractor, InputOutputMonitoring) {91 LLVMContext Ctx;92 SMDiagnostic Err;93 std::unique_ptr<Module> M(parseAssemblyString(R"invalid(94 define i32 @foo(i32 %x, i32 %y, i32 %z) {95 header:96 %0 = icmp ugt i32 %x, %y97 br i1 %0, label %body1, label %body298 99 body1:100 %1 = add i32 %z, 2101 br label %notExtracted102 103 body2:104 %2 = mul i32 %z, 7105 br label %notExtracted106 107 notExtracted:108 %3 = phi i32 [ %1, %body1 ], [ %2, %body2 ]109 %4 = add i32 %3, %x110 ret i32 %4111 }112 )invalid",113 Err, Ctx));114 115 Function *Func = M->getFunction("foo");116 SmallVector<BasicBlock *, 3> Candidates{getBlockByName(Func, "header"),117 getBlockByName(Func, "body1"),118 getBlockByName(Func, "body2")};119 120 CodeExtractor CE(Candidates);121 EXPECT_TRUE(CE.isEligible());122 123 CodeExtractorAnalysisCache CEAC(*Func);124 SetVector<Value *> Inputs, Outputs;125 Function *Outlined = CE.extractCodeRegion(CEAC, Inputs, Outputs);126 EXPECT_TRUE(Outlined);127 128 EXPECT_EQ(Inputs.size(), 3u);129 EXPECT_EQ(Inputs[0], Func->getArg(2));130 EXPECT_EQ(Inputs[1], Func->getArg(0));131 EXPECT_EQ(Inputs[2], Func->getArg(1));132 EXPECT_EQ(Outputs.size(), 1u);133 StoreInst *SI = cast<StoreInst>(Outlined->getArg(3)->user_back());134 Value *OutputVal = SI->getValueOperand();135 EXPECT_EQ(Outputs[0], OutputVal);136 BasicBlock *Exit = getBlockByName(Func, "notExtracted");137 BasicBlock *ExitSplit = getBlockByName(Outlined, "notExtracted.split");138 // Ensure that PHI in exit block has only one incoming value (from code139 // replacer block).140 EXPECT_TRUE(Exit && cast<PHINode>(Exit->front()).getNumIncomingValues() == 1);141 // Ensure that there is a PHI in outlined function with 2 incoming values.142 EXPECT_TRUE(ExitSplit &&143 cast<PHINode>(ExitSplit->front()).getNumIncomingValues() == 2);144 EXPECT_FALSE(verifyFunction(*Outlined));145 EXPECT_FALSE(verifyFunction(*Func));146}147 148TEST(CodeExtractor, ExitBlockOrderingPhis) {149 LLVMContext Ctx;150 SMDiagnostic Err;151 std::unique_ptr<Module> M(parseAssemblyString(R"invalid(152 define void @foo(i32 %a, i32 %b) {153 entry:154 %0 = alloca i32, align 4155 br label %test0156 test0:157 %c = load i32, ptr %0, align 4158 br label %test1159 test1:160 %e = load i32, ptr %0, align 4161 br i1 true, label %first, label %test162 test:163 %d = load i32, ptr %0, align 4164 br i1 true, label %first, label %next165 first:166 %1 = phi i32 [ %c, %test ], [ %e, %test1 ]167 ret void168 next:169 %2 = add i32 %d, 1170 %3 = add i32 %e, 1171 ret void172 }173 )invalid",174 Err, Ctx));175 Function *Func = M->getFunction("foo");176 SmallVector<BasicBlock *, 3> Candidates{ getBlockByName(Func, "test0"),177 getBlockByName(Func, "test1"),178 getBlockByName(Func, "test") };179 180 CodeExtractor CE(Candidates);181 EXPECT_TRUE(CE.isEligible());182 183 CodeExtractorAnalysisCache CEAC(*Func);184 Function *Outlined = CE.extractCodeRegion(CEAC);185 EXPECT_TRUE(Outlined);186 187 BasicBlock *FirstExitStub = getBlockByName(Outlined, "first.exitStub");188 BasicBlock *NextExitStub = getBlockByName(Outlined, "next.exitStub");189 190 Instruction *FirstTerm = FirstExitStub->getTerminator();191 ReturnInst *FirstReturn = dyn_cast<ReturnInst>(FirstTerm);192 EXPECT_TRUE(FirstReturn);193 ConstantInt *CIFirst = dyn_cast<ConstantInt>(FirstReturn->getReturnValue());194 EXPECT_TRUE(CIFirst->getLimitedValue() == 1u);195 196 Instruction *NextTerm = NextExitStub->getTerminator();197 ReturnInst *NextReturn = dyn_cast<ReturnInst>(NextTerm);198 EXPECT_TRUE(NextReturn);199 ConstantInt *CINext = dyn_cast<ConstantInt>(NextReturn->getReturnValue());200 EXPECT_TRUE(CINext->getLimitedValue() == 0u);201 202 EXPECT_FALSE(verifyFunction(*Outlined));203 EXPECT_FALSE(verifyFunction(*Func));204}205 206TEST(CodeExtractor, ExitBlockOrdering) {207 LLVMContext Ctx;208 SMDiagnostic Err;209 std::unique_ptr<Module> M(parseAssemblyString(R"invalid(210 define void @foo(i32 %a, i32 %b) {211 entry:212 %0 = alloca i32, align 4213 br label %test0214 test0:215 %c = load i32, ptr %0, align 4216 br label %test1217 test1:218 %e = load i32, ptr %0, align 4219 br i1 true, label %first, label %test220 test:221 %d = load i32, ptr %0, align 4222 br i1 true, label %first, label %next223 first:224 ret void225 next:226 %1 = add i32 %d, 1227 %2 = add i32 %e, 1228 ret void229 }230 )invalid",231 Err, Ctx));232 Function *Func = M->getFunction("foo");233 SmallVector<BasicBlock *, 3> Candidates{ getBlockByName(Func, "test0"),234 getBlockByName(Func, "test1"),235 getBlockByName(Func, "test") };236 237 CodeExtractor CE(Candidates);238 EXPECT_TRUE(CE.isEligible());239 240 CodeExtractorAnalysisCache CEAC(*Func);241 Function *Outlined = CE.extractCodeRegion(CEAC);242 EXPECT_TRUE(Outlined);243 244 BasicBlock *FirstExitStub = getBlockByName(Outlined, "first.exitStub");245 BasicBlock *NextExitStub = getBlockByName(Outlined, "next.exitStub");246 247 Instruction *FirstTerm = FirstExitStub->getTerminator();248 ReturnInst *FirstReturn = dyn_cast<ReturnInst>(FirstTerm);249 EXPECT_TRUE(FirstReturn);250 ConstantInt *CIFirst = dyn_cast<ConstantInt>(FirstReturn->getReturnValue());251 EXPECT_TRUE(CIFirst->getLimitedValue() == 1u);252 253 Instruction *NextTerm = NextExitStub->getTerminator();254 ReturnInst *NextReturn = dyn_cast<ReturnInst>(NextTerm);255 EXPECT_TRUE(NextReturn);256 ConstantInt *CINext = dyn_cast<ConstantInt>(NextReturn->getReturnValue());257 EXPECT_TRUE(CINext->getLimitedValue() == 0u);258 259 EXPECT_FALSE(verifyFunction(*Outlined));260 EXPECT_FALSE(verifyFunction(*Func));261}262 263TEST(CodeExtractor, ExitPHIOnePredFromRegion) {264 LLVMContext Ctx;265 SMDiagnostic Err;266 std::unique_ptr<Module> M(parseAssemblyString(R"invalid(267 define i32 @foo() {268 header:269 br i1 undef, label %extracted1, label %pred270 271 pred:272 br i1 undef, label %exit1, label %exit2273 274 extracted1:275 br i1 undef, label %extracted2, label %exit1276 277 extracted2:278 br label %exit2279 280 exit1:281 %0 = phi i32 [ 1, %extracted1 ], [ 2, %pred ]282 ret i32 %0283 284 exit2:285 %1 = phi i32 [ 3, %extracted2 ], [ 4, %pred ]286 ret i32 %1287 }288 )invalid", Err, Ctx));289 290 Function *Func = M->getFunction("foo");291 SmallVector<BasicBlock *, 2> ExtractedBlocks{292 getBlockByName(Func, "extracted1"),293 getBlockByName(Func, "extracted2")294 };295 296 CodeExtractor CE(ExtractedBlocks);297 EXPECT_TRUE(CE.isEligible());298 299 CodeExtractorAnalysisCache CEAC(*Func);300 Function *Outlined = CE.extractCodeRegion(CEAC);301 EXPECT_TRUE(Outlined);302 BasicBlock *Exit1 = getBlockByName(Func, "exit1");303 BasicBlock *Exit2 = getBlockByName(Func, "exit2");304 // Ensure that PHIs in exits are not splitted (since that they have only one305 // incoming value from extracted region).306 EXPECT_TRUE(Exit1 &&307 cast<PHINode>(Exit1->front()).getNumIncomingValues() == 2);308 EXPECT_TRUE(Exit2 &&309 cast<PHINode>(Exit2->front()).getNumIncomingValues() == 2);310 EXPECT_FALSE(verifyFunction(*Outlined));311 EXPECT_FALSE(verifyFunction(*Func));312}313 314TEST(CodeExtractor, StoreOutputInvokeResultAfterEHPad) {315 LLVMContext Ctx;316 SMDiagnostic Err;317 std::unique_ptr<Module> M(parseAssemblyString(R"invalid(318 declare i8 @hoge()319 320 define i32 @foo() personality ptr null {321 entry:322 %call = invoke i8 @hoge()323 to label %invoke.cont unwind label %lpad324 325 invoke.cont: ; preds = %entry326 unreachable327 328 lpad: ; preds = %entry329 %0 = landingpad { ptr, i32 }330 catch ptr null331 br i1 undef, label %catch, label %finally.catchall332 333 catch: ; preds = %lpad334 %call2 = invoke i8 @hoge()335 to label %invoke.cont2 unwind label %lpad2336 337 invoke.cont2: ; preds = %catch338 %call3 = invoke i8 @hoge()339 to label %invoke.cont3 unwind label %lpad2340 341 invoke.cont3: ; preds = %invoke.cont2342 unreachable343 344 lpad2: ; preds = %invoke.cont2, %catch345 %ex.1 = phi ptr [ undef, %invoke.cont2 ], [ null, %catch ]346 %1 = landingpad { ptr, i32 }347 catch ptr null348 br label %finally.catchall349 350 finally.catchall: ; preds = %lpad33, %lpad351 %ex.2 = phi ptr [ %ex.1, %lpad2 ], [ null, %lpad ]352 unreachable353 }354 )invalid", Err, Ctx));355 356 if (!M) {357 Err.print("unit", errs());358 exit(1);359 }360 361 Function *Func = M->getFunction("foo");362 EXPECT_FALSE(verifyFunction(*Func, &errs()));363 364 SmallVector<BasicBlock *, 2> ExtractedBlocks{365 getBlockByName(Func, "catch"),366 getBlockByName(Func, "invoke.cont2"),367 getBlockByName(Func, "invoke.cont3"),368 getBlockByName(Func, "lpad2")369 };370 371 CodeExtractor CE(ExtractedBlocks);372 EXPECT_TRUE(CE.isEligible());373 374 CodeExtractorAnalysisCache CEAC(*Func);375 Function *Outlined = CE.extractCodeRegion(CEAC);376 EXPECT_TRUE(Outlined);377 EXPECT_FALSE(verifyFunction(*Outlined, &errs()));378 EXPECT_FALSE(verifyFunction(*Func, &errs()));379}380 381TEST(CodeExtractor, StoreOutputInvokeResultInExitStub) {382 LLVMContext Ctx;383 SMDiagnostic Err;384 std::unique_ptr<Module> M(parseAssemblyString(R"invalid(385 declare i32 @bar()386 387 define i32 @foo() personality ptr null {388 entry:389 %0 = invoke i32 @bar() to label %exit unwind label %lpad390 391 exit:392 ret i32 %0393 394 lpad:395 %1 = landingpad { ptr, i32 }396 cleanup397 resume { ptr, i32 } %1398 }399 )invalid",400 Err, Ctx));401 402 Function *Func = M->getFunction("foo");403 SmallVector<BasicBlock *, 1> Blocks{ getBlockByName(Func, "entry"),404 getBlockByName(Func, "lpad") };405 406 CodeExtractor CE(Blocks);407 EXPECT_TRUE(CE.isEligible());408 409 CodeExtractorAnalysisCache CEAC(*Func);410 Function *Outlined = CE.extractCodeRegion(CEAC);411 EXPECT_TRUE(Outlined);412 EXPECT_FALSE(verifyFunction(*Outlined));413 EXPECT_FALSE(verifyFunction(*Func));414}415 416TEST(CodeExtractor, ExtractAndInvalidateAssumptionCache) {417 LLVMContext Ctx;418 SMDiagnostic Err;419 std::unique_ptr<Module> M(parseAssemblyString(R"ir(420 target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"421 target triple = "aarch64"422 423 %b = type { i64 }424 declare void @g(ptr)425 426 declare void @llvm.assume(i1) #0427 428 define void @test() {429 entry:430 br label %label431 432 label:433 %0 = load ptr, ptr inttoptr (i64 8 to ptr), align 8434 %1 = getelementptr inbounds %b, ptr %0, i64 undef, i32 0435 %2 = load i64, ptr %1, align 8436 %3 = icmp ugt i64 %2, 1437 br i1 %3, label %if.then, label %if.else438 439 if.then:440 unreachable441 442 if.else:443 call void @g(ptr undef)444 store i64 undef, ptr null, align 536870912445 %4 = icmp eq i64 %2, 0446 call void @llvm.assume(i1 %4)447 unreachable448 }449 450 attributes #0 = { nounwind willreturn }451 )ir",452 Err, Ctx));453 454 assert(M && "Could not parse module?");455 Function *Func = M->getFunction("test");456 SmallVector<BasicBlock *, 1> Blocks{ getBlockByName(Func, "if.else") };457 AssumptionCache AC(*Func);458 CodeExtractor CE(Blocks, nullptr, false, nullptr, nullptr, &AC);459 EXPECT_TRUE(CE.isEligible());460 461 CodeExtractorAnalysisCache CEAC(*Func);462 Function *Outlined = CE.extractCodeRegion(CEAC);463 EXPECT_TRUE(Outlined);464 EXPECT_FALSE(verifyFunction(*Outlined));465 EXPECT_FALSE(verifyFunction(*Func));466 EXPECT_FALSE(CE.verifyAssumptionCache(*Func, *Outlined, &AC));467}468 469TEST(CodeExtractor, RemoveBitcastUsesFromOuterLifetimeMarkers) {470 LLVMContext Ctx;471 SMDiagnostic Err;472 std::unique_ptr<Module> M(parseAssemblyString(R"ir(473 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"474 target triple = "x86_64-unknown-linux-gnu"475 476 declare void @use(ptr)477 declare void @llvm.lifetime.start.p0i8(i64, ptr)478 declare void @llvm.lifetime.end.p0i8(i64, ptr)479 480 define void @foo() {481 entry:482 %0 = alloca i32483 br label %extract484 485 extract:486 %1 = bitcast ptr %0 to ptr487 call void @llvm.lifetime.start.p0i8(i64 4, ptr %1)488 call void @use(ptr %0)489 br label %exit490 491 exit:492 call void @use(ptr %0)493 call void @llvm.lifetime.end.p0i8(i64 4, ptr %1)494 ret void495 }496 )ir",497 Err, Ctx));498 499 Function *Func = M->getFunction("foo");500 SmallVector<BasicBlock *, 1> Blocks{getBlockByName(Func, "extract")};501 502 CodeExtractor CE(Blocks);503 EXPECT_TRUE(CE.isEligible());504 505 CodeExtractorAnalysisCache CEAC(*Func);506 SetVector<Value *> Inputs, Outputs, SinkingCands, HoistingCands;507 BasicBlock *CommonExit = nullptr;508 CE.findAllocas(CEAC, SinkingCands, HoistingCands, CommonExit);509 CE.findInputsOutputs(Inputs, Outputs, SinkingCands);510 EXPECT_EQ(Outputs.size(), 0U);511 512 Function *Outlined = CE.extractCodeRegion(CEAC);513 EXPECT_TRUE(Outlined);514 EXPECT_FALSE(verifyFunction(*Outlined));515 EXPECT_FALSE(verifyFunction(*Func));516}517 518TEST(CodeExtractor, PartialAggregateArgs) {519 LLVMContext Ctx;520 SMDiagnostic Err;521 std::unique_ptr<Module> M(parseAssemblyString(R"ir(522 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"523 target triple = "x86_64-unknown-linux-gnu"524 525 ; use different types such that an index mismatch will result in a type mismatch during verification.526 declare void @use16(i16)527 declare void @use32(i32)528 declare void @use64(i64)529 530 define void @foo(i16 %a, i32 %b, i64 %c) {531 entry:532 br label %extract533 534 extract:535 call void @use16(i16 %a)536 call void @use32(i32 %b)537 call void @use64(i64 %c)538 %d = add i16 21, 21539 %e = add i32 21, 21540 %f = add i64 21, 21541 br label %exit542 543 exit:544 call void @use16(i16 %d)545 call void @use32(i32 %e)546 call void @use64(i64 %f)547 ret void548 }549 )ir",550 Err, Ctx));551 552 Function *Func = M->getFunction("foo");553 SmallVector<BasicBlock *, 1> Blocks{getBlockByName(Func, "extract")};554 555 // Create the CodeExtractor with arguments aggregation enabled.556 CodeExtractor CE(Blocks, /* DominatorTree */ nullptr,557 /* AggregateArgs */ true);558 EXPECT_TRUE(CE.isEligible());559 560 CodeExtractorAnalysisCache CEAC(*Func);561 SetVector<Value *> Inputs, Outputs, SinkingCands, HoistingCands;562 BasicBlock *CommonExit = nullptr;563 CE.findAllocas(CEAC, SinkingCands, HoistingCands, CommonExit);564 CE.findInputsOutputs(Inputs, Outputs, SinkingCands);565 // Exclude the middle input and output from the argument aggregate.566 CE.excludeArgFromAggregate(Inputs[1]);567 CE.excludeArgFromAggregate(Outputs[1]);568 569 Function *Outlined = CE.extractCodeRegion(CEAC, Inputs, Outputs);570 EXPECT_TRUE(Outlined);571 // Expect 3 arguments in the outlined function: the excluded input, the572 // excluded output, and the struct aggregate for the remaining inputs.573 EXPECT_EQ(Outlined->arg_size(), 3U);574 EXPECT_FALSE(verifyFunction(*Outlined));575 EXPECT_FALSE(verifyFunction(*Func));576}577 578TEST(CodeExtractor, AllocaBlock) {579 LLVMContext Ctx;580 SMDiagnostic Err;581 std::unique_ptr<Module> M(parseAssemblyString(R"invalid(582 define i32 @foo(i32 %x, i32 %y, i32 %z) {583 entry:584 br label %allocas585 586 allocas:587 br label %body588 589 body:590 %w = add i32 %x, %y591 br label %notExtracted592 593 notExtracted:594 %r = add i32 %w, %x595 ret i32 %r596 }597 )invalid",598 Err, Ctx));599 600 Function *Func = M->getFunction("foo");601 SmallVector<BasicBlock *, 3> Candidates{getBlockByName(Func, "body")};602 603 BasicBlock *AllocaBlock = getBlockByName(Func, "allocas");604 CodeExtractor CE(Candidates, nullptr, true, nullptr, nullptr, nullptr, false,605 false, AllocaBlock);606 CE.excludeArgFromAggregate(Func->getArg(0));607 CE.excludeArgFromAggregate(getInstByName(Func, "w"));608 EXPECT_TRUE(CE.isEligible());609 610 CodeExtractorAnalysisCache CEAC(*Func);611 SetVector<Value *> Inputs, Outputs;612 Function *Outlined = CE.extractCodeRegion(CEAC, Inputs, Outputs);613 EXPECT_TRUE(Outlined);614 EXPECT_FALSE(verifyFunction(*Outlined));615 EXPECT_FALSE(verifyFunction(*Func));616 617 // The only added allocas may be in the dedicated alloca block. There should618 // be one alloca for the struct, and another one for the reload value.619 int NumAllocas = 0;620 for (Instruction &I : instructions(Func)) {621 if (!isa<AllocaInst>(I))622 continue;623 EXPECT_EQ(I.getParent(), AllocaBlock);624 NumAllocas += 1;625 }626 EXPECT_EQ(NumAllocas, 2);627}628 629/// Regression test to ensure we don't crash trying to set the name of the ptr630/// argument631TEST(CodeExtractor, PartialAggregateArgs2) {632 LLVMContext Ctx;633 SMDiagnostic Err;634 std::unique_ptr<Module> M(parseAssemblyString(R"ir(635 declare void @usei(i32)636 declare void @usep(ptr)637 638 define void @foo(i32 %a, i32 %b, ptr %p) {639 entry:640 br label %extract641 642 extract:643 call void @usei(i32 %a)644 call void @usei(i32 %b)645 call void @usep(ptr %p)646 br label %exit647 648 exit:649 ret void650 }651 )ir",652 Err, Ctx));653 654 Function *Func = M->getFunction("foo");655 SmallVector<BasicBlock *, 1> Blocks{getBlockByName(Func, "extract")};656 657 // Create the CodeExtractor with arguments aggregation enabled.658 CodeExtractor CE(Blocks, /* DominatorTree */ nullptr,659 /* AggregateArgs */ true);660 EXPECT_TRUE(CE.isEligible());661 662 CodeExtractorAnalysisCache CEAC(*Func);663 SetVector<Value *> Inputs, Outputs, SinkingCands, HoistingCands;664 BasicBlock *CommonExit = nullptr;665 CE.findAllocas(CEAC, SinkingCands, HoistingCands, CommonExit);666 CE.findInputsOutputs(Inputs, Outputs, SinkingCands);667 // Exclude the last input from the argument aggregate.668 CE.excludeArgFromAggregate(Inputs[2]);669 670 Function *Outlined = CE.extractCodeRegion(CEAC, Inputs, Outputs);671 EXPECT_TRUE(Outlined);672 EXPECT_FALSE(verifyFunction(*Outlined));673 EXPECT_FALSE(verifyFunction(*Func));674}675 676TEST(CodeExtractor, OpenMPAggregateArgs) {677 LLVMContext Ctx;678 SMDiagnostic Err;679 std::unique_ptr<Module> M(parseAssemblyString(R"ir(680 target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128:128:48-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9"681 target triple = "amdgcn-amd-amdhsa"682 683 define void @foo(ptr %0) {684 %2= alloca ptr, align 8, addrspace(5)685 %3 = addrspacecast ptr addrspace(5) %2 to ptr686 store ptr %0, ptr %3, align 8687 %4 = load ptr, ptr %3, align 8688 br label %entry689 690 entry:691 br label %extract692 693 extract:694 store i64 10, ptr %4, align 4695 br label %exit696 697 exit:698 ret void699 }700 )ir",701 Err, Ctx));702 Function *Func = M->getFunction("foo");703 SmallVector<BasicBlock *, 1> Blocks{getBlockByName(Func, "extract")};704 705 // Create the CodeExtractor with arguments aggregation enabled.706 // Outlined function argument should be declared in 0 address space707 // even if the default alloca address space is 5.708 CodeExtractor CE(Blocks, /* DominatorTree */ nullptr,709 /* AggregateArgs */ true, /* BlockFrequencyInfo */ nullptr,710 /* BranchProbabilityInfo */ nullptr,711 /* AssumptionCache */ nullptr,712 /* AllowVarArgs */ true,713 /* AllowAlloca */ true,714 /* AllocaBlock*/ &Func->getEntryBlock(),715 /* Suffix */ ".outlined",716 /* ArgsInZeroAddressSpace */ true);717 718 EXPECT_TRUE(CE.isEligible());719 720 CodeExtractorAnalysisCache CEAC(*Func);721 SetVector<Value *> Inputs, Outputs, SinkingCands, HoistingCands;722 BasicBlock *CommonExit = nullptr;723 CE.findAllocas(CEAC, SinkingCands, HoistingCands, CommonExit);724 CE.findInputsOutputs(Inputs, Outputs, SinkingCands);725 726 Function *Outlined = CE.extractCodeRegion(CEAC, Inputs, Outputs);727 EXPECT_TRUE(Outlined);728 EXPECT_EQ(Outlined->arg_size(), 1U);729 // Check address space of outlined argument is ptr in address space 0730 EXPECT_EQ(Outlined->getArg(0)->getType(),731 PointerType::get(M->getContext(), 0));732 EXPECT_FALSE(verifyFunction(*Outlined));733 EXPECT_FALSE(verifyFunction(*Func));734}735 736TEST(CodeExtractor, ArgsDebugInfo) {737 LLVMContext Ctx;738 SMDiagnostic Err;739 std::unique_ptr<Module> M(parseAssemblyString(R"ir(740 741 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"742 target triple = "x86_64-unknown-linux-gnu"743 744 define void @foo(i32 %a, i32 %b) !dbg !2 {745 %1 = alloca i32, i64 1, align 4, !dbg !1746 store i32 %a, ptr %1, align 4, !dbg !1747 #dbg_declare(ptr %1, !8, !DIExpression(), !1)748 #dbg_value(i32 %b, !9, !DIExpression(), !1)749 br label %entry750 751 entry:752 br label %extract753 754 extract:755 store i32 10, ptr %1, align 4, !dbg !1756 %2 = add i32 %b, 1, !dbg !1757 br label %exit758 759 exit:760 ret void761 }762 !llvm.dbg.cu = !{!6}763 !llvm.module.flags = !{!0}764 !0 = !{i32 2, !"Debug Info Version", i32 3}765 !1 = !DILocation(line: 11, column: 7, scope: !2)766 !2 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, type: !4, spFlags: DISPFlagDefinition, unit: !6)767 !3 = !DIFile(filename: "test.f90", directory: "")768 !4 = !DISubroutineType(cc: DW_CC_program, types: !5)769 !5 = !{null}770 !6 = distinct !DICompileUnit(language: DW_LANG_Fortran95, file: !3)771 !7 = !DIBasicType(name: "integer", size: 32, encoding: DW_ATE_signed)772 !8 = !DILocalVariable(name: "a", scope: !2, file: !3, type: !7)773 !9 = !DILocalVariable(name: "b", scope: !2, file: !3, type: !7)774 775 )ir",776 Err, Ctx));777 778 Function *Func = M->getFunction("foo");779 SmallVector<BasicBlock *, 1> Blocks{getBlockByName(Func, "extract")};780 781 auto TestExtracted = [&](bool AggregateArgs) {782 CodeExtractor CE(Blocks, /* DominatorTree */ nullptr, AggregateArgs);783 EXPECT_TRUE(CE.isEligible());784 CodeExtractorAnalysisCache CEAC(*Func);785 SetVector<Value *> Inputs, Outputs, SinkingCands, HoistingCands;786 BasicBlock *CommonExit = nullptr;787 CE.findAllocas(CEAC, SinkingCands, HoistingCands, CommonExit);788 CE.findInputsOutputs(Inputs, Outputs, SinkingCands);789 Function *Outlined = CE.extractCodeRegion(CEAC, Inputs, Outputs);790 EXPECT_TRUE(Outlined);791 BasicBlock &EB = Outlined->getEntryBlock();792 Instruction *Term = EB.getTerminator();793 EXPECT_TRUE(Term);794 EXPECT_TRUE(Term->hasDbgRecords());795 for (DbgVariableRecord &DVR : filterDbgVars(Term->getDbgRecordRange())) {796 DILocalVariable *Var = DVR.getVariable();797 EXPECT_TRUE(Var);798 if (DVR.isDbgDeclare())799 EXPECT_TRUE(Var->getName() == "a");800 else801 EXPECT_TRUE(Var->getName() == "b");802 for (Value *Loc : DVR.location_ops()) {803 if (Instruction *I = dyn_cast<Instruction>(Loc))804 EXPECT_TRUE(I->getParent() == &EB);805 else if (Argument *A = dyn_cast<Argument>(Loc))806 EXPECT_TRUE(A->getParent() == Outlined);807 }808 }809 EXPECT_FALSE(verifyFunction(*Outlined));810 };811 // Test with both true and false for AggregateArgs.812 TestExtracted(true);813 TestExtracted(false);814 EXPECT_FALSE(verifyFunction(*Func));815}816 817} // end anonymous namespace818