brintos

brintos / llvm-project-archived public Read only

0
0
Text · 26.1 KiB · 90f0620 Raw
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