brintos

brintos / llvm-project-archived public Read only

0
0
Text · 306.3 KiB · 4595590 Raw
7967 lines · cpp
1//===- llvm/unittest/IR/OpenMPIRBuilderTest.cpp - OpenMPIRBuilder tests ---===//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/Frontend/OpenMP/OMPConstants.h"10#include "llvm/Frontend/OpenMP/OMPDeviceConstants.h"11#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"12#include "llvm/IR/BasicBlock.h"13#include "llvm/IR/DIBuilder.h"14#include "llvm/IR/DebugInfoMetadata.h"15#include "llvm/IR/Function.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/Passes/PassBuilder.h"22#include "llvm/Support/Casting.h"23#include "llvm/Testing/Support/Error.h"24#include "llvm/Transforms/Utils/BasicBlockUtils.h"25#include "gmock/gmock.h"26#include "gtest/gtest.h"27#include <cstdlib>28#include <optional>29 30using namespace llvm;31using namespace omp;32 33// Helper that intends to be functionally equivalent to `VarType VarName = Init`34// for an `Init` that returns an `Expected<VarType>` value. It produces an error35// message and returns if `Init` didn't produce a valid result.36#define ASSERT_EXPECTED_INIT(VarType, VarName, Init)                           \37  auto __Expected##VarName = Init;                                             \38  ASSERT_THAT_EXPECTED(__Expected##VarName, Succeeded());                      \39  VarType VarName = *__Expected##VarName40 41// Similar to ASSERT_EXPECTED_INIT, but returns a given expression in case of42// error after printing the error message.43#define ASSERT_EXPECTED_INIT_RETURN(VarType, VarName, Init, Return)            \44  auto __Expected##VarName = Init;                                             \45  EXPECT_THAT_EXPECTED(__Expected##VarName, Succeeded());                      \46  if (!__Expected##VarName)                                                    \47    return Return;                                                             \48  VarType VarName = *__Expected##VarName49 50// Wrapper lambdas to allow using EXPECT*() macros inside of error-returning51// callbacks.52#define FINICB_WRAPPER(cb)                                                     \53  [&cb](InsertPointTy IP) -> Error {                                           \54    cb(IP);                                                                    \55    return Error::success();                                                   \56  }57 58#define BODYGENCB_WRAPPER(cb)                                                  \59  [&cb](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) -> Error {            \60    cb(AllocaIP, CodeGenIP);                                                   \61    return Error::success();                                                   \62  }63 64#define LOOP_BODYGENCB_WRAPPER(cb)                                             \65  [&cb](InsertPointTy CodeGenIP, Value *LC) -> Error {                         \66    cb(CodeGenIP, LC);                                                         \67    return Error::success();                                                   \68  }69 70namespace {71 72/// Create an instruction that uses the values in \p Values. We use "printf"73/// just because it is often used for this purpose in test code, but it is never74/// executed here.75static CallInst *createPrintfCall(IRBuilder<> &Builder, StringRef FormatStr,76                                  ArrayRef<Value *> Values) {77  Module *M = Builder.GetInsertBlock()->getParent()->getParent();78 79  GlobalVariable *GV = Builder.CreateGlobalString(FormatStr, "", 0, M);80  Constant *Zero = ConstantInt::get(Type::getInt32Ty(M->getContext()), 0);81  Constant *Indices[] = {Zero, Zero};82  Constant *FormatStrConst =83      ConstantExpr::getInBoundsGetElementPtr(GV->getValueType(), GV, Indices);84 85  Function *PrintfDecl = M->getFunction("printf");86  if (!PrintfDecl) {87    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;88    FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(), true);89    PrintfDecl = Function::Create(Ty, Linkage, "printf", M);90  }91 92  SmallVector<Value *, 4> Args;93  Args.push_back(FormatStrConst);94  Args.append(Values.begin(), Values.end());95  return Builder.CreateCall(PrintfDecl, Args);96}97 98/// Verify that blocks in \p RefOrder are corresponds to the depth-first visit99/// order the control flow of \p F.100///101/// This is an easy way to verify the branching structure of the CFG without102/// checking every branch instruction individually. For the CFG of a103/// CanonicalLoopInfo, the Cond BB's terminating branch's first edge is entering104/// the body, i.e. the DFS order corresponds to the execution order with one105/// loop iteration.106static testing::AssertionResult107verifyDFSOrder(Function *F, ArrayRef<BasicBlock *> RefOrder) {108  ArrayRef<BasicBlock *>::iterator It = RefOrder.begin();109  ArrayRef<BasicBlock *>::iterator E = RefOrder.end();110 111  df_iterator_default_set<BasicBlock *, 16> Visited;112  auto DFS = llvm::depth_first_ext(&F->getEntryBlock(), Visited);113 114  BasicBlock *Prev = nullptr;115  for (BasicBlock *BB : DFS) {116    if (It != E && BB == *It) {117      Prev = *It;118      ++It;119    }120  }121 122  if (It == E)123    return testing::AssertionSuccess();124  if (!Prev)125    return testing::AssertionFailure()126           << "Did not find " << (*It)->getName() << " in control flow";127  return testing::AssertionFailure()128         << "Expected " << Prev->getName() << " before " << (*It)->getName()129         << " in control flow";130}131 132/// Verify that blocks in \p RefOrder are in the same relative order in the133/// linked lists of blocks in \p F. The linked list may contain additional134/// blocks in-between.135///136/// While the order in the linked list is not relevant for semantics, keeping137/// the order roughly in execution order makes its printout easier to read.138static testing::AssertionResult139verifyListOrder(Function *F, ArrayRef<BasicBlock *> RefOrder) {140  ArrayRef<BasicBlock *>::iterator It = RefOrder.begin();141  ArrayRef<BasicBlock *>::iterator E = RefOrder.end();142 143  BasicBlock *Prev = nullptr;144  for (BasicBlock &BB : *F) {145    if (It != E && &BB == *It) {146      Prev = *It;147      ++It;148    }149  }150 151  if (It == E)152    return testing::AssertionSuccess();153  if (!Prev)154    return testing::AssertionFailure() << "Did not find " << (*It)->getName()155                                       << " in function " << F->getName();156  return testing::AssertionFailure()157         << "Expected " << Prev->getName() << " before " << (*It)->getName()158         << " in function " << F->getName();159}160 161/// Populate Calls with call instructions calling the function with the given162/// FnID from the given function F.163static void findCalls(Function *F, omp::RuntimeFunction FnID,164                      OpenMPIRBuilder &OMPBuilder,165                      SmallVectorImpl<CallInst *> &Calls) {166  Function *Fn = OMPBuilder.getOrCreateRuntimeFunctionPtr(FnID);167  for (BasicBlock &BB : *F) {168    for (Instruction &I : BB) {169      auto *Call = dyn_cast<CallInst>(&I);170      if (Call && Call->getCalledFunction() == Fn)171        Calls.push_back(Call);172    }173  }174}175 176/// Assuming \p F contains only one call to the function with the given \p FnID,177/// return that call.178static CallInst *findSingleCall(Function *F, omp::RuntimeFunction FnID,179                                OpenMPIRBuilder &OMPBuilder) {180  SmallVector<CallInst *, 1> Calls;181  findCalls(F, FnID, OMPBuilder, Calls);182  EXPECT_EQ(1u, Calls.size());183  if (Calls.size() != 1)184    return nullptr;185  return Calls.front();186}187 188static omp::ScheduleKind getSchedKind(omp::OMPScheduleType SchedType) {189  switch (SchedType & ~omp::OMPScheduleType::ModifierMask) {190  case omp::OMPScheduleType::BaseDynamicChunked:191    return omp::OMP_SCHEDULE_Dynamic;192  case omp::OMPScheduleType::BaseGuidedChunked:193    return omp::OMP_SCHEDULE_Guided;194  case omp::OMPScheduleType::BaseAuto:195    return omp::OMP_SCHEDULE_Auto;196  case omp::OMPScheduleType::BaseRuntime:197    return omp::OMP_SCHEDULE_Runtime;198  default:199    llvm_unreachable("unknown type for this test");200  }201}202 203class OpenMPIRBuilderTest : public testing::Test {204protected:205  void SetUp() override {206    M.reset(new Module("MyModule", Ctx));207    FunctionType *FTy =208        FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt32Ty(Ctx)},209                          /*isVarArg=*/false);210    F = Function::Create(FTy, Function::ExternalLinkage, "", M.get());211    BB = BasicBlock::Create(Ctx, "", F);212 213    DIBuilder DIB(*M);214    auto File = DIB.createFile("test.dbg", "/src", std::nullopt,215                               std::optional<StringRef>("/src/test.dbg"));216    auto CU = DIB.createCompileUnit(DISourceLanguageName(dwarf::DW_LANG_C),217                                    File, "llvm-C", true, "", 0);218    auto Type = DIB.createSubroutineType(DIB.getOrCreateTypeArray({}));219    auto SP = DIB.createFunction(220        CU, "foo", "", File, 1, Type, 1, DINode::FlagZero,221        DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized);222    F->setSubprogram(SP);223    auto Scope = DIB.createLexicalBlockFile(SP, File, 0);224    DIB.finalize();225    DL = DILocation::get(Ctx, 3, 7, Scope);226  }227 228  void TearDown() override {229    BB = nullptr;230    M.reset();231  }232 233  /// Create a function with a simple loop that calls printf using the logical234  /// loop counter for use with tests that need a CanonicalLoopInfo object.235  CanonicalLoopInfo *buildSingleLoopFunction(DebugLoc DL,236                                             OpenMPIRBuilder &OMPBuilder,237                                             int UseIVBits,238                                             CallInst **Call = nullptr,239                                             BasicBlock **BodyCode = nullptr) {240    OMPBuilder.initialize();241    F->setName("func");242 243    IRBuilder<> Builder(BB);244    OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});245    Value *TripCount = F->getArg(0);246 247    Type *IVType = Type::getIntNTy(Builder.getContext(), UseIVBits);248    Value *CastedTripCount =249        Builder.CreateZExtOrTrunc(TripCount, IVType, "tripcount");250 251    auto LoopBodyGenCB = [&](OpenMPIRBuilder::InsertPointTy CodeGenIP,252                             llvm::Value *LC) {253      Builder.restoreIP(CodeGenIP);254      if (BodyCode)255        *BodyCode = Builder.GetInsertBlock();256 257      // Add something that consumes the induction variable to the body.258      CallInst *CallInst = createPrintfCall(Builder, "%d\\n", {LC});259      if (Call)260        *Call = CallInst;261 262      return Error::success();263    };264 265    ASSERT_EXPECTED_INIT_RETURN(266        CanonicalLoopInfo *, Loop,267        OMPBuilder.createCanonicalLoop(Loc, LoopBodyGenCB, CastedTripCount),268        nullptr);269 270    // Finalize the function.271    Builder.restoreIP(Loop->getAfterIP());272    Builder.CreateRetVoid();273 274    return Loop;275  }276 277  LLVMContext Ctx;278  std::unique_ptr<Module> M;279  Function *F;280  BasicBlock *BB;281  DebugLoc DL;282};283 284class OpenMPIRBuilderTestWithParams285    : public OpenMPIRBuilderTest,286      public ::testing::WithParamInterface<omp::OMPScheduleType> {};287 288class OpenMPIRBuilderTestWithIVBits289    : public OpenMPIRBuilderTest,290      public ::testing::WithParamInterface<int> {};291 292// Returns the value stored in the given allocation. Returns null if the given293// value is not a result of an InstTy instruction, if no value is stored or if294// there is more than one store.295template <typename InstTy> static Value *findStoredValue(Value *AllocaValue) {296  Instruction *Inst = dyn_cast<InstTy>(AllocaValue);297  if (!Inst)298    return nullptr;299  StoreInst *Store = nullptr;300  for (Use &U : Inst->uses()) {301    if (auto *CandidateStore = dyn_cast<StoreInst>(U.getUser())) {302      EXPECT_EQ(Store, nullptr);303      Store = CandidateStore;304    }305  }306  if (!Store)307    return nullptr;308  return Store->getValueOperand();309}310 311// Returns the value stored in the aggregate argument of an outlined function,312// or nullptr if it is not found.313static Value *findStoredValueInAggregateAt(LLVMContext &Ctx, Value *Aggregate,314                                           unsigned Idx) {315  GetElementPtrInst *GEPAtIdx = nullptr;316  // Find GEP instruction at that index.317  for (User *Usr : Aggregate->users()) {318    GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Usr);319    if (!GEP)320      continue;321 322    if (GEP->getOperand(2) != ConstantInt::get(Type::getInt32Ty(Ctx), Idx))323      continue;324 325    EXPECT_EQ(GEPAtIdx, nullptr);326    GEPAtIdx = GEP;327  }328 329  EXPECT_NE(GEPAtIdx, nullptr);330  EXPECT_TRUE(GEPAtIdx->hasOneUse());331 332  // Find the value stored to the aggregate.333  StoreInst *StoreToAgg = dyn_cast<StoreInst>(*GEPAtIdx->user_begin());334  Value *StoredAggValue = StoreToAgg->getValueOperand();335 336  Value *StoredValue = nullptr;337 338  // Find the value stored to the value stored in the aggregate.339  for (User *Usr : StoredAggValue->users()) {340    StoreInst *Store = dyn_cast<StoreInst>(Usr);341    if (!Store)342      continue;343 344    if (Store->getPointerOperand() != StoredAggValue)345      continue;346 347    EXPECT_EQ(StoredValue, nullptr);348    StoredValue = Store->getValueOperand();349  }350 351  return StoredValue;352}353 354// Returns the aggregate that the value is originating from.355static Value *findAggregateFromValue(Value *V) {356  // Expects a load instruction that loads from the aggregate.357  LoadInst *Load = dyn_cast<LoadInst>(V);358  EXPECT_NE(Load, nullptr);359  // Find the GEP instruction used in the load instruction.360  GetElementPtrInst *GEP =361      dyn_cast<GetElementPtrInst>(Load->getPointerOperand());362  EXPECT_NE(GEP, nullptr);363  // Find the aggregate used in the GEP instruction.364  Value *Aggregate = GEP->getPointerOperand();365 366  return Aggregate;367}368 369TEST_F(OpenMPIRBuilderTest, CreateBarrier) {370  OpenMPIRBuilder OMPBuilder(*M);371  OMPBuilder.initialize();372 373  IRBuilder<> Builder(BB);374 375  ASSERT_THAT_EXPECTED(376      OMPBuilder.createBarrier({IRBuilder<>::InsertPoint()}, OMPD_for),377      Succeeded());378  EXPECT_TRUE(M->global_empty());379  EXPECT_EQ(M->size(), 1U);380  EXPECT_EQ(F->size(), 1U);381  EXPECT_EQ(BB->size(), 0U);382 383  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()});384  ASSERT_THAT_EXPECTED(OMPBuilder.createBarrier(Loc, OMPD_for), Succeeded());385  EXPECT_FALSE(M->global_empty());386  EXPECT_EQ(M->size(), 3U);387  EXPECT_EQ(F->size(), 1U);388  EXPECT_EQ(BB->size(), 2U);389 390  CallInst *GTID = dyn_cast<CallInst>(&BB->front());391  EXPECT_NE(GTID, nullptr);392  EXPECT_EQ(GTID->arg_size(), 1U);393  EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num");394  EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory());395  EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory());396 397  CallInst *Barrier = dyn_cast<CallInst>(GTID->getNextNode());398  EXPECT_NE(Barrier, nullptr);399  EXPECT_EQ(Barrier->arg_size(), 2U);400  EXPECT_EQ(Barrier->getCalledFunction()->getName(), "__kmpc_barrier");401  EXPECT_FALSE(Barrier->getCalledFunction()->doesNotAccessMemory());402  EXPECT_FALSE(Barrier->getCalledFunction()->doesNotFreeMemory());403 404  EXPECT_EQ(cast<CallInst>(Barrier)->getArgOperand(1), GTID);405 406  Builder.CreateUnreachable();407  EXPECT_FALSE(verifyModule(*M, &errs()));408}409 410TEST_F(OpenMPIRBuilderTest, CreateCancel) {411  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;412  OpenMPIRBuilder OMPBuilder(*M);413  OMPBuilder.initialize();414 415  BasicBlock *CBB = BasicBlock::Create(Ctx, "", F);416  new UnreachableInst(Ctx, CBB);417  auto FiniCB = [&](InsertPointTy IP) {418    ASSERT_NE(IP.getBlock(), nullptr);419    ASSERT_EQ(IP.getBlock()->end(), IP.getPoint());420    BranchInst::Create(CBB, IP.getBlock());421  };422  OMPBuilder.pushFinalizationCB({FINICB_WRAPPER(FiniCB), OMPD_parallel, true});423 424  IRBuilder<> Builder(BB);425 426  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()});427  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, NewIP,428                       OMPBuilder.createCancel(Loc, nullptr, OMPD_parallel));429  Builder.restoreIP(NewIP);430  EXPECT_FALSE(M->global_empty());431  EXPECT_EQ(M->size(), 3U);432  EXPECT_EQ(F->size(), 5U);433  EXPECT_EQ(BB->size(), 4U);434 435  CallInst *GTID = dyn_cast<CallInst>(&BB->front());436  EXPECT_NE(GTID, nullptr);437  EXPECT_EQ(GTID->arg_size(), 1U);438  EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num");439  EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory());440  EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory());441 442  CallInst *Cancel = dyn_cast<CallInst>(GTID->getNextNode());443  EXPECT_NE(Cancel, nullptr);444  EXPECT_EQ(Cancel->arg_size(), 3U);445  EXPECT_EQ(Cancel->getCalledFunction()->getName(), "__kmpc_cancel");446  EXPECT_FALSE(Cancel->getCalledFunction()->doesNotAccessMemory());447  EXPECT_FALSE(Cancel->getCalledFunction()->doesNotFreeMemory());448  EXPECT_TRUE(Cancel->hasOneUse());449  Instruction *CancelBBTI = Cancel->getParent()->getTerminator();450  EXPECT_EQ(CancelBBTI->getNumSuccessors(), 2U);451  EXPECT_EQ(CancelBBTI->getSuccessor(0), NewIP.getBlock());452  EXPECT_EQ(CancelBBTI->getSuccessor(1)->size(), 1U);453  EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getNumSuccessors(),454            1U);455  // cancel branch instruction (1) -> .cncl -> .fini -> CBB456  EXPECT_EQ(CancelBBTI->getSuccessor(1)457                ->getTerminator()458                ->getSuccessor(0)459                ->getTerminator()460                ->getSuccessor(0),461            CBB);462 463  EXPECT_EQ(cast<CallInst>(Cancel)->getArgOperand(1), GTID);464 465  OMPBuilder.popFinalizationCB();466 467  Builder.CreateUnreachable();468  EXPECT_FALSE(verifyModule(*M, &errs()));469}470 471TEST_F(OpenMPIRBuilderTest, CreateCancelIfCond) {472  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;473  OpenMPIRBuilder OMPBuilder(*M);474  OMPBuilder.initialize();475 476  BasicBlock *CBB = BasicBlock::Create(Ctx, "", F);477  new UnreachableInst(Ctx, CBB);478  auto FiniCB = [&](InsertPointTy IP) {479    ASSERT_NE(IP.getBlock(), nullptr);480    ASSERT_EQ(IP.getBlock()->end(), IP.getPoint());481    BranchInst::Create(CBB, IP.getBlock());482  };483  OMPBuilder.pushFinalizationCB({FINICB_WRAPPER(FiniCB), OMPD_parallel, true});484 485  IRBuilder<> Builder(BB);486 487  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()});488  ASSERT_EXPECTED_INIT(489      OpenMPIRBuilder::InsertPointTy, NewIP,490      OMPBuilder.createCancel(Loc, Builder.getTrue(), OMPD_parallel));491  Builder.restoreIP(NewIP);492  EXPECT_FALSE(M->global_empty());493  EXPECT_EQ(M->size(), 4U);494  EXPECT_EQ(F->size(), 10U);495  EXPECT_EQ(BB->size(), 1U);496  ASSERT_TRUE(isa<BranchInst>(BB->getTerminator()));497  ASSERT_EQ(BB->getTerminator()->getNumSuccessors(), 2U);498  BB = BB->getTerminator()->getSuccessor(0);499  EXPECT_EQ(BB->size(), 4U);500 501  CallInst *GTID = dyn_cast<CallInst>(&BB->front());502  EXPECT_NE(GTID, nullptr);503  EXPECT_EQ(GTID->arg_size(), 1U);504  EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num");505  EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory());506  EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory());507 508  CallInst *Cancel = dyn_cast<CallInst>(GTID->getNextNode());509  EXPECT_NE(Cancel, nullptr);510  EXPECT_EQ(Cancel->arg_size(), 3U);511  EXPECT_EQ(Cancel->getCalledFunction()->getName(), "__kmpc_cancel");512  EXPECT_FALSE(Cancel->getCalledFunction()->doesNotAccessMemory());513  EXPECT_FALSE(Cancel->getCalledFunction()->doesNotFreeMemory());514  EXPECT_TRUE(Cancel->hasOneUse());515  Instruction *CancelBBTI = Cancel->getParent()->getTerminator();516  EXPECT_EQ(CancelBBTI->getNumSuccessors(), 2U);517  EXPECT_EQ(CancelBBTI->getSuccessor(0)->size(), 1U);518  EXPECT_EQ(CancelBBTI->getSuccessor(0)->getUniqueSuccessor(),519            NewIP.getBlock());520  EXPECT_EQ(CancelBBTI->getSuccessor(1)->size(), 1U);521  EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getNumSuccessors(),522            1U);523  EXPECT_EQ(CancelBBTI->getSuccessor(1)524                ->getTerminator()525                ->getSuccessor(0)526                ->getTerminator()527                ->getSuccessor(0),528            CBB);529 530  EXPECT_EQ(cast<CallInst>(Cancel)->getArgOperand(1), GTID);531 532  OMPBuilder.popFinalizationCB();533 534  Builder.CreateUnreachable();535  EXPECT_FALSE(verifyModule(*M, &errs()));536}537 538TEST_F(OpenMPIRBuilderTest, CreateCancelBarrier) {539  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;540  OpenMPIRBuilder OMPBuilder(*M);541  OMPBuilder.initialize();542 543  BasicBlock *CBB = BasicBlock::Create(Ctx, "", F);544  new UnreachableInst(Ctx, CBB);545  auto FiniCB = [&](InsertPointTy IP) {546    ASSERT_NE(IP.getBlock(), nullptr);547    ASSERT_EQ(IP.getBlock()->end(), IP.getPoint());548    BranchInst::Create(CBB, IP.getBlock());549  };550  OMPBuilder.pushFinalizationCB({FINICB_WRAPPER(FiniCB), OMPD_parallel, true});551 552  IRBuilder<> Builder(BB);553 554  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()});555  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, NewIP,556                       OMPBuilder.createBarrier(Loc, OMPD_for));557  Builder.restoreIP(NewIP);558  EXPECT_FALSE(M->global_empty());559  EXPECT_EQ(M->size(), 3U);560  EXPECT_EQ(F->size(), 5U);561  EXPECT_EQ(BB->size(), 4U);562 563  CallInst *GTID = dyn_cast<CallInst>(&BB->front());564  EXPECT_NE(GTID, nullptr);565  EXPECT_EQ(GTID->arg_size(), 1U);566  EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num");567  EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory());568  EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory());569 570  CallInst *Barrier = dyn_cast<CallInst>(GTID->getNextNode());571  EXPECT_NE(Barrier, nullptr);572  EXPECT_EQ(Barrier->arg_size(), 2U);573  EXPECT_EQ(Barrier->getCalledFunction()->getName(), "__kmpc_cancel_barrier");574  EXPECT_FALSE(Barrier->getCalledFunction()->doesNotAccessMemory());575  EXPECT_FALSE(Barrier->getCalledFunction()->doesNotFreeMemory());576  EXPECT_TRUE(Barrier->hasOneUse());577  Instruction *BarrierBBTI = Barrier->getParent()->getTerminator();578  EXPECT_EQ(BarrierBBTI->getNumSuccessors(), 2U);579  EXPECT_EQ(BarrierBBTI->getSuccessor(0), NewIP.getBlock());580  EXPECT_EQ(BarrierBBTI->getSuccessor(1)->size(), 1U);581  EXPECT_EQ(BarrierBBTI->getSuccessor(1)->getTerminator()->getNumSuccessors(),582            1U);583  EXPECT_EQ(BarrierBBTI->getSuccessor(1)584                ->getTerminator()585                ->getSuccessor(0)586                ->getTerminator()587                ->getSuccessor(0),588            CBB);589 590  EXPECT_EQ(cast<CallInst>(Barrier)->getArgOperand(1), GTID);591 592  OMPBuilder.popFinalizationCB();593 594  Builder.CreateUnreachable();595  EXPECT_FALSE(verifyModule(*M, &errs()));596}597 598TEST_F(OpenMPIRBuilderTest, DbgLoc) {599  OpenMPIRBuilder OMPBuilder(*M);600  OMPBuilder.initialize();601  F->setName("func");602 603  IRBuilder<> Builder(BB);604 605  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});606  ASSERT_THAT_EXPECTED(OMPBuilder.createBarrier(Loc, OMPD_for), Succeeded());607  CallInst *GTID = dyn_cast<CallInst>(&BB->front());608  CallInst *Barrier = dyn_cast<CallInst>(GTID->getNextNode());609  EXPECT_EQ(GTID->getDebugLoc(), DL);610  EXPECT_EQ(Barrier->getDebugLoc(), DL);611  EXPECT_TRUE(isa<GlobalVariable>(Barrier->getOperand(0)));612  if (!isa<GlobalVariable>(Barrier->getOperand(0)))613    return;614  GlobalVariable *Ident = cast<GlobalVariable>(Barrier->getOperand(0));615  EXPECT_TRUE(Ident->hasInitializer());616  if (!Ident->hasInitializer())617    return;618  Constant *Initializer = Ident->getInitializer();619  EXPECT_TRUE(620      isa<GlobalVariable>(Initializer->getOperand(4)->stripPointerCasts()));621  GlobalVariable *SrcStrGlob =622      cast<GlobalVariable>(Initializer->getOperand(4)->stripPointerCasts());623  if (!SrcStrGlob)624    return;625  EXPECT_TRUE(isa<ConstantDataArray>(SrcStrGlob->getInitializer()));626  ConstantDataArray *SrcSrc =627      dyn_cast<ConstantDataArray>(SrcStrGlob->getInitializer());628  if (!SrcSrc)629    return;630  EXPECT_EQ(SrcSrc->getAsCString(), ";/src/test.dbg;foo;3;7;;");631}632 633TEST_F(OpenMPIRBuilderTest, ParallelSimpleGPU) {634  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;635  std::string oldDLStr = M->getDataLayoutStr();636  M->setDataLayout(637      "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:"638      "256:256:32-p8:128:128:128:48-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-"639      "v192:"640      "256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8");641  OpenMPIRBuilder OMPBuilder(*M);642  OMPBuilder.Config.IsTargetDevice = true;643  OMPBuilder.initialize();644  F->setName("func");645  IRBuilder<> Builder(BB);646  BasicBlock *EnterBB = BasicBlock::Create(Ctx, "parallel.enter", F);647  Builder.CreateBr(EnterBB);648  Builder.SetInsertPoint(EnterBB);649  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});650 651  AllocaInst *PrivAI = nullptr;652 653  unsigned NumBodiesGenerated = 0;654  unsigned NumPrivatizedVars = 0;655  unsigned NumFinalizationPoints = 0;656 657  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {658    ++NumBodiesGenerated;659 660    Builder.restoreIP(AllocaIP);661    PrivAI = Builder.CreateAlloca(F->arg_begin()->getType());662    Builder.CreateStore(F->arg_begin(), PrivAI);663 664    Builder.restoreIP(CodeGenIP);665    Value *PrivLoad =666        Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use");667    Value *Cmp = Builder.CreateICmpNE(F->arg_begin(), PrivLoad);668    Instruction *ThenTerm, *ElseTerm;669    SplitBlockAndInsertIfThenElse(Cmp, CodeGenIP.getBlock()->getTerminator(),670                                  &ThenTerm, &ElseTerm);671    return Error::success();672  };673 674  auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,675                    Value &Orig, Value &Inner,676                    Value *&ReplacementValue) -> InsertPointTy {677    ++NumPrivatizedVars;678 679    if (!isa<AllocaInst>(Orig)) {680      EXPECT_EQ(&Orig, F->arg_begin());681      ReplacementValue = &Inner;682      return CodeGenIP;683    }684 685    // Since the original value is an allocation, it has a pointer type and686    // therefore no additional wrapping should happen.687    EXPECT_EQ(&Orig, &Inner);688 689    // Trivial copy (=firstprivate).690    Builder.restoreIP(AllocaIP);691    Type *VTy = ReplacementValue->getType();692    Value *V = Builder.CreateLoad(VTy, &Inner, Orig.getName() + ".reload");693    ReplacementValue = Builder.CreateAlloca(VTy, 0, Orig.getName() + ".copy");694    Builder.restoreIP(CodeGenIP);695    Builder.CreateStore(V, ReplacementValue);696    return CodeGenIP;697  };698 699  auto FiniCB = [&](InsertPointTy CodeGenIP) {700    ++NumFinalizationPoints;701    return Error::success();702  };703 704  IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(),705                                    F->getEntryBlock().getFirstInsertionPt());706  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,707                       OMPBuilder.createParallel(708                           Loc, AllocaIP, BodyGenCB, PrivCB, FiniCB, nullptr,709                           nullptr, OMP_PROC_BIND_default, false));710 711  EXPECT_EQ(NumBodiesGenerated, 1U);712  EXPECT_EQ(NumPrivatizedVars, 1U);713  EXPECT_EQ(NumFinalizationPoints, 1U);714 715  Builder.restoreIP(AfterIP);716  Builder.CreateRetVoid();717 718  OMPBuilder.finalize();719  Function *OutlinedFn = PrivAI->getFunction();720  EXPECT_FALSE(verifyModule(*M, &errs()));721  EXPECT_NE(OutlinedFn, F);722  EXPECT_TRUE(OutlinedFn->hasFnAttribute(Attribute::NoUnwind));723  EXPECT_TRUE(OutlinedFn->hasParamAttribute(0, Attribute::NoAlias));724  EXPECT_TRUE(OutlinedFn->hasParamAttribute(1, Attribute::NoAlias));725 726  EXPECT_TRUE(OutlinedFn->hasInternalLinkage());727  EXPECT_EQ(OutlinedFn->arg_size(), 3U);728  // Make sure that arguments are pointers in 0 address address space729  EXPECT_EQ(OutlinedFn->getArg(0)->getType(),730            PointerType::get(M->getContext(), 0));731  EXPECT_EQ(OutlinedFn->getArg(1)->getType(),732            PointerType::get(M->getContext(), 0));733  EXPECT_EQ(OutlinedFn->getArg(2)->getType(),734            PointerType::get(M->getContext(), 0));735  EXPECT_EQ(&OutlinedFn->getEntryBlock(), PrivAI->getParent());736  EXPECT_TRUE(OutlinedFn->hasOneUse());737  User *Usr = OutlinedFn->user_back();738  ASSERT_TRUE(isa<CallInst>(Usr));739  CallInst *Parallel51CI = dyn_cast<CallInst>(Usr);740  ASSERT_NE(Parallel51CI, nullptr);741 742  EXPECT_EQ(Parallel51CI->getCalledFunction()->getName(), "__kmpc_parallel_51");743  EXPECT_EQ(Parallel51CI->arg_size(), 9U);744  EXPECT_EQ(Parallel51CI->getArgOperand(5), OutlinedFn);745  EXPECT_TRUE(746      isa<GlobalVariable>(Parallel51CI->getArgOperand(0)->stripPointerCasts()));747  EXPECT_EQ(Parallel51CI, Usr);748  M->setDataLayout(oldDLStr);749}750 751TEST_F(OpenMPIRBuilderTest, ParallelSimple) {752  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;753  OpenMPIRBuilder OMPBuilder(*M);754  OMPBuilder.Config.IsTargetDevice = false;755  OMPBuilder.initialize();756  F->setName("func");757  IRBuilder<> Builder(BB);758 759  BasicBlock *EnterBB = BasicBlock::Create(Ctx, "parallel.enter", F);760  Builder.CreateBr(EnterBB);761  Builder.SetInsertPoint(EnterBB);762  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});763 764  AllocaInst *PrivAI = nullptr;765 766  unsigned NumBodiesGenerated = 0;767  unsigned NumPrivatizedVars = 0;768  unsigned NumFinalizationPoints = 0;769 770  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {771    ++NumBodiesGenerated;772 773    Builder.restoreIP(AllocaIP);774    PrivAI = Builder.CreateAlloca(F->arg_begin()->getType());775    Builder.CreateStore(F->arg_begin(), PrivAI);776 777    Builder.restoreIP(CodeGenIP);778    Value *PrivLoad =779        Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use");780    Value *Cmp = Builder.CreateICmpNE(F->arg_begin(), PrivLoad);781    Instruction *ThenTerm, *ElseTerm;782    SplitBlockAndInsertIfThenElse(Cmp, CodeGenIP.getBlock()->getTerminator(),783                                  &ThenTerm, &ElseTerm);784    return Error::success();785  };786 787  auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,788                    Value &Orig, Value &Inner,789                    Value *&ReplacementValue) -> InsertPointTy {790    ++NumPrivatizedVars;791 792    if (!isa<AllocaInst>(Orig)) {793      EXPECT_EQ(&Orig, F->arg_begin());794      ReplacementValue = &Inner;795      return CodeGenIP;796    }797 798    // Since the original value is an allocation, it has a pointer type and799    // therefore no additional wrapping should happen.800    EXPECT_EQ(&Orig, &Inner);801 802    // Trivial copy (=firstprivate).803    Builder.restoreIP(AllocaIP);804    Type *VTy = ReplacementValue->getType();805    Value *V = Builder.CreateLoad(VTy, &Inner, Orig.getName() + ".reload");806    ReplacementValue = Builder.CreateAlloca(VTy, 0, Orig.getName() + ".copy");807    Builder.restoreIP(CodeGenIP);808    Builder.CreateStore(V, ReplacementValue);809    return CodeGenIP;810  };811 812  auto FiniCB = [&](InsertPointTy CodeGenIP) {813    ++NumFinalizationPoints;814    return Error::success();815  };816 817  IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(),818                                    F->getEntryBlock().getFirstInsertionPt());819  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,820                       OMPBuilder.createParallel(821                           Loc, AllocaIP, BodyGenCB, PrivCB, FiniCB, nullptr,822                           nullptr, OMP_PROC_BIND_default, false));823  EXPECT_EQ(NumBodiesGenerated, 1U);824  EXPECT_EQ(NumPrivatizedVars, 1U);825  EXPECT_EQ(NumFinalizationPoints, 1U);826 827  Builder.restoreIP(AfterIP);828  Builder.CreateRetVoid();829 830  OMPBuilder.finalize();831 832  EXPECT_NE(PrivAI, nullptr);833  Function *OutlinedFn = PrivAI->getFunction();834  EXPECT_NE(F, OutlinedFn);835  EXPECT_FALSE(verifyModule(*M, &errs()));836  EXPECT_TRUE(OutlinedFn->hasFnAttribute(Attribute::NoUnwind));837  EXPECT_TRUE(OutlinedFn->hasParamAttribute(0, Attribute::NoAlias));838  EXPECT_TRUE(OutlinedFn->hasParamAttribute(1, Attribute::NoAlias));839 840  EXPECT_TRUE(OutlinedFn->hasInternalLinkage());841  EXPECT_EQ(OutlinedFn->arg_size(), 3U);842 843  EXPECT_EQ(&OutlinedFn->getEntryBlock(), PrivAI->getParent());844  EXPECT_TRUE(OutlinedFn->hasOneUse());845  User *Usr = OutlinedFn->user_back();846  ASSERT_TRUE(isa<CallInst>(Usr));847  CallInst *ForkCI = dyn_cast<CallInst>(Usr);848  ASSERT_NE(ForkCI, nullptr);849 850  EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call");851  EXPECT_EQ(ForkCI->arg_size(), 4U);852  EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0)));853  EXPECT_EQ(ForkCI->getArgOperand(1),854            ConstantInt::get(Type::getInt32Ty(Ctx), 1U));855  EXPECT_EQ(ForkCI, Usr);856  Value *StoredValue =857      findStoredValueInAggregateAt(Ctx, ForkCI->getArgOperand(3), 0);858  EXPECT_EQ(StoredValue, F->arg_begin());859}860 861TEST_F(OpenMPIRBuilderTest, ParallelNested) {862  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;863  OpenMPIRBuilder OMPBuilder(*M);864  OMPBuilder.Config.IsTargetDevice = false;865  OMPBuilder.initialize();866  F->setName("func");867  IRBuilder<> Builder(BB);868 869  BasicBlock *EnterBB = BasicBlock::Create(Ctx, "parallel.enter", F);870  Builder.CreateBr(EnterBB);871  Builder.SetInsertPoint(EnterBB);872  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});873 874  unsigned NumInnerBodiesGenerated = 0;875  unsigned NumOuterBodiesGenerated = 0;876  unsigned NumFinalizationPoints = 0;877 878  auto InnerBodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {879    ++NumInnerBodiesGenerated;880    return Error::success();881  };882 883  auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,884                    Value &Orig, Value &Inner,885                    Value *&ReplacementValue) -> InsertPointTy {886    // Trivial copy (=firstprivate).887    Builder.restoreIP(AllocaIP);888    Type *VTy = ReplacementValue->getType();889    Value *V = Builder.CreateLoad(VTy, &Inner, Orig.getName() + ".reload");890    ReplacementValue = Builder.CreateAlloca(VTy, 0, Orig.getName() + ".copy");891    Builder.restoreIP(CodeGenIP);892    Builder.CreateStore(V, ReplacementValue);893    return CodeGenIP;894  };895 896  auto FiniCB = [&](InsertPointTy CodeGenIP) {897    ++NumFinalizationPoints;898    return Error::success();899  };900 901  auto OuterBodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {902    ++NumOuterBodiesGenerated;903    Builder.restoreIP(CodeGenIP);904    BasicBlock *CGBB = CodeGenIP.getBlock();905    BasicBlock *NewBB = SplitBlock(CGBB, &*CodeGenIP.getPoint());906    CGBB->getTerminator()->eraseFromParent();907 908    ASSERT_EXPECTED_INIT(909        OpenMPIRBuilder::InsertPointTy, AfterIP,910        OMPBuilder.createParallel(InsertPointTy(CGBB, CGBB->end()), AllocaIP,911                                  InnerBodyGenCB, PrivCB, FiniCB, nullptr,912                                  nullptr, OMP_PROC_BIND_default, false));913 914    Builder.restoreIP(AfterIP);915    Builder.CreateBr(NewBB);916  };917 918  IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(),919                                    F->getEntryBlock().getFirstInsertionPt());920  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,921                       OMPBuilder.createParallel(922                           Loc, AllocaIP, BODYGENCB_WRAPPER(OuterBodyGenCB),923                           PrivCB, FiniCB, nullptr, nullptr,924                           OMP_PROC_BIND_default, false));925 926  EXPECT_EQ(NumInnerBodiesGenerated, 1U);927  EXPECT_EQ(NumOuterBodiesGenerated, 1U);928  EXPECT_EQ(NumFinalizationPoints, 2U);929 930  Builder.restoreIP(AfterIP);931  Builder.CreateRetVoid();932 933  OMPBuilder.finalize();934 935  EXPECT_EQ(M->size(), 5U);936  for (Function &OutlinedFn : *M) {937    if (F == &OutlinedFn || OutlinedFn.isDeclaration())938      continue;939    EXPECT_FALSE(verifyModule(*M, &errs()));940    EXPECT_TRUE(OutlinedFn.hasFnAttribute(Attribute::NoUnwind));941    EXPECT_TRUE(OutlinedFn.hasParamAttribute(0, Attribute::NoAlias));942    EXPECT_TRUE(OutlinedFn.hasParamAttribute(1, Attribute::NoAlias));943 944    EXPECT_TRUE(OutlinedFn.hasInternalLinkage());945    EXPECT_EQ(OutlinedFn.arg_size(), 2U);946 947    EXPECT_TRUE(OutlinedFn.hasOneUse());948    User *Usr = OutlinedFn.user_back();949    ASSERT_TRUE(isa<CallInst>(Usr));950    CallInst *ForkCI = dyn_cast<CallInst>(Usr);951    ASSERT_NE(ForkCI, nullptr);952 953    EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call");954    EXPECT_EQ(ForkCI->arg_size(), 3U);955    EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0)));956    EXPECT_EQ(ForkCI->getArgOperand(1),957              ConstantInt::get(Type::getInt32Ty(Ctx), 0U));958    EXPECT_EQ(ForkCI, Usr);959  }960}961 962TEST_F(OpenMPIRBuilderTest, ParallelNested2Inner) {963  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;964  OpenMPIRBuilder OMPBuilder(*M);965  OMPBuilder.Config.IsTargetDevice = false;966  OMPBuilder.initialize();967  F->setName("func");968  IRBuilder<> Builder(BB);969 970  BasicBlock *EnterBB = BasicBlock::Create(Ctx, "parallel.enter", F);971  Builder.CreateBr(EnterBB);972  Builder.SetInsertPoint(EnterBB);973  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});974 975  unsigned NumInnerBodiesGenerated = 0;976  unsigned NumOuterBodiesGenerated = 0;977  unsigned NumFinalizationPoints = 0;978 979  auto InnerBodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {980    ++NumInnerBodiesGenerated;981    return Error::success();982  };983 984  auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,985                    Value &Orig, Value &Inner,986                    Value *&ReplacementValue) -> InsertPointTy {987    // Trivial copy (=firstprivate).988    Builder.restoreIP(AllocaIP);989    Type *VTy = ReplacementValue->getType();990    Value *V = Builder.CreateLoad(VTy, &Inner, Orig.getName() + ".reload");991    ReplacementValue = Builder.CreateAlloca(VTy, 0, Orig.getName() + ".copy");992    Builder.restoreIP(CodeGenIP);993    Builder.CreateStore(V, ReplacementValue);994    return CodeGenIP;995  };996 997  auto FiniCB = [&](InsertPointTy CodeGenIP) {998    ++NumFinalizationPoints;999    return Error::success();1000  };1001 1002  auto OuterBodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {1003    ++NumOuterBodiesGenerated;1004    Builder.restoreIP(CodeGenIP);1005    BasicBlock *CGBB = CodeGenIP.getBlock();1006    BasicBlock *NewBB1 = SplitBlock(CGBB, &*CodeGenIP.getPoint());1007    BasicBlock *NewBB2 = SplitBlock(NewBB1, &*NewBB1->getFirstInsertionPt());1008    CGBB->getTerminator()->eraseFromParent();1009    ;1010    NewBB1->getTerminator()->eraseFromParent();1011    ;1012 1013    ASSERT_EXPECTED_INIT(1014        OpenMPIRBuilder::InsertPointTy, AfterIP1,1015        OMPBuilder.createParallel(InsertPointTy(CGBB, CGBB->end()), AllocaIP,1016                                  InnerBodyGenCB, PrivCB, FiniCB, nullptr,1017                                  nullptr, OMP_PROC_BIND_default, false));1018 1019    Builder.restoreIP(AfterIP1);1020    Builder.CreateBr(NewBB1);1021 1022    ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP2,1023                         OMPBuilder.createParallel(1024                             InsertPointTy(NewBB1, NewBB1->end()), AllocaIP,1025                             InnerBodyGenCB, PrivCB, FiniCB, nullptr, nullptr,1026                             OMP_PROC_BIND_default, false));1027 1028    Builder.restoreIP(AfterIP2);1029    Builder.CreateBr(NewBB2);1030  };1031 1032  IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(),1033                                    F->getEntryBlock().getFirstInsertionPt());1034  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,1035                       OMPBuilder.createParallel(1036                           Loc, AllocaIP, BODYGENCB_WRAPPER(OuterBodyGenCB),1037                           PrivCB, FiniCB, nullptr, nullptr,1038                           OMP_PROC_BIND_default, false));1039 1040  EXPECT_EQ(NumInnerBodiesGenerated, 2U);1041  EXPECT_EQ(NumOuterBodiesGenerated, 1U);1042  EXPECT_EQ(NumFinalizationPoints, 3U);1043 1044  Builder.restoreIP(AfterIP);1045  Builder.CreateRetVoid();1046 1047  OMPBuilder.finalize();1048 1049  EXPECT_EQ(M->size(), 6U);1050  for (Function &OutlinedFn : *M) {1051    if (F == &OutlinedFn || OutlinedFn.isDeclaration())1052      continue;1053    EXPECT_FALSE(verifyModule(*M, &errs()));1054    EXPECT_TRUE(OutlinedFn.hasFnAttribute(Attribute::NoUnwind));1055    EXPECT_TRUE(OutlinedFn.hasParamAttribute(0, Attribute::NoAlias));1056    EXPECT_TRUE(OutlinedFn.hasParamAttribute(1, Attribute::NoAlias));1057 1058    EXPECT_TRUE(OutlinedFn.hasInternalLinkage());1059    EXPECT_EQ(OutlinedFn.arg_size(), 2U);1060 1061    unsigned NumAllocas = 0;1062    for (Instruction &I : instructions(OutlinedFn))1063      NumAllocas += isa<AllocaInst>(I);1064    EXPECT_EQ(NumAllocas, 1U);1065 1066    EXPECT_TRUE(OutlinedFn.hasOneUse());1067    User *Usr = OutlinedFn.user_back();1068    ASSERT_TRUE(isa<CallInst>(Usr));1069    CallInst *ForkCI = dyn_cast<CallInst>(Usr);1070    ASSERT_NE(ForkCI, nullptr);1071 1072    EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call");1073    EXPECT_EQ(ForkCI->arg_size(), 3U);1074    EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0)));1075    EXPECT_EQ(ForkCI->getArgOperand(1),1076              ConstantInt::get(Type::getInt32Ty(Ctx), 0U));1077    EXPECT_EQ(ForkCI, Usr);1078  }1079}1080 1081TEST_F(OpenMPIRBuilderTest, ParallelIfCond) {1082  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;1083  OpenMPIRBuilder OMPBuilder(*M);1084  OMPBuilder.Config.IsTargetDevice = false;1085  OMPBuilder.initialize();1086  F->setName("func");1087  IRBuilder<> Builder(BB);1088 1089  BasicBlock *EnterBB = BasicBlock::Create(Ctx, "parallel.enter", F);1090  Builder.CreateBr(EnterBB);1091  Builder.SetInsertPoint(EnterBB);1092  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});1093 1094  AllocaInst *PrivAI = nullptr;1095 1096  unsigned NumBodiesGenerated = 0;1097  unsigned NumPrivatizedVars = 0;1098  unsigned NumFinalizationPoints = 0;1099 1100  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {1101    ++NumBodiesGenerated;1102 1103    Builder.restoreIP(AllocaIP);1104    PrivAI = Builder.CreateAlloca(F->arg_begin()->getType());1105    Builder.CreateStore(F->arg_begin(), PrivAI);1106 1107    Builder.restoreIP(CodeGenIP);1108    Value *PrivLoad =1109        Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use");1110    Value *Cmp = Builder.CreateICmpNE(F->arg_begin(), PrivLoad);1111    Instruction *ThenTerm, *ElseTerm;1112    SplitBlockAndInsertIfThenElse(Cmp, &*Builder.GetInsertPoint(), &ThenTerm,1113                                  &ElseTerm);1114    return Error::success();1115  };1116 1117  auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,1118                    Value &Orig, Value &Inner,1119                    Value *&ReplacementValue) -> InsertPointTy {1120    ++NumPrivatizedVars;1121 1122    if (!isa<AllocaInst>(Orig)) {1123      EXPECT_EQ(&Orig, F->arg_begin());1124      ReplacementValue = &Inner;1125      return CodeGenIP;1126    }1127 1128    // Since the original value is an allocation, it has a pointer type and1129    // therefore no additional wrapping should happen.1130    EXPECT_EQ(&Orig, &Inner);1131 1132    // Trivial copy (=firstprivate).1133    Builder.restoreIP(AllocaIP);1134    Type *VTy = ReplacementValue->getType();1135    Value *V = Builder.CreateLoad(VTy, &Inner, Orig.getName() + ".reload");1136    ReplacementValue = Builder.CreateAlloca(VTy, 0, Orig.getName() + ".copy");1137    Builder.restoreIP(CodeGenIP);1138    Builder.CreateStore(V, ReplacementValue);1139    return CodeGenIP;1140  };1141 1142  auto FiniCB = [&](InsertPointTy CodeGenIP) {1143    ++NumFinalizationPoints;1144    // No destructors.1145    return Error::success();1146  };1147 1148  IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(),1149                                    F->getEntryBlock().getFirstInsertionPt());1150  ASSERT_EXPECTED_INIT(1151      OpenMPIRBuilder::InsertPointTy, AfterIP,1152      OMPBuilder.createParallel(Loc, AllocaIP, BodyGenCB, PrivCB, FiniCB,1153                                Builder.CreateIsNotNull(F->arg_begin()),1154                                nullptr, OMP_PROC_BIND_default, false));1155 1156  EXPECT_EQ(NumBodiesGenerated, 1U);1157  EXPECT_EQ(NumPrivatizedVars, 1U);1158  EXPECT_EQ(NumFinalizationPoints, 1U);1159 1160  Builder.restoreIP(AfterIP);1161  Builder.CreateRetVoid();1162  OMPBuilder.finalize();1163 1164  EXPECT_NE(PrivAI, nullptr);1165  Function *OutlinedFn = PrivAI->getFunction();1166  EXPECT_NE(F, OutlinedFn);1167  EXPECT_FALSE(verifyModule(*M, &errs()));1168 1169  EXPECT_TRUE(OutlinedFn->hasInternalLinkage());1170  EXPECT_EQ(OutlinedFn->arg_size(), 3U);1171 1172  EXPECT_EQ(&OutlinedFn->getEntryBlock(), PrivAI->getParent());1173  ASSERT_TRUE(OutlinedFn->hasOneUse());1174 1175  CallInst *ForkCI = nullptr;1176  for (User *Usr : OutlinedFn->users()) {1177    ASSERT_TRUE(isa<CallInst>(Usr));1178    ForkCI = cast<CallInst>(Usr);1179  }1180 1181  EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call_if");1182  EXPECT_EQ(ForkCI->arg_size(), 5U);1183  EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0)));1184  EXPECT_EQ(ForkCI->getArgOperand(1),1185            ConstantInt::get(Type::getInt32Ty(Ctx), 1));1186  EXPECT_EQ(ForkCI->getArgOperand(3)->getType(), Type::getInt32Ty(Ctx));1187}1188 1189TEST_F(OpenMPIRBuilderTest, ParallelCancelBarrier) {1190  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;1191  OpenMPIRBuilder OMPBuilder(*M);1192  OMPBuilder.Config.IsTargetDevice = false;1193  OMPBuilder.initialize();1194  F->setName("func");1195  IRBuilder<> Builder(BB);1196 1197  BasicBlock *EnterBB = BasicBlock::Create(Ctx, "parallel.enter", F);1198  Builder.CreateBr(EnterBB);1199  Builder.SetInsertPoint(EnterBB);1200  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});1201 1202  unsigned NumBodiesGenerated = 0;1203  unsigned NumPrivatizedVars = 0;1204  unsigned NumFinalizationPoints = 0;1205 1206  CallInst *CheckedBarrier = nullptr;1207  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {1208    ++NumBodiesGenerated;1209 1210    Builder.restoreIP(CodeGenIP);1211 1212    // Create three barriers, two cancel barriers but only one checked.1213    Function *CBFn, *BFn;1214 1215    ASSERT_EXPECTED_INIT(1216        OpenMPIRBuilder::InsertPointTy, BarrierIP1,1217        OMPBuilder.createBarrier(Builder.saveIP(), OMPD_parallel));1218    Builder.restoreIP(BarrierIP1);1219 1220    CBFn = M->getFunction("__kmpc_cancel_barrier");1221    BFn = M->getFunction("__kmpc_barrier");1222    ASSERT_NE(CBFn, nullptr);1223    ASSERT_EQ(BFn, nullptr);1224    ASSERT_TRUE(CBFn->hasOneUse());1225    ASSERT_TRUE(isa<CallInst>(CBFn->user_back()));1226    ASSERT_TRUE(CBFn->user_back()->hasOneUse());1227    CheckedBarrier = cast<CallInst>(CBFn->user_back());1228 1229    ASSERT_EXPECTED_INIT(1230        OpenMPIRBuilder::InsertPointTy, BarrierIP2,1231        OMPBuilder.createBarrier(Builder.saveIP(), OMPD_parallel, true));1232    Builder.restoreIP(BarrierIP2);1233    CBFn = M->getFunction("__kmpc_cancel_barrier");1234    BFn = M->getFunction("__kmpc_barrier");1235    ASSERT_NE(CBFn, nullptr);1236    ASSERT_NE(BFn, nullptr);1237    ASSERT_TRUE(CBFn->hasOneUse());1238    ASSERT_TRUE(BFn->hasOneUse());1239    ASSERT_TRUE(isa<CallInst>(BFn->user_back()));1240    ASSERT_TRUE(BFn->user_back()->use_empty());1241 1242    ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, BarrierIP3,1243                         OMPBuilder.createBarrier(Builder.saveIP(),1244                                                  OMPD_parallel, false, false));1245    Builder.restoreIP(BarrierIP3);1246    ASSERT_TRUE(CBFn->hasNUses(2));1247    ASSERT_TRUE(BFn->hasOneUse());1248    ASSERT_TRUE(CBFn->user_back() != CheckedBarrier);1249    ASSERT_TRUE(isa<CallInst>(CBFn->user_back()));1250    ASSERT_TRUE(CBFn->user_back()->use_empty());1251  };1252 1253  auto PrivCB = [&](InsertPointTy, InsertPointTy, Value &V, Value &,1254                    Value *&) -> InsertPointTy {1255    ++NumPrivatizedVars;1256    llvm_unreachable("No privatization callback call expected!");1257  };1258 1259  FunctionType *FakeDestructorTy =1260      FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt32Ty(Ctx)},1261                        /*isVarArg=*/false);1262  auto *FakeDestructor = Function::Create(1263      FakeDestructorTy, Function::ExternalLinkage, "fakeDestructor", M.get());1264 1265  auto FiniCB = [&](InsertPointTy IP) {1266    ++NumFinalizationPoints;1267    Builder.restoreIP(IP);1268    Builder.CreateCall(FakeDestructor,1269                       {Builder.getInt32(NumFinalizationPoints)});1270    return Error::success();1271  };1272 1273  IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(),1274                                    F->getEntryBlock().getFirstInsertionPt());1275  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,1276                       OMPBuilder.createParallel(1277                           Loc, AllocaIP, BODYGENCB_WRAPPER(BodyGenCB), PrivCB,1278                           FiniCB, Builder.CreateIsNotNull(F->arg_begin()),1279                           nullptr, OMP_PROC_BIND_default, true));1280 1281  EXPECT_EQ(NumBodiesGenerated, 1U);1282  EXPECT_EQ(NumPrivatizedVars, 0U);1283  EXPECT_EQ(NumFinalizationPoints, 1U);1284  EXPECT_TRUE(FakeDestructor->hasNUses(1));1285 1286  Builder.restoreIP(AfterIP);1287  Builder.CreateRetVoid();1288  OMPBuilder.finalize();1289 1290  EXPECT_FALSE(verifyModule(*M, &errs()));1291 1292  BasicBlock *ExitBB = nullptr;1293  for (const User *Usr : FakeDestructor->users()) {1294    const CallInst *CI = dyn_cast<CallInst>(Usr);1295    ASSERT_EQ(CI->getCalledFunction(), FakeDestructor);1296    ASSERT_TRUE(isa<BranchInst>(CI->getNextNode()));1297    ASSERT_EQ(CI->getNextNode()->getNumSuccessors(), 1U);1298    if (ExitBB)1299      ASSERT_EQ(CI->getNextNode()->getSuccessor(0), ExitBB);1300    else1301      ExitBB = CI->getNextNode()->getSuccessor(0);1302    ASSERT_EQ(ExitBB->size(), 1U);1303    if (!isa<ReturnInst>(ExitBB->front())) {1304      ASSERT_TRUE(isa<BranchInst>(ExitBB->front()));1305      ASSERT_EQ(cast<BranchInst>(ExitBB->front()).getNumSuccessors(), 1U);1306      ASSERT_TRUE(isa<ReturnInst>(1307          cast<BranchInst>(ExitBB->front()).getSuccessor(0)->front()));1308    }1309  }1310}1311 1312TEST_F(OpenMPIRBuilderTest, ParallelForwardAsPointers) {1313  OpenMPIRBuilder OMPBuilder(*M);1314  OMPBuilder.Config.IsTargetDevice = false;1315  OMPBuilder.initialize();1316  F->setName("func");1317  IRBuilder<> Builder(BB);1318  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});1319  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;1320 1321  Type *I32Ty = Type::getInt32Ty(M->getContext());1322  Type *PtrTy = PointerType::get(M->getContext(), 0);1323  Type *StructTy = StructType::get(I32Ty, PtrTy);1324  Type *VoidTy = Type::getVoidTy(M->getContext());1325  FunctionCallee RetI32Func = M->getOrInsertFunction("ret_i32", I32Ty);1326  FunctionCallee TakeI32Func =1327      M->getOrInsertFunction("take_i32", VoidTy, I32Ty);1328  FunctionCallee RetI32PtrFunc = M->getOrInsertFunction("ret_i32ptr", PtrTy);1329  FunctionCallee TakeI32PtrFunc =1330      M->getOrInsertFunction("take_i32ptr", VoidTy, PtrTy);1331  FunctionCallee RetStructFunc = M->getOrInsertFunction("ret_struct", StructTy);1332  FunctionCallee TakeStructFunc =1333      M->getOrInsertFunction("take_struct", VoidTy, StructTy);1334  FunctionCallee RetStructPtrFunc =1335      M->getOrInsertFunction("ret_structptr", PtrTy);1336  FunctionCallee TakeStructPtrFunc =1337      M->getOrInsertFunction("take_structPtr", VoidTy, PtrTy);1338  Value *I32Val = Builder.CreateCall(RetI32Func);1339  Value *I32PtrVal = Builder.CreateCall(RetI32PtrFunc);1340  Value *StructVal = Builder.CreateCall(RetStructFunc);1341  Value *StructPtrVal = Builder.CreateCall(RetStructPtrFunc);1342 1343  Instruction *Internal;1344  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {1345    IRBuilder<>::InsertPointGuard Guard(Builder);1346    Builder.restoreIP(CodeGenIP);1347    Internal = Builder.CreateCall(TakeI32Func, I32Val);1348    Builder.CreateCall(TakeI32PtrFunc, I32PtrVal);1349    Builder.CreateCall(TakeStructFunc, StructVal);1350    Builder.CreateCall(TakeStructPtrFunc, StructPtrVal);1351    return Error::success();1352  };1353  auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, Value &,1354                    Value &Inner, Value *&ReplacementValue) {1355    ReplacementValue = &Inner;1356    return CodeGenIP;1357  };1358  auto FiniCB = [](InsertPointTy) { return Error::success(); };1359 1360  IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(),1361                                    F->getEntryBlock().getFirstInsertionPt());1362  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,1363                       OMPBuilder.createParallel(1364                           Loc, AllocaIP, BodyGenCB, PrivCB, FiniCB, nullptr,1365                           nullptr, OMP_PROC_BIND_default, false));1366  Builder.restoreIP(AfterIP);1367  Builder.CreateRetVoid();1368 1369  OMPBuilder.finalize();1370 1371  EXPECT_FALSE(verifyModule(*M, &errs()));1372  Function *OutlinedFn = Internal->getFunction();1373 1374  Type *Arg2Type = OutlinedFn->getArg(2)->getType();1375  EXPECT_TRUE(Arg2Type->isPointerTy());1376}1377 1378TEST_F(OpenMPIRBuilderTest, CanonicalLoopSimple) {1379  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;1380  OpenMPIRBuilder OMPBuilder(*M);1381  OMPBuilder.initialize();1382  IRBuilder<> Builder(BB);1383  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});1384  Value *TripCount = F->getArg(0);1385 1386  unsigned NumBodiesGenerated = 0;1387  auto LoopBodyGenCB = [&](InsertPointTy CodeGenIP, llvm::Value *LC) {1388    NumBodiesGenerated += 1;1389 1390    Builder.restoreIP(CodeGenIP);1391 1392    Value *Cmp = Builder.CreateICmpEQ(LC, TripCount);1393    Instruction *ThenTerm, *ElseTerm;1394    SplitBlockAndInsertIfThenElse(Cmp, CodeGenIP.getBlock()->getTerminator(),1395                                  &ThenTerm, &ElseTerm);1396    return Error::success();1397  };1398 1399  ASSERT_EXPECTED_INIT(1400      CanonicalLoopInfo *, Loop,1401      OMPBuilder.createCanonicalLoop(Loc, LoopBodyGenCB, TripCount));1402 1403  Builder.restoreIP(Loop->getAfterIP());1404  ReturnInst *RetInst = Builder.CreateRetVoid();1405  OMPBuilder.finalize();1406 1407  Loop->assertOK();1408  EXPECT_FALSE(verifyModule(*M, &errs()));1409 1410  EXPECT_EQ(NumBodiesGenerated, 1U);1411 1412  // Verify control flow structure (in addition to Loop->assertOK()).1413  EXPECT_EQ(Loop->getPreheader()->getSinglePredecessor(), &F->getEntryBlock());1414  EXPECT_EQ(Loop->getAfter(), Builder.GetInsertBlock());1415 1416  Instruction *IndVar = Loop->getIndVar();1417  EXPECT_TRUE(isa<PHINode>(IndVar));1418  EXPECT_EQ(IndVar->getType(), TripCount->getType());1419  EXPECT_EQ(IndVar->getParent(), Loop->getHeader());1420 1421  EXPECT_EQ(Loop->getTripCount(), TripCount);1422 1423  BasicBlock *Body = Loop->getBody();1424  Instruction *CmpInst = &Body->front();1425  EXPECT_TRUE(isa<ICmpInst>(CmpInst));1426  EXPECT_EQ(CmpInst->getOperand(0), IndVar);1427 1428  BasicBlock *LatchPred = Loop->getLatch()->getSinglePredecessor();1429  EXPECT_TRUE(llvm::all_of(successors(Body), [=](BasicBlock *SuccBB) {1430    return SuccBB->getSingleSuccessor() == LatchPred;1431  }));1432 1433  EXPECT_EQ(&Loop->getAfter()->front(), RetInst);1434}1435 1436TEST_F(OpenMPIRBuilderTest, CanonicalLoopTripCount) {1437  OpenMPIRBuilder OMPBuilder(*M);1438  OMPBuilder.initialize();1439  IRBuilder<> Builder(BB);1440 1441  // Check the trip count is computed correctly. We generate the canonical loop1442  // but rely on the IRBuilder's constant folder to compute the final result1443  // since all inputs are constant. To verify overflow situations, limit the1444  // trip count / loop counter widths to 16 bits.1445  auto EvalTripCount = [&](int64_t Start, int64_t Stop, int64_t Step,1446                           bool IsSigned, bool InclusiveStop) -> int64_t {1447    OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});1448    Type *LCTy = Type::getInt16Ty(Ctx);1449    Value *StartVal = ConstantInt::get(LCTy, Start);1450    Value *StopVal = ConstantInt::get(LCTy, Stop);1451    Value *StepVal = ConstantInt::get(LCTy, Step);1452    Value *TripCount = OMPBuilder.calculateCanonicalLoopTripCount(1453        Loc, StartVal, StopVal, StepVal, IsSigned, InclusiveStop);1454    return cast<ConstantInt>(TripCount)->getValue().getZExtValue();1455  };1456 1457  EXPECT_EQ(EvalTripCount(0, 0, 1, false, false), 0);1458  EXPECT_EQ(EvalTripCount(0, 1, 2, false, false), 1);1459  EXPECT_EQ(EvalTripCount(0, 42, 1, false, false), 42);1460  EXPECT_EQ(EvalTripCount(0, 42, 2, false, false), 21);1461  EXPECT_EQ(EvalTripCount(21, 42, 1, false, false), 21);1462  EXPECT_EQ(EvalTripCount(0, 5, 5, false, false), 1);1463  EXPECT_EQ(EvalTripCount(0, 9, 5, false, false), 2);1464  EXPECT_EQ(EvalTripCount(0, 11, 5, false, false), 3);1465  EXPECT_EQ(EvalTripCount(0, 0xFFFF, 1, false, false), 0xFFFF);1466  EXPECT_EQ(EvalTripCount(0xFFFF, 0, 1, false, false), 0);1467  EXPECT_EQ(EvalTripCount(0xFFFE, 0xFFFF, 1, false, false), 1);1468  EXPECT_EQ(EvalTripCount(0, 0xFFFF, 0x100, false, false), 0x100);1469  EXPECT_EQ(EvalTripCount(0, 0xFFFF, 0xFFFF, false, false), 1);1470 1471  EXPECT_EQ(EvalTripCount(0, 6, 5, false, false), 2);1472  EXPECT_EQ(EvalTripCount(0, 0xFFFF, 0xFFFE, false, false), 2);1473  EXPECT_EQ(EvalTripCount(0, 0, 1, false, true), 1);1474  EXPECT_EQ(EvalTripCount(0, 0, 0xFFFF, false, true), 1);1475  EXPECT_EQ(EvalTripCount(0, 0xFFFE, 1, false, true), 0xFFFF);1476  EXPECT_EQ(EvalTripCount(0, 0xFFFE, 2, false, true), 0x8000);1477 1478  EXPECT_EQ(EvalTripCount(0, 0, -1, true, false), 0);1479  EXPECT_EQ(EvalTripCount(0, 1, -1, true, true), 0);1480  EXPECT_EQ(EvalTripCount(20, 5, -5, true, false), 3);1481  EXPECT_EQ(EvalTripCount(20, 5, -5, true, true), 4);1482  EXPECT_EQ(EvalTripCount(-4, -2, 2, true, false), 1);1483  EXPECT_EQ(EvalTripCount(-4, -3, 2, true, false), 1);1484  EXPECT_EQ(EvalTripCount(-4, -2, 2, true, true), 2);1485 1486  EXPECT_EQ(EvalTripCount(INT16_MIN, 0, 1, true, false), 0x8000);1487  EXPECT_EQ(EvalTripCount(INT16_MIN, 0, 1, true, true), 0x8001);1488  EXPECT_EQ(EvalTripCount(INT16_MIN, 0x7FFF, 1, true, false), 0xFFFF);1489  EXPECT_EQ(EvalTripCount(INT16_MIN + 1, 0x7FFF, 1, true, true), 0xFFFF);1490  EXPECT_EQ(EvalTripCount(INT16_MIN, 0, 0x7FFF, true, false), 2);1491  EXPECT_EQ(EvalTripCount(0x7FFF, 0, -1, true, false), 0x7FFF);1492  EXPECT_EQ(EvalTripCount(0, INT16_MIN, -1, true, false), 0x8000);1493  EXPECT_EQ(EvalTripCount(0, INT16_MIN, -16, true, false), 0x800);1494  EXPECT_EQ(EvalTripCount(0x7FFF, INT16_MIN, -1, true, false), 0xFFFF);1495  EXPECT_EQ(EvalTripCount(0x7FFF, 1, INT16_MIN, true, false), 1);1496  EXPECT_EQ(EvalTripCount(0x7FFF, -1, INT16_MIN, true, true), 2);1497 1498  // Finalize the function and verify it.1499  Builder.CreateRetVoid();1500  OMPBuilder.finalize();1501  EXPECT_FALSE(verifyModule(*M, &errs()));1502}1503 1504TEST_F(OpenMPIRBuilderTest, CollapseNestedLoops) {1505  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;1506  OpenMPIRBuilder OMPBuilder(*M);1507  OMPBuilder.initialize();1508  F->setName("func");1509 1510  IRBuilder<> Builder(BB);1511 1512  Type *LCTy = F->getArg(0)->getType();1513  Constant *One = ConstantInt::get(LCTy, 1);1514  Constant *Two = ConstantInt::get(LCTy, 2);1515  Value *OuterTripCount =1516      Builder.CreateAdd(F->getArg(0), Two, "tripcount.outer");1517  Value *InnerTripCount =1518      Builder.CreateAdd(F->getArg(0), One, "tripcount.inner");1519 1520  // Fix an insertion point for ComputeIP.1521  BasicBlock *LoopNextEnter =1522      BasicBlock::Create(M->getContext(), "loopnest.enter", F,1523                         Builder.GetInsertBlock()->getNextNode());1524  BranchInst *EnterBr = Builder.CreateBr(LoopNextEnter);1525  InsertPointTy ComputeIP{EnterBr->getParent(), EnterBr->getIterator()};1526 1527  Builder.SetInsertPoint(LoopNextEnter);1528  OpenMPIRBuilder::LocationDescription OuterLoc(Builder.saveIP(), DL);1529 1530  CanonicalLoopInfo *InnerLoop = nullptr;1531  CallInst *InbetweenLead = nullptr;1532  CallInst *InbetweenTrail = nullptr;1533  CallInst *Call = nullptr;1534  auto OuterLoopBodyGenCB = [&](InsertPointTy OuterCodeGenIP, Value *OuterLC) {1535    Builder.restoreIP(OuterCodeGenIP);1536    InbetweenLead =1537        createPrintfCall(Builder, "In-between lead i=%d\\n", {OuterLC});1538 1539    auto InnerLoopBodyGenCB = [&](InsertPointTy InnerCodeGenIP,1540                                  Value *InnerLC) {1541      Builder.restoreIP(InnerCodeGenIP);1542      Call = createPrintfCall(Builder, "body i=%d j=%d\\n", {OuterLC, InnerLC});1543      return Error::success();1544    };1545    ASSERT_EXPECTED_INIT(1546        CanonicalLoopInfo *, InnerLoopResult,1547        OMPBuilder.createCanonicalLoop(Builder.saveIP(), InnerLoopBodyGenCB,1548                                       InnerTripCount, "inner"));1549    InnerLoop = InnerLoopResult;1550 1551    Builder.restoreIP(InnerLoop->getAfterIP());1552    InbetweenTrail =1553        createPrintfCall(Builder, "In-between trail i=%d\\n", {OuterLC});1554  };1555  ASSERT_EXPECTED_INIT(CanonicalLoopInfo *, OuterLoop,1556                       OMPBuilder.createCanonicalLoop(1557                           OuterLoc, LOOP_BODYGENCB_WRAPPER(OuterLoopBodyGenCB),1558                           OuterTripCount, "outer"));1559 1560  // Finish the function.1561  Builder.restoreIP(OuterLoop->getAfterIP());1562  Builder.CreateRetVoid();1563 1564  CanonicalLoopInfo *Collapsed =1565      OMPBuilder.collapseLoops(DL, {OuterLoop, InnerLoop}, ComputeIP);1566 1567  OMPBuilder.finalize();1568  EXPECT_FALSE(verifyModule(*M, &errs()));1569 1570  // Verify control flow and BB order.1571  BasicBlock *RefOrder[] = {1572      Collapsed->getPreheader(),   Collapsed->getHeader(),1573      Collapsed->getCond(),        Collapsed->getBody(),1574      InbetweenLead->getParent(),  Call->getParent(),1575      InbetweenTrail->getParent(), Collapsed->getLatch(),1576      Collapsed->getExit(),        Collapsed->getAfter(),1577  };1578  EXPECT_TRUE(verifyDFSOrder(F, RefOrder));1579  EXPECT_TRUE(verifyListOrder(F, RefOrder));1580 1581  // Verify the total trip count.1582  auto *TripCount = cast<MulOperator>(Collapsed->getTripCount());1583  EXPECT_EQ(TripCount->getOperand(0), OuterTripCount);1584  EXPECT_EQ(TripCount->getOperand(1), InnerTripCount);1585 1586  // Verify the changed indvar.1587  auto *OuterIV = cast<BinaryOperator>(Call->getOperand(1));1588  EXPECT_EQ(OuterIV->getOpcode(), Instruction::UDiv);1589  EXPECT_EQ(OuterIV->getParent(), Collapsed->getBody());1590  EXPECT_EQ(OuterIV->getOperand(1), InnerTripCount);1591  EXPECT_EQ(OuterIV->getOperand(0), Collapsed->getIndVar());1592 1593  auto *InnerIV = cast<BinaryOperator>(Call->getOperand(2));1594  EXPECT_EQ(InnerIV->getOpcode(), Instruction::URem);1595  EXPECT_EQ(InnerIV->getParent(), Collapsed->getBody());1596  EXPECT_EQ(InnerIV->getOperand(0), Collapsed->getIndVar());1597  EXPECT_EQ(InnerIV->getOperand(1), InnerTripCount);1598 1599  EXPECT_EQ(InbetweenLead->getOperand(1), OuterIV);1600  EXPECT_EQ(InbetweenTrail->getOperand(1), OuterIV);1601}1602 1603TEST_F(OpenMPIRBuilderTest, TileSingleLoop) {1604  OpenMPIRBuilder OMPBuilder(*M);1605  CallInst *Call;1606  BasicBlock *BodyCode;1607  CanonicalLoopInfo *Loop =1608      buildSingleLoopFunction(DL, OMPBuilder, 32, &Call, &BodyCode);1609  ASSERT_NE(Loop, nullptr);1610 1611  Instruction *OrigIndVar = Loop->getIndVar();1612  EXPECT_EQ(Call->getOperand(1), OrigIndVar);1613 1614  // Tile the loop.1615  Constant *TileSize = ConstantInt::get(Loop->getIndVarType(), APInt(32, 7));1616  std::vector<CanonicalLoopInfo *> GenLoops =1617      OMPBuilder.tileLoops(DL, {Loop}, {TileSize});1618 1619  OMPBuilder.finalize();1620  EXPECT_FALSE(verifyModule(*M, &errs()));1621 1622  EXPECT_EQ(GenLoops.size(), 2u);1623  CanonicalLoopInfo *Floor = GenLoops[0];1624  CanonicalLoopInfo *Tile = GenLoops[1];1625 1626  BasicBlock *RefOrder[] = {1627      Floor->getPreheader(), Floor->getHeader(),   Floor->getCond(),1628      Floor->getBody(),      Tile->getPreheader(), Tile->getHeader(),1629      Tile->getCond(),       Tile->getBody(),      BodyCode,1630      Tile->getLatch(),      Tile->getExit(),      Tile->getAfter(),1631      Floor->getLatch(),     Floor->getExit(),     Floor->getAfter(),1632  };1633  EXPECT_TRUE(verifyDFSOrder(F, RefOrder));1634  EXPECT_TRUE(verifyListOrder(F, RefOrder));1635 1636  // Check the induction variable.1637  EXPECT_EQ(Call->getParent(), BodyCode);1638  auto *Shift = cast<AddOperator>(Call->getOperand(1));1639  EXPECT_EQ(cast<Instruction>(Shift)->getParent(), Tile->getBody());1640  EXPECT_EQ(Shift->getOperand(1), Tile->getIndVar());1641  auto *Scale = cast<MulOperator>(Shift->getOperand(0));1642  EXPECT_EQ(cast<Instruction>(Scale)->getParent(), Tile->getBody());1643  EXPECT_EQ(Scale->getOperand(0), TileSize);1644  EXPECT_EQ(Scale->getOperand(1), Floor->getIndVar());1645}1646 1647TEST_F(OpenMPIRBuilderTest, TileNestedLoops) {1648  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;1649  OpenMPIRBuilder OMPBuilder(*M);1650  OMPBuilder.initialize();1651  F->setName("func");1652 1653  IRBuilder<> Builder(BB);1654  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});1655  Value *TripCount = F->getArg(0);1656  Type *LCTy = TripCount->getType();1657 1658  BasicBlock *BodyCode = nullptr;1659  CanonicalLoopInfo *InnerLoop = nullptr;1660  auto OuterLoopBodyGenCB = [&](InsertPointTy OuterCodeGenIP,1661                                llvm::Value *OuterLC) {1662    auto InnerLoopBodyGenCB = [&](InsertPointTy InnerCodeGenIP,1663                                  llvm::Value *InnerLC) {1664      Builder.restoreIP(InnerCodeGenIP);1665      BodyCode = Builder.GetInsertBlock();1666 1667      // Add something that consumes the induction variables to the body.1668      createPrintfCall(Builder, "i=%d j=%d\\n", {OuterLC, InnerLC});1669      return Error::success();1670    };1671    ASSERT_EXPECTED_INIT(CanonicalLoopInfo *, InnerLoopResult,1672                         OMPBuilder.createCanonicalLoop(OuterCodeGenIP,1673                                                        InnerLoopBodyGenCB,1674                                                        TripCount, "inner"));1675    InnerLoop = InnerLoopResult;1676  };1677  ASSERT_EXPECTED_INIT(1678      CanonicalLoopInfo *, OuterLoop,1679      OMPBuilder.createCanonicalLoop(1680          Loc, LOOP_BODYGENCB_WRAPPER(OuterLoopBodyGenCB), TripCount, "outer"));1681 1682  // Finalize the function.1683  Builder.restoreIP(OuterLoop->getAfterIP());1684  Builder.CreateRetVoid();1685 1686  // Tile to loop nest.1687  Constant *OuterTileSize = ConstantInt::get(LCTy, APInt(32, 11));1688  Constant *InnerTileSize = ConstantInt::get(LCTy, APInt(32, 7));1689  std::vector<CanonicalLoopInfo *> GenLoops = OMPBuilder.tileLoops(1690      DL, {OuterLoop, InnerLoop}, {OuterTileSize, InnerTileSize});1691 1692  OMPBuilder.finalize();1693  EXPECT_FALSE(verifyModule(*M, &errs()));1694 1695  EXPECT_EQ(GenLoops.size(), 4u);1696  CanonicalLoopInfo *Floor1 = GenLoops[0];1697  CanonicalLoopInfo *Floor2 = GenLoops[1];1698  CanonicalLoopInfo *Tile1 = GenLoops[2];1699  CanonicalLoopInfo *Tile2 = GenLoops[3];1700 1701  BasicBlock *RefOrder[] = {1702      Floor1->getPreheader(),1703      Floor1->getHeader(),1704      Floor1->getCond(),1705      Floor1->getBody(),1706      Floor2->getPreheader(),1707      Floor2->getHeader(),1708      Floor2->getCond(),1709      Floor2->getBody(),1710      Tile1->getPreheader(),1711      Tile1->getHeader(),1712      Tile1->getCond(),1713      Tile1->getBody(),1714      Tile2->getPreheader(),1715      Tile2->getHeader(),1716      Tile2->getCond(),1717      Tile2->getBody(),1718      BodyCode,1719      Tile2->getLatch(),1720      Tile2->getExit(),1721      Tile2->getAfter(),1722      Tile1->getLatch(),1723      Tile1->getExit(),1724      Tile1->getAfter(),1725      Floor2->getLatch(),1726      Floor2->getExit(),1727      Floor2->getAfter(),1728      Floor1->getLatch(),1729      Floor1->getExit(),1730      Floor1->getAfter(),1731  };1732  EXPECT_TRUE(verifyDFSOrder(F, RefOrder));1733  EXPECT_TRUE(verifyListOrder(F, RefOrder));1734}1735 1736TEST_F(OpenMPIRBuilderTest, TileNestedLoopsWithBounds) {1737  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;1738  OpenMPIRBuilder OMPBuilder(*M);1739  OMPBuilder.initialize();1740  F->setName("func");1741 1742  IRBuilder<> Builder(BB);1743  Value *TripCount = F->getArg(0);1744  Type *LCTy = TripCount->getType();1745 1746  Value *OuterStartVal = ConstantInt::get(LCTy, 2);1747  Value *OuterStopVal = TripCount;1748  Value *OuterStep = ConstantInt::get(LCTy, 5);1749  Value *InnerStartVal = ConstantInt::get(LCTy, 13);1750  Value *InnerStopVal = TripCount;1751  Value *InnerStep = ConstantInt::get(LCTy, 3);1752 1753  // Fix an insertion point for ComputeIP.1754  BasicBlock *LoopNextEnter =1755      BasicBlock::Create(M->getContext(), "loopnest.enter", F,1756                         Builder.GetInsertBlock()->getNextNode());1757  BranchInst *EnterBr = Builder.CreateBr(LoopNextEnter);1758  InsertPointTy ComputeIP{EnterBr->getParent(), EnterBr->getIterator()};1759 1760  InsertPointTy LoopIP{LoopNextEnter, LoopNextEnter->begin()};1761  OpenMPIRBuilder::LocationDescription Loc({LoopIP, DL});1762 1763  BasicBlock *BodyCode = nullptr;1764  CanonicalLoopInfo *InnerLoop = nullptr;1765  CallInst *Call = nullptr;1766  auto OuterLoopBodyGenCB = [&](InsertPointTy OuterCodeGenIP,1767                                llvm::Value *OuterLC) {1768    auto InnerLoopBodyGenCB = [&](InsertPointTy InnerCodeGenIP,1769                                  llvm::Value *InnerLC) {1770      Builder.restoreIP(InnerCodeGenIP);1771      BodyCode = Builder.GetInsertBlock();1772 1773      // Add something that consumes the induction variable to the body.1774      Call = createPrintfCall(Builder, "i=%d j=%d\\n", {OuterLC, InnerLC});1775      return Error::success();1776    };1777    ASSERT_EXPECTED_INIT(1778        CanonicalLoopInfo *, InnerLoopResult,1779        OMPBuilder.createCanonicalLoop(OuterCodeGenIP, InnerLoopBodyGenCB,1780                                       InnerStartVal, InnerStopVal, InnerStep,1781                                       false, false, ComputeIP, "inner"));1782    InnerLoop = InnerLoopResult;1783  };1784  ASSERT_EXPECTED_INIT(CanonicalLoopInfo *, OuterLoop,1785                       OMPBuilder.createCanonicalLoop(1786                           Loc, LOOP_BODYGENCB_WRAPPER(OuterLoopBodyGenCB),1787                           OuterStartVal, OuterStopVal, OuterStep, false, false,1788                           ComputeIP, "outer"));1789 1790  // Finalize the function1791  Builder.restoreIP(OuterLoop->getAfterIP());1792  Builder.CreateRetVoid();1793 1794  // Tile the loop nest.1795  Constant *TileSize0 = ConstantInt::get(LCTy, APInt(32, 11));1796  Constant *TileSize1 = ConstantInt::get(LCTy, APInt(32, 7));1797  std::vector<CanonicalLoopInfo *> GenLoops =1798      OMPBuilder.tileLoops(DL, {OuterLoop, InnerLoop}, {TileSize0, TileSize1});1799 1800  OMPBuilder.finalize();1801  EXPECT_FALSE(verifyModule(*M, &errs()));1802 1803  EXPECT_EQ(GenLoops.size(), 4u);1804  CanonicalLoopInfo *Floor0 = GenLoops[0];1805  CanonicalLoopInfo *Floor1 = GenLoops[1];1806  CanonicalLoopInfo *Tile0 = GenLoops[2];1807  CanonicalLoopInfo *Tile1 = GenLoops[3];1808 1809  BasicBlock *RefOrder[] = {1810      Floor0->getPreheader(),1811      Floor0->getHeader(),1812      Floor0->getCond(),1813      Floor0->getBody(),1814      Floor1->getPreheader(),1815      Floor1->getHeader(),1816      Floor1->getCond(),1817      Floor1->getBody(),1818      Tile0->getPreheader(),1819      Tile0->getHeader(),1820      Tile0->getCond(),1821      Tile0->getBody(),1822      Tile1->getPreheader(),1823      Tile1->getHeader(),1824      Tile1->getCond(),1825      Tile1->getBody(),1826      BodyCode,1827      Tile1->getLatch(),1828      Tile1->getExit(),1829      Tile1->getAfter(),1830      Tile0->getLatch(),1831      Tile0->getExit(),1832      Tile0->getAfter(),1833      Floor1->getLatch(),1834      Floor1->getExit(),1835      Floor1->getAfter(),1836      Floor0->getLatch(),1837      Floor0->getExit(),1838      Floor0->getAfter(),1839  };1840  EXPECT_TRUE(verifyDFSOrder(F, RefOrder));1841  EXPECT_TRUE(verifyListOrder(F, RefOrder));1842 1843  EXPECT_EQ(Call->getParent(), BodyCode);1844 1845  auto *RangeShift0 = cast<AddOperator>(Call->getOperand(1));1846  EXPECT_EQ(RangeShift0->getOperand(1), OuterStartVal);1847  auto *RangeScale0 = cast<MulOperator>(RangeShift0->getOperand(0));1848  EXPECT_EQ(RangeScale0->getOperand(1), OuterStep);1849  auto *TileShift0 = cast<AddOperator>(RangeScale0->getOperand(0));1850  EXPECT_EQ(cast<Instruction>(TileShift0)->getParent(), Tile1->getBody());1851  EXPECT_EQ(TileShift0->getOperand(1), Tile0->getIndVar());1852  auto *TileScale0 = cast<MulOperator>(TileShift0->getOperand(0));1853  EXPECT_EQ(cast<Instruction>(TileScale0)->getParent(), Tile1->getBody());1854  EXPECT_EQ(TileScale0->getOperand(0), TileSize0);1855  EXPECT_EQ(TileScale0->getOperand(1), Floor0->getIndVar());1856 1857  auto *RangeShift1 = cast<AddOperator>(Call->getOperand(2));1858  EXPECT_EQ(cast<Instruction>(RangeShift1)->getParent(), BodyCode);1859  EXPECT_EQ(RangeShift1->getOperand(1), InnerStartVal);1860  auto *RangeScale1 = cast<MulOperator>(RangeShift1->getOperand(0));1861  EXPECT_EQ(cast<Instruction>(RangeScale1)->getParent(), BodyCode);1862  EXPECT_EQ(RangeScale1->getOperand(1), InnerStep);1863  auto *TileShift1 = cast<AddOperator>(RangeScale1->getOperand(0));1864  EXPECT_EQ(cast<Instruction>(TileShift1)->getParent(), Tile1->getBody());1865  EXPECT_EQ(TileShift1->getOperand(1), Tile1->getIndVar());1866  auto *TileScale1 = cast<MulOperator>(TileShift1->getOperand(0));1867  EXPECT_EQ(cast<Instruction>(TileScale1)->getParent(), Tile1->getBody());1868  EXPECT_EQ(TileScale1->getOperand(0), TileSize1);1869  EXPECT_EQ(TileScale1->getOperand(1), Floor1->getIndVar());1870}1871 1872TEST_F(OpenMPIRBuilderTest, TileSingleLoopCounts) {1873  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;1874  OpenMPIRBuilder OMPBuilder(*M);1875  OMPBuilder.initialize();1876  IRBuilder<> Builder(BB);1877 1878  // Create a loop, tile it, and extract its trip count. All input values are1879  // constant and IRBuilder evaluates all-constant arithmetic inplace, such that1880  // the floor trip count itself will be a ConstantInt. Unfortunately we cannot1881  // do the same for the tile loop.1882  auto GetFloorCount = [&](int64_t Start, int64_t Stop, int64_t Step,1883                           bool IsSigned, bool InclusiveStop,1884                           int64_t TileSize) -> uint64_t {1885    OpenMPIRBuilder::LocationDescription Loc(Builder.saveIP(), DL);1886    Type *LCTy = Type::getInt16Ty(Ctx);1887    Value *StartVal = ConstantInt::get(LCTy, Start);1888    Value *StopVal = ConstantInt::get(LCTy, Stop);1889    Value *StepVal = ConstantInt::get(LCTy, Step);1890 1891    // Generate a loop.1892    auto LoopBodyGenCB = [&](InsertPointTy CodeGenIP, llvm::Value *LC) {1893      return Error::success();1894    };1895    ASSERT_EXPECTED_INIT_RETURN(1896        CanonicalLoopInfo *, Loop,1897        OMPBuilder.createCanonicalLoop(Loc, LoopBodyGenCB, StartVal, StopVal,1898                                       StepVal, IsSigned, InclusiveStop),1899        (unsigned)-1);1900    InsertPointTy AfterIP = Loop->getAfterIP();1901 1902    // Tile the loop.1903    Value *TileSizeVal = ConstantInt::get(LCTy, TileSize);1904    std::vector<CanonicalLoopInfo *> GenLoops =1905        OMPBuilder.tileLoops(Loc.DL, {Loop}, {TileSizeVal});1906 1907    // Set the insertion pointer to after loop, where the next loop will be1908    // emitted.1909    Builder.restoreIP(AfterIP);1910 1911    // Extract the trip count.1912    CanonicalLoopInfo *FloorLoop = GenLoops[0];1913    Value *FloorTripCount = FloorLoop->getTripCount();1914    return cast<ConstantInt>(FloorTripCount)->getValue().getZExtValue();1915  };1916 1917  // Empty iteration domain.1918  EXPECT_EQ(GetFloorCount(0, 0, 1, false, false, 7), 0u);1919  EXPECT_EQ(GetFloorCount(0, -1, 1, false, true, 7), 0u);1920  EXPECT_EQ(GetFloorCount(-1, -1, -1, true, false, 7), 0u);1921  EXPECT_EQ(GetFloorCount(-1, 0, -1, true, true, 7), 0u);1922  EXPECT_EQ(GetFloorCount(-1, -1, 3, true, false, 7), 0u);1923 1924  // Only complete tiles.1925  EXPECT_EQ(GetFloorCount(0, 14, 1, false, false, 7), 2u);1926  EXPECT_EQ(GetFloorCount(0, 14, 1, false, false, 7), 2u);1927  EXPECT_EQ(GetFloorCount(1, 15, 1, false, false, 7), 2u);1928  EXPECT_EQ(GetFloorCount(0, -14, -1, true, false, 7), 2u);1929  EXPECT_EQ(GetFloorCount(-1, -14, -1, true, true, 7), 2u);1930  EXPECT_EQ(GetFloorCount(0, 3 * 7 * 2, 3, false, false, 7), 2u);1931 1932  // Only a partial tile.1933  EXPECT_EQ(GetFloorCount(0, 1, 1, false, false, 7), 1u);1934  EXPECT_EQ(GetFloorCount(0, 6, 1, false, false, 7), 1u);1935  EXPECT_EQ(GetFloorCount(-1, 1, 3, true, false, 7), 1u);1936  EXPECT_EQ(GetFloorCount(-1, -2, -1, true, false, 7), 1u);1937  EXPECT_EQ(GetFloorCount(0, 2, 3, false, false, 7), 1u);1938 1939  // Complete and partial tiles.1940  EXPECT_EQ(GetFloorCount(0, 13, 1, false, false, 7), 2u);1941  EXPECT_EQ(GetFloorCount(0, 15, 1, false, false, 7), 3u);1942  EXPECT_EQ(GetFloorCount(-1, -14, -1, true, false, 7), 2u);1943  EXPECT_EQ(GetFloorCount(0, 3 * 7 * 5 - 1, 3, false, false, 7), 5u);1944  EXPECT_EQ(GetFloorCount(-1, -3 * 7 * 5, -3, true, false, 7), 5u);1945 1946  // Close to 16-bit integer range.1947  EXPECT_EQ(GetFloorCount(0, 0xFFFF, 1, false, false, 1), 0xFFFFu);1948  EXPECT_EQ(GetFloorCount(0, 0xFFFF, 1, false, false, 7), 0xFFFFu / 7 + 1);1949  EXPECT_EQ(GetFloorCount(0, 0xFFFE, 1, false, true, 7), 0xFFFFu / 7 + 1);1950  EXPECT_EQ(GetFloorCount(-0x8000, 0x7FFF, 1, true, false, 7), 0xFFFFu / 7 + 1);1951  EXPECT_EQ(GetFloorCount(-0x7FFF, 0x7FFF, 1, true, true, 7), 0xFFFFu / 7 + 1);1952  EXPECT_EQ(GetFloorCount(0, 0xFFFE, 1, false, false, 0xFFFF), 1u);1953  EXPECT_EQ(GetFloorCount(-0x8000, 0x7FFF, 1, true, false, 0xFFFF), 1u);1954 1955  // Finalize the function.1956  Builder.CreateRetVoid();1957  OMPBuilder.finalize();1958 1959  EXPECT_FALSE(verifyModule(*M, &errs()));1960}1961 1962TEST_F(OpenMPIRBuilderTest, ApplySimd) {1963  OpenMPIRBuilder OMPBuilder(*M);1964  MapVector<Value *, Value *> AlignedVars;1965  CanonicalLoopInfo *CLI = buildSingleLoopFunction(DL, OMPBuilder, 32);1966  ASSERT_NE(CLI, nullptr);1967 1968  // Simd-ize the loop.1969  OMPBuilder.applySimd(CLI, AlignedVars, /* IfCond */ nullptr,1970                       OrderKind::OMP_ORDER_unknown,1971                       /* Simdlen */ nullptr,1972                       /* Safelen */ nullptr);1973 1974  OMPBuilder.finalize();1975  EXPECT_FALSE(verifyModule(*M, &errs()));1976 1977  PassBuilder PB;1978  FunctionAnalysisManager FAM;1979  PB.registerFunctionAnalyses(FAM);1980  LoopInfo &LI = FAM.getResult<LoopAnalysis>(*F);1981 1982  const std::vector<Loop *> &TopLvl = LI.getTopLevelLoops();1983  EXPECT_EQ(TopLvl.size(), 1u);1984 1985  Loop *L = TopLvl.front();1986  EXPECT_TRUE(findStringMetadataForLoop(L, "llvm.loop.parallel_accesses"));1987  EXPECT_TRUE(getBooleanLoopAttribute(L, "llvm.loop.vectorize.enable"));1988 1989  // Check for llvm.access.group metadata attached to the printf1990  // function in the loop body.1991  BasicBlock *LoopBody = CLI->getBody();1992  EXPECT_TRUE(any_of(*LoopBody, [](Instruction &I) {1993    return I.getMetadata("llvm.access.group") != nullptr;1994  }));1995}1996 1997TEST_F(OpenMPIRBuilderTest, ApplySimdCustomAligned) {1998  OpenMPIRBuilder OMPBuilder(*M);1999  IRBuilder<> Builder(BB);2000  const int AlignmentValue = 32;2001  llvm::BasicBlock *sourceBlock = Builder.GetInsertBlock();2002  AllocaInst *Alloc1 =2003      Builder.CreateAlloca(Builder.getPtrTy(), Builder.getInt64(1));2004  LoadInst *Load1 = Builder.CreateLoad(Alloc1->getAllocatedType(), Alloc1);2005  MapVector<Value *, Value *> AlignedVars;2006  AlignedVars.insert({Load1, Builder.getInt64(AlignmentValue)});2007 2008  CanonicalLoopInfo *CLI = buildSingleLoopFunction(DL, OMPBuilder, 32);2009  ASSERT_NE(CLI, nullptr);2010 2011  // Simd-ize the loop.2012  OMPBuilder.applySimd(CLI, AlignedVars, /* IfCond */ nullptr,2013                       OrderKind::OMP_ORDER_unknown,2014                       /* Simdlen */ nullptr,2015                       /* Safelen */ nullptr);2016 2017  OMPBuilder.finalize();2018  EXPECT_FALSE(verifyModule(*M, &errs()));2019 2020  PassBuilder PB;2021  FunctionAnalysisManager FAM;2022  PB.registerFunctionAnalyses(FAM);2023  LoopInfo &LI = FAM.getResult<LoopAnalysis>(*F);2024 2025  const std::vector<Loop *> &TopLvl = LI.getTopLevelLoops();2026  EXPECT_EQ(TopLvl.size(), 1u);2027 2028  Loop *L = TopLvl.front();2029  EXPECT_TRUE(findStringMetadataForLoop(L, "llvm.loop.parallel_accesses"));2030  EXPECT_TRUE(getBooleanLoopAttribute(L, "llvm.loop.vectorize.enable"));2031 2032  // Check for llvm.access.group metadata attached to the printf2033  // function in the loop body.2034  BasicBlock *LoopBody = CLI->getBody();2035  EXPECT_TRUE(any_of(*LoopBody, [](Instruction &I) {2036    return I.getMetadata("llvm.access.group") != nullptr;2037  }));2038 2039  // Check if number of assumption instructions is equal to number of aligned2040  // variables2041  size_t NumAssummptionCallsInPreheader =2042      count_if(*sourceBlock, [](Instruction &I) { return isa<AssumeInst>(I); });2043  EXPECT_EQ(NumAssummptionCallsInPreheader, AlignedVars.size());2044 2045  // Check if variables are correctly aligned2046  for (Instruction &Instr : *sourceBlock) {2047    if (!isa<AssumeInst>(Instr))2048      continue;2049    AssumeInst *AssumeInstruction = cast<AssumeInst>(&Instr);2050    if (AssumeInstruction->getNumTotalBundleOperands()) {2051      auto Bundle = AssumeInstruction->getOperandBundleAt(0);2052      if (Bundle.getTagName() == "align") {2053        EXPECT_TRUE(isa<ConstantInt>(Bundle.Inputs[1]));2054        auto ConstIntVal = dyn_cast<ConstantInt>(Bundle.Inputs[1]);2055        EXPECT_EQ(ConstIntVal->getSExtValue(), AlignmentValue);2056      }2057    }2058  }2059}2060TEST_F(OpenMPIRBuilderTest, ApplySimdlen) {2061  OpenMPIRBuilder OMPBuilder(*M);2062  MapVector<Value *, Value *> AlignedVars;2063  CanonicalLoopInfo *CLI = buildSingleLoopFunction(DL, OMPBuilder, 32);2064  ASSERT_NE(CLI, nullptr);2065 2066  // Simd-ize the loop.2067  OMPBuilder.applySimd(CLI, AlignedVars,2068                       /* IfCond */ nullptr, OrderKind::OMP_ORDER_unknown,2069                       ConstantInt::get(Type::getInt32Ty(Ctx), 3),2070                       /* Safelen */ nullptr);2071 2072  OMPBuilder.finalize();2073  EXPECT_FALSE(verifyModule(*M, &errs()));2074 2075  PassBuilder PB;2076  FunctionAnalysisManager FAM;2077  PB.registerFunctionAnalyses(FAM);2078  LoopInfo &LI = FAM.getResult<LoopAnalysis>(*F);2079 2080  const std::vector<Loop *> &TopLvl = LI.getTopLevelLoops();2081  EXPECT_EQ(TopLvl.size(), 1u);2082 2083  Loop *L = TopLvl.front();2084  EXPECT_TRUE(findStringMetadataForLoop(L, "llvm.loop.parallel_accesses"));2085  EXPECT_TRUE(getBooleanLoopAttribute(L, "llvm.loop.vectorize.enable"));2086  EXPECT_EQ(getIntLoopAttribute(L, "llvm.loop.vectorize.width"), 3);2087 2088  // Check for llvm.access.group metadata attached to the printf2089  // function in the loop body.2090  BasicBlock *LoopBody = CLI->getBody();2091  EXPECT_TRUE(any_of(*LoopBody, [](Instruction &I) {2092    return I.getMetadata("llvm.access.group") != nullptr;2093  }));2094}2095 2096TEST_F(OpenMPIRBuilderTest, ApplySafelenOrderConcurrent) {2097  OpenMPIRBuilder OMPBuilder(*M);2098  MapVector<Value *, Value *> AlignedVars;2099 2100  CanonicalLoopInfo *CLI = buildSingleLoopFunction(DL, OMPBuilder, 32);2101  ASSERT_NE(CLI, nullptr);2102 2103  // Simd-ize the loop.2104  OMPBuilder.applySimd(2105      CLI, AlignedVars, /* IfCond */ nullptr, OrderKind::OMP_ORDER_concurrent,2106      /* Simdlen */ nullptr, ConstantInt::get(Type::getInt32Ty(Ctx), 3));2107 2108  OMPBuilder.finalize();2109  EXPECT_FALSE(verifyModule(*M, &errs()));2110 2111  PassBuilder PB;2112  FunctionAnalysisManager FAM;2113  PB.registerFunctionAnalyses(FAM);2114  LoopInfo &LI = FAM.getResult<LoopAnalysis>(*F);2115 2116  const std::vector<Loop *> &TopLvl = LI.getTopLevelLoops();2117  EXPECT_EQ(TopLvl.size(), 1u);2118 2119  Loop *L = TopLvl.front();2120  // Parallel metadata shoudl be attached because of presence of2121  // the order(concurrent) OpenMP clause2122  EXPECT_TRUE(findStringMetadataForLoop(L, "llvm.loop.parallel_accesses"));2123  EXPECT_TRUE(getBooleanLoopAttribute(L, "llvm.loop.vectorize.enable"));2124  EXPECT_EQ(getIntLoopAttribute(L, "llvm.loop.vectorize.width"), 3);2125 2126  // Check for llvm.access.group metadata attached to the printf2127  // function in the loop body.2128  BasicBlock *LoopBody = CLI->getBody();2129  EXPECT_TRUE(any_of(*LoopBody, [](Instruction &I) {2130    return I.getMetadata("llvm.access.group") != nullptr;2131  }));2132}2133 2134TEST_F(OpenMPIRBuilderTest, ApplySafelen) {2135  OpenMPIRBuilder OMPBuilder(*M);2136  MapVector<Value *, Value *> AlignedVars;2137 2138  CanonicalLoopInfo *CLI = buildSingleLoopFunction(DL, OMPBuilder, 32);2139  ASSERT_NE(CLI, nullptr);2140 2141  OMPBuilder.applySimd(2142      CLI, AlignedVars, /* IfCond */ nullptr, OrderKind::OMP_ORDER_unknown,2143      /* Simdlen */ nullptr, ConstantInt::get(Type::getInt32Ty(Ctx), 3));2144 2145  OMPBuilder.finalize();2146  EXPECT_FALSE(verifyModule(*M, &errs()));2147 2148  PassBuilder PB;2149  FunctionAnalysisManager FAM;2150  PB.registerFunctionAnalyses(FAM);2151  LoopInfo &LI = FAM.getResult<LoopAnalysis>(*F);2152 2153  const std::vector<Loop *> &TopLvl = LI.getTopLevelLoops();2154  EXPECT_EQ(TopLvl.size(), 1u);2155 2156  Loop *L = TopLvl.front();2157  EXPECT_FALSE(findStringMetadataForLoop(L, "llvm.loop.parallel_accesses"));2158  EXPECT_TRUE(getBooleanLoopAttribute(L, "llvm.loop.vectorize.enable"));2159  EXPECT_EQ(getIntLoopAttribute(L, "llvm.loop.vectorize.width"), 3);2160 2161  // Check for llvm.access.group metadata attached to the printf2162  // function in the loop body.2163  BasicBlock *LoopBody = CLI->getBody();2164  EXPECT_FALSE(any_of(*LoopBody, [](Instruction &I) {2165    return I.getMetadata("llvm.access.group") != nullptr;2166  }));2167}2168 2169TEST_F(OpenMPIRBuilderTest, ApplySimdlenSafelen) {2170  OpenMPIRBuilder OMPBuilder(*M);2171  MapVector<Value *, Value *> AlignedVars;2172 2173  CanonicalLoopInfo *CLI = buildSingleLoopFunction(DL, OMPBuilder, 32);2174  ASSERT_NE(CLI, nullptr);2175 2176  OMPBuilder.applySimd(CLI, AlignedVars, /* IfCond */ nullptr,2177                       OrderKind::OMP_ORDER_unknown,2178                       ConstantInt::get(Type::getInt32Ty(Ctx), 2),2179                       ConstantInt::get(Type::getInt32Ty(Ctx), 3));2180 2181  OMPBuilder.finalize();2182  EXPECT_FALSE(verifyModule(*M, &errs()));2183 2184  PassBuilder PB;2185  FunctionAnalysisManager FAM;2186  PB.registerFunctionAnalyses(FAM);2187  LoopInfo &LI = FAM.getResult<LoopAnalysis>(*F);2188 2189  const std::vector<Loop *> &TopLvl = LI.getTopLevelLoops();2190  EXPECT_EQ(TopLvl.size(), 1u);2191 2192  Loop *L = TopLvl.front();2193  EXPECT_FALSE(findStringMetadataForLoop(L, "llvm.loop.parallel_accesses"));2194  EXPECT_TRUE(getBooleanLoopAttribute(L, "llvm.loop.vectorize.enable"));2195  EXPECT_EQ(getIntLoopAttribute(L, "llvm.loop.vectorize.width"), 2);2196 2197  // Check for llvm.access.group metadata attached to the printf2198  // function in the loop body.2199  BasicBlock *LoopBody = CLI->getBody();2200  EXPECT_FALSE(any_of(*LoopBody, [](Instruction &I) {2201    return I.getMetadata("llvm.access.group") != nullptr;2202  }));2203}2204 2205TEST_F(OpenMPIRBuilderTest, ApplySimdIf) {2206  OpenMPIRBuilder OMPBuilder(*M);2207  IRBuilder<> Builder(BB);2208  MapVector<Value *, Value *> AlignedVars;2209  AllocaInst *Alloc1 = Builder.CreateAlloca(Builder.getInt32Ty());2210  AllocaInst *Alloc2 = Builder.CreateAlloca(Builder.getInt32Ty());2211 2212  // Generation of if condition2213  Builder.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx), 0U), Alloc1);2214  Builder.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx), 1U), Alloc2);2215  LoadInst *Load1 = Builder.CreateLoad(Alloc1->getAllocatedType(), Alloc1);2216  LoadInst *Load2 = Builder.CreateLoad(Alloc2->getAllocatedType(), Alloc2);2217 2218  Value *IfCmp = Builder.CreateICmpNE(Load1, Load2);2219 2220  CanonicalLoopInfo *CLI = buildSingleLoopFunction(DL, OMPBuilder, 32);2221  ASSERT_NE(CLI, nullptr);2222 2223  // Simd-ize the loop with if condition2224  OMPBuilder.applySimd(CLI, AlignedVars, IfCmp, OrderKind::OMP_ORDER_unknown,2225                       ConstantInt::get(Type::getInt32Ty(Ctx), 3),2226                       /* Safelen */ nullptr);2227 2228  OMPBuilder.finalize();2229  EXPECT_FALSE(verifyModule(*M, &errs()));2230 2231  PassBuilder PB;2232  FunctionAnalysisManager FAM;2233  PB.registerFunctionAnalyses(FAM);2234  LoopInfo &LI = FAM.getResult<LoopAnalysis>(*F);2235 2236  // Check if there is one loop containing branches with and without2237  // vectorization2238  const std::vector<Loop *> &TopLvl = LI.getTopLevelLoops();2239  EXPECT_EQ(TopLvl.size(), 1u);2240 2241  Loop *L = TopLvl[0];2242  EXPECT_TRUE(findStringMetadataForLoop(L, "llvm.loop.parallel_accesses"));2243  // These attributes cannot not be set because the loop is shared between simd2244  // and non-simd versions2245  EXPECT_FALSE(getBooleanLoopAttribute(L, "llvm.loop.vectorize.enable"));2246  EXPECT_EQ(getIntLoopAttribute(L, "llvm.loop.vectorize.width"), 0);2247 2248  // Check for if condition2249  BasicBlock *LoopBody = CLI->getBody();2250  BranchInst *IfCond = cast<BranchInst>(LoopBody->getTerminator());2251  EXPECT_EQ(IfCond->getCondition(), IfCmp);2252  BasicBlock *TrueBranch = IfCond->getSuccessor(0);2253  BasicBlock *FalseBranch = IfCond->getSuccessor(1)->getUniqueSuccessor();2254 2255  // Check for llvm.access.group metadata attached to the printf2256  // function in the true body.2257  EXPECT_TRUE(any_of(*TrueBranch, [](Instruction &I) {2258    return I.getMetadata("llvm.access.group") != nullptr;2259  }));2260 2261  // Check for llvm.access.group metadata attached to the printf2262  // function in the false body.2263  EXPECT_FALSE(any_of(*FalseBranch, [](Instruction &I) {2264    return I.getMetadata("llvm.access.group") != nullptr;2265  }));2266}2267 2268TEST_F(OpenMPIRBuilderTest, UnrollLoopFull) {2269  OpenMPIRBuilder OMPBuilder(*M);2270 2271  CanonicalLoopInfo *CLI = buildSingleLoopFunction(DL, OMPBuilder, 32);2272  ASSERT_NE(CLI, nullptr);2273 2274  // Unroll the loop.2275  OMPBuilder.unrollLoopFull(DL, CLI);2276 2277  OMPBuilder.finalize();2278  EXPECT_FALSE(verifyModule(*M, &errs()));2279 2280  PassBuilder PB;2281  FunctionAnalysisManager FAM;2282  PB.registerFunctionAnalyses(FAM);2283  LoopInfo &LI = FAM.getResult<LoopAnalysis>(*F);2284 2285  const std::vector<Loop *> &TopLvl = LI.getTopLevelLoops();2286  EXPECT_EQ(TopLvl.size(), 1u);2287 2288  Loop *L = TopLvl.front();2289  EXPECT_TRUE(getBooleanLoopAttribute(L, "llvm.loop.unroll.enable"));2290  EXPECT_TRUE(getBooleanLoopAttribute(L, "llvm.loop.unroll.full"));2291}2292 2293TEST_F(OpenMPIRBuilderTest, UnrollLoopPartial) {2294  OpenMPIRBuilder OMPBuilder(*M);2295  CanonicalLoopInfo *CLI = buildSingleLoopFunction(DL, OMPBuilder, 32);2296  ASSERT_NE(CLI, nullptr);2297 2298  // Unroll the loop.2299  CanonicalLoopInfo *UnrolledLoop = nullptr;2300  OMPBuilder.unrollLoopPartial(DL, CLI, 5, &UnrolledLoop);2301  ASSERT_NE(UnrolledLoop, nullptr);2302 2303  OMPBuilder.finalize();2304  EXPECT_FALSE(verifyModule(*M, &errs()));2305  UnrolledLoop->assertOK();2306 2307  PassBuilder PB;2308  FunctionAnalysisManager FAM;2309  PB.registerFunctionAnalyses(FAM);2310  LoopInfo &LI = FAM.getResult<LoopAnalysis>(*F);2311 2312  const std::vector<Loop *> &TopLvl = LI.getTopLevelLoops();2313  EXPECT_EQ(TopLvl.size(), 1u);2314  Loop *Outer = TopLvl.front();2315  EXPECT_EQ(Outer->getHeader(), UnrolledLoop->getHeader());2316  EXPECT_EQ(Outer->getLoopLatch(), UnrolledLoop->getLatch());2317  EXPECT_EQ(Outer->getExitingBlock(), UnrolledLoop->getCond());2318  EXPECT_EQ(Outer->getExitBlock(), UnrolledLoop->getExit());2319 2320  EXPECT_EQ(Outer->getSubLoops().size(), 1u);2321  Loop *Inner = Outer->getSubLoops().front();2322 2323  EXPECT_TRUE(getBooleanLoopAttribute(Inner, "llvm.loop.unroll.enable"));2324  EXPECT_EQ(getIntLoopAttribute(Inner, "llvm.loop.unroll.count"), 5);2325}2326 2327TEST_F(OpenMPIRBuilderTest, UnrollLoopHeuristic) {2328  OpenMPIRBuilder OMPBuilder(*M);2329 2330  CanonicalLoopInfo *CLI = buildSingleLoopFunction(DL, OMPBuilder, 32);2331  ASSERT_NE(CLI, nullptr);2332 2333  // Unroll the loop.2334  OMPBuilder.unrollLoopHeuristic(DL, CLI);2335 2336  OMPBuilder.finalize();2337  EXPECT_FALSE(verifyModule(*M, &errs()));2338 2339  PassBuilder PB;2340  FunctionAnalysisManager FAM;2341  PB.registerFunctionAnalyses(FAM);2342  LoopInfo &LI = FAM.getResult<LoopAnalysis>(*F);2343 2344  const std::vector<Loop *> &TopLvl = LI.getTopLevelLoops();2345  EXPECT_EQ(TopLvl.size(), 1u);2346 2347  Loop *L = TopLvl.front();2348  EXPECT_TRUE(getBooleanLoopAttribute(L, "llvm.loop.unroll.enable"));2349}2350 2351TEST_F(OpenMPIRBuilderTest, StaticWorkshareLoopTarget) {2352  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;2353  M->setDataLayout(2354      "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:"2355      "256:256:32-p8:128:128:128:48-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-"2356      "v192:"2357      "256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8");2358  OpenMPIRBuilder OMPBuilder(*M);2359  OMPBuilder.Config.IsTargetDevice = true;2360  OMPBuilder.Config.setIsGPU(false);2361  OMPBuilder.initialize();2362  IRBuilder<> Builder(BB);2363  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});2364  InsertPointTy AllocaIP = Builder.saveIP();2365 2366  Type *LCTy = Type::getInt32Ty(Ctx);2367  Value *StartVal = ConstantInt::get(LCTy, 10);2368  Value *StopVal = ConstantInt::get(LCTy, 52);2369  Value *StepVal = ConstantInt::get(LCTy, 2);2370  auto LoopBodyGen = [&](InsertPointTy, Value *) { return Error::success(); };2371 2372  ASSERT_EXPECTED_INIT(CanonicalLoopInfo *, CLI,2373                       OMPBuilder.createCanonicalLoop(Loc, LoopBodyGen,2374                                                      StartVal, StopVal,2375                                                      StepVal, false, false));2376  BasicBlock *Preheader = CLI->getPreheader();2377  Value *TripCount = CLI->getTripCount();2378 2379  Builder.SetInsertPoint(BB, BB->getFirstInsertionPt());2380 2381  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,2382                       OMPBuilder.applyWorkshareLoop(2383                           DL, CLI, AllocaIP, true, OMP_SCHEDULE_Static,2384                           nullptr, false, false, false, false,2385                           WorksharingLoopType::ForStaticLoop));2386  Builder.restoreIP(AfterIP);2387  Builder.CreateRetVoid();2388 2389  OMPBuilder.finalize();2390  EXPECT_FALSE(verifyModule(*M, &errs()));2391 2392  CallInst *WorkshareLoopRuntimeCall = nullptr;2393  int WorkshareLoopRuntimeCallCnt = 0;2394  for (auto Inst = Preheader->begin(); Inst != Preheader->end(); ++Inst) {2395    CallInst *Call = dyn_cast<CallInst>(Inst);2396    if (!Call)2397      continue;2398    if (!Call->getCalledFunction())2399      continue;2400 2401    if (Call->getCalledFunction()->getName() == "__kmpc_for_static_loop_4u") {2402      WorkshareLoopRuntimeCall = Call;2403      WorkshareLoopRuntimeCallCnt++;2404    }2405  }2406  EXPECT_NE(WorkshareLoopRuntimeCall, nullptr);2407  // Verify that there is only one call to workshare loop function2408  EXPECT_EQ(WorkshareLoopRuntimeCallCnt, 1);2409  // Check that pointer to loop body function is passed as second argument2410  Value *LoopBodyFuncArg = WorkshareLoopRuntimeCall->getArgOperand(1);2411  EXPECT_EQ(Builder.getPtrTy(), LoopBodyFuncArg->getType());2412  Function *ArgFunction = dyn_cast<Function>(LoopBodyFuncArg);2413  EXPECT_NE(ArgFunction, nullptr);2414  EXPECT_EQ(ArgFunction->arg_size(), 1u);2415  EXPECT_EQ(ArgFunction->getArg(0)->getType(), TripCount->getType());2416  // Check that no variables except for loop counter are used in loop body2417  EXPECT_EQ(Constant::getNullValue(Builder.getPtrTy()),2418            WorkshareLoopRuntimeCall->getArgOperand(2));2419  // Check loop trip count argument2420  EXPECT_EQ(TripCount, WorkshareLoopRuntimeCall->getArgOperand(3));2421}2422 2423TEST_F(OpenMPIRBuilderTest, StaticWorkShareLoop) {2424  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;2425  OpenMPIRBuilder OMPBuilder(*M);2426  OMPBuilder.Config.IsTargetDevice = false;2427  OMPBuilder.initialize();2428  IRBuilder<> Builder(BB);2429  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});2430 2431  Type *LCTy = Type::getInt32Ty(Ctx);2432  Value *StartVal = ConstantInt::get(LCTy, 10);2433  Value *StopVal = ConstantInt::get(LCTy, 52);2434  Value *StepVal = ConstantInt::get(LCTy, 2);2435  auto LoopBodyGen = [&](InsertPointTy, llvm::Value *) {2436    return Error::success();2437  };2438  ASSERT_EXPECTED_INIT(CanonicalLoopInfo *, CLI,2439                       OMPBuilder.createCanonicalLoop(2440                           Loc, LoopBodyGen, StartVal, StopVal, StepVal,2441                           /*IsSigned=*/false, /*InclusiveStop=*/false));2442  BasicBlock *Preheader = CLI->getPreheader();2443  BasicBlock *Body = CLI->getBody();2444  Value *IV = CLI->getIndVar();2445  BasicBlock *ExitBlock = CLI->getExit();2446 2447  Builder.SetInsertPoint(BB, BB->getFirstInsertionPt());2448  InsertPointTy AllocaIP = Builder.saveIP();2449 2450  ASSERT_THAT_EXPECTED(OMPBuilder.applyWorkshareLoop(DL, CLI, AllocaIP,2451                                                     /*NeedsBarrier=*/true,2452                                                     OMP_SCHEDULE_Static),2453                       Succeeded());2454 2455  BasicBlock *Cond = Body->getSinglePredecessor();2456  Instruction *Cmp = &*Cond->begin();2457  Value *TripCount = Cmp->getOperand(1);2458 2459  auto AllocaIter = BB->begin();2460  ASSERT_GE(std::distance(BB->begin(), BB->end()), 4);2461  AllocaInst *PLastIter = dyn_cast<AllocaInst>(&*(AllocaIter++));2462  AllocaInst *PLowerBound = dyn_cast<AllocaInst>(&*(AllocaIter++));2463  AllocaInst *PUpperBound = dyn_cast<AllocaInst>(&*(AllocaIter++));2464  AllocaInst *PStride = dyn_cast<AllocaInst>(&*(AllocaIter++));2465  EXPECT_NE(PLastIter, nullptr);2466  EXPECT_NE(PLowerBound, nullptr);2467  EXPECT_NE(PUpperBound, nullptr);2468  EXPECT_NE(PStride, nullptr);2469 2470  auto PreheaderIter = Preheader->begin();2471  ASSERT_GE(std::distance(Preheader->begin(), Preheader->end()), 7);2472  StoreInst *LowerBoundStore = dyn_cast<StoreInst>(&*(PreheaderIter++));2473  StoreInst *UpperBoundStore = dyn_cast<StoreInst>(&*(PreheaderIter++));2474  StoreInst *StrideStore = dyn_cast<StoreInst>(&*(PreheaderIter++));2475  ASSERT_NE(LowerBoundStore, nullptr);2476  ASSERT_NE(UpperBoundStore, nullptr);2477  ASSERT_NE(StrideStore, nullptr);2478 2479  auto *OrigLowerBound =2480      dyn_cast<ConstantInt>(LowerBoundStore->getValueOperand());2481  auto *OrigUpperBound =2482      dyn_cast<ConstantInt>(UpperBoundStore->getValueOperand());2483  auto *OrigStride = dyn_cast<ConstantInt>(StrideStore->getValueOperand());2484  ASSERT_NE(OrigLowerBound, nullptr);2485  ASSERT_NE(OrigUpperBound, nullptr);2486  ASSERT_NE(OrigStride, nullptr);2487  EXPECT_EQ(OrigLowerBound->getValue(), 0);2488  EXPECT_EQ(OrigUpperBound->getValue(), 20);2489  EXPECT_EQ(OrigStride->getValue(), 1);2490 2491  // Check that the loop IV is updated to account for the lower bound returned2492  // by the OpenMP runtime call.2493  BinaryOperator *Add = dyn_cast<BinaryOperator>(&Body->front());2494  EXPECT_EQ(Add->getOperand(0), IV);2495  auto *LoadedLowerBound = dyn_cast<LoadInst>(Add->getOperand(1));2496  ASSERT_NE(LoadedLowerBound, nullptr);2497  EXPECT_EQ(LoadedLowerBound->getPointerOperand(), PLowerBound);2498 2499  // Check that the trip count is updated to account for the lower and upper2500  // bounds return by the OpenMP runtime call.2501  auto *AddOne = dyn_cast<Instruction>(TripCount);2502  ASSERT_NE(AddOne, nullptr);2503  ASSERT_TRUE(AddOne->isBinaryOp());2504  auto *One = dyn_cast<ConstantInt>(AddOne->getOperand(1));2505  ASSERT_NE(One, nullptr);2506  EXPECT_EQ(One->getValue(), 1);2507  auto *Difference = dyn_cast<Instruction>(AddOne->getOperand(0));2508  ASSERT_NE(Difference, nullptr);2509  ASSERT_TRUE(Difference->isBinaryOp());2510  EXPECT_EQ(Difference->getOperand(1), LoadedLowerBound);2511  auto *LoadedUpperBound = dyn_cast<LoadInst>(Difference->getOperand(0));2512  ASSERT_NE(LoadedUpperBound, nullptr);2513  EXPECT_EQ(LoadedUpperBound->getPointerOperand(), PUpperBound);2514 2515  // The original loop iterator should only be used in the condition, in the2516  // increment and in the statement that adds the lower bound to it.2517  EXPECT_EQ(std::distance(IV->use_begin(), IV->use_end()), 3);2518 2519  // The exit block should contain the "fini" call and the barrier call,2520  // plus the call to obtain the thread ID.2521  size_t NumCallsInExitBlock =2522      count_if(*ExitBlock, [](Instruction &I) { return isa<CallInst>(I); });2523  EXPECT_EQ(NumCallsInExitBlock, 3u);2524}2525 2526TEST_P(OpenMPIRBuilderTestWithIVBits, StaticChunkedWorkshareLoop) {2527  unsigned IVBits = GetParam();2528 2529  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;2530  OpenMPIRBuilder OMPBuilder(*M);2531  OMPBuilder.Config.IsTargetDevice = false;2532 2533  BasicBlock *Body;2534  CallInst *Call;2535  CanonicalLoopInfo *CLI =2536      buildSingleLoopFunction(DL, OMPBuilder, IVBits, &Call, &Body);2537  ASSERT_NE(CLI, nullptr);2538 2539  Instruction *OrigIndVar = CLI->getIndVar();2540  EXPECT_EQ(Call->getOperand(1), OrigIndVar);2541 2542  Type *LCTy = Type::getInt32Ty(Ctx);2543  Value *ChunkSize = ConstantInt::get(LCTy, 5);2544  InsertPointTy AllocaIP{&F->getEntryBlock(),2545                         F->getEntryBlock().getFirstInsertionPt()};2546  ASSERT_THAT_EXPECTED(OMPBuilder.applyWorkshareLoop(DL, CLI, AllocaIP,2547                                                     /*NeedsBarrier=*/true,2548                                                     OMP_SCHEDULE_Static,2549                                                     ChunkSize),2550                       Succeeded());2551 2552  OMPBuilder.finalize();2553  EXPECT_FALSE(verifyModule(*M, &errs()));2554 2555  BasicBlock *Entry = &F->getEntryBlock();2556  BasicBlock *Preheader = Entry->getSingleSuccessor();2557 2558  BasicBlock *DispatchPreheader = Preheader->getSingleSuccessor();2559  BasicBlock *DispatchHeader = DispatchPreheader->getSingleSuccessor();2560  BasicBlock *DispatchCond = DispatchHeader->getSingleSuccessor();2561  BasicBlock *DispatchBody = succ_begin(DispatchCond)[0];2562  BasicBlock *DispatchExit = succ_begin(DispatchCond)[1];2563  BasicBlock *DispatchAfter = DispatchExit->getSingleSuccessor();2564  BasicBlock *Return = DispatchAfter->getSingleSuccessor();2565 2566  BasicBlock *ChunkPreheader = DispatchBody->getSingleSuccessor();2567  BasicBlock *ChunkHeader = ChunkPreheader->getSingleSuccessor();2568  BasicBlock *ChunkCond = ChunkHeader->getSingleSuccessor();2569  BasicBlock *ChunkBody = succ_begin(ChunkCond)[0];2570  BasicBlock *ChunkExit = succ_begin(ChunkCond)[1];2571  BasicBlock *ChunkInc = ChunkBody->getSingleSuccessor();2572  BasicBlock *ChunkAfter = ChunkExit->getSingleSuccessor();2573 2574  BasicBlock *DispatchInc = ChunkAfter;2575 2576  EXPECT_EQ(ChunkBody, Body);2577  EXPECT_EQ(ChunkInc->getSingleSuccessor(), ChunkHeader);2578  EXPECT_EQ(DispatchInc->getSingleSuccessor(), DispatchHeader);2579 2580  EXPECT_TRUE(isa<ReturnInst>(Return->front()));2581 2582  Value *NewIV = Call->getOperand(1);2583  EXPECT_EQ(NewIV->getType()->getScalarSizeInBits(), IVBits);2584 2585  CallInst *InitCall = findSingleCall(2586      F,2587      (IVBits > 32) ? omp::RuntimeFunction::OMPRTL___kmpc_for_static_init_8u2588                    : omp::RuntimeFunction::OMPRTL___kmpc_for_static_init_4u,2589      OMPBuilder);2590  EXPECT_EQ(InitCall->getParent(), Preheader);2591  EXPECT_EQ(cast<ConstantInt>(InitCall->getArgOperand(2))->getSExtValue(), 33);2592  EXPECT_EQ(cast<ConstantInt>(InitCall->getArgOperand(7))->getSExtValue(), 1);2593  EXPECT_EQ(cast<ConstantInt>(InitCall->getArgOperand(8))->getSExtValue(), 5);2594 2595  CallInst *FiniCall = findSingleCall(2596      F, omp::RuntimeFunction::OMPRTL___kmpc_for_static_fini, OMPBuilder);2597  EXPECT_EQ(FiniCall->getParent(), DispatchExit);2598 2599  CallInst *BarrierCall = findSingleCall(2600      F, omp::RuntimeFunction::OMPRTL___kmpc_barrier, OMPBuilder);2601  EXPECT_EQ(BarrierCall->getParent(), DispatchExit);2602}2603 2604INSTANTIATE_TEST_SUITE_P(IVBits, OpenMPIRBuilderTestWithIVBits,2605                         ::testing::Values(8, 16, 32, 64));2606 2607TEST_P(OpenMPIRBuilderTestWithParams, DynamicWorkShareLoop) {2608  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;2609  OpenMPIRBuilder OMPBuilder(*M);2610  OMPBuilder.Config.IsTargetDevice = false;2611  OMPBuilder.initialize();2612  IRBuilder<> Builder(BB);2613  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});2614 2615  omp::OMPScheduleType SchedType = GetParam();2616  uint32_t ChunkSize = 1;2617  switch (SchedType & ~OMPScheduleType::ModifierMask) {2618  case omp::OMPScheduleType::BaseDynamicChunked:2619  case omp::OMPScheduleType::BaseGuidedChunked:2620    ChunkSize = 7;2621    break;2622  case omp::OMPScheduleType::BaseAuto:2623  case omp::OMPScheduleType::BaseRuntime:2624    ChunkSize = 1;2625    break;2626  default:2627    assert(0 && "unknown type for this test");2628    break;2629  }2630 2631  Type *LCTy = Type::getInt32Ty(Ctx);2632  Value *StartVal = ConstantInt::get(LCTy, 10);2633  Value *StopVal = ConstantInt::get(LCTy, 52);2634  Value *StepVal = ConstantInt::get(LCTy, 2);2635  Value *ChunkVal =2636      (ChunkSize == 1) ? nullptr : ConstantInt::get(LCTy, ChunkSize);2637  auto LoopBodyGen = [&](InsertPointTy, llvm::Value *) {2638    return Error::success();2639  };2640 2641  ASSERT_EXPECTED_INIT(CanonicalLoopInfo *, CLI,2642                       OMPBuilder.createCanonicalLoop(2643                           Loc, LoopBodyGen, StartVal, StopVal, StepVal,2644                           /*IsSigned=*/false, /*InclusiveStop=*/false));2645 2646  Builder.SetInsertPoint(BB, BB->getFirstInsertionPt());2647  InsertPointTy AllocaIP = Builder.saveIP();2648 2649  // Collect all the info from CLI, as it isn't usable after the call to2650  // createDynamicWorkshareLoop.2651  InsertPointTy AfterIP = CLI->getAfterIP();2652  BasicBlock *Preheader = CLI->getPreheader();2653  BasicBlock *ExitBlock = CLI->getExit();2654  BasicBlock *LatchBlock = CLI->getLatch();2655  Value *IV = CLI->getIndVar();2656 2657  ASSERT_EXPECTED_INIT(2658      OpenMPIRBuilder::InsertPointTy, EndIP,2659      OMPBuilder.applyWorkshareLoop(2660          DL, CLI, AllocaIP, /*NeedsBarrier=*/true, getSchedKind(SchedType),2661          ChunkVal, /*Simd=*/false,2662          (SchedType & omp::OMPScheduleType::ModifierMonotonic) ==2663              omp::OMPScheduleType::ModifierMonotonic,2664          (SchedType & omp::OMPScheduleType::ModifierNonmonotonic) ==2665              omp::OMPScheduleType::ModifierNonmonotonic,2666          /*Ordered=*/false));2667 2668  // The returned value should be the "after" point.2669  ASSERT_EQ(EndIP.getBlock(), AfterIP.getBlock());2670  ASSERT_EQ(EndIP.getPoint(), AfterIP.getPoint());2671 2672  auto AllocaIter = BB->begin();2673  ASSERT_GE(std::distance(BB->begin(), BB->end()), 4);2674  AllocaInst *PLastIter = dyn_cast<AllocaInst>(&*(AllocaIter++));2675  AllocaInst *PLowerBound = dyn_cast<AllocaInst>(&*(AllocaIter++));2676  AllocaInst *PUpperBound = dyn_cast<AllocaInst>(&*(AllocaIter++));2677  AllocaInst *PStride = dyn_cast<AllocaInst>(&*(AllocaIter++));2678  EXPECT_NE(PLastIter, nullptr);2679  EXPECT_NE(PLowerBound, nullptr);2680  EXPECT_NE(PUpperBound, nullptr);2681  EXPECT_NE(PStride, nullptr);2682 2683  auto PreheaderIter = Preheader->begin();2684  ASSERT_GE(std::distance(Preheader->begin(), Preheader->end()), 6);2685  StoreInst *LowerBoundStore = dyn_cast<StoreInst>(&*(PreheaderIter++));2686  StoreInst *UpperBoundStore = dyn_cast<StoreInst>(&*(PreheaderIter++));2687  StoreInst *StrideStore = dyn_cast<StoreInst>(&*(PreheaderIter++));2688  ASSERT_NE(LowerBoundStore, nullptr);2689  ASSERT_NE(UpperBoundStore, nullptr);2690  ASSERT_NE(StrideStore, nullptr);2691 2692  CallInst *ThreadIdCall = dyn_cast<CallInst>(&*(PreheaderIter++));2693  ASSERT_NE(ThreadIdCall, nullptr);2694  EXPECT_EQ(ThreadIdCall->getCalledFunction()->getName(),2695            "__kmpc_global_thread_num");2696 2697  CallInst *InitCall = dyn_cast<CallInst>(&*PreheaderIter);2698 2699  ASSERT_NE(InitCall, nullptr);2700  EXPECT_EQ(InitCall->getCalledFunction()->getName(),2701            "__kmpc_dispatch_init_4u");2702  EXPECT_EQ(InitCall->arg_size(), 7U);2703  EXPECT_EQ(InitCall->getArgOperand(6), ConstantInt::get(LCTy, ChunkSize));2704  ConstantInt *SchedVal = cast<ConstantInt>(InitCall->getArgOperand(2));2705  if ((SchedType & OMPScheduleType::MonotonicityMask) ==2706      OMPScheduleType::None) {2707    // Implementation is allowed to add default nonmonotonicity flag2708    EXPECT_EQ(2709        static_cast<OMPScheduleType>(SchedVal->getValue().getZExtValue()) |2710            OMPScheduleType::ModifierNonmonotonic,2711        SchedType | OMPScheduleType::ModifierNonmonotonic);2712  } else {2713    EXPECT_EQ(static_cast<OMPScheduleType>(SchedVal->getValue().getZExtValue()),2714              SchedType);2715  }2716 2717  ConstantInt *OrigLowerBound =2718      dyn_cast<ConstantInt>(LowerBoundStore->getValueOperand());2719  ConstantInt *OrigUpperBound =2720      dyn_cast<ConstantInt>(UpperBoundStore->getValueOperand());2721  ConstantInt *OrigStride =2722      dyn_cast<ConstantInt>(StrideStore->getValueOperand());2723  ASSERT_NE(OrigLowerBound, nullptr);2724  ASSERT_NE(OrigUpperBound, nullptr);2725  ASSERT_NE(OrigStride, nullptr);2726  EXPECT_EQ(OrigLowerBound->getValue(), 1);2727  EXPECT_EQ(OrigUpperBound->getValue(), 21);2728  EXPECT_EQ(OrigStride->getValue(), 1);2729 2730  CallInst *FiniCall =2731      dyn_cast<CallInst>(&*(LatchBlock->getTerminator()->getPrevNode()));2732  EXPECT_EQ(FiniCall, nullptr);2733 2734  // The original loop iterator should only be used in the condition, in the2735  // increment and in the statement that adds the lower bound to it.2736  EXPECT_EQ(std::distance(IV->use_begin(), IV->use_end()), 3);2737 2738  // The exit block should contain the barrier call, plus the call to obtain2739  // the thread ID.2740  size_t NumCallsInExitBlock =2741      count_if(*ExitBlock, [](Instruction &I) { return isa<CallInst>(I); });2742  EXPECT_EQ(NumCallsInExitBlock, 2u);2743 2744  // Add a termination to our block and check that it is internally consistent.2745  Builder.restoreIP(EndIP);2746  Builder.CreateRetVoid();2747  OMPBuilder.finalize();2748  EXPECT_FALSE(verifyModule(*M, &errs()));2749}2750 2751INSTANTIATE_TEST_SUITE_P(2752    OpenMPWSLoopSchedulingTypes, OpenMPIRBuilderTestWithParams,2753    ::testing::Values(omp::OMPScheduleType::UnorderedDynamicChunked,2754                      omp::OMPScheduleType::UnorderedGuidedChunked,2755                      omp::OMPScheduleType::UnorderedAuto,2756                      omp::OMPScheduleType::UnorderedRuntime,2757                      omp::OMPScheduleType::UnorderedDynamicChunked |2758                          omp::OMPScheduleType::ModifierMonotonic,2759                      omp::OMPScheduleType::UnorderedDynamicChunked |2760                          omp::OMPScheduleType::ModifierNonmonotonic,2761                      omp::OMPScheduleType::UnorderedGuidedChunked |2762                          omp::OMPScheduleType::ModifierMonotonic,2763                      omp::OMPScheduleType::UnorderedGuidedChunked |2764                          omp::OMPScheduleType::ModifierNonmonotonic,2765                      omp::OMPScheduleType::UnorderedAuto |2766                          omp::OMPScheduleType::ModifierMonotonic,2767                      omp::OMPScheduleType::UnorderedRuntime |2768                          omp::OMPScheduleType::ModifierMonotonic));2769 2770TEST_F(OpenMPIRBuilderTest, DynamicWorkShareLoopOrdered) {2771  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;2772  OpenMPIRBuilder OMPBuilder(*M);2773  OMPBuilder.Config.IsTargetDevice = false;2774  OMPBuilder.initialize();2775  IRBuilder<> Builder(BB);2776  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});2777 2778  uint32_t ChunkSize = 1;2779  Type *LCTy = Type::getInt32Ty(Ctx);2780  Value *StartVal = ConstantInt::get(LCTy, 10);2781  Value *StopVal = ConstantInt::get(LCTy, 52);2782  Value *StepVal = ConstantInt::get(LCTy, 2);2783  Value *ChunkVal = ConstantInt::get(LCTy, ChunkSize);2784  auto LoopBodyGen = [&](InsertPointTy, llvm::Value *) {2785    return llvm::Error::success();2786  };2787 2788  ASSERT_EXPECTED_INIT(CanonicalLoopInfo *, CLI,2789                       OMPBuilder.createCanonicalLoop(2790                           Loc, LoopBodyGen, StartVal, StopVal, StepVal,2791                           /*IsSigned=*/false, /*InclusiveStop=*/false));2792 2793  Builder.SetInsertPoint(BB, BB->getFirstInsertionPt());2794  InsertPointTy AllocaIP = Builder.saveIP();2795 2796  // Collect all the info from CLI, as it isn't usable after the call to2797  // createDynamicWorkshareLoop.2798  BasicBlock *Preheader = CLI->getPreheader();2799  BasicBlock *ExitBlock = CLI->getExit();2800  BasicBlock *LatchBlock = CLI->getLatch();2801  Value *IV = CLI->getIndVar();2802 2803  ASSERT_EXPECTED_INIT(2804      OpenMPIRBuilder::InsertPointTy, EndIP,2805      OMPBuilder.applyWorkshareLoop(DL, CLI, AllocaIP, /*NeedsBarrier=*/true,2806                                    OMP_SCHEDULE_Static, ChunkVal,2807                                    /*HasSimdModifier=*/false,2808                                    /*HasMonotonicModifier=*/false,2809                                    /*HasNonmonotonicModifier=*/false,2810                                    /*HasOrderedClause=*/true));2811 2812  // Add a termination to our block and check that it is internally consistent.2813  Builder.restoreIP(EndIP);2814  Builder.CreateRetVoid();2815  OMPBuilder.finalize();2816  EXPECT_FALSE(verifyModule(*M, &errs()));2817 2818  CallInst *InitCall = nullptr;2819  for (Instruction &EI : *Preheader) {2820    Instruction *Cur = &EI;2821    if (isa<CallInst>(Cur)) {2822      InitCall = cast<CallInst>(Cur);2823      if (InitCall->getCalledFunction()->getName() == "__kmpc_dispatch_init_4u")2824        break;2825      InitCall = nullptr;2826    }2827  }2828  EXPECT_NE(InitCall, nullptr);2829  EXPECT_EQ(InitCall->arg_size(), 7U);2830  ConstantInt *SchedVal = cast<ConstantInt>(InitCall->getArgOperand(2));2831  EXPECT_EQ(SchedVal->getValue(),2832            static_cast<uint64_t>(OMPScheduleType::OrderedStaticChunked));2833 2834  CallInst *FiniCall =2835      dyn_cast<CallInst>(&*(LatchBlock->getTerminator()->getPrevNode()));2836  ASSERT_NE(FiniCall, nullptr);2837  EXPECT_EQ(FiniCall->getCalledFunction()->getName(),2838            "__kmpc_dispatch_fini_4u");2839  EXPECT_EQ(FiniCall->arg_size(), 2U);2840  EXPECT_EQ(InitCall->getArgOperand(0), FiniCall->getArgOperand(0));2841  EXPECT_EQ(InitCall->getArgOperand(1), FiniCall->getArgOperand(1));2842 2843  // The original loop iterator should only be used in the condition, in the2844  // increment and in the statement that adds the lower bound to it.2845  EXPECT_EQ(std::distance(IV->use_begin(), IV->use_end()), 3);2846 2847  // The exit block should contain the barrier call, plus the call to obtain2848  // the thread ID.2849  size_t NumCallsInExitBlock =2850      count_if(*ExitBlock, [](Instruction &I) { return isa<CallInst>(I); });2851  EXPECT_EQ(NumCallsInExitBlock, 2u);2852}2853 2854TEST_F(OpenMPIRBuilderTest, MasterDirective) {2855  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;2856  OpenMPIRBuilder OMPBuilder(*M);2857  OMPBuilder.initialize();2858  F->setName("func");2859  IRBuilder<> Builder(BB);2860 2861  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});2862 2863  AllocaInst *PrivAI = nullptr;2864 2865  BasicBlock *EntryBB = nullptr;2866  BasicBlock *ThenBB = nullptr;2867 2868  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {2869    if (AllocaIP.isSet())2870      Builder.restoreIP(AllocaIP);2871    else2872      Builder.SetInsertPoint(&*(F->getEntryBlock().getFirstInsertionPt()));2873    PrivAI = Builder.CreateAlloca(F->arg_begin()->getType());2874    Builder.CreateStore(F->arg_begin(), PrivAI);2875 2876    llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock();2877    llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint();2878    EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst);2879 2880    Builder.restoreIP(CodeGenIP);2881 2882    // collect some info for checks later2883    ThenBB = Builder.GetInsertBlock();2884    EntryBB = ThenBB->getUniquePredecessor();2885 2886    // simple instructions for body2887    Value *PrivLoad =2888        Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use");2889    Builder.CreateICmpNE(F->arg_begin(), PrivLoad);2890  };2891 2892  auto FiniCB = [&](InsertPointTy IP) {2893    BasicBlock *IPBB = IP.getBlock();2894    EXPECT_NE(IPBB->end(), IP.getPoint());2895  };2896 2897  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,2898                       OMPBuilder.createMaster(Builder,2899                                               BODYGENCB_WRAPPER(BodyGenCB),2900                                               FINICB_WRAPPER(FiniCB)));2901  Builder.restoreIP(AfterIP);2902  Value *EntryBBTI = EntryBB->getTerminator();2903  EXPECT_NE(EntryBBTI, nullptr);2904  EXPECT_TRUE(isa<BranchInst>(EntryBBTI));2905  BranchInst *EntryBr = cast<BranchInst>(EntryBB->getTerminator());2906  EXPECT_TRUE(EntryBr->isConditional());2907  EXPECT_EQ(EntryBr->getSuccessor(0), ThenBB);2908  BasicBlock *FinalizeBB = ThenBB->getUniqueSuccessor();2909  BasicBlock *ExitBB = FinalizeBB->getUniqueSuccessor();2910  EXPECT_EQ(EntryBr->getSuccessor(1), ExitBB);2911 2912  CmpInst *CondInst = cast<CmpInst>(EntryBr->getCondition());2913  EXPECT_TRUE(isa<CallInst>(CondInst->getOperand(0)));2914 2915  CallInst *MasterEntryCI = cast<CallInst>(CondInst->getOperand(0));2916  EXPECT_EQ(MasterEntryCI->arg_size(), 2U);2917  EXPECT_EQ(MasterEntryCI->getCalledFunction()->getName(), "__kmpc_master");2918  EXPECT_TRUE(isa<GlobalVariable>(MasterEntryCI->getArgOperand(0)));2919 2920  CallInst *MasterEndCI = nullptr;2921  for (auto &FI : *FinalizeBB) {2922    Instruction *cur = &FI;2923    if (isa<CallInst>(cur)) {2924      MasterEndCI = cast<CallInst>(cur);2925      if (MasterEndCI->getCalledFunction()->getName() == "__kmpc_end_master")2926        break;2927      MasterEndCI = nullptr;2928    }2929  }2930  EXPECT_NE(MasterEndCI, nullptr);2931  EXPECT_EQ(MasterEndCI->arg_size(), 2U);2932  EXPECT_TRUE(isa<GlobalVariable>(MasterEndCI->getArgOperand(0)));2933  EXPECT_EQ(MasterEndCI->getArgOperand(1), MasterEntryCI->getArgOperand(1));2934}2935 2936TEST_F(OpenMPIRBuilderTest, MaskedDirective) {2937  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;2938  OpenMPIRBuilder OMPBuilder(*M);2939  OMPBuilder.initialize();2940  F->setName("func");2941  IRBuilder<> Builder(BB);2942 2943  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});2944 2945  AllocaInst *PrivAI = nullptr;2946 2947  BasicBlock *EntryBB = nullptr;2948  BasicBlock *ThenBB = nullptr;2949 2950  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {2951    if (AllocaIP.isSet())2952      Builder.restoreIP(AllocaIP);2953    else2954      Builder.SetInsertPoint(&*(F->getEntryBlock().getFirstInsertionPt()));2955    PrivAI = Builder.CreateAlloca(F->arg_begin()->getType());2956    Builder.CreateStore(F->arg_begin(), PrivAI);2957 2958    llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock();2959    llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint();2960    EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst);2961 2962    Builder.restoreIP(CodeGenIP);2963 2964    // collect some info for checks later2965    ThenBB = Builder.GetInsertBlock();2966    EntryBB = ThenBB->getUniquePredecessor();2967 2968    // simple instructions for body2969    Value *PrivLoad =2970        Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use");2971    Builder.CreateICmpNE(F->arg_begin(), PrivLoad);2972  };2973 2974  auto FiniCB = [&](InsertPointTy IP) {2975    BasicBlock *IPBB = IP.getBlock();2976    EXPECT_NE(IPBB->end(), IP.getPoint());2977  };2978 2979  Constant *Filter = ConstantInt::get(Type::getInt32Ty(M->getContext()), 0);2980  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,2981                       OMPBuilder.createMasked(Builder,2982                                               BODYGENCB_WRAPPER(BodyGenCB),2983                                               FINICB_WRAPPER(FiniCB), Filter));2984  Builder.restoreIP(AfterIP);2985  Value *EntryBBTI = EntryBB->getTerminator();2986  EXPECT_NE(EntryBBTI, nullptr);2987  EXPECT_TRUE(isa<BranchInst>(EntryBBTI));2988  BranchInst *EntryBr = cast<BranchInst>(EntryBB->getTerminator());2989  EXPECT_TRUE(EntryBr->isConditional());2990  EXPECT_EQ(EntryBr->getSuccessor(0), ThenBB);2991  BasicBlock *FinalizeBB = ThenBB->getUniqueSuccessor();2992  BasicBlock *ExitBB = FinalizeBB->getUniqueSuccessor();2993  EXPECT_EQ(EntryBr->getSuccessor(1), ExitBB);2994 2995  CmpInst *CondInst = cast<CmpInst>(EntryBr->getCondition());2996  EXPECT_TRUE(isa<CallInst>(CondInst->getOperand(0)));2997 2998  CallInst *MaskedEntryCI = cast<CallInst>(CondInst->getOperand(0));2999  EXPECT_EQ(MaskedEntryCI->arg_size(), 3U);3000  EXPECT_EQ(MaskedEntryCI->getCalledFunction()->getName(), "__kmpc_masked");3001  EXPECT_TRUE(isa<GlobalVariable>(MaskedEntryCI->getArgOperand(0)));3002 3003  CallInst *MaskedEndCI = nullptr;3004  for (auto &FI : *FinalizeBB) {3005    Instruction *cur = &FI;3006    if (isa<CallInst>(cur)) {3007      MaskedEndCI = cast<CallInst>(cur);3008      if (MaskedEndCI->getCalledFunction()->getName() == "__kmpc_end_masked")3009        break;3010      MaskedEndCI = nullptr;3011    }3012  }3013  EXPECT_NE(MaskedEndCI, nullptr);3014  EXPECT_EQ(MaskedEndCI->arg_size(), 2U);3015  EXPECT_TRUE(isa<GlobalVariable>(MaskedEndCI->getArgOperand(0)));3016  EXPECT_EQ(MaskedEndCI->getArgOperand(1), MaskedEntryCI->getArgOperand(1));3017}3018 3019TEST_F(OpenMPIRBuilderTest, CriticalDirective) {3020  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;3021  OpenMPIRBuilder OMPBuilder(*M);3022  OMPBuilder.initialize();3023  F->setName("func");3024  IRBuilder<> Builder(BB);3025 3026  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});3027 3028  AllocaInst *PrivAI = Builder.CreateAlloca(F->arg_begin()->getType());3029 3030  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {3031    // actual start for bodyCB3032    llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock();3033    llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint();3034    EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst);3035 3036    // body begin3037    Builder.restoreIP(CodeGenIP);3038    Builder.CreateStore(F->arg_begin(), PrivAI);3039    Value *PrivLoad =3040        Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use");3041    Builder.CreateICmpNE(F->arg_begin(), PrivLoad);3042  };3043 3044  auto FiniCB = [&](InsertPointTy IP) {3045    BasicBlock *IPBB = IP.getBlock();3046    EXPECT_NE(IPBB->end(), IP.getPoint());3047  };3048  BasicBlock *EntryBB = Builder.GetInsertBlock();3049 3050  ASSERT_EXPECTED_INIT(3051      OpenMPIRBuilder::InsertPointTy, AfterIP,3052      OMPBuilder.createCritical(Builder, BODYGENCB_WRAPPER(BodyGenCB),3053                                FINICB_WRAPPER(FiniCB), "testCRT", nullptr));3054  Builder.restoreIP(AfterIP);3055 3056  BasicBlock *FinalizeBB = EntryBB->getUniqueSuccessor();3057  EXPECT_NE(FinalizeBB, nullptr);3058 3059  CallInst *CriticalEntryCI = nullptr;3060  for (auto &EI : *EntryBB) {3061    Instruction *cur = &EI;3062    if (isa<CallInst>(cur)) {3063      CriticalEntryCI = cast<CallInst>(cur);3064      if (CriticalEntryCI->getCalledFunction()->getName() == "__kmpc_critical")3065        break;3066      CriticalEntryCI = nullptr;3067    }3068  }3069  EXPECT_NE(CriticalEntryCI, nullptr);3070  EXPECT_EQ(CriticalEntryCI->arg_size(), 3U);3071  EXPECT_EQ(CriticalEntryCI->getCalledFunction()->getName(), "__kmpc_critical");3072  EXPECT_TRUE(isa<GlobalVariable>(CriticalEntryCI->getArgOperand(0)));3073 3074  CallInst *CriticalEndCI = nullptr;3075  for (auto &FI : *FinalizeBB) {3076    Instruction *cur = &FI;3077    if (isa<CallInst>(cur)) {3078      CriticalEndCI = cast<CallInst>(cur);3079      if (CriticalEndCI->getCalledFunction()->getName() ==3080          "__kmpc_end_critical")3081        break;3082      CriticalEndCI = nullptr;3083    }3084  }3085  EXPECT_NE(CriticalEndCI, nullptr);3086  EXPECT_EQ(CriticalEndCI->arg_size(), 3U);3087  EXPECT_TRUE(isa<GlobalVariable>(CriticalEndCI->getArgOperand(0)));3088  EXPECT_EQ(CriticalEndCI->getArgOperand(1), CriticalEntryCI->getArgOperand(1));3089  PointerType *CriticalNamePtrTy = PointerType::getUnqual(Ctx);3090  EXPECT_EQ(CriticalEndCI->getArgOperand(2), CriticalEntryCI->getArgOperand(2));3091  GlobalVariable *GV =3092      dyn_cast<GlobalVariable>(CriticalEndCI->getArgOperand(2));3093  ASSERT_NE(GV, nullptr);3094  EXPECT_EQ(GV->getType(), CriticalNamePtrTy);3095  const DataLayout &DL = M->getDataLayout();3096  const llvm::Align TypeAlign = DL.getABITypeAlign(CriticalNamePtrTy);3097  const llvm::Align PtrAlign = DL.getPointerABIAlignment(GV->getAddressSpace());3098  if (const llvm::MaybeAlign Alignment = GV->getAlign())3099    EXPECT_EQ(*Alignment, std::max(TypeAlign, PtrAlign));3100}3101 3102TEST_F(OpenMPIRBuilderTest, OrderedDirectiveDependSource) {3103  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;3104  OpenMPIRBuilder OMPBuilder(*M);3105  OMPBuilder.initialize();3106  F->setName("func");3107  IRBuilder<> Builder(BB);3108  LLVMContext &Ctx = M->getContext();3109 3110  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});3111 3112  InsertPointTy AllocaIP(&F->getEntryBlock(),3113                         F->getEntryBlock().getFirstInsertionPt());3114 3115  unsigned NumLoops = 2;3116  SmallVector<Value *, 2> StoreValues;3117  Type *LCTy = Type::getInt64Ty(Ctx);3118  StoreValues.emplace_back(ConstantInt::get(LCTy, 1));3119  StoreValues.emplace_back(ConstantInt::get(LCTy, 2));3120 3121  // Test for "#omp ordered depend(source)"3122  Builder.restoreIP(OMPBuilder.createOrderedDepend(Builder, AllocaIP, NumLoops,3123                                                   StoreValues, ".cnt.addr",3124                                                   /*IsDependSource=*/true));3125 3126  Builder.CreateRetVoid();3127  OMPBuilder.finalize();3128  EXPECT_FALSE(verifyModule(*M, &errs()));3129 3130  AllocaInst *AllocInst = dyn_cast<AllocaInst>(&BB->front());3131  ASSERT_NE(AllocInst, nullptr);3132  ArrayType *ArrType = dyn_cast<ArrayType>(AllocInst->getAllocatedType());3133  EXPECT_EQ(ArrType->getNumElements(), NumLoops);3134  EXPECT_TRUE(3135      AllocInst->getAllocatedType()->getArrayElementType()->isIntegerTy(64));3136 3137  Instruction *IterInst = dyn_cast<Instruction>(AllocInst);3138  for (unsigned Iter = 0; Iter < NumLoops; Iter++) {3139    GetElementPtrInst *DependAddrGEPIter =3140        dyn_cast<GetElementPtrInst>(IterInst->getNextNode());3141    ASSERT_NE(DependAddrGEPIter, nullptr);3142    EXPECT_EQ(DependAddrGEPIter->getPointerOperand(), AllocInst);3143    EXPECT_EQ(DependAddrGEPIter->getNumIndices(), (unsigned)2);3144    auto *FirstIdx = dyn_cast<ConstantInt>(DependAddrGEPIter->getOperand(1));3145    auto *SecondIdx = dyn_cast<ConstantInt>(DependAddrGEPIter->getOperand(2));3146    ASSERT_NE(FirstIdx, nullptr);3147    ASSERT_NE(SecondIdx, nullptr);3148    EXPECT_EQ(FirstIdx->getValue(), 0);3149    EXPECT_EQ(SecondIdx->getValue(), Iter);3150    StoreInst *StoreValue =3151        dyn_cast<StoreInst>(DependAddrGEPIter->getNextNode());3152    ASSERT_NE(StoreValue, nullptr);3153    EXPECT_EQ(StoreValue->getValueOperand(), StoreValues[Iter]);3154    EXPECT_EQ(StoreValue->getPointerOperand(), DependAddrGEPIter);3155    EXPECT_EQ(StoreValue->getAlign(), Align(8));3156    IterInst = dyn_cast<Instruction>(StoreValue);3157  }3158 3159  GetElementPtrInst *DependBaseAddrGEP =3160      dyn_cast<GetElementPtrInst>(IterInst->getNextNode());3161  ASSERT_NE(DependBaseAddrGEP, nullptr);3162  EXPECT_EQ(DependBaseAddrGEP->getPointerOperand(), AllocInst);3163  EXPECT_EQ(DependBaseAddrGEP->getNumIndices(), (unsigned)2);3164  auto *FirstIdx = dyn_cast<ConstantInt>(DependBaseAddrGEP->getOperand(1));3165  auto *SecondIdx = dyn_cast<ConstantInt>(DependBaseAddrGEP->getOperand(2));3166  ASSERT_NE(FirstIdx, nullptr);3167  ASSERT_NE(SecondIdx, nullptr);3168  EXPECT_EQ(FirstIdx->getValue(), 0);3169  EXPECT_EQ(SecondIdx->getValue(), 0);3170 3171  CallInst *GTID = dyn_cast<CallInst>(DependBaseAddrGEP->getNextNode());3172  ASSERT_NE(GTID, nullptr);3173  EXPECT_EQ(GTID->arg_size(), 1U);3174  EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num");3175  EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory());3176  EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory());3177 3178  CallInst *Depend = dyn_cast<CallInst>(GTID->getNextNode());3179  ASSERT_NE(Depend, nullptr);3180  EXPECT_EQ(Depend->arg_size(), 3U);3181  EXPECT_EQ(Depend->getCalledFunction()->getName(), "__kmpc_doacross_post");3182  EXPECT_TRUE(isa<GlobalVariable>(Depend->getArgOperand(0)));3183  EXPECT_EQ(Depend->getArgOperand(1), GTID);3184  EXPECT_EQ(Depend->getArgOperand(2), DependBaseAddrGEP);3185}3186 3187TEST_F(OpenMPIRBuilderTest, OrderedDirectiveDependSink) {3188  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;3189  OpenMPIRBuilder OMPBuilder(*M);3190  OMPBuilder.initialize();3191  F->setName("func");3192  IRBuilder<> Builder(BB);3193  LLVMContext &Ctx = M->getContext();3194 3195  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});3196 3197  InsertPointTy AllocaIP(&F->getEntryBlock(),3198                         F->getEntryBlock().getFirstInsertionPt());3199 3200  unsigned NumLoops = 2;3201  SmallVector<Value *, 2> StoreValues;3202  Type *LCTy = Type::getInt64Ty(Ctx);3203  StoreValues.emplace_back(ConstantInt::get(LCTy, 1));3204  StoreValues.emplace_back(ConstantInt::get(LCTy, 2));3205 3206  // Test for "#omp ordered depend(sink: vec)"3207  Builder.restoreIP(OMPBuilder.createOrderedDepend(Builder, AllocaIP, NumLoops,3208                                                   StoreValues, ".cnt.addr",3209                                                   /*IsDependSource=*/false));3210 3211  Builder.CreateRetVoid();3212  OMPBuilder.finalize();3213  EXPECT_FALSE(verifyModule(*M, &errs()));3214 3215  AllocaInst *AllocInst = dyn_cast<AllocaInst>(&BB->front());3216  ASSERT_NE(AllocInst, nullptr);3217  ArrayType *ArrType = dyn_cast<ArrayType>(AllocInst->getAllocatedType());3218  EXPECT_EQ(ArrType->getNumElements(), NumLoops);3219  EXPECT_TRUE(3220      AllocInst->getAllocatedType()->getArrayElementType()->isIntegerTy(64));3221 3222  Instruction *IterInst = dyn_cast<Instruction>(AllocInst);3223  for (unsigned Iter = 0; Iter < NumLoops; Iter++) {3224    GetElementPtrInst *DependAddrGEPIter =3225        dyn_cast<GetElementPtrInst>(IterInst->getNextNode());3226    ASSERT_NE(DependAddrGEPIter, nullptr);3227    EXPECT_EQ(DependAddrGEPIter->getPointerOperand(), AllocInst);3228    EXPECT_EQ(DependAddrGEPIter->getNumIndices(), (unsigned)2);3229    auto *FirstIdx = dyn_cast<ConstantInt>(DependAddrGEPIter->getOperand(1));3230    auto *SecondIdx = dyn_cast<ConstantInt>(DependAddrGEPIter->getOperand(2));3231    ASSERT_NE(FirstIdx, nullptr);3232    ASSERT_NE(SecondIdx, nullptr);3233    EXPECT_EQ(FirstIdx->getValue(), 0);3234    EXPECT_EQ(SecondIdx->getValue(), Iter);3235    StoreInst *StoreValue =3236        dyn_cast<StoreInst>(DependAddrGEPIter->getNextNode());3237    ASSERT_NE(StoreValue, nullptr);3238    EXPECT_EQ(StoreValue->getValueOperand(), StoreValues[Iter]);3239    EXPECT_EQ(StoreValue->getPointerOperand(), DependAddrGEPIter);3240    EXPECT_EQ(StoreValue->getAlign(), Align(8));3241    IterInst = dyn_cast<Instruction>(StoreValue);3242  }3243 3244  GetElementPtrInst *DependBaseAddrGEP =3245      dyn_cast<GetElementPtrInst>(IterInst->getNextNode());3246  ASSERT_NE(DependBaseAddrGEP, nullptr);3247  EXPECT_EQ(DependBaseAddrGEP->getPointerOperand(), AllocInst);3248  EXPECT_EQ(DependBaseAddrGEP->getNumIndices(), (unsigned)2);3249  auto *FirstIdx = dyn_cast<ConstantInt>(DependBaseAddrGEP->getOperand(1));3250  auto *SecondIdx = dyn_cast<ConstantInt>(DependBaseAddrGEP->getOperand(2));3251  ASSERT_NE(FirstIdx, nullptr);3252  ASSERT_NE(SecondIdx, nullptr);3253  EXPECT_EQ(FirstIdx->getValue(), 0);3254  EXPECT_EQ(SecondIdx->getValue(), 0);3255 3256  CallInst *GTID = dyn_cast<CallInst>(DependBaseAddrGEP->getNextNode());3257  ASSERT_NE(GTID, nullptr);3258  EXPECT_EQ(GTID->arg_size(), 1U);3259  EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num");3260  EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory());3261  EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory());3262 3263  CallInst *Depend = dyn_cast<CallInst>(GTID->getNextNode());3264  ASSERT_NE(Depend, nullptr);3265  EXPECT_EQ(Depend->arg_size(), 3U);3266  EXPECT_EQ(Depend->getCalledFunction()->getName(), "__kmpc_doacross_wait");3267  EXPECT_TRUE(isa<GlobalVariable>(Depend->getArgOperand(0)));3268  EXPECT_EQ(Depend->getArgOperand(1), GTID);3269  EXPECT_EQ(Depend->getArgOperand(2), DependBaseAddrGEP);3270}3271 3272TEST_F(OpenMPIRBuilderTest, OrderedDirectiveThreads) {3273  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;3274  OpenMPIRBuilder OMPBuilder(*M);3275  OMPBuilder.initialize();3276  F->setName("func");3277  IRBuilder<> Builder(BB);3278 3279  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});3280 3281  AllocaInst *PrivAI =3282      Builder.CreateAlloca(F->arg_begin()->getType(), nullptr, "priv.inst");3283 3284  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {3285    llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock();3286    llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint();3287    EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst);3288 3289    Builder.restoreIP(CodeGenIP);3290    Builder.CreateStore(F->arg_begin(), PrivAI);3291    Value *PrivLoad =3292        Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use");3293    Builder.CreateICmpNE(F->arg_begin(), PrivLoad);3294  };3295 3296  auto FiniCB = [&](InsertPointTy IP) {3297    BasicBlock *IPBB = IP.getBlock();3298    EXPECT_NE(IPBB->end(), IP.getPoint());3299  };3300 3301  // Test for "#omp ordered [threads]"3302  BasicBlock *EntryBB = Builder.GetInsertBlock();3303  ASSERT_EXPECTED_INIT(3304      OpenMPIRBuilder::InsertPointTy, AfterIP,3305      OMPBuilder.createOrderedThreadsSimd(Builder, BODYGENCB_WRAPPER(BodyGenCB),3306                                          FINICB_WRAPPER(FiniCB), true));3307  Builder.restoreIP(AfterIP);3308 3309  BasicBlock *FinalizeBB = EntryBB->getUniqueSuccessor();3310  EXPECT_NE(FinalizeBB, nullptr);3311 3312  Builder.CreateRetVoid();3313  OMPBuilder.finalize();3314  EXPECT_FALSE(verifyModule(*M, &errs()));3315 3316  EXPECT_NE(EntryBB->getTerminator(), nullptr);3317 3318  CallInst *OrderedEntryCI = nullptr;3319  for (auto &EI : *EntryBB) {3320    Instruction *Cur = &EI;3321    if (isa<CallInst>(Cur)) {3322      OrderedEntryCI = cast<CallInst>(Cur);3323      if (OrderedEntryCI->getCalledFunction()->getName() == "__kmpc_ordered")3324        break;3325      OrderedEntryCI = nullptr;3326    }3327  }3328  EXPECT_NE(OrderedEntryCI, nullptr);3329  EXPECT_EQ(OrderedEntryCI->arg_size(), 2U);3330  EXPECT_EQ(OrderedEntryCI->getCalledFunction()->getName(), "__kmpc_ordered");3331  EXPECT_TRUE(isa<GlobalVariable>(OrderedEntryCI->getArgOperand(0)));3332 3333  CallInst *OrderedEndCI = nullptr;3334  for (auto &FI : *FinalizeBB) {3335    Instruction *Cur = &FI;3336    if (isa<CallInst>(Cur)) {3337      OrderedEndCI = cast<CallInst>(Cur);3338      if (OrderedEndCI->getCalledFunction()->getName() == "__kmpc_end_ordered")3339        break;3340      OrderedEndCI = nullptr;3341    }3342  }3343  EXPECT_NE(OrderedEndCI, nullptr);3344  EXPECT_EQ(OrderedEndCI->arg_size(), 2U);3345  EXPECT_TRUE(isa<GlobalVariable>(OrderedEndCI->getArgOperand(0)));3346  EXPECT_EQ(OrderedEndCI->getArgOperand(1), OrderedEntryCI->getArgOperand(1));3347}3348 3349TEST_F(OpenMPIRBuilderTest, OrderedDirectiveSimd) {3350  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;3351  OpenMPIRBuilder OMPBuilder(*M);3352  OMPBuilder.initialize();3353  F->setName("func");3354  IRBuilder<> Builder(BB);3355 3356  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});3357 3358  AllocaInst *PrivAI =3359      Builder.CreateAlloca(F->arg_begin()->getType(), nullptr, "priv.inst");3360 3361  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {3362    llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock();3363    llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint();3364    EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst);3365 3366    Builder.restoreIP(CodeGenIP);3367    Builder.CreateStore(F->arg_begin(), PrivAI);3368    Value *PrivLoad =3369        Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use");3370    Builder.CreateICmpNE(F->arg_begin(), PrivLoad);3371  };3372 3373  auto FiniCB = [&](InsertPointTy IP) {3374    BasicBlock *IPBB = IP.getBlock();3375    EXPECT_NE(IPBB->end(), IP.getPoint());3376  };3377 3378  // Test for "#omp ordered simd"3379  BasicBlock *EntryBB = Builder.GetInsertBlock();3380  ASSERT_EXPECTED_INIT(3381      OpenMPIRBuilder::InsertPointTy, AfterIP,3382      OMPBuilder.createOrderedThreadsSimd(Builder, BODYGENCB_WRAPPER(BodyGenCB),3383                                          FINICB_WRAPPER(FiniCB), false));3384  Builder.restoreIP(AfterIP);3385 3386  Builder.CreateRetVoid();3387  OMPBuilder.finalize();3388  EXPECT_FALSE(verifyModule(*M, &errs()));3389 3390  EXPECT_NE(EntryBB->getTerminator(), nullptr);3391 3392  CallInst *OrderedEntryCI = nullptr;3393  for (auto &EI : *EntryBB) {3394    Instruction *Cur = &EI;3395    if (isa<CallInst>(Cur)) {3396      OrderedEntryCI = cast<CallInst>(Cur);3397      if (OrderedEntryCI->getCalledFunction()->getName() == "__kmpc_ordered")3398        break;3399      OrderedEntryCI = nullptr;3400    }3401  }3402  EXPECT_EQ(OrderedEntryCI, nullptr);3403 3404  CallInst *OrderedEndCI = nullptr;3405  for (auto &FI : *EntryBB) {3406    Instruction *Cur = &FI;3407    if (isa<CallInst>(Cur)) {3408      OrderedEndCI = cast<CallInst>(Cur);3409      if (OrderedEndCI->getCalledFunction()->getName() == "__kmpc_end_ordered")3410        break;3411      OrderedEndCI = nullptr;3412    }3413  }3414  EXPECT_EQ(OrderedEndCI, nullptr);3415}3416 3417TEST_F(OpenMPIRBuilderTest, CopyinBlocks) {3418  OpenMPIRBuilder OMPBuilder(*M);3419  OMPBuilder.initialize();3420  F->setName("func");3421  IRBuilder<> Builder(BB);3422 3423  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});3424 3425  IntegerType *Int32 = Type::getInt32Ty(M->getContext());3426  AllocaInst *MasterAddress = Builder.CreateAlloca(Builder.getPtrTy());3427  AllocaInst *PrivAddress = Builder.CreateAlloca(Builder.getPtrTy());3428 3429  BasicBlock *EntryBB = BB;3430 3431  OMPBuilder.createCopyinClauseBlocks(Builder.saveIP(), MasterAddress,3432                                      PrivAddress, Int32, /*BranchtoEnd*/ true);3433 3434  BranchInst *EntryBr = dyn_cast_or_null<BranchInst>(EntryBB->getTerminator());3435 3436  EXPECT_NE(EntryBr, nullptr);3437  EXPECT_TRUE(EntryBr->isConditional());3438 3439  BasicBlock *NotMasterBB = EntryBr->getSuccessor(0);3440  BasicBlock *CopyinEnd = EntryBr->getSuccessor(1);3441  CmpInst *CMP = dyn_cast_or_null<CmpInst>(EntryBr->getCondition());3442 3443  EXPECT_NE(CMP, nullptr);3444  EXPECT_NE(NotMasterBB, nullptr);3445  EXPECT_NE(CopyinEnd, nullptr);3446 3447  BranchInst *NotMasterBr =3448      dyn_cast_or_null<BranchInst>(NotMasterBB->getTerminator());3449  EXPECT_NE(NotMasterBr, nullptr);3450  EXPECT_FALSE(NotMasterBr->isConditional());3451  EXPECT_EQ(CopyinEnd, NotMasterBr->getSuccessor(0));3452}3453 3454TEST_F(OpenMPIRBuilderTest, SingleDirective) {3455  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;3456  OpenMPIRBuilder OMPBuilder(*M);3457  OMPBuilder.initialize();3458  F->setName("func");3459  IRBuilder<> Builder(BB);3460 3461  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});3462 3463  AllocaInst *PrivAI = nullptr;3464 3465  BasicBlock *EntryBB = nullptr;3466  BasicBlock *ThenBB = nullptr;3467 3468  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {3469    if (AllocaIP.isSet())3470      Builder.restoreIP(AllocaIP);3471    else3472      Builder.SetInsertPoint(&*(F->getEntryBlock().getFirstInsertionPt()));3473    PrivAI = Builder.CreateAlloca(F->arg_begin()->getType());3474    Builder.CreateStore(F->arg_begin(), PrivAI);3475 3476    llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock();3477    llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint();3478    EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst);3479 3480    Builder.restoreIP(CodeGenIP);3481 3482    // collect some info for checks later3483    ThenBB = Builder.GetInsertBlock();3484    EntryBB = ThenBB->getUniquePredecessor();3485 3486    // simple instructions for body3487    Value *PrivLoad =3488        Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use");3489    Builder.CreateICmpNE(F->arg_begin(), PrivLoad);3490  };3491 3492  auto FiniCB = [&](InsertPointTy IP) {3493    BasicBlock *IPBB = IP.getBlock();3494    EXPECT_NE(IPBB->end(), IP.getPoint());3495  };3496 3497  ASSERT_EXPECTED_INIT(3498      OpenMPIRBuilder::InsertPointTy, AfterIP,3499      OMPBuilder.createSingle(Builder, BODYGENCB_WRAPPER(BodyGenCB),3500                              FINICB_WRAPPER(FiniCB), /*IsNowait*/ false));3501  Builder.restoreIP(AfterIP);3502  Value *EntryBBTI = EntryBB->getTerminator();3503  EXPECT_NE(EntryBBTI, nullptr);3504  EXPECT_TRUE(isa<BranchInst>(EntryBBTI));3505  BranchInst *EntryBr = cast<BranchInst>(EntryBB->getTerminator());3506  EXPECT_TRUE(EntryBr->isConditional());3507  EXPECT_EQ(EntryBr->getSuccessor(0), ThenBB);3508  BasicBlock *FinalizeBB = ThenBB->getUniqueSuccessor();3509  BasicBlock *ExitBB = FinalizeBB->getUniqueSuccessor();3510  EXPECT_EQ(EntryBr->getSuccessor(1), ExitBB);3511 3512  CmpInst *CondInst = cast<CmpInst>(EntryBr->getCondition());3513  EXPECT_TRUE(isa<CallInst>(CondInst->getOperand(0)));3514 3515  CallInst *SingleEntryCI = cast<CallInst>(CondInst->getOperand(0));3516  EXPECT_EQ(SingleEntryCI->arg_size(), 2U);3517  EXPECT_EQ(SingleEntryCI->getCalledFunction()->getName(), "__kmpc_single");3518  EXPECT_TRUE(isa<GlobalVariable>(SingleEntryCI->getArgOperand(0)));3519 3520  CallInst *SingleEndCI = nullptr;3521  for (auto &FI : *FinalizeBB) {3522    Instruction *cur = &FI;3523    if (isa<CallInst>(cur)) {3524      SingleEndCI = cast<CallInst>(cur);3525      if (SingleEndCI->getCalledFunction()->getName() == "__kmpc_end_single")3526        break;3527      SingleEndCI = nullptr;3528    }3529  }3530  EXPECT_NE(SingleEndCI, nullptr);3531  EXPECT_EQ(SingleEndCI->arg_size(), 2U);3532  EXPECT_TRUE(isa<GlobalVariable>(SingleEndCI->getArgOperand(0)));3533  EXPECT_EQ(SingleEndCI->getArgOperand(1), SingleEntryCI->getArgOperand(1));3534 3535  bool FoundBarrier = false;3536  for (auto &FI : *ExitBB) {3537    Instruction *cur = &FI;3538    if (auto CI = dyn_cast<CallInst>(cur)) {3539      if (CI->getCalledFunction()->getName() == "__kmpc_barrier") {3540        FoundBarrier = true;3541        break;3542      }3543    }3544  }3545  EXPECT_TRUE(FoundBarrier);3546}3547 3548TEST_F(OpenMPIRBuilderTest, SingleDirectiveNowait) {3549  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;3550  OpenMPIRBuilder OMPBuilder(*M);3551  OMPBuilder.initialize();3552  F->setName("func");3553  IRBuilder<> Builder(BB);3554 3555  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});3556 3557  AllocaInst *PrivAI = nullptr;3558 3559  BasicBlock *EntryBB = nullptr;3560  BasicBlock *ThenBB = nullptr;3561 3562  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {3563    if (AllocaIP.isSet())3564      Builder.restoreIP(AllocaIP);3565    else3566      Builder.SetInsertPoint(&*(F->getEntryBlock().getFirstInsertionPt()));3567    PrivAI = Builder.CreateAlloca(F->arg_begin()->getType());3568    Builder.CreateStore(F->arg_begin(), PrivAI);3569 3570    llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock();3571    llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint();3572    EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst);3573 3574    Builder.restoreIP(CodeGenIP);3575 3576    // collect some info for checks later3577    ThenBB = Builder.GetInsertBlock();3578    EntryBB = ThenBB->getUniquePredecessor();3579 3580    // simple instructions for body3581    Value *PrivLoad =3582        Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use");3583    Builder.CreateICmpNE(F->arg_begin(), PrivLoad);3584  };3585 3586  auto FiniCB = [&](InsertPointTy IP) {3587    BasicBlock *IPBB = IP.getBlock();3588    EXPECT_NE(IPBB->end(), IP.getPoint());3589  };3590 3591  ASSERT_EXPECTED_INIT(3592      OpenMPIRBuilder::InsertPointTy, AfterIP,3593      OMPBuilder.createSingle(Builder, BODYGENCB_WRAPPER(BodyGenCB),3594                              FINICB_WRAPPER(FiniCB), /*IsNowait*/ true));3595  Builder.restoreIP(AfterIP);3596  Value *EntryBBTI = EntryBB->getTerminator();3597  EXPECT_NE(EntryBBTI, nullptr);3598  EXPECT_TRUE(isa<BranchInst>(EntryBBTI));3599  BranchInst *EntryBr = cast<BranchInst>(EntryBB->getTerminator());3600  EXPECT_TRUE(EntryBr->isConditional());3601  EXPECT_EQ(EntryBr->getSuccessor(0), ThenBB);3602  BasicBlock *FinalizeBB = ThenBB->getUniqueSuccessor();3603  BasicBlock *ExitBB = FinalizeBB->getUniqueSuccessor();3604  EXPECT_EQ(EntryBr->getSuccessor(1), ExitBB);3605 3606  CmpInst *CondInst = cast<CmpInst>(EntryBr->getCondition());3607  EXPECT_TRUE(isa<CallInst>(CondInst->getOperand(0)));3608 3609  CallInst *SingleEntryCI = cast<CallInst>(CondInst->getOperand(0));3610  EXPECT_EQ(SingleEntryCI->arg_size(), 2U);3611  EXPECT_EQ(SingleEntryCI->getCalledFunction()->getName(), "__kmpc_single");3612  EXPECT_TRUE(isa<GlobalVariable>(SingleEntryCI->getArgOperand(0)));3613 3614  CallInst *SingleEndCI = nullptr;3615  for (auto &FI : *FinalizeBB) {3616    Instruction *cur = &FI;3617    if (isa<CallInst>(cur)) {3618      SingleEndCI = cast<CallInst>(cur);3619      if (SingleEndCI->getCalledFunction()->getName() == "__kmpc_end_single")3620        break;3621      SingleEndCI = nullptr;3622    }3623  }3624  EXPECT_NE(SingleEndCI, nullptr);3625  EXPECT_EQ(SingleEndCI->arg_size(), 2U);3626  EXPECT_TRUE(isa<GlobalVariable>(SingleEndCI->getArgOperand(0)));3627  EXPECT_EQ(SingleEndCI->getArgOperand(1), SingleEntryCI->getArgOperand(1));3628 3629  CallInst *ExitBarrier = nullptr;3630  for (auto &FI : *ExitBB) {3631    Instruction *cur = &FI;3632    if (auto CI = dyn_cast<CallInst>(cur)) {3633      if (CI->getCalledFunction()->getName() == "__kmpc_barrier") {3634        ExitBarrier = CI;3635        break;3636      }3637    }3638  }3639  EXPECT_EQ(ExitBarrier, nullptr);3640}3641 3642// Helper class to check each instruction of a BB.3643class BBInstIter {3644  BasicBlock *BB;3645  BasicBlock::iterator BBI;3646 3647public:3648  BBInstIter(BasicBlock *BB) : BB(BB), BBI(BB->begin()) {}3649 3650  bool hasNext() const { return BBI != BB->end(); }3651 3652  template <typename InstTy> InstTy *next() {3653    if (!hasNext())3654      return nullptr;3655    Instruction *Cur = &*BBI++;3656    if (!isa<InstTy>(Cur))3657      return nullptr;3658    return cast<InstTy>(Cur);3659  }3660};3661 3662TEST_F(OpenMPIRBuilderTest, SingleDirectiveCopyPrivate) {3663  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;3664  OpenMPIRBuilder OMPBuilder(*M);3665  OMPBuilder.initialize();3666  F->setName("func");3667  IRBuilder<> Builder(BB);3668 3669  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});3670 3671  AllocaInst *PrivAI = nullptr;3672 3673  BasicBlock *EntryBB = nullptr;3674  BasicBlock *ThenBB = nullptr;3675 3676  Value *CPVar = Builder.CreateAlloca(F->arg_begin()->getType());3677  Builder.CreateStore(F->arg_begin(), CPVar);3678 3679  FunctionType *CopyFuncTy = FunctionType::get(3680      Builder.getVoidTy(), {Builder.getPtrTy(), Builder.getPtrTy()}, false);3681  Function *CopyFunc =3682      Function::Create(CopyFuncTy, Function::PrivateLinkage, "copy_var", *M);3683 3684  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {3685    if (AllocaIP.isSet())3686      Builder.restoreIP(AllocaIP);3687    else3688      Builder.SetInsertPoint(&*(F->getEntryBlock().getFirstInsertionPt()));3689    PrivAI = Builder.CreateAlloca(F->arg_begin()->getType());3690    Builder.CreateStore(F->arg_begin(), PrivAI);3691 3692    llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock();3693    llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint();3694    EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst);3695 3696    Builder.restoreIP(CodeGenIP);3697 3698    // collect some info for checks later3699    ThenBB = Builder.GetInsertBlock();3700    EntryBB = ThenBB->getUniquePredecessor();3701 3702    // simple instructions for body3703    Value *PrivLoad =3704        Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use");3705    Builder.CreateICmpNE(F->arg_begin(), PrivLoad);3706  };3707 3708  auto FiniCB = [&](InsertPointTy IP) {3709    BasicBlock *IPBB = IP.getBlock();3710    // IP must be before the unconditional branch to ExitBB3711    EXPECT_NE(IPBB->end(), IP.getPoint());3712  };3713 3714  ASSERT_EXPECTED_INIT(3715      OpenMPIRBuilder::InsertPointTy, AfterIP,3716      OMPBuilder.createSingle(Builder, BODYGENCB_WRAPPER(BodyGenCB),3717                              FINICB_WRAPPER(FiniCB),3718                              /*IsNowait*/ false, {CPVar}, {CopyFunc}));3719  Builder.restoreIP(AfterIP);3720  Value *EntryBBTI = EntryBB->getTerminator();3721  EXPECT_NE(EntryBBTI, nullptr);3722  EXPECT_TRUE(isa<BranchInst>(EntryBBTI));3723  BranchInst *EntryBr = cast<BranchInst>(EntryBB->getTerminator());3724  EXPECT_TRUE(EntryBr->isConditional());3725  EXPECT_EQ(EntryBr->getSuccessor(0), ThenBB);3726  BasicBlock *FinalizeBB = ThenBB->getUniqueSuccessor();3727  BasicBlock *ExitBB = FinalizeBB->getUniqueSuccessor();3728  EXPECT_EQ(EntryBr->getSuccessor(1), ExitBB);3729 3730  CmpInst *CondInst = cast<CmpInst>(EntryBr->getCondition());3731  EXPECT_TRUE(isa<CallInst>(CondInst->getOperand(0)));3732 3733  CallInst *SingleEntryCI = cast<CallInst>(CondInst->getOperand(0));3734  EXPECT_EQ(SingleEntryCI->arg_size(), 2U);3735  EXPECT_EQ(SingleEntryCI->getCalledFunction()->getName(), "__kmpc_single");3736  EXPECT_TRUE(isa<GlobalVariable>(SingleEntryCI->getArgOperand(0)));3737 3738  // check ThenBB3739  BBInstIter ThenBBI(ThenBB);3740  // load PrivAI3741  auto *PrivLI = ThenBBI.next<LoadInst>();3742  EXPECT_NE(PrivLI, nullptr);3743  EXPECT_EQ(PrivLI->getPointerOperand(), PrivAI);3744  // icmp3745  EXPECT_TRUE(ThenBBI.next<ICmpInst>());3746 3747  // check FinalizeBB3748  BBInstIter FinalizeBBI(FinalizeBB);3749  // store 1, DidIt3750  auto *DidItSI = FinalizeBBI.next<StoreInst>();3751  EXPECT_NE(DidItSI, nullptr);3752  EXPECT_EQ(DidItSI->getValueOperand(),3753            ConstantInt::get(Type::getInt32Ty(Ctx), 1));3754  Value *DidIt = DidItSI->getPointerOperand();3755  // call __kmpc_end_single3756  auto *SingleEndCI = FinalizeBBI.next<CallInst>();3757  EXPECT_NE(SingleEndCI, nullptr);3758  EXPECT_EQ(SingleEndCI->getCalledFunction()->getName(), "__kmpc_end_single");3759  EXPECT_EQ(SingleEndCI->arg_size(), 2U);3760  EXPECT_TRUE(isa<GlobalVariable>(SingleEndCI->getArgOperand(0)));3761  EXPECT_EQ(SingleEndCI->getArgOperand(1), SingleEntryCI->getArgOperand(1));3762  // br ExitBB3763  auto *ExitBBBI = FinalizeBBI.next<BranchInst>();3764  EXPECT_NE(ExitBBBI, nullptr);3765  EXPECT_TRUE(ExitBBBI->isUnconditional());3766  EXPECT_EQ(ExitBBBI->getOperand(0), ExitBB);3767  EXPECT_FALSE(FinalizeBBI.hasNext());3768 3769  // check ExitBB3770  BBInstIter ExitBBI(ExitBB);3771  // call __kmpc_global_thread_num3772  auto *ThreadNumCI = ExitBBI.next<CallInst>();3773  EXPECT_NE(ThreadNumCI, nullptr);3774  EXPECT_EQ(ThreadNumCI->getCalledFunction()->getName(),3775            "__kmpc_global_thread_num");3776  // load DidIt3777  auto *DidItLI = ExitBBI.next<LoadInst>();3778  EXPECT_NE(DidItLI, nullptr);3779  EXPECT_EQ(DidItLI->getPointerOperand(), DidIt);3780  // call __kmpc_copyprivate3781  auto *CopyPrivateCI = ExitBBI.next<CallInst>();3782  EXPECT_NE(CopyPrivateCI, nullptr);3783  EXPECT_EQ(CopyPrivateCI->arg_size(), 6U);3784  EXPECT_TRUE(isa<AllocaInst>(CopyPrivateCI->getArgOperand(3)));3785  EXPECT_EQ(CopyPrivateCI->getArgOperand(3), CPVar);3786  EXPECT_TRUE(isa<Function>(CopyPrivateCI->getArgOperand(4)));3787  EXPECT_EQ(CopyPrivateCI->getArgOperand(4), CopyFunc);3788  EXPECT_TRUE(isa<LoadInst>(CopyPrivateCI->getArgOperand(5)));3789  DidItLI = cast<LoadInst>(CopyPrivateCI->getArgOperand(5));3790  EXPECT_EQ(DidItLI->getOperand(0), DidIt);3791  EXPECT_FALSE(ExitBBI.hasNext());3792}3793 3794TEST_F(OpenMPIRBuilderTest, OMPAtomicReadFlt) {3795  OpenMPIRBuilder OMPBuilder(*M);3796  OMPBuilder.initialize();3797  F->setName("func");3798  IRBuilder<> Builder(BB);3799 3800  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});3801  BasicBlock *EntryBB = BB;3802  OpenMPIRBuilder::InsertPointTy AllocaIP(EntryBB,3803                                          EntryBB->getFirstInsertionPt());3804 3805  Type *Float32 = Type::getFloatTy(M->getContext());3806  AllocaInst *XVal = Builder.CreateAlloca(Float32);3807  XVal->setName("AtomicVar");3808  AllocaInst *VVal = Builder.CreateAlloca(Float32);3809  VVal->setName("AtomicRead");3810  AtomicOrdering AO = AtomicOrdering::Monotonic;3811  OpenMPIRBuilder::AtomicOpValue X = {XVal, Float32, false, false};3812  OpenMPIRBuilder::AtomicOpValue V = {VVal, Float32, false, false};3813 3814  Builder.restoreIP(OMPBuilder.createAtomicRead(Loc, X, V, AO, AllocaIP));3815 3816  IntegerType *IntCastTy =3817      IntegerType::get(M->getContext(), Float32->getScalarSizeInBits());3818 3819  LoadInst *AtomicLoad = cast<LoadInst>(VVal->getNextNode());3820  EXPECT_TRUE(AtomicLoad->isAtomic());3821  EXPECT_EQ(AtomicLoad->getPointerOperand(), XVal);3822 3823  BitCastInst *CastToFlt = cast<BitCastInst>(AtomicLoad->getNextNode());3824  EXPECT_EQ(CastToFlt->getSrcTy(), IntCastTy);3825  EXPECT_EQ(CastToFlt->getDestTy(), Float32);3826  EXPECT_EQ(CastToFlt->getOperand(0), AtomicLoad);3827 3828  StoreInst *StoreofAtomic = cast<StoreInst>(CastToFlt->getNextNode());3829  EXPECT_EQ(StoreofAtomic->getValueOperand(), CastToFlt);3830  EXPECT_EQ(StoreofAtomic->getPointerOperand(), VVal);3831 3832  Builder.CreateRetVoid();3833  OMPBuilder.finalize();3834  EXPECT_FALSE(verifyModule(*M, &errs()));3835}3836 3837TEST_F(OpenMPIRBuilderTest, OMPAtomicReadInt) {3838  OpenMPIRBuilder OMPBuilder(*M);3839  OMPBuilder.initialize();3840  F->setName("func");3841  IRBuilder<> Builder(BB);3842 3843  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});3844  BasicBlock *EntryBB = BB;3845  OpenMPIRBuilder::InsertPointTy AllocaIP(EntryBB,3846                                          EntryBB->getFirstInsertionPt());3847 3848  IntegerType *Int32 = Type::getInt32Ty(M->getContext());3849  AllocaInst *XVal = Builder.CreateAlloca(Int32);3850  XVal->setName("AtomicVar");3851  AllocaInst *VVal = Builder.CreateAlloca(Int32);3852  VVal->setName("AtomicRead");3853  AtomicOrdering AO = AtomicOrdering::Monotonic;3854  OpenMPIRBuilder::AtomicOpValue X = {XVal, Int32, false, false};3855  OpenMPIRBuilder::AtomicOpValue V = {VVal, Int32, false, false};3856 3857  Builder.restoreIP(OMPBuilder.createAtomicRead(Loc, X, V, AO, AllocaIP));3858 3859  LoadInst *AtomicLoad = nullptr;3860  StoreInst *StoreofAtomic = nullptr;3861 3862  for (Instruction &Cur : *EntryBB) {3863    if (isa<LoadInst>(Cur)) {3864      AtomicLoad = cast<LoadInst>(&Cur);3865      if (AtomicLoad->getPointerOperand() == XVal)3866        continue;3867      AtomicLoad = nullptr;3868    } else if (isa<StoreInst>(Cur)) {3869      StoreofAtomic = cast<StoreInst>(&Cur);3870      if (StoreofAtomic->getPointerOperand() == VVal)3871        continue;3872      StoreofAtomic = nullptr;3873    }3874  }3875 3876  EXPECT_NE(AtomicLoad, nullptr);3877  EXPECT_TRUE(AtomicLoad->isAtomic());3878 3879  EXPECT_NE(StoreofAtomic, nullptr);3880  EXPECT_EQ(StoreofAtomic->getValueOperand(), AtomicLoad);3881 3882  Builder.CreateRetVoid();3883  OMPBuilder.finalize();3884 3885  EXPECT_FALSE(verifyModule(*M, &errs()));3886}3887 3888TEST_F(OpenMPIRBuilderTest, OMPAtomicWriteFlt) {3889  OpenMPIRBuilder OMPBuilder(*M);3890  OMPBuilder.initialize();3891  F->setName("func");3892  IRBuilder<> Builder(BB);3893 3894  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});3895  BasicBlock *EntryBB = BB;3896  OpenMPIRBuilder::InsertPointTy AllocaIP(EntryBB,3897                                          EntryBB->getFirstInsertionPt());3898 3899  LLVMContext &Ctx = M->getContext();3900  Type *Float32 = Type::getFloatTy(Ctx);3901  AllocaInst *XVal = Builder.CreateAlloca(Float32);3902  XVal->setName("AtomicVar");3903  OpenMPIRBuilder::AtomicOpValue X = {XVal, Float32, false, false};3904  AtomicOrdering AO = AtomicOrdering::Monotonic;3905  Constant *ValToWrite = ConstantFP::get(Float32, 1.0);3906 3907  Builder.restoreIP(3908      OMPBuilder.createAtomicWrite(Loc, X, ValToWrite, AO, AllocaIP));3909 3910  IntegerType *IntCastTy =3911      IntegerType::get(M->getContext(), Float32->getScalarSizeInBits());3912 3913  Value *ExprCast = Builder.CreateBitCast(ValToWrite, IntCastTy);3914 3915  StoreInst *StoreofAtomic = cast<StoreInst>(XVal->getNextNode());3916  EXPECT_EQ(StoreofAtomic->getValueOperand(), ExprCast);3917  EXPECT_EQ(StoreofAtomic->getPointerOperand(), XVal);3918  EXPECT_TRUE(StoreofAtomic->isAtomic());3919 3920  Builder.CreateRetVoid();3921  OMPBuilder.finalize();3922  EXPECT_FALSE(verifyModule(*M, &errs()));3923}3924 3925TEST_F(OpenMPIRBuilderTest, OMPAtomicWriteInt) {3926  OpenMPIRBuilder OMPBuilder(*M);3927  OMPBuilder.initialize();3928  F->setName("func");3929  IRBuilder<> Builder(BB);3930 3931  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});3932 3933  LLVMContext &Ctx = M->getContext();3934  IntegerType *Int32 = Type::getInt32Ty(Ctx);3935  AllocaInst *XVal = Builder.CreateAlloca(Int32);3936  XVal->setName("AtomicVar");3937  OpenMPIRBuilder::AtomicOpValue X = {XVal, Int32, false, false};3938  AtomicOrdering AO = AtomicOrdering::Monotonic;3939  ConstantInt *ValToWrite = ConstantInt::get(Type::getInt32Ty(Ctx), 1U);3940 3941  BasicBlock *EntryBB = BB;3942  OpenMPIRBuilder::InsertPointTy AllocaIP(EntryBB,3943                                          EntryBB->getFirstInsertionPt());3944 3945  Builder.restoreIP(3946      OMPBuilder.createAtomicWrite(Loc, X, ValToWrite, AO, AllocaIP));3947 3948  StoreInst *StoreofAtomic = nullptr;3949 3950  for (Instruction &Cur : *EntryBB) {3951    if (isa<StoreInst>(Cur)) {3952      StoreofAtomic = cast<StoreInst>(&Cur);3953      if (StoreofAtomic->getPointerOperand() == XVal)3954        continue;3955      StoreofAtomic = nullptr;3956    }3957  }3958 3959  EXPECT_NE(StoreofAtomic, nullptr);3960  EXPECT_TRUE(StoreofAtomic->isAtomic());3961  EXPECT_EQ(StoreofAtomic->getValueOperand(), ValToWrite);3962 3963  Builder.CreateRetVoid();3964  OMPBuilder.finalize();3965  EXPECT_FALSE(verifyModule(*M, &errs()));3966}3967 3968TEST_F(OpenMPIRBuilderTest, OMPAtomicUpdate) {3969  OpenMPIRBuilder OMPBuilder(*M);3970  OMPBuilder.initialize();3971  F->setName("func");3972  IRBuilder<> Builder(BB);3973 3974  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});3975 3976  IntegerType *Int32 = Type::getInt32Ty(M->getContext());3977  AllocaInst *XVal = Builder.CreateAlloca(Int32);3978  XVal->setName("AtomicVar");3979  Builder.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx), 0U), XVal);3980  OpenMPIRBuilder::AtomicOpValue X = {XVal, Int32, false, false};3981  AtomicOrdering AO = AtomicOrdering::Monotonic;3982  ConstantInt *ConstVal = ConstantInt::get(Type::getInt32Ty(Ctx), 1U);3983  Value *Expr = nullptr;3984  AtomicRMWInst::BinOp RMWOp = AtomicRMWInst::Sub;3985  bool IsXLHSInRHSPart = false;3986 3987  BasicBlock *EntryBB = BB;3988  OpenMPIRBuilder::InsertPointTy AllocaIP(EntryBB,3989                                          EntryBB->getFirstInsertionPt());3990  Value *Sub = nullptr;3991 3992  auto UpdateOp = [&](Value *Atomic, IRBuilder<> &IRB) {3993    Sub = IRB.CreateSub(ConstVal, Atomic);3994    return Sub;3995  };3996  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,3997                       OMPBuilder.createAtomicUpdate(Builder, AllocaIP, X, Expr,3998                                                     AO, RMWOp, UpdateOp,3999                                                     IsXLHSInRHSPart));4000  Builder.restoreIP(AfterIP);4001  BasicBlock *ContBB = EntryBB->getSingleSuccessor();4002  BranchInst *ContTI = dyn_cast<BranchInst>(ContBB->getTerminator());4003  EXPECT_NE(ContTI, nullptr);4004  BasicBlock *EndBB = ContTI->getSuccessor(0);4005  EXPECT_TRUE(ContTI->isConditional());4006  EXPECT_EQ(ContTI->getSuccessor(1), ContBB);4007  EXPECT_NE(EndBB, nullptr);4008 4009  PHINode *Phi = dyn_cast<PHINode>(&ContBB->front());4010  EXPECT_NE(Phi, nullptr);4011  EXPECT_EQ(Phi->getNumIncomingValues(), 2U);4012  EXPECT_EQ(Phi->getIncomingBlock(0), EntryBB);4013  EXPECT_EQ(Phi->getIncomingBlock(1), ContBB);4014 4015  EXPECT_TRUE(Sub->hasOneUse());4016  StoreInst *St = dyn_cast<StoreInst>(Sub->user_back());4017  AllocaInst *UpdateTemp = dyn_cast<AllocaInst>(St->getPointerOperand());4018 4019  ExtractValueInst *ExVI1 =4020      dyn_cast<ExtractValueInst>(Phi->getIncomingValueForBlock(ContBB));4021  EXPECT_NE(ExVI1, nullptr);4022  AtomicCmpXchgInst *CmpExchg =4023      dyn_cast<AtomicCmpXchgInst>(ExVI1->getAggregateOperand());4024  EXPECT_NE(CmpExchg, nullptr);4025  EXPECT_EQ(CmpExchg->getPointerOperand(), XVal);4026  EXPECT_EQ(CmpExchg->getCompareOperand(), Phi);4027  EXPECT_EQ(CmpExchg->getSuccessOrdering(), AtomicOrdering::Monotonic);4028 4029  LoadInst *Ld = dyn_cast<LoadInst>(CmpExchg->getNewValOperand());4030  EXPECT_NE(Ld, nullptr);4031  EXPECT_EQ(UpdateTemp, Ld->getPointerOperand());4032 4033  Builder.CreateRetVoid();4034  OMPBuilder.finalize();4035  EXPECT_FALSE(verifyModule(*M, &errs()));4036}4037 4038TEST_F(OpenMPIRBuilderTest, OMPAtomicUpdateFloat) {4039  OpenMPIRBuilder OMPBuilder(*M);4040  OMPBuilder.initialize();4041  F->setName("func");4042  IRBuilder<> Builder(BB);4043 4044  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});4045 4046  Type *FloatTy = Type::getFloatTy(M->getContext());4047  AllocaInst *XVal = Builder.CreateAlloca(FloatTy);4048  XVal->setName("AtomicVar");4049  Builder.CreateStore(ConstantFP::get(Type::getFloatTy(Ctx), 0.0), XVal);4050  OpenMPIRBuilder::AtomicOpValue X = {XVal, FloatTy, false, false};4051  AtomicOrdering AO = AtomicOrdering::Monotonic;4052  Constant *ConstVal = ConstantFP::get(Type::getFloatTy(Ctx), 1.0);4053  Value *Expr = nullptr;4054  AtomicRMWInst::BinOp RMWOp = AtomicRMWInst::FSub;4055  bool IsXLHSInRHSPart = false;4056 4057  BasicBlock *EntryBB = BB;4058  OpenMPIRBuilder::InsertPointTy AllocaIP(EntryBB,4059                                          EntryBB->getFirstInsertionPt());4060  Value *Sub = nullptr;4061 4062  auto UpdateOp = [&](Value *Atomic, IRBuilder<> &IRB) {4063    Sub = IRB.CreateFSub(ConstVal, Atomic);4064    return Sub;4065  };4066  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,4067                       OMPBuilder.createAtomicUpdate(Builder, AllocaIP, X, Expr,4068                                                     AO, RMWOp, UpdateOp,4069                                                     IsXLHSInRHSPart));4070  Builder.restoreIP(AfterIP);4071  BasicBlock *ContBB = EntryBB->getSingleSuccessor();4072  BranchInst *ContTI = dyn_cast<BranchInst>(ContBB->getTerminator());4073  EXPECT_NE(ContTI, nullptr);4074  BasicBlock *EndBB = ContTI->getSuccessor(0);4075  EXPECT_TRUE(ContTI->isConditional());4076  EXPECT_EQ(ContTI->getSuccessor(1), ContBB);4077  EXPECT_NE(EndBB, nullptr);4078 4079  PHINode *Phi = dyn_cast<PHINode>(&ContBB->front());4080  EXPECT_NE(Phi, nullptr);4081  EXPECT_EQ(Phi->getNumIncomingValues(), 2U);4082  EXPECT_EQ(Phi->getIncomingBlock(0), EntryBB);4083  EXPECT_EQ(Phi->getIncomingBlock(1), ContBB);4084 4085  EXPECT_TRUE(Sub->hasOneUse());4086  StoreInst *St = dyn_cast<StoreInst>(Sub->user_back());4087  AllocaInst *UpdateTemp = dyn_cast<AllocaInst>(St->getPointerOperand());4088 4089  ExtractValueInst *ExVI1 =4090      dyn_cast<ExtractValueInst>(Phi->getIncomingValueForBlock(ContBB));4091  EXPECT_NE(ExVI1, nullptr);4092  AtomicCmpXchgInst *CmpExchg =4093      dyn_cast<AtomicCmpXchgInst>(ExVI1->getAggregateOperand());4094  EXPECT_NE(CmpExchg, nullptr);4095  EXPECT_EQ(CmpExchg->getPointerOperand(), XVal);4096  EXPECT_EQ(CmpExchg->getCompareOperand(), Phi);4097  EXPECT_EQ(CmpExchg->getSuccessOrdering(), AtomicOrdering::Monotonic);4098 4099  LoadInst *Ld = dyn_cast<LoadInst>(CmpExchg->getNewValOperand());4100  EXPECT_NE(Ld, nullptr);4101  EXPECT_EQ(UpdateTemp, Ld->getPointerOperand());4102  Builder.CreateRetVoid();4103  OMPBuilder.finalize();4104  EXPECT_FALSE(verifyModule(*M, &errs()));4105}4106 4107TEST_F(OpenMPIRBuilderTest, OMPAtomicUpdateIntr) {4108  OpenMPIRBuilder OMPBuilder(*M);4109  OMPBuilder.initialize();4110  F->setName("func");4111  IRBuilder<> Builder(BB);4112 4113  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});4114 4115  Type *IntTy = Type::getInt32Ty(M->getContext());4116  AllocaInst *XVal = Builder.CreateAlloca(IntTy);4117  XVal->setName("AtomicVar");4118  Builder.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx), 0), XVal);4119  OpenMPIRBuilder::AtomicOpValue X = {XVal, IntTy, false, false};4120  AtomicOrdering AO = AtomicOrdering::Monotonic;4121  Constant *ConstVal = ConstantInt::get(Type::getInt32Ty(Ctx), 1);4122  Value *Expr = ConstantInt::get(Type::getInt32Ty(Ctx), 1);4123  AtomicRMWInst::BinOp RMWOp = AtomicRMWInst::UMax;4124  bool IsXLHSInRHSPart = false;4125 4126  BasicBlock *EntryBB = BB;4127  OpenMPIRBuilder::InsertPointTy AllocaIP(EntryBB,4128                                          EntryBB->getFirstInsertionPt());4129  Value *Sub = nullptr;4130 4131  auto UpdateOp = [&](Value *Atomic, IRBuilder<> &IRB) {4132    Sub = IRB.CreateSub(ConstVal, Atomic);4133    return Sub;4134  };4135  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,4136                       OMPBuilder.createAtomicUpdate(Builder, AllocaIP, X, Expr,4137                                                     AO, RMWOp, UpdateOp,4138                                                     IsXLHSInRHSPart));4139  Builder.restoreIP(AfterIP);4140  BasicBlock *ContBB = EntryBB->getSingleSuccessor();4141  BranchInst *ContTI = dyn_cast<BranchInst>(ContBB->getTerminator());4142  EXPECT_NE(ContTI, nullptr);4143  BasicBlock *EndBB = ContTI->getSuccessor(0);4144  EXPECT_TRUE(ContTI->isConditional());4145  EXPECT_EQ(ContTI->getSuccessor(1), ContBB);4146  EXPECT_NE(EndBB, nullptr);4147 4148  PHINode *Phi = dyn_cast<PHINode>(&ContBB->front());4149  EXPECT_NE(Phi, nullptr);4150  EXPECT_EQ(Phi->getNumIncomingValues(), 2U);4151  EXPECT_EQ(Phi->getIncomingBlock(0), EntryBB);4152  EXPECT_EQ(Phi->getIncomingBlock(1), ContBB);4153 4154  EXPECT_TRUE(Sub->hasOneUse());4155  StoreInst *St = dyn_cast<StoreInst>(Sub->user_back());4156  AllocaInst *UpdateTemp = dyn_cast<AllocaInst>(St->getPointerOperand());4157 4158  ExtractValueInst *ExVI1 =4159      dyn_cast<ExtractValueInst>(Phi->getIncomingValueForBlock(ContBB));4160  EXPECT_NE(ExVI1, nullptr);4161  AtomicCmpXchgInst *CmpExchg =4162      dyn_cast<AtomicCmpXchgInst>(ExVI1->getAggregateOperand());4163  EXPECT_NE(CmpExchg, nullptr);4164  EXPECT_EQ(CmpExchg->getPointerOperand(), XVal);4165  EXPECT_EQ(CmpExchg->getCompareOperand(), Phi);4166  EXPECT_EQ(CmpExchg->getSuccessOrdering(), AtomicOrdering::Monotonic);4167 4168  LoadInst *Ld = dyn_cast<LoadInst>(CmpExchg->getNewValOperand());4169  EXPECT_NE(Ld, nullptr);4170  EXPECT_EQ(UpdateTemp, Ld->getPointerOperand());4171 4172  Builder.CreateRetVoid();4173  OMPBuilder.finalize();4174  EXPECT_FALSE(verifyModule(*M, &errs()));4175}4176 4177TEST_F(OpenMPIRBuilderTest, OMPAtomicCapture) {4178  OpenMPIRBuilder OMPBuilder(*M);4179  OMPBuilder.initialize();4180  F->setName("func");4181  IRBuilder<> Builder(BB);4182 4183  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});4184 4185  LLVMContext &Ctx = M->getContext();4186  IntegerType *Int32 = Type::getInt32Ty(Ctx);4187  AllocaInst *XVal = Builder.CreateAlloca(Int32);4188  XVal->setName("AtomicVar");4189  AllocaInst *VVal = Builder.CreateAlloca(Int32);4190  VVal->setName("AtomicCapTar");4191  StoreInst *Init =4192      Builder.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx), 0U), XVal);4193 4194  OpenMPIRBuilder::AtomicOpValue X = {XVal, Int32, false, false};4195  OpenMPIRBuilder::AtomicOpValue V = {VVal, Int32, false, false};4196  AtomicOrdering AO = AtomicOrdering::Monotonic;4197  ConstantInt *Expr = ConstantInt::get(Type::getInt32Ty(Ctx), 1U);4198  AtomicRMWInst::BinOp RMWOp = AtomicRMWInst::Add;4199  bool IsXLHSInRHSPart = true;4200  bool IsPostfixUpdate = true;4201  bool UpdateExpr = true;4202 4203  BasicBlock *EntryBB = BB;4204  OpenMPIRBuilder::InsertPointTy AllocaIP(EntryBB,4205                                          EntryBB->getFirstInsertionPt());4206 4207  // integer update - not used4208  auto UpdateOp = [&](Value *Atomic, IRBuilder<> &IRB) { return nullptr; };4209 4210  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,4211                       OMPBuilder.createAtomicCapture(4212                           Builder, AllocaIP, X, V, Expr, AO, RMWOp, UpdateOp,4213                           UpdateExpr, IsPostfixUpdate, IsXLHSInRHSPart));4214  Builder.restoreIP(AfterIP);4215  EXPECT_EQ(EntryBB->getParent()->size(), 1U);4216  AtomicRMWInst *ARWM = dyn_cast<AtomicRMWInst>(Init->getNextNode());4217  EXPECT_NE(ARWM, nullptr);4218  EXPECT_EQ(ARWM->getPointerOperand(), XVal);4219  EXPECT_EQ(ARWM->getOperation(), RMWOp);4220  StoreInst *St = dyn_cast<StoreInst>(ARWM->user_back());4221  EXPECT_NE(St, nullptr);4222  EXPECT_EQ(St->getPointerOperand(), VVal);4223 4224  Builder.CreateRetVoid();4225  OMPBuilder.finalize();4226  EXPECT_FALSE(verifyModule(*M, &errs()));4227}4228 4229TEST_F(OpenMPIRBuilderTest, OMPAtomicCompare) {4230  OpenMPIRBuilder OMPBuilder(*M);4231  OMPBuilder.initialize();4232  F->setName("func");4233  IRBuilder<> Builder(BB);4234 4235  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});4236 4237  LLVMContext &Ctx = M->getContext();4238  IntegerType *Int32 = Type::getInt32Ty(Ctx);4239  AllocaInst *XVal = Builder.CreateAlloca(Int32);4240  XVal->setName("x");4241  StoreInst *Init =4242      Builder.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx), 0U), XVal);4243 4244  OpenMPIRBuilder::AtomicOpValue XSigned = {XVal, Int32, true, false};4245  OpenMPIRBuilder::AtomicOpValue XUnsigned = {XVal, Int32, false, false};4246  // V and R are not used in atomic compare4247  OpenMPIRBuilder::AtomicOpValue V = {nullptr, nullptr, false, false};4248  OpenMPIRBuilder::AtomicOpValue R = {nullptr, nullptr, false, false};4249  AtomicOrdering AO = AtomicOrdering::Monotonic;4250  ConstantInt *Expr = ConstantInt::get(Type::getInt32Ty(Ctx), 1U);4251  ConstantInt *D = ConstantInt::get(Type::getInt32Ty(Ctx), 1U);4252  OMPAtomicCompareOp OpMax = OMPAtomicCompareOp::MAX;4253  OMPAtomicCompareOp OpEQ = OMPAtomicCompareOp::EQ;4254 4255  Builder.restoreIP(OMPBuilder.createAtomicCompare(4256      Builder, XSigned, V, R, Expr, nullptr, AO, OpMax, true, false, false));4257  Builder.restoreIP(OMPBuilder.createAtomicCompare(4258      Builder, XUnsigned, V, R, Expr, nullptr, AO, OpMax, false, false, false));4259  Builder.restoreIP(OMPBuilder.createAtomicCompare(4260      Builder, XSigned, V, R, Expr, D, AO, OpEQ, true, false, false));4261 4262  BasicBlock *EntryBB = BB;4263  EXPECT_EQ(EntryBB->getParent()->size(), 1U);4264  EXPECT_EQ(EntryBB->size(), 5U);4265 4266  AtomicRMWInst *ARWM1 = dyn_cast<AtomicRMWInst>(Init->getNextNode());4267  EXPECT_NE(ARWM1, nullptr);4268  EXPECT_EQ(ARWM1->getPointerOperand(), XVal);4269  EXPECT_EQ(ARWM1->getValOperand(), Expr);4270  EXPECT_EQ(ARWM1->getOperation(), AtomicRMWInst::Min);4271 4272  AtomicRMWInst *ARWM2 = dyn_cast<AtomicRMWInst>(ARWM1->getNextNode());4273  EXPECT_NE(ARWM2, nullptr);4274  EXPECT_EQ(ARWM2->getPointerOperand(), XVal);4275  EXPECT_EQ(ARWM2->getValOperand(), Expr);4276  EXPECT_EQ(ARWM2->getOperation(), AtomicRMWInst::UMax);4277 4278  AtomicCmpXchgInst *AXCHG = dyn_cast<AtomicCmpXchgInst>(ARWM2->getNextNode());4279  EXPECT_NE(AXCHG, nullptr);4280  EXPECT_EQ(AXCHG->getPointerOperand(), XVal);4281  EXPECT_EQ(AXCHG->getCompareOperand(), Expr);4282  EXPECT_EQ(AXCHG->getNewValOperand(), D);4283 4284  Builder.CreateRetVoid();4285  OMPBuilder.finalize();4286  EXPECT_FALSE(verifyModule(*M, &errs()));4287}4288 4289TEST_F(OpenMPIRBuilderTest, OMPAtomicCompareCapture) {4290  OpenMPIRBuilder OMPBuilder(*M);4291  OMPBuilder.initialize();4292  F->setName("func");4293  IRBuilder<> Builder(BB);4294 4295  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});4296 4297  LLVMContext &Ctx = M->getContext();4298  IntegerType *Int32 = Type::getInt32Ty(Ctx);4299  AllocaInst *XVal = Builder.CreateAlloca(Int32);4300  XVal->setName("x");4301  AllocaInst *VVal = Builder.CreateAlloca(Int32);4302  VVal->setName("v");4303  AllocaInst *RVal = Builder.CreateAlloca(Int32);4304  RVal->setName("r");4305 4306  StoreInst *Init =4307      Builder.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx), 0U), XVal);4308 4309  OpenMPIRBuilder::AtomicOpValue X = {XVal, Int32, true, false};4310  OpenMPIRBuilder::AtomicOpValue V = {VVal, Int32, false, false};4311  OpenMPIRBuilder::AtomicOpValue NoV = {nullptr, nullptr, false, false};4312  OpenMPIRBuilder::AtomicOpValue R = {RVal, Int32, false, false};4313  OpenMPIRBuilder::AtomicOpValue NoR = {nullptr, nullptr, false, false};4314 4315  AtomicOrdering AO = AtomicOrdering::Monotonic;4316  ConstantInt *Expr = ConstantInt::get(Type::getInt32Ty(Ctx), 1U);4317  ConstantInt *D = ConstantInt::get(Type::getInt32Ty(Ctx), 1U);4318  OMPAtomicCompareOp OpMax = OMPAtomicCompareOp::MAX;4319  OMPAtomicCompareOp OpEQ = OMPAtomicCompareOp::EQ;4320 4321  // { cond-update-stmt v = x; }4322  Builder.restoreIP(OMPBuilder.createAtomicCompare(4323      Builder, X, V, NoR, Expr, D, AO, OpEQ, /* IsXBinopExpr */ true,4324      /* IsPostfixUpdate */ false,4325      /* IsFailOnly */ false));4326  // { v = x; cond-update-stmt }4327  Builder.restoreIP(OMPBuilder.createAtomicCompare(4328      Builder, X, V, NoR, Expr, D, AO, OpEQ, /* IsXBinopExpr */ true,4329      /* IsPostfixUpdate */ true,4330      /* IsFailOnly */ false));4331  // if(x == e) { x = d; } else { v = x; }4332  Builder.restoreIP(OMPBuilder.createAtomicCompare(4333      Builder, X, V, NoR, Expr, D, AO, OpEQ, /* IsXBinopExpr */ true,4334      /* IsPostfixUpdate */ false,4335      /* IsFailOnly */ true));4336  // { r = x == e; if(r) { x = d; } }4337  Builder.restoreIP(OMPBuilder.createAtomicCompare(4338      Builder, X, NoV, R, Expr, D, AO, OpEQ, /* IsXBinopExpr */ true,4339      /* IsPostfixUpdate */ false,4340      /* IsFailOnly */ false));4341  // { r = x == e; if(r) { x = d; } else { v = x; } }4342  Builder.restoreIP(OMPBuilder.createAtomicCompare(4343      Builder, X, V, R, Expr, D, AO, OpEQ, /* IsXBinopExpr */ true,4344      /* IsPostfixUpdate */ false,4345      /* IsFailOnly */ true));4346 4347  // { v = x; cond-update-stmt }4348  Builder.restoreIP(OMPBuilder.createAtomicCompare(4349      Builder, X, V, NoR, Expr, nullptr, AO, OpMax, /* IsXBinopExpr */ true,4350      /* IsPostfixUpdate */ true,4351      /* IsFailOnly */ false));4352  // { cond-update-stmt v = x; }4353  Builder.restoreIP(OMPBuilder.createAtomicCompare(4354      Builder, X, V, NoR, Expr, nullptr, AO, OpMax, /* IsXBinopExpr */ false,4355      /* IsPostfixUpdate */ false,4356      /* IsFailOnly */ false));4357 4358  BasicBlock *EntryBB = BB;4359  EXPECT_EQ(EntryBB->getParent()->size(), 5U);4360  BasicBlock *Cont1 = dyn_cast<BasicBlock>(EntryBB->getNextNode());4361  EXPECT_NE(Cont1, nullptr);4362  BasicBlock *Exit1 = dyn_cast<BasicBlock>(Cont1->getNextNode());4363  EXPECT_NE(Exit1, nullptr);4364  BasicBlock *Cont2 = dyn_cast<BasicBlock>(Exit1->getNextNode());4365  EXPECT_NE(Cont2, nullptr);4366  BasicBlock *Exit2 = dyn_cast<BasicBlock>(Cont2->getNextNode());4367  EXPECT_NE(Exit2, nullptr);4368 4369  AtomicCmpXchgInst *CmpXchg1 =4370      dyn_cast<AtomicCmpXchgInst>(Init->getNextNode());4371  EXPECT_NE(CmpXchg1, nullptr);4372  EXPECT_EQ(CmpXchg1->getPointerOperand(), XVal);4373  EXPECT_EQ(CmpXchg1->getCompareOperand(), Expr);4374  EXPECT_EQ(CmpXchg1->getNewValOperand(), D);4375  ExtractValueInst *ExtVal1 =4376      dyn_cast<ExtractValueInst>(CmpXchg1->getNextNode());4377  EXPECT_NE(ExtVal1, nullptr);4378  EXPECT_EQ(ExtVal1->getAggregateOperand(), CmpXchg1);4379  EXPECT_EQ(ExtVal1->getIndices(), ArrayRef<unsigned int>(0U));4380  ExtractValueInst *ExtVal2 =4381      dyn_cast<ExtractValueInst>(ExtVal1->getNextNode());4382  EXPECT_NE(ExtVal2, nullptr);4383  EXPECT_EQ(ExtVal2->getAggregateOperand(), CmpXchg1);4384  EXPECT_EQ(ExtVal2->getIndices(), ArrayRef<unsigned int>(1U));4385  SelectInst *Sel1 = dyn_cast<SelectInst>(ExtVal2->getNextNode());4386  EXPECT_NE(Sel1, nullptr);4387  EXPECT_EQ(Sel1->getCondition(), ExtVal2);4388  EXPECT_EQ(Sel1->getTrueValue(), Expr);4389  EXPECT_EQ(Sel1->getFalseValue(), ExtVal1);4390  StoreInst *Store1 = dyn_cast<StoreInst>(Sel1->getNextNode());4391  EXPECT_NE(Store1, nullptr);4392  EXPECT_EQ(Store1->getPointerOperand(), VVal);4393  EXPECT_EQ(Store1->getValueOperand(), Sel1);4394 4395  AtomicCmpXchgInst *CmpXchg2 =4396      dyn_cast<AtomicCmpXchgInst>(Store1->getNextNode());4397  EXPECT_NE(CmpXchg2, nullptr);4398  EXPECT_EQ(CmpXchg2->getPointerOperand(), XVal);4399  EXPECT_EQ(CmpXchg2->getCompareOperand(), Expr);4400  EXPECT_EQ(CmpXchg2->getNewValOperand(), D);4401  ExtractValueInst *ExtVal3 =4402      dyn_cast<ExtractValueInst>(CmpXchg2->getNextNode());4403  EXPECT_NE(ExtVal3, nullptr);4404  EXPECT_EQ(ExtVal3->getAggregateOperand(), CmpXchg2);4405  EXPECT_EQ(ExtVal3->getIndices(), ArrayRef<unsigned int>(0U));4406  StoreInst *Store2 = dyn_cast<StoreInst>(ExtVal3->getNextNode());4407  EXPECT_NE(Store2, nullptr);4408  EXPECT_EQ(Store2->getPointerOperand(), VVal);4409  EXPECT_EQ(Store2->getValueOperand(), ExtVal3);4410 4411  AtomicCmpXchgInst *CmpXchg3 =4412      dyn_cast<AtomicCmpXchgInst>(Store2->getNextNode());4413  EXPECT_NE(CmpXchg3, nullptr);4414  EXPECT_EQ(CmpXchg3->getPointerOperand(), XVal);4415  EXPECT_EQ(CmpXchg3->getCompareOperand(), Expr);4416  EXPECT_EQ(CmpXchg3->getNewValOperand(), D);4417  ExtractValueInst *ExtVal4 =4418      dyn_cast<ExtractValueInst>(CmpXchg3->getNextNode());4419  EXPECT_NE(ExtVal4, nullptr);4420  EXPECT_EQ(ExtVal4->getAggregateOperand(), CmpXchg3);4421  EXPECT_EQ(ExtVal4->getIndices(), ArrayRef<unsigned int>(0U));4422  ExtractValueInst *ExtVal5 =4423      dyn_cast<ExtractValueInst>(ExtVal4->getNextNode());4424  EXPECT_NE(ExtVal5, nullptr);4425  EXPECT_EQ(ExtVal5->getAggregateOperand(), CmpXchg3);4426  EXPECT_EQ(ExtVal5->getIndices(), ArrayRef<unsigned int>(1U));4427  BranchInst *Br1 = dyn_cast<BranchInst>(ExtVal5->getNextNode());4428  EXPECT_NE(Br1, nullptr);4429  EXPECT_EQ(Br1->isConditional(), true);4430  EXPECT_EQ(Br1->getCondition(), ExtVal5);4431  EXPECT_EQ(Br1->getSuccessor(0), Exit1);4432  EXPECT_EQ(Br1->getSuccessor(1), Cont1);4433 4434  StoreInst *Store3 = dyn_cast<StoreInst>(&Cont1->front());4435  EXPECT_NE(Store3, nullptr);4436  EXPECT_EQ(Store3->getPointerOperand(), VVal);4437  EXPECT_EQ(Store3->getValueOperand(), ExtVal4);4438  BranchInst *Br2 = dyn_cast<BranchInst>(Store3->getNextNode());4439  EXPECT_NE(Br2, nullptr);4440  EXPECT_EQ(Br2->isUnconditional(), true);4441  EXPECT_EQ(Br2->getSuccessor(0), Exit1);4442 4443  AtomicCmpXchgInst *CmpXchg4 = dyn_cast<AtomicCmpXchgInst>(&Exit1->front());4444  EXPECT_NE(CmpXchg4, nullptr);4445  EXPECT_EQ(CmpXchg4->getPointerOperand(), XVal);4446  EXPECT_EQ(CmpXchg4->getCompareOperand(), Expr);4447  EXPECT_EQ(CmpXchg4->getNewValOperand(), D);4448  ExtractValueInst *ExtVal6 =4449      dyn_cast<ExtractValueInst>(CmpXchg4->getNextNode());4450  EXPECT_NE(ExtVal6, nullptr);4451  EXPECT_EQ(ExtVal6->getAggregateOperand(), CmpXchg4);4452  EXPECT_EQ(ExtVal6->getIndices(), ArrayRef<unsigned int>(1U));4453  ZExtInst *ZExt1 = dyn_cast<ZExtInst>(ExtVal6->getNextNode());4454  EXPECT_NE(ZExt1, nullptr);4455  EXPECT_EQ(ZExt1->getDestTy(), Int32);4456  StoreInst *Store4 = dyn_cast<StoreInst>(ZExt1->getNextNode());4457  EXPECT_NE(Store4, nullptr);4458  EXPECT_EQ(Store4->getPointerOperand(), RVal);4459  EXPECT_EQ(Store4->getValueOperand(), ZExt1);4460 4461  AtomicCmpXchgInst *CmpXchg5 =4462      dyn_cast<AtomicCmpXchgInst>(Store4->getNextNode());4463  EXPECT_NE(CmpXchg5, nullptr);4464  EXPECT_EQ(CmpXchg5->getPointerOperand(), XVal);4465  EXPECT_EQ(CmpXchg5->getCompareOperand(), Expr);4466  EXPECT_EQ(CmpXchg5->getNewValOperand(), D);4467  ExtractValueInst *ExtVal7 =4468      dyn_cast<ExtractValueInst>(CmpXchg5->getNextNode());4469  EXPECT_NE(ExtVal7, nullptr);4470  EXPECT_EQ(ExtVal7->getAggregateOperand(), CmpXchg5);4471  EXPECT_EQ(ExtVal7->getIndices(), ArrayRef<unsigned int>(0U));4472  ExtractValueInst *ExtVal8 =4473      dyn_cast<ExtractValueInst>(ExtVal7->getNextNode());4474  EXPECT_NE(ExtVal8, nullptr);4475  EXPECT_EQ(ExtVal8->getAggregateOperand(), CmpXchg5);4476  EXPECT_EQ(ExtVal8->getIndices(), ArrayRef<unsigned int>(1U));4477  BranchInst *Br3 = dyn_cast<BranchInst>(ExtVal8->getNextNode());4478  EXPECT_NE(Br3, nullptr);4479  EXPECT_EQ(Br3->isConditional(), true);4480  EXPECT_EQ(Br3->getCondition(), ExtVal8);4481  EXPECT_EQ(Br3->getSuccessor(0), Exit2);4482  EXPECT_EQ(Br3->getSuccessor(1), Cont2);4483 4484  StoreInst *Store5 = dyn_cast<StoreInst>(&Cont2->front());4485  EXPECT_NE(Store5, nullptr);4486  EXPECT_EQ(Store5->getPointerOperand(), VVal);4487  EXPECT_EQ(Store5->getValueOperand(), ExtVal7);4488  BranchInst *Br4 = dyn_cast<BranchInst>(Store5->getNextNode());4489  EXPECT_NE(Br4, nullptr);4490  EXPECT_EQ(Br4->isUnconditional(), true);4491  EXPECT_EQ(Br4->getSuccessor(0), Exit2);4492 4493  ExtractValueInst *ExtVal9 = dyn_cast<ExtractValueInst>(&Exit2->front());4494  EXPECT_NE(ExtVal9, nullptr);4495  EXPECT_EQ(ExtVal9->getAggregateOperand(), CmpXchg5);4496  EXPECT_EQ(ExtVal9->getIndices(), ArrayRef<unsigned int>(1U));4497  ZExtInst *ZExt2 = dyn_cast<ZExtInst>(ExtVal9->getNextNode());4498  EXPECT_NE(ZExt2, nullptr);4499  EXPECT_EQ(ZExt2->getDestTy(), Int32);4500  StoreInst *Store6 = dyn_cast<StoreInst>(ZExt2->getNextNode());4501  EXPECT_NE(Store6, nullptr);4502  EXPECT_EQ(Store6->getPointerOperand(), RVal);4503  EXPECT_EQ(Store6->getValueOperand(), ZExt2);4504 4505  AtomicRMWInst *ARWM1 = dyn_cast<AtomicRMWInst>(Store6->getNextNode());4506  EXPECT_NE(ARWM1, nullptr);4507  EXPECT_EQ(ARWM1->getPointerOperand(), XVal);4508  EXPECT_EQ(ARWM1->getValOperand(), Expr);4509  EXPECT_EQ(ARWM1->getOperation(), AtomicRMWInst::Min);4510  StoreInst *Store7 = dyn_cast<StoreInst>(ARWM1->getNextNode());4511  EXPECT_NE(Store7, nullptr);4512  EXPECT_EQ(Store7->getPointerOperand(), VVal);4513  EXPECT_EQ(Store7->getValueOperand(), ARWM1);4514 4515  AtomicRMWInst *ARWM2 = dyn_cast<AtomicRMWInst>(Store7->getNextNode());4516  EXPECT_NE(ARWM2, nullptr);4517  EXPECT_EQ(ARWM2->getPointerOperand(), XVal);4518  EXPECT_EQ(ARWM2->getValOperand(), Expr);4519  EXPECT_EQ(ARWM2->getOperation(), AtomicRMWInst::Max);4520  CmpInst *Cmp1 = dyn_cast<CmpInst>(ARWM2->getNextNode());4521  EXPECT_NE(Cmp1, nullptr);4522  EXPECT_EQ(Cmp1->getPredicate(), CmpInst::ICMP_SGT);4523  EXPECT_EQ(Cmp1->getOperand(0), ARWM2);4524  EXPECT_EQ(Cmp1->getOperand(1), Expr);4525  SelectInst *Sel2 = dyn_cast<SelectInst>(Cmp1->getNextNode());4526  EXPECT_NE(Sel2, nullptr);4527  EXPECT_EQ(Sel2->getCondition(), Cmp1);4528  EXPECT_EQ(Sel2->getTrueValue(), Expr);4529  EXPECT_EQ(Sel2->getFalseValue(), ARWM2);4530  StoreInst *Store8 = dyn_cast<StoreInst>(Sel2->getNextNode());4531  EXPECT_NE(Store8, nullptr);4532  EXPECT_EQ(Store8->getPointerOperand(), VVal);4533  EXPECT_EQ(Store8->getValueOperand(), Sel2);4534 4535  Builder.CreateRetVoid();4536  OMPBuilder.finalize();4537  EXPECT_FALSE(verifyModule(*M, &errs()));4538}4539 4540TEST_F(OpenMPIRBuilderTest, OMPAtomicRWStructType) {4541  // Test for issue #165184: atomic read/write on struct types should use4542  // element type size, not pointer size.4543  OpenMPIRBuilder OMPBuilder(*M);4544  OMPBuilder.initialize();4545  F->setName("func");4546  IRBuilder<> Builder(BB);4547 4548  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});4549  BasicBlock *EntryBB = BB;4550  OpenMPIRBuilder::InsertPointTy AllocaIP(EntryBB,4551                                          EntryBB->getFirstInsertionPt());4552 4553  LLVMContext &Ctx = M->getContext();4554 4555  // Create a struct type {double, double} to simulate complex(8) - 16 bytes4556  StructType *Complex8Ty = StructType::create(4557      Ctx, {Type::getDoubleTy(Ctx), Type::getDoubleTy(Ctx)}, "complex");4558 4559  AllocaInst *XVal = Builder.CreateAlloca(Complex8Ty);4560  XVal->setName("AtomicVar");4561  OpenMPIRBuilder::AtomicOpValue X = {XVal, Complex8Ty, false, false};4562  AtomicOrdering AO = AtomicOrdering::SequentiallyConsistent;4563 4564  // Create value to write: {1.0, 1.0}4565  Constant *Real = ConstantFP::get(Type::getDoubleTy(Ctx), 1.0);4566  Constant *Imag = ConstantFP::get(Type::getDoubleTy(Ctx), 1.0);4567  Constant *ValToWrite = ConstantStruct::get(Complex8Ty, {Real, Imag});4568 4569  // Test atomic write4570  Builder.restoreIP(4571      OMPBuilder.createAtomicWrite(Loc, X, ValToWrite, AO, AllocaIP));4572 4573  // Test atomic read4574  AllocaInst *VVal = Builder.CreateAlloca(Complex8Ty);4575  VVal->setName("ReadDest");4576  OpenMPIRBuilder::AtomicOpValue V = {VVal, Complex8Ty, false, false};4577 4578  Builder.restoreIP(OMPBuilder.createAtomicRead(Loc, X, V, AO, AllocaIP));4579 4580  Builder.CreateRetVoid();4581  OMPBuilder.finalize();4582  EXPECT_FALSE(verifyModule(*M, &errs()));4583 4584  // Verify that __atomic_store and __atomic_load are called with size 164585  bool FoundAtomicStore = false;4586  bool FoundAtomicLoad = false;4587 4588  for (Function &Fn : *M) {4589    if (Fn.getName().starts_with("__atomic_store")) {4590      // Check that first call to __atomic_store has size argument = 164591      for (User *U : Fn.users()) {4592        if (auto *CB = dyn_cast<CallBase>(U)) {4593          if (auto *SizeArg = dyn_cast<ConstantInt>(CB->getArgOperand(0))) {4594            EXPECT_EQ(SizeArg->getZExtValue(), 16U);4595            FoundAtomicStore = true;4596            break;4597          }4598        }4599      }4600    }4601    if (Fn.getName().starts_with("__atomic_load")) {4602      // Check that first call to __atomic_load has size argument = 164603      for (User *U : Fn.users()) {4604        if (auto *CB = dyn_cast<CallBase>(U)) {4605          if (auto *SizeArg = dyn_cast<ConstantInt>(CB->getArgOperand(0))) {4606            EXPECT_EQ(SizeArg->getZExtValue(), 16U);4607            FoundAtomicLoad = true;4608            break;4609          }4610        }4611      }4612    }4613  }4614 4615  EXPECT_TRUE(FoundAtomicStore) << "Did not find __atomic_store call";4616  EXPECT_TRUE(FoundAtomicLoad) << "Did not find __atomic_load call";4617}4618 4619TEST_F(OpenMPIRBuilderTest, CreateTeams) {4620  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;4621  OpenMPIRBuilder OMPBuilder(*M);4622  OMPBuilder.Config.IsTargetDevice = false;4623  OMPBuilder.initialize();4624  F->setName("func");4625  IRBuilder<> Builder(BB);4626 4627  AllocaInst *ValPtr32 = Builder.CreateAlloca(Builder.getInt32Ty());4628  AllocaInst *ValPtr128 = Builder.CreateAlloca(Builder.getInt128Ty());4629  Value *Val128 = Builder.CreateLoad(Builder.getInt128Ty(), ValPtr128, "load");4630 4631  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {4632    Builder.restoreIP(AllocaIP);4633    AllocaInst *Local128 = Builder.CreateAlloca(Builder.getInt128Ty(), nullptr,4634                                                "bodygen.alloca128");4635 4636    Builder.restoreIP(CodeGenIP);4637    // Loading and storing captured pointer and values4638    Builder.CreateStore(Val128, Local128);4639    Value *Val32 = Builder.CreateLoad(ValPtr32->getAllocatedType(), ValPtr32,4640                                      "bodygen.load32");4641 4642    LoadInst *PrivLoad128 = Builder.CreateLoad(4643        Local128->getAllocatedType(), Local128, "bodygen.local.load128");4644    Value *Cmp = Builder.CreateICmpNE(4645        Val32, Builder.CreateTrunc(PrivLoad128, Val32->getType()));4646    Instruction *ThenTerm, *ElseTerm;4647    SplitBlockAndInsertIfThenElse(Cmp, CodeGenIP.getBlock()->getTerminator(),4648                                  &ThenTerm, &ElseTerm);4649    return Error::success();4650  };4651 4652  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});4653  ASSERT_EXPECTED_INIT(4654      OpenMPIRBuilder::InsertPointTy, AfterIP,4655      OMPBuilder.createTeams(Builder, BodyGenCB, /*NumTeamsLower=*/nullptr,4656                             /*NumTeamsUpper=*/nullptr,4657                             /*ThreadLimit=*/nullptr, /*IfExpr=*/nullptr));4658  Builder.restoreIP(AfterIP);4659 4660  OMPBuilder.finalize();4661  Builder.CreateRetVoid();4662 4663  EXPECT_FALSE(verifyModule(*M, &errs()));4664 4665  CallInst *TeamsForkCall = dyn_cast<CallInst>(4666      OMPBuilder.getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_fork_teams)4667          ->user_back());4668 4669  // Verify the Ident argument4670  GlobalVariable *Ident = cast<GlobalVariable>(TeamsForkCall->getArgOperand(0));4671  ASSERT_NE(Ident, nullptr);4672  EXPECT_TRUE(Ident->hasInitializer());4673  Constant *Initializer = Ident->getInitializer();4674  GlobalVariable *SrcStrGlob =4675      cast<GlobalVariable>(Initializer->getOperand(4)->stripPointerCasts());4676  ASSERT_NE(SrcStrGlob, nullptr);4677  ConstantDataArray *SrcSrc =4678      dyn_cast<ConstantDataArray>(SrcStrGlob->getInitializer());4679  ASSERT_NE(SrcSrc, nullptr);4680 4681  // Verify the outlined function signature.4682  Function *OutlinedFn =4683      dyn_cast<Function>(TeamsForkCall->getArgOperand(2)->stripPointerCasts());4684  ASSERT_NE(OutlinedFn, nullptr);4685  EXPECT_FALSE(OutlinedFn->isDeclaration());4686  EXPECT_TRUE(OutlinedFn->arg_size() >= 3);4687  EXPECT_EQ(OutlinedFn->getArg(0)->getType(), Builder.getPtrTy()); // global_tid4688  EXPECT_EQ(OutlinedFn->getArg(1)->getType(), Builder.getPtrTy()); // bound_tid4689  EXPECT_EQ(OutlinedFn->getArg(2)->getType(),4690            Builder.getPtrTy()); // captured args4691 4692  // Check for TruncInst and ICmpInst in the outlined function.4693  EXPECT_TRUE(any_of(instructions(OutlinedFn),4694                     [](Instruction &inst) { return isa<TruncInst>(&inst); }));4695  EXPECT_TRUE(any_of(instructions(OutlinedFn),4696                     [](Instruction &inst) { return isa<ICmpInst>(&inst); }));4697}4698 4699TEST_F(OpenMPIRBuilderTest, CreateTeamsWithThreadLimit) {4700  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;4701  OpenMPIRBuilder OMPBuilder(*M);4702  OMPBuilder.Config.IsTargetDevice = false;4703  OMPBuilder.initialize();4704  F->setName("func");4705  IRBuilder<> &Builder = OMPBuilder.Builder;4706  Builder.SetInsertPoint(BB);4707 4708  Function *FakeFunction =4709      Function::Create(FunctionType::get(Builder.getVoidTy(), false),4710                       GlobalValue::ExternalLinkage, "fakeFunction", M.get());4711 4712  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {4713    Builder.restoreIP(CodeGenIP);4714    Builder.CreateCall(FakeFunction, {});4715    return Error::success();4716  };4717 4718  // `F` has an argument - an integer, so we use that as the thread limit.4719  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,4720                       OMPBuilder.createTeams(4721                           /*=*/Builder, BodyGenCB, /*NumTeamsLower=*/nullptr,4722                           /*NumTeamsUpper=*/nullptr,4723                           /*ThreadLimit=*/F->arg_begin(),4724                           /*IfExpr=*/nullptr));4725  Builder.restoreIP(AfterIP);4726 4727  Builder.CreateRetVoid();4728  OMPBuilder.finalize();4729 4730  ASSERT_FALSE(verifyModule(*M));4731 4732  CallInst *PushNumTeamsCallInst =4733      findSingleCall(F, OMPRTL___kmpc_push_num_teams_51, OMPBuilder);4734  ASSERT_NE(PushNumTeamsCallInst, nullptr);4735 4736  EXPECT_EQ(PushNumTeamsCallInst->getArgOperand(2), Builder.getInt32(0));4737  EXPECT_EQ(PushNumTeamsCallInst->getArgOperand(3), Builder.getInt32(0));4738  EXPECT_EQ(PushNumTeamsCallInst->getArgOperand(4), &*F->arg_begin());4739 4740  // Verifying that the next instruction to execute is kmpc_fork_teams4741  BranchInst *BrInst =4742      dyn_cast<BranchInst>(PushNumTeamsCallInst->getNextNode());4743  ASSERT_NE(BrInst, nullptr);4744  ASSERT_EQ(BrInst->getNumSuccessors(), 1U);4745  BasicBlock::iterator NextInstruction =4746      BrInst->getSuccessor(0)->getFirstNonPHIOrDbgOrLifetime();4747  CallInst *ForkTeamsCI = nullptr;4748  if (NextInstruction != BrInst->getSuccessor(0)->end())4749    ForkTeamsCI = dyn_cast_if_present<CallInst>(NextInstruction);4750  ASSERT_NE(ForkTeamsCI, nullptr);4751  EXPECT_EQ(ForkTeamsCI->getCalledFunction(),4752            OMPBuilder.getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_fork_teams));4753}4754 4755TEST_F(OpenMPIRBuilderTest, CreateTeamsWithNumTeamsUpper) {4756  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;4757  OpenMPIRBuilder OMPBuilder(*M);4758  OMPBuilder.Config.IsTargetDevice = false;4759  OMPBuilder.initialize();4760  F->setName("func");4761  IRBuilder<> &Builder = OMPBuilder.Builder;4762  Builder.SetInsertPoint(BB);4763 4764  Function *FakeFunction =4765      Function::Create(FunctionType::get(Builder.getVoidTy(), false),4766                       GlobalValue::ExternalLinkage, "fakeFunction", M.get());4767 4768  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {4769    Builder.restoreIP(CodeGenIP);4770    Builder.CreateCall(FakeFunction, {});4771    return Error::success();4772  };4773 4774  // `F` already has an integer argument, so we use that as upper bound to4775  // `num_teams`4776  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,4777                       OMPBuilder.createTeams(Builder, BodyGenCB,4778                                              /*NumTeamsLower=*/nullptr,4779                                              /*NumTeamsUpper=*/F->arg_begin(),4780                                              /*ThreadLimit=*/nullptr,4781                                              /*IfExpr=*/nullptr));4782  Builder.restoreIP(AfterIP);4783 4784  Builder.CreateRetVoid();4785  OMPBuilder.finalize();4786 4787  ASSERT_FALSE(verifyModule(*M));4788 4789  CallInst *PushNumTeamsCallInst =4790      findSingleCall(F, OMPRTL___kmpc_push_num_teams_51, OMPBuilder);4791  ASSERT_NE(PushNumTeamsCallInst, nullptr);4792 4793  EXPECT_EQ(PushNumTeamsCallInst->getArgOperand(2), &*F->arg_begin());4794  EXPECT_EQ(PushNumTeamsCallInst->getArgOperand(3), &*F->arg_begin());4795  EXPECT_EQ(PushNumTeamsCallInst->getArgOperand(4), Builder.getInt32(0));4796 4797  // Verifying that the next instruction to execute is kmpc_fork_teams4798  BranchInst *BrInst =4799      dyn_cast<BranchInst>(PushNumTeamsCallInst->getNextNode());4800  ASSERT_NE(BrInst, nullptr);4801  ASSERT_EQ(BrInst->getNumSuccessors(), 1U);4802  BasicBlock::iterator NextInstruction =4803      BrInst->getSuccessor(0)->getFirstNonPHIOrDbgOrLifetime();4804  CallInst *ForkTeamsCI = nullptr;4805  if (NextInstruction != BrInst->getSuccessor(0)->end())4806    ForkTeamsCI = dyn_cast_if_present<CallInst>(NextInstruction);4807  ASSERT_NE(ForkTeamsCI, nullptr);4808  EXPECT_EQ(ForkTeamsCI->getCalledFunction(),4809            OMPBuilder.getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_fork_teams));4810}4811 4812TEST_F(OpenMPIRBuilderTest, CreateTeamsWithNumTeamsBoth) {4813  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;4814  OpenMPIRBuilder OMPBuilder(*M);4815  OMPBuilder.Config.IsTargetDevice = false;4816  OMPBuilder.initialize();4817  F->setName("func");4818  IRBuilder<> &Builder = OMPBuilder.Builder;4819  Builder.SetInsertPoint(BB);4820 4821  Function *FakeFunction =4822      Function::Create(FunctionType::get(Builder.getVoidTy(), false),4823                       GlobalValue::ExternalLinkage, "fakeFunction", M.get());4824 4825  Value *NumTeamsLower =4826      Builder.CreateAdd(F->arg_begin(), Builder.getInt32(5), "numTeamsLower");4827  Value *NumTeamsUpper =4828      Builder.CreateAdd(F->arg_begin(), Builder.getInt32(10), "numTeamsUpper");4829 4830  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {4831    Builder.restoreIP(CodeGenIP);4832    Builder.CreateCall(FakeFunction, {});4833    return Error::success();4834  };4835 4836  // `F` already has an integer argument, so we use that as upper bound to4837  // `num_teams`4838  ASSERT_EXPECTED_INIT(4839      OpenMPIRBuilder::InsertPointTy, AfterIP,4840      OMPBuilder.createTeams(Builder, BodyGenCB, NumTeamsLower, NumTeamsUpper,4841                             /*ThreadLimit=*/nullptr, /*IfExpr=*/nullptr));4842  Builder.restoreIP(AfterIP);4843 4844  Builder.CreateRetVoid();4845  OMPBuilder.finalize();4846 4847  ASSERT_FALSE(verifyModule(*M));4848 4849  CallInst *PushNumTeamsCallInst =4850      findSingleCall(F, OMPRTL___kmpc_push_num_teams_51, OMPBuilder);4851  ASSERT_NE(PushNumTeamsCallInst, nullptr);4852 4853  EXPECT_EQ(PushNumTeamsCallInst->getArgOperand(2), NumTeamsLower);4854  EXPECT_EQ(PushNumTeamsCallInst->getArgOperand(3), NumTeamsUpper);4855  EXPECT_EQ(PushNumTeamsCallInst->getArgOperand(4), Builder.getInt32(0));4856 4857  // Verifying that the next instruction to execute is kmpc_fork_teams4858  BranchInst *BrInst =4859      dyn_cast<BranchInst>(PushNumTeamsCallInst->getNextNode());4860  ASSERT_NE(BrInst, nullptr);4861  ASSERT_EQ(BrInst->getNumSuccessors(), 1U);4862  BasicBlock::iterator NextInstruction =4863      BrInst->getSuccessor(0)->getFirstNonPHIOrDbgOrLifetime();4864  CallInst *ForkTeamsCI = nullptr;4865  if (NextInstruction != BrInst->getSuccessor(0)->end())4866    ForkTeamsCI = dyn_cast_if_present<CallInst>(NextInstruction);4867  ASSERT_NE(ForkTeamsCI, nullptr);4868  EXPECT_EQ(ForkTeamsCI->getCalledFunction(),4869            OMPBuilder.getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_fork_teams));4870}4871 4872TEST_F(OpenMPIRBuilderTest, CreateTeamsWithNumTeamsAndThreadLimit) {4873  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;4874  OpenMPIRBuilder OMPBuilder(*M);4875  OMPBuilder.Config.IsTargetDevice = false;4876  OMPBuilder.initialize();4877  F->setName("func");4878  IRBuilder<> &Builder = OMPBuilder.Builder;4879  Builder.SetInsertPoint(BB);4880 4881  BasicBlock *CodegenBB = splitBB(Builder, true);4882  Builder.SetInsertPoint(CodegenBB);4883 4884  // Generate values for `num_teams` and `thread_limit` using the first argument4885  // of the testing function.4886  Value *NumTeamsLower =4887      Builder.CreateAdd(F->arg_begin(), Builder.getInt32(5), "numTeamsLower");4888  Value *NumTeamsUpper =4889      Builder.CreateAdd(F->arg_begin(), Builder.getInt32(10), "numTeamsUpper");4890  Value *ThreadLimit =4891      Builder.CreateAdd(F->arg_begin(), Builder.getInt32(20), "threadLimit");4892 4893  Function *FakeFunction =4894      Function::Create(FunctionType::get(Builder.getVoidTy(), false),4895                       GlobalValue::ExternalLinkage, "fakeFunction", M.get());4896 4897  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {4898    Builder.restoreIP(CodeGenIP);4899    Builder.CreateCall(FakeFunction, {});4900    return Error::success();4901  };4902 4903  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});4904  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,4905                       OMPBuilder.createTeams(Builder, BodyGenCB, NumTeamsLower,4906                                              NumTeamsUpper, ThreadLimit,4907                                              nullptr));4908  Builder.restoreIP(AfterIP);4909 4910  Builder.CreateRetVoid();4911  OMPBuilder.finalize();4912 4913  ASSERT_FALSE(verifyModule(*M));4914 4915  CallInst *PushNumTeamsCallInst =4916      findSingleCall(F, OMPRTL___kmpc_push_num_teams_51, OMPBuilder);4917  ASSERT_NE(PushNumTeamsCallInst, nullptr);4918 4919  EXPECT_EQ(PushNumTeamsCallInst->getArgOperand(2), NumTeamsLower);4920  EXPECT_EQ(PushNumTeamsCallInst->getArgOperand(3), NumTeamsUpper);4921  EXPECT_EQ(PushNumTeamsCallInst->getArgOperand(4), ThreadLimit);4922 4923  // Verifying that the next instruction to execute is kmpc_fork_teams4924  BranchInst *BrInst =4925      dyn_cast<BranchInst>(PushNumTeamsCallInst->getNextNode());4926  ASSERT_NE(BrInst, nullptr);4927  ASSERT_EQ(BrInst->getNumSuccessors(), 1U);4928  BasicBlock::iterator NextInstruction =4929      BrInst->getSuccessor(0)->getFirstNonPHIOrDbgOrLifetime();4930  CallInst *ForkTeamsCI = nullptr;4931  if (NextInstruction != BrInst->getSuccessor(0)->end())4932    ForkTeamsCI = dyn_cast_if_present<CallInst>(NextInstruction);4933  ASSERT_NE(ForkTeamsCI, nullptr);4934  EXPECT_EQ(ForkTeamsCI->getCalledFunction(),4935            OMPBuilder.getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_fork_teams));4936}4937 4938TEST_F(OpenMPIRBuilderTest, CreateTeamsWithIfCondition) {4939  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;4940  OpenMPIRBuilder OMPBuilder(*M);4941  OMPBuilder.Config.IsTargetDevice = false;4942  OMPBuilder.initialize();4943  F->setName("func");4944  IRBuilder<> &Builder = OMPBuilder.Builder;4945  Builder.SetInsertPoint(BB);4946 4947  Value *IfExpr = Builder.CreateLoad(Builder.getInt1Ty(),4948                                     Builder.CreateAlloca(Builder.getInt1Ty()));4949 4950  Function *FakeFunction =4951      Function::Create(FunctionType::get(Builder.getVoidTy(), false),4952                       GlobalValue::ExternalLinkage, "fakeFunction", M.get());4953 4954  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {4955    Builder.restoreIP(CodeGenIP);4956    Builder.CreateCall(FakeFunction, {});4957    return Error::success();4958  };4959 4960  // `F` already has an integer argument, so we use that as upper bound to4961  // `num_teams`4962  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,4963                       OMPBuilder.createTeams(Builder, BodyGenCB,4964                                              /*NumTeamsLower=*/nullptr,4965                                              /*NumTeamsUpper=*/nullptr,4966                                              /*ThreadLimit=*/nullptr, IfExpr));4967  Builder.restoreIP(AfterIP);4968 4969  Builder.CreateRetVoid();4970  OMPBuilder.finalize();4971 4972  ASSERT_FALSE(verifyModule(*M));4973 4974  CallInst *PushNumTeamsCallInst =4975      findSingleCall(F, OMPRTL___kmpc_push_num_teams_51, OMPBuilder);4976  ASSERT_NE(PushNumTeamsCallInst, nullptr);4977  Value *NumTeamsLower = PushNumTeamsCallInst->getArgOperand(2);4978  Value *NumTeamsUpper = PushNumTeamsCallInst->getArgOperand(3);4979  Value *ThreadLimit = PushNumTeamsCallInst->getArgOperand(4);4980 4981  // Check the lower_bound4982  ASSERT_NE(NumTeamsLower, nullptr);4983  SelectInst *NumTeamsLowerSelectInst = dyn_cast<SelectInst>(NumTeamsLower);4984  ASSERT_NE(NumTeamsLowerSelectInst, nullptr);4985  EXPECT_EQ(NumTeamsLowerSelectInst->getCondition(), IfExpr);4986  EXPECT_EQ(NumTeamsLowerSelectInst->getTrueValue(), Builder.getInt32(0));4987  EXPECT_EQ(NumTeamsLowerSelectInst->getFalseValue(), Builder.getInt32(1));4988 4989  // Check the upper_bound4990  ASSERT_NE(NumTeamsUpper, nullptr);4991  SelectInst *NumTeamsUpperSelectInst = dyn_cast<SelectInst>(NumTeamsUpper);4992  ASSERT_NE(NumTeamsUpperSelectInst, nullptr);4993  EXPECT_EQ(NumTeamsUpperSelectInst->getCondition(), IfExpr);4994  EXPECT_EQ(NumTeamsUpperSelectInst->getTrueValue(), Builder.getInt32(0));4995  EXPECT_EQ(NumTeamsUpperSelectInst->getFalseValue(), Builder.getInt32(1));4996 4997  // Check thread_limit4998  EXPECT_EQ(ThreadLimit, Builder.getInt32(0));4999}5000 5001TEST_F(OpenMPIRBuilderTest, CreateTeamsWithIfConditionAndNumTeams) {5002  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;5003  OpenMPIRBuilder OMPBuilder(*M);5004  OMPBuilder.Config.IsTargetDevice = false;5005  OMPBuilder.initialize();5006  F->setName("func");5007  IRBuilder<> &Builder = OMPBuilder.Builder;5008  Builder.SetInsertPoint(BB);5009 5010  Value *IfExpr = Builder.CreateLoad(5011      Builder.getInt32Ty(), Builder.CreateAlloca(Builder.getInt32Ty()));5012  Value *NumTeamsLower = Builder.CreateAdd(F->arg_begin(), Builder.getInt32(5));5013  Value *NumTeamsUpper =5014      Builder.CreateAdd(F->arg_begin(), Builder.getInt32(10));5015  Value *ThreadLimit = Builder.CreateAdd(F->arg_begin(), Builder.getInt32(20));5016 5017  Function *FakeFunction =5018      Function::Create(FunctionType::get(Builder.getVoidTy(), false),5019                       GlobalValue::ExternalLinkage, "fakeFunction", M.get());5020 5021  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {5022    Builder.restoreIP(CodeGenIP);5023    Builder.CreateCall(FakeFunction, {});5024    return Error::success();5025  };5026 5027  // `F` already has an integer argument, so we use that as upper bound to5028  // `num_teams`5029  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,5030                       OMPBuilder.createTeams(Builder, BodyGenCB, NumTeamsLower,5031                                              NumTeamsUpper, ThreadLimit,5032                                              IfExpr));5033  Builder.restoreIP(AfterIP);5034 5035  Builder.CreateRetVoid();5036  OMPBuilder.finalize();5037 5038  ASSERT_FALSE(verifyModule(*M));5039 5040  CallInst *PushNumTeamsCallInst =5041      findSingleCall(F, OMPRTL___kmpc_push_num_teams_51, OMPBuilder);5042  ASSERT_NE(PushNumTeamsCallInst, nullptr);5043  Value *NumTeamsLowerArg = PushNumTeamsCallInst->getArgOperand(2);5044  Value *NumTeamsUpperArg = PushNumTeamsCallInst->getArgOperand(3);5045  Value *ThreadLimitArg = PushNumTeamsCallInst->getArgOperand(4);5046 5047  // Get the boolean conversion of if expression5048  ASSERT_TRUE(IfExpr->hasOneUse());5049  User *IfExprInst = IfExpr->user_back();5050  ICmpInst *IfExprCmpInst = dyn_cast<ICmpInst>(IfExprInst);5051  ASSERT_NE(IfExprCmpInst, nullptr);5052  EXPECT_EQ(IfExprCmpInst->getPredicate(), ICmpInst::Predicate::ICMP_NE);5053  EXPECT_EQ(IfExprCmpInst->getOperand(0), IfExpr);5054  EXPECT_EQ(IfExprCmpInst->getOperand(1), Builder.getInt32(0));5055 5056  // Check the lower_bound5057  ASSERT_NE(NumTeamsLowerArg, nullptr);5058  SelectInst *NumTeamsLowerSelectInst = dyn_cast<SelectInst>(NumTeamsLowerArg);5059  ASSERT_NE(NumTeamsLowerSelectInst, nullptr);5060  EXPECT_EQ(NumTeamsLowerSelectInst->getCondition(), IfExprCmpInst);5061  EXPECT_EQ(NumTeamsLowerSelectInst->getTrueValue(), NumTeamsLower);5062  EXPECT_EQ(NumTeamsLowerSelectInst->getFalseValue(), Builder.getInt32(1));5063 5064  // Check the upper_bound5065  ASSERT_NE(NumTeamsUpperArg, nullptr);5066  SelectInst *NumTeamsUpperSelectInst = dyn_cast<SelectInst>(NumTeamsUpperArg);5067  ASSERT_NE(NumTeamsUpperSelectInst, nullptr);5068  EXPECT_EQ(NumTeamsUpperSelectInst->getCondition(), IfExprCmpInst);5069  EXPECT_EQ(NumTeamsUpperSelectInst->getTrueValue(), NumTeamsUpper);5070  EXPECT_EQ(NumTeamsUpperSelectInst->getFalseValue(), Builder.getInt32(1));5071 5072  // Check thread_limit5073  EXPECT_EQ(ThreadLimitArg, ThreadLimit);5074}5075 5076/// Returns the single instruction of InstTy type in BB that uses the value V.5077/// If there is more than one such instruction, returns null.5078template <typename InstTy>5079static InstTy *findSingleUserInBlock(Value *V, BasicBlock *BB) {5080  InstTy *Result = nullptr;5081  for (User *U : V->users()) {5082    auto *Inst = dyn_cast<InstTy>(U);5083    if (!Inst || Inst->getParent() != BB)5084      continue;5085    if (Result) {5086      if (auto *SI = dyn_cast<StoreInst>(Inst)) {5087        if (V == SI->getValueOperand())5088          continue;5089      } else {5090        return nullptr;5091      }5092    }5093    Result = Inst;5094  }5095  return Result;5096}5097 5098/// Returns true if BB contains a simple binary reduction that loads a value5099/// from Accum, performs some binary operation with it, and stores it back to5100/// Accum.5101static bool isSimpleBinaryReduction(Value *Accum, BasicBlock *BB,5102                                    Instruction::BinaryOps *OpCode = nullptr) {5103  StoreInst *Store = findSingleUserInBlock<StoreInst>(Accum, BB);5104  if (!Store)5105    return false;5106  auto *Stored = dyn_cast<BinaryOperator>(Store->getOperand(0));5107  if (!Stored)5108    return false;5109  if (OpCode && *OpCode != Stored->getOpcode())5110    return false;5111  auto *Load = dyn_cast<LoadInst>(Stored->getOperand(0));5112  return Load && Load->getOperand(0) == Accum;5113}5114 5115/// Returns true if BB contains a binary reduction that reduces V using a binary5116/// operator into an accumulator that is a function argument.5117static bool isValueReducedToFuncArg(Value *V, BasicBlock *BB) {5118  auto *ReductionOp = findSingleUserInBlock<BinaryOperator>(V, BB);5119  if (!ReductionOp)5120    return false;5121 5122  auto *GlobalLoad = dyn_cast<LoadInst>(ReductionOp->getOperand(0));5123  if (!GlobalLoad)5124    return false;5125 5126  auto *Store = findSingleUserInBlock<StoreInst>(ReductionOp, BB);5127  if (!Store)5128    return false;5129 5130  return Store->getPointerOperand() == GlobalLoad->getPointerOperand() &&5131         isa<Argument>(findAggregateFromValue(GlobalLoad->getPointerOperand()));5132}5133 5134/// Finds among users of Ptr a pair of GEP instructions with indices [0, 0] and5135/// [0, 1], respectively, and assigns results of these instructions to Zero and5136/// One. Returns true on success, false on failure or if such instructions are5137/// not unique among the users of Ptr.5138static bool findGEPZeroOne(Value *Ptr, Value *&Zero, Value *&One) {5139  Zero = nullptr;5140  One = nullptr;5141  for (User *U : Ptr->users()) {5142    if (auto *GEP = dyn_cast<GetElementPtrInst>(U)) {5143      if (GEP->getNumIndices() != 2)5144        continue;5145      auto *FirstIdx = dyn_cast<ConstantInt>(GEP->getOperand(1));5146      auto *SecondIdx = dyn_cast<ConstantInt>(GEP->getOperand(2));5147      EXPECT_NE(FirstIdx, nullptr);5148      EXPECT_NE(SecondIdx, nullptr);5149 5150      EXPECT_TRUE(FirstIdx->isZero());5151      if (SecondIdx->isZero()) {5152        if (Zero)5153          return false;5154        Zero = GEP;5155      } else if (SecondIdx->isOne()) {5156        if (One)5157          return false;5158        One = GEP;5159      } else {5160        return false;5161      }5162    }5163  }5164  return Zero != nullptr && One != nullptr;5165}5166 5167static OpenMPIRBuilder::InsertPointTy5168sumReduction(OpenMPIRBuilder::InsertPointTy IP, Value *LHS, Value *RHS,5169             Value *&Result) {5170  IRBuilder<> Builder(IP.getBlock(), IP.getPoint());5171  Result = Builder.CreateFAdd(LHS, RHS, "red.add");5172  return Builder.saveIP();5173}5174 5175static OpenMPIRBuilder::InsertPointTy5176sumAtomicReduction(OpenMPIRBuilder::InsertPointTy IP, Type *Ty, Value *LHS,5177                   Value *RHS) {5178  IRBuilder<> Builder(IP.getBlock(), IP.getPoint());5179  Value *Partial = Builder.CreateLoad(Ty, RHS, "red.partial");5180  Builder.CreateAtomicRMW(AtomicRMWInst::FAdd, LHS, Partial, std::nullopt,5181                          AtomicOrdering::Monotonic);5182  return Builder.saveIP();5183}5184 5185static OpenMPIRBuilder::InsertPointTy5186xorReduction(OpenMPIRBuilder::InsertPointTy IP, Value *LHS, Value *RHS,5187             Value *&Result) {5188  IRBuilder<> Builder(IP.getBlock(), IP.getPoint());5189  Result = Builder.CreateXor(LHS, RHS, "red.xor");5190  return Builder.saveIP();5191}5192 5193static OpenMPIRBuilder::InsertPointTy5194xorAtomicReduction(OpenMPIRBuilder::InsertPointTy IP, Type *Ty, Value *LHS,5195                   Value *RHS) {5196  IRBuilder<> Builder(IP.getBlock(), IP.getPoint());5197  Value *Partial = Builder.CreateLoad(Ty, RHS, "red.partial");5198  Builder.CreateAtomicRMW(AtomicRMWInst::Xor, LHS, Partial, std::nullopt,5199                          AtomicOrdering::Monotonic);5200  return Builder.saveIP();5201}5202 5203TEST_F(OpenMPIRBuilderTest, CreateReductions) {5204  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;5205  OpenMPIRBuilder OMPBuilder(*M);5206  OMPBuilder.Config.IsTargetDevice = false;5207  OMPBuilder.initialize();5208  F->setName("func");5209  IRBuilder<> Builder(BB);5210 5211  BasicBlock *EnterBB = BasicBlock::Create(Ctx, "parallel.enter", F);5212  Builder.CreateBr(EnterBB);5213  Builder.SetInsertPoint(EnterBB);5214  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});5215 5216  // Create variables to be reduced.5217  InsertPointTy OuterAllocaIP(&F->getEntryBlock(),5218                              F->getEntryBlock().getFirstInsertionPt());5219  Type *SumType = Builder.getFloatTy();5220  Type *XorType = Builder.getInt32Ty();5221  Value *SumReduced;5222  Value *XorReduced;5223  {5224    IRBuilderBase::InsertPointGuard Guard(Builder);5225    Builder.restoreIP(OuterAllocaIP);5226    SumReduced = Builder.CreateAlloca(SumType);5227    XorReduced = Builder.CreateAlloca(XorType);5228  }5229 5230  // Store initial values of reductions into global variables.5231  Builder.CreateStore(ConstantFP::get(Builder.getFloatTy(), 0.0), SumReduced);5232  Builder.CreateStore(Builder.getInt32(1), XorReduced);5233 5234  // The loop body computes two reductions:5235  //   sum of (float) thread-id;5236  //   xor of thread-id;5237  // and store the result in global variables.5238  InsertPointTy BodyIP, BodyAllocaIP;5239  auto BodyGenCB = [&](InsertPointTy InnerAllocaIP, InsertPointTy CodeGenIP) {5240    IRBuilderBase::InsertPointGuard Guard(Builder);5241    Builder.restoreIP(CodeGenIP);5242 5243    uint32_t StrSize;5244    Constant *SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(Loc, StrSize);5245    Value *Ident = OMPBuilder.getOrCreateIdent(SrcLocStr, StrSize);5246    Value *TID = OMPBuilder.getOrCreateThreadID(Ident);5247    Value *SumLocal =5248        Builder.CreateUIToFP(TID, Builder.getFloatTy(), "sum.local");5249    Value *SumPartial = Builder.CreateLoad(SumType, SumReduced, "sum.partial");5250    Value *XorPartial = Builder.CreateLoad(XorType, XorReduced, "xor.partial");5251    Value *Sum = Builder.CreateFAdd(SumPartial, SumLocal, "sum");5252    Value *Xor = Builder.CreateXor(XorPartial, TID, "xor");5253    Builder.CreateStore(Sum, SumReduced);5254    Builder.CreateStore(Xor, XorReduced);5255 5256    BodyIP = Builder.saveIP();5257    BodyAllocaIP = InnerAllocaIP;5258    return Error::success();5259  };5260 5261  // Privatization for reduction creates local copies of reduction variables and5262  // initializes them to reduction-neutral values.5263  Value *SumPrivatized;5264  Value *XorPrivatized;5265  auto PrivCB = [&](InsertPointTy InnerAllocaIP, InsertPointTy CodeGenIP,5266                    Value &Original, Value &Inner, Value *&ReplVal) {5267    IRBuilderBase::InsertPointGuard Guard(Builder);5268    Builder.restoreIP(InnerAllocaIP);5269    if (&Original == SumReduced) {5270      SumPrivatized = Builder.CreateAlloca(Builder.getFloatTy());5271      ReplVal = SumPrivatized;5272    } else if (&Original == XorReduced) {5273      XorPrivatized = Builder.CreateAlloca(Builder.getInt32Ty());5274      ReplVal = XorPrivatized;5275    } else {5276      ReplVal = &Inner;5277      return CodeGenIP;5278    }5279 5280    Builder.restoreIP(CodeGenIP);5281    if (&Original == SumReduced)5282      Builder.CreateStore(ConstantFP::get(Builder.getFloatTy(), 0.0),5283                          SumPrivatized);5284    else if (&Original == XorReduced)5285      Builder.CreateStore(Builder.getInt32(0), XorPrivatized);5286 5287    return Builder.saveIP();5288  };5289 5290  // Do nothing in finalization.5291  auto FiniCB = [&](InsertPointTy CodeGenIP) { return Error::success(); };5292 5293  ASSERT_EXPECTED_INIT(5294      OpenMPIRBuilder::InsertPointTy, AfterIP,5295      OMPBuilder.createParallel(Loc, OuterAllocaIP, BodyGenCB, PrivCB, FiniCB,5296                                /* IfCondition */ nullptr,5297                                /* NumThreads */ nullptr, OMP_PROC_BIND_default,5298                                /* IsCancellable */ false));5299  Builder.restoreIP(AfterIP);5300 5301  OpenMPIRBuilder::ReductionInfo ReductionInfos[] = {5302      {SumType, SumReduced, SumPrivatized,5303       /*EvaluationKind=*/OpenMPIRBuilder::EvalKind::Scalar, sumReduction,5304       /*ReductionGenClang=*/nullptr, sumAtomicReduction,5305       /*DataPtrPtrGen=*/nullptr},5306      {XorType, XorReduced, XorPrivatized,5307       /*EvaluationKind=*/OpenMPIRBuilder::EvalKind::Scalar, xorReduction,5308       /*ReductionGenClang=*/nullptr, xorAtomicReduction,5309       /*DataPtrPtrGen=*/nullptr}};5310  OMPBuilder.Config.setIsGPU(false);5311 5312  bool ReduceVariableByRef[] = {false, false};5313  ASSERT_THAT_EXPECTED(OMPBuilder.createReductions(BodyIP, BodyAllocaIP,5314                                                   ReductionInfos,5315                                                   ReduceVariableByRef),5316                       Succeeded());5317 5318  Builder.restoreIP(AfterIP);5319  Builder.CreateRetVoid();5320 5321  OMPBuilder.finalize(F);5322 5323  // The IR must be valid.5324  EXPECT_FALSE(verifyModule(*M));5325 5326  // Outlining must have happened.5327  SmallVector<CallInst *> ForkCalls;5328  findCalls(F, omp::RuntimeFunction::OMPRTL___kmpc_fork_call, OMPBuilder,5329            ForkCalls);5330  ASSERT_EQ(ForkCalls.size(), 1u);5331  Value *CalleeVal = ForkCalls[0]->getOperand(2);5332  Function *Outlined = dyn_cast<Function>(CalleeVal);5333  EXPECT_NE(Outlined, nullptr);5334 5335  // Check that the lock variable was created with the expected name.5336  GlobalVariable *LockVar =5337      M->getGlobalVariable(".gomp_critical_user_.reduction.var");5338  EXPECT_NE(LockVar, nullptr);5339 5340  // Find the allocation of a local array that will be used to call the runtime5341  // reduciton function.5342  BasicBlock &AllocBlock = Outlined->getEntryBlock();5343  Value *LocalArray = nullptr;5344  for (Instruction &I : AllocBlock) {5345    if (AllocaInst *Alloc = dyn_cast<AllocaInst>(&I)) {5346      if (!Alloc->getAllocatedType()->isArrayTy() ||5347          !Alloc->getAllocatedType()->getArrayElementType()->isPointerTy())5348        continue;5349      LocalArray = Alloc;5350      break;5351    }5352  }5353  ASSERT_NE(LocalArray, nullptr);5354 5355  // Find the call to the runtime reduction function.5356  BasicBlock *BB = AllocBlock.getUniqueSuccessor();5357  Value *LocalArrayPtr = nullptr;5358  Value *ReductionFnVal = nullptr;5359  Value *SwitchArg = nullptr;5360  for (Instruction &I : *BB) {5361    if (CallInst *Call = dyn_cast<CallInst>(&I)) {5362      if (Call->getCalledFunction() !=5363          OMPBuilder.getOrCreateRuntimeFunctionPtr(5364              RuntimeFunction::OMPRTL___kmpc_reduce))5365        continue;5366      LocalArrayPtr = Call->getOperand(4);5367      ReductionFnVal = Call->getOperand(5);5368      SwitchArg = Call;5369      break;5370    }5371  }5372 5373  // Check that the local array is passed to the function.5374  ASSERT_NE(LocalArrayPtr, nullptr);5375  EXPECT_EQ(LocalArrayPtr, LocalArray);5376 5377  // Find the GEP instructions preceding stores to the local array.5378  Value *FirstArrayElemPtr = nullptr;5379  Value *SecondArrayElemPtr = nullptr;5380  EXPECT_TRUE(LocalArray->hasNUses(3));5381  ASSERT_TRUE(5382      findGEPZeroOne(LocalArray, FirstArrayElemPtr, SecondArrayElemPtr));5383 5384  // Check that the values stored into the local array are privatized reduction5385  // variables.5386  auto *FirstPrivatized = dyn_cast_or_null<AllocaInst>(5387      findStoredValue<GetElementPtrInst>(FirstArrayElemPtr));5388  auto *SecondPrivatized = dyn_cast_or_null<AllocaInst>(5389      findStoredValue<GetElementPtrInst>(SecondArrayElemPtr));5390  ASSERT_NE(FirstPrivatized, nullptr);5391  ASSERT_NE(SecondPrivatized, nullptr);5392  ASSERT_TRUE(isa<Instruction>(FirstArrayElemPtr));5393  EXPECT_TRUE(isSimpleBinaryReduction(5394      FirstPrivatized, cast<Instruction>(FirstArrayElemPtr)->getParent()));5395  EXPECT_TRUE(isSimpleBinaryReduction(5396      SecondPrivatized, cast<Instruction>(FirstArrayElemPtr)->getParent()));5397 5398  // Check that the result of the runtime reduction call is used for further5399  // dispatch.5400  ASSERT_TRUE(SwitchArg->hasOneUse());5401  SwitchInst *Switch = dyn_cast<SwitchInst>(*SwitchArg->user_begin());5402  ASSERT_NE(Switch, nullptr);5403  EXPECT_EQ(Switch->getNumSuccessors(), 3u);5404  BasicBlock *NonAtomicBB = Switch->case_begin()->getCaseSuccessor();5405  BasicBlock *AtomicBB = std::next(Switch->case_begin())->getCaseSuccessor();5406 5407  // Non-atomic block contains reductions to the global reduction variable,5408  // which is passed into the outlined function as an argument.5409  Value *FirstLoad =5410      findSingleUserInBlock<LoadInst>(FirstPrivatized, NonAtomicBB);5411  Value *SecondLoad =5412      findSingleUserInBlock<LoadInst>(SecondPrivatized, NonAtomicBB);5413  EXPECT_TRUE(isValueReducedToFuncArg(FirstLoad, NonAtomicBB));5414  EXPECT_TRUE(isValueReducedToFuncArg(SecondLoad, NonAtomicBB));5415 5416  // Atomic block also constains reductions to the global reduction variable.5417  FirstLoad = findSingleUserInBlock<LoadInst>(FirstPrivatized, AtomicBB);5418  SecondLoad = findSingleUserInBlock<LoadInst>(SecondPrivatized, AtomicBB);5419  auto *FirstAtomic = findSingleUserInBlock<AtomicRMWInst>(FirstLoad, AtomicBB);5420  auto *SecondAtomic =5421      findSingleUserInBlock<AtomicRMWInst>(SecondLoad, AtomicBB);5422  ASSERT_NE(FirstAtomic, nullptr);5423  Value *AtomicStorePointer = FirstAtomic->getPointerOperand();5424  EXPECT_TRUE(isa<Argument>(findAggregateFromValue(AtomicStorePointer)));5425  ASSERT_NE(SecondAtomic, nullptr);5426  AtomicStorePointer = SecondAtomic->getPointerOperand();5427  EXPECT_TRUE(isa<Argument>(findAggregateFromValue(AtomicStorePointer)));5428 5429  // Check that the separate reduction function also performs (non-atomic)5430  // reductions after extracting reduction variables from its arguments.5431  Function *ReductionFn = cast<Function>(ReductionFnVal);5432  BasicBlock *FnReductionBB = &ReductionFn->getEntryBlock();5433  Value *FirstLHSPtr;5434  Value *SecondLHSPtr;5435  ASSERT_TRUE(5436      findGEPZeroOne(ReductionFn->getArg(0), FirstLHSPtr, SecondLHSPtr));5437  Value *Opaque = findSingleUserInBlock<LoadInst>(FirstLHSPtr, FnReductionBB);5438  ASSERT_NE(Opaque, nullptr);5439  EXPECT_TRUE(isSimpleBinaryReduction(Opaque, FnReductionBB));5440  Opaque = findSingleUserInBlock<LoadInst>(SecondLHSPtr, FnReductionBB);5441  ASSERT_NE(Opaque, nullptr);5442  EXPECT_TRUE(isSimpleBinaryReduction(Opaque, FnReductionBB));5443 5444  Value *FirstRHS;5445  Value *SecondRHS;5446  EXPECT_TRUE(findGEPZeroOne(ReductionFn->getArg(1), FirstRHS, SecondRHS));5447}5448 5449static void createScan(llvm::Value *scanVar, llvm::Type *scanType,5450                       OpenMPIRBuilder &OMPBuilder, IRBuilder<> &Builder,5451                       OpenMPIRBuilder::LocationDescription Loc,5452                       OpenMPIRBuilder::InsertPointTy &allocaIP,5453                       ScanInfo *&ScanRedInfo) {5454  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;5455  ASSERT_EXPECTED_INIT(InsertPointTy, retIp,5456                       OMPBuilder.createScan(Loc, allocaIP, {scanVar},5457                                             {scanType}, true, ScanRedInfo));5458  Builder.restoreIP(retIp);5459}5460/*5461 Following is the pseudocode of the code generated by the test case5462 <declare pointer to buffer> ptr5463  size num_iters = 1005464  // temp buffer allocation5465  omp masked {5466    buff = malloc(num_iters*scanvarstype)5467    *ptr = buff5468  }5469 barrier;5470  // input phase loop5471  for (i: 0..<num_iters>) {5472    <input phase>;5473    buffer = *ptr;5474    buffer[i] = red;5475  }5476  // scan reduction5477  omp masked5478  {5479    for (int k = 0; k != ceil(log2(num_iters)); ++k) {5480      i=pow(2,k)5481      for (size cnt = last_iter; cnt >= i; --cnt) {5482        buffer = *ptr;5483        buffer[cnt] op= buffer[cnt-i];5484      }5485    }5486  }5487 barrier;5488 // scan phase loop5489  for (0..<num_iters>) {5490    buffer = *ptr;5491    red = buffer[i] ;5492    <scan phase>;5493  }5494  // temp buffer deletion5495  omp masked {5496    free(*ptr)5497  }5498  barrier;5499*/5500TEST_F(OpenMPIRBuilderTest, ScanReduction) {5501  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;5502  OpenMPIRBuilder OMPBuilder(*M);5503  OMPBuilder.initialize();5504  IRBuilder<> Builder(BB);5505  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});5506  Value *TripCount = F->getArg(0);5507  Type *LCTy = TripCount->getType();5508  Value *StartVal = ConstantInt::get(LCTy, 1);5509  Value *StopVal = ConstantInt::get(LCTy, 100);5510  Value *Step = ConstantInt::get(LCTy, 1);5511  auto AllocaIP = Builder.saveIP();5512 5513  llvm::Value *ScanVar = Builder.CreateAlloca(Builder.getFloatTy());5514  llvm::Value *OrigVar = Builder.CreateAlloca(Builder.getFloatTy());5515  unsigned NumBodiesGenerated = 0;5516  ScanInfo *ScanRedInfo;5517  ASSERT_EXPECTED_INIT(ScanInfo *, ScanInformation,5518                       OMPBuilder.scanInfoInitialize());5519  ScanRedInfo = ScanInformation;5520  auto LoopBodyGenCB = [&](InsertPointTy CodeGenIP, llvm::Value *LC) {5521    NumBodiesGenerated += 1;5522    Builder.restoreIP(CodeGenIP);5523    createScan(ScanVar, Builder.getFloatTy(), OMPBuilder, Builder, Loc,5524               AllocaIP, ScanRedInfo);5525    return Error::success();5526  };5527  llvm::SmallVector<CanonicalLoopInfo *> loops;5528  ASSERT_EXPECTED_INIT(llvm::SmallVector<CanonicalLoopInfo *>, loopvec,5529                       OMPBuilder.createCanonicalScanLoops(5530                           Loc, LoopBodyGenCB, StartVal, StopVal, Step, false,5531                           false, Builder.saveIP(), "scan", ScanRedInfo));5532  loops = loopvec;5533  CanonicalLoopInfo *InputLoop = loops.front();5534  CanonicalLoopInfo *ScanLoop = loops.back();5535  Builder.restoreIP(ScanLoop->getAfterIP());5536  InputLoop->assertOK();5537  ScanLoop->assertOK();5538 5539  EXPECT_EQ(ScanLoop->getAfter(), Builder.GetInsertBlock());5540  EXPECT_EQ(NumBodiesGenerated, 2U);5541  SmallVector<OpenMPIRBuilder::ReductionInfo, 2> ReductionInfos = {5542      {Builder.getFloatTy(), OrigVar, ScanVar,5543       /*EvaluationKind=*/OpenMPIRBuilder::EvalKind::Scalar, sumReduction,5544       /*ReductionGenClang=*/nullptr, sumAtomicReduction,5545       /*DataPtrPtrGen=*/nullptr}};5546  OpenMPIRBuilder::LocationDescription RedLoc({InputLoop->getAfterIP(), DL});5547  llvm::BasicBlock *Cont = splitBB(Builder, false, "omp.scan.loop.cont");5548  ASSERT_EXPECTED_INIT(5549      InsertPointTy, retIp,5550      OMPBuilder.emitScanReduction(RedLoc, ReductionInfos, ScanRedInfo));5551  Builder.restoreIP(retIp);5552  Builder.CreateBr(Cont);5553  Builder.SetInsertPoint(Cont);5554  unsigned NumMallocs = 0;5555  unsigned NumFrees = 0;5556  unsigned NumMasked = 0;5557  unsigned NumEndMasked = 0;5558  unsigned NumLog = 0;5559  unsigned NumCeil = 0;5560  for (Instruction &I : instructions(F)) {5561    if (!isa<CallInst>(I))5562      continue;5563    CallInst *Call = dyn_cast<CallInst>(&I);5564    StringRef Name = Call->getCalledFunction()->getName();5565    if (Name.equals_insensitive("malloc")) {5566      NumMallocs += 1;5567    } else if (Name.equals_insensitive("free")) {5568      NumFrees += 1;5569    } else if (Name.equals_insensitive("__kmpc_masked")) {5570      NumMasked += 1;5571    } else if (Name.equals_insensitive("__kmpc_end_masked")) {5572      NumEndMasked += 1;5573    } else if (Name.equals_insensitive("llvm.log2.f64")) {5574      NumLog += 1;5575    } else if (Name.equals_insensitive("llvm.ceil.f64")) {5576      NumCeil += 1;5577    }5578  }5579  EXPECT_EQ(NumBodiesGenerated, 2U);5580  EXPECT_EQ(NumMasked, 3U);5581  EXPECT_EQ(NumEndMasked, 3U);5582  EXPECT_EQ(NumMallocs, 1U);5583  EXPECT_EQ(NumFrees, 1U);5584  EXPECT_EQ(NumLog, 1U);5585  EXPECT_EQ(NumCeil, 1U);5586}5587 5588TEST_F(OpenMPIRBuilderTest, CreateTwoReductions) {5589  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;5590  OpenMPIRBuilder OMPBuilder(*M);5591  OMPBuilder.Config.IsTargetDevice = false;5592  OMPBuilder.initialize();5593  F->setName("func");5594  IRBuilder<> Builder(BB);5595 5596  BasicBlock *EnterBB = BasicBlock::Create(Ctx, "parallel.enter", F);5597  Builder.CreateBr(EnterBB);5598  Builder.SetInsertPoint(EnterBB);5599  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});5600 5601  // Create variables to be reduced.5602  InsertPointTy OuterAllocaIP(&F->getEntryBlock(),5603                              F->getEntryBlock().getFirstInsertionPt());5604  Type *SumType = Builder.getFloatTy();5605  Type *XorType = Builder.getInt32Ty();5606  Value *SumReduced;5607  Value *XorReduced;5608  {5609    IRBuilderBase::InsertPointGuard Guard(Builder);5610    Builder.restoreIP(OuterAllocaIP);5611    SumReduced = Builder.CreateAlloca(SumType);5612    XorReduced = Builder.CreateAlloca(XorType);5613  }5614 5615  // Store initial values of reductions into global variables.5616  Builder.CreateStore(ConstantFP::get(Builder.getFloatTy(), 0.0), SumReduced);5617  Builder.CreateStore(Builder.getInt32(1), XorReduced);5618 5619  InsertPointTy FirstBodyIP, FirstBodyAllocaIP;5620  auto FirstBodyGenCB = [&](InsertPointTy InnerAllocaIP,5621                            InsertPointTy CodeGenIP) {5622    IRBuilderBase::InsertPointGuard Guard(Builder);5623    Builder.restoreIP(CodeGenIP);5624 5625    uint32_t StrSize;5626    Constant *SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(Loc, StrSize);5627    Value *Ident = OMPBuilder.getOrCreateIdent(SrcLocStr, StrSize);5628    Value *TID = OMPBuilder.getOrCreateThreadID(Ident);5629    Value *SumLocal =5630        Builder.CreateUIToFP(TID, Builder.getFloatTy(), "sum.local");5631    Value *SumPartial = Builder.CreateLoad(SumType, SumReduced, "sum.partial");5632    Value *Sum = Builder.CreateFAdd(SumPartial, SumLocal, "sum");5633    Builder.CreateStore(Sum, SumReduced);5634 5635    FirstBodyIP = Builder.saveIP();5636    FirstBodyAllocaIP = InnerAllocaIP;5637    return Error::success();5638  };5639 5640  InsertPointTy SecondBodyIP, SecondBodyAllocaIP;5641  auto SecondBodyGenCB = [&](InsertPointTy InnerAllocaIP,5642                             InsertPointTy CodeGenIP) {5643    IRBuilderBase::InsertPointGuard Guard(Builder);5644    Builder.restoreIP(CodeGenIP);5645 5646    uint32_t StrSize;5647    Constant *SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(Loc, StrSize);5648    Value *Ident = OMPBuilder.getOrCreateIdent(SrcLocStr, StrSize);5649    Value *TID = OMPBuilder.getOrCreateThreadID(Ident);5650    Value *XorPartial = Builder.CreateLoad(XorType, XorReduced, "xor.partial");5651    Value *Xor = Builder.CreateXor(XorPartial, TID, "xor");5652    Builder.CreateStore(Xor, XorReduced);5653 5654    SecondBodyIP = Builder.saveIP();5655    SecondBodyAllocaIP = InnerAllocaIP;5656    return Error::success();5657  };5658 5659  // Privatization for reduction creates local copies of reduction variables and5660  // initializes them to reduction-neutral values. The same privatization5661  // callback is used for both loops, with dispatch based on the value being5662  // privatized.5663  Value *SumPrivatized;5664  Value *XorPrivatized;5665  auto PrivCB = [&](InsertPointTy InnerAllocaIP, InsertPointTy CodeGenIP,5666                    Value &Original, Value &Inner, Value *&ReplVal) {5667    IRBuilderBase::InsertPointGuard Guard(Builder);5668    Builder.restoreIP(InnerAllocaIP);5669    if (&Original == SumReduced) {5670      SumPrivatized = Builder.CreateAlloca(Builder.getFloatTy());5671      ReplVal = SumPrivatized;5672    } else if (&Original == XorReduced) {5673      XorPrivatized = Builder.CreateAlloca(Builder.getInt32Ty());5674      ReplVal = XorPrivatized;5675    } else {5676      ReplVal = &Inner;5677      return CodeGenIP;5678    }5679 5680    Builder.restoreIP(CodeGenIP);5681    if (&Original == SumReduced)5682      Builder.CreateStore(ConstantFP::get(Builder.getFloatTy(), 0.0),5683                          SumPrivatized);5684    else if (&Original == XorReduced)5685      Builder.CreateStore(Builder.getInt32(0), XorPrivatized);5686 5687    return Builder.saveIP();5688  };5689 5690  // Do nothing in finalization.5691  auto FiniCB = [&](InsertPointTy CodeGenIP) { return Error::success(); };5692 5693  ASSERT_EXPECTED_INIT(5694      OpenMPIRBuilder::InsertPointTy, AfterIP1,5695      OMPBuilder.createParallel(Loc, OuterAllocaIP, FirstBodyGenCB, PrivCB,5696                                FiniCB, /* IfCondition */ nullptr,5697                                /* NumThreads */ nullptr, OMP_PROC_BIND_default,5698                                /* IsCancellable */ false));5699  Builder.restoreIP(AfterIP1);5700  ASSERT_EXPECTED_INIT(5701      OpenMPIRBuilder::InsertPointTy, AfterIP2,5702      OMPBuilder.createParallel({Builder.saveIP(), DL}, OuterAllocaIP,5703                                SecondBodyGenCB, PrivCB, FiniCB,5704                                /* IfCondition */ nullptr,5705                                /* NumThreads */ nullptr, OMP_PROC_BIND_default,5706                                /* IsCancellable */ false));5707  Builder.restoreIP(AfterIP2);5708 5709  OMPBuilder.Config.setIsGPU(false);5710  bool ReduceVariableByRef[] = {false};5711 5712  ASSERT_THAT_EXPECTED(5713      OMPBuilder.createReductions(5714          FirstBodyIP, FirstBodyAllocaIP,5715          {{SumType, SumReduced, SumPrivatized,5716            /*EvaluationKind=*/OpenMPIRBuilder::EvalKind::Scalar, sumReduction,5717            /*ReductionGenClang=*/nullptr, sumAtomicReduction,5718            /*DataPtrPtrGen=*/nullptr}},5719          ReduceVariableByRef),5720      Succeeded());5721  ASSERT_THAT_EXPECTED(5722      OMPBuilder.createReductions(5723          SecondBodyIP, SecondBodyAllocaIP,5724          {{XorType, XorReduced, XorPrivatized,5725            /*EvaluationKind=*/OpenMPIRBuilder::EvalKind::Scalar, xorReduction,5726            /*ReductionGenClang=*/nullptr, xorAtomicReduction,5727            /*DataPtrPtrGen=*/nullptr}},5728          ReduceVariableByRef),5729      Succeeded());5730 5731  Builder.restoreIP(AfterIP2);5732  Builder.CreateRetVoid();5733 5734  OMPBuilder.finalize(F);5735 5736  // The IR must be valid.5737  EXPECT_FALSE(verifyModule(*M));5738 5739  // Two different outlined functions must have been created.5740  SmallVector<CallInst *> ForkCalls;5741  findCalls(F, omp::RuntimeFunction::OMPRTL___kmpc_fork_call, OMPBuilder,5742            ForkCalls);5743  ASSERT_EQ(ForkCalls.size(), 2u);5744  Value *CalleeVal = ForkCalls[0]->getOperand(2);5745  Function *FirstCallee = cast<Function>(CalleeVal);5746  CalleeVal = ForkCalls[1]->getOperand(2);5747  Function *SecondCallee = cast<Function>(CalleeVal);5748  EXPECT_NE(FirstCallee, SecondCallee);5749 5750  // Two different reduction functions must have been created.5751  SmallVector<CallInst *> ReduceCalls;5752  findCalls(FirstCallee, omp::RuntimeFunction::OMPRTL___kmpc_reduce, OMPBuilder,5753            ReduceCalls);5754  ASSERT_EQ(ReduceCalls.size(), 1u);5755  auto *AddReduction = cast<Function>(ReduceCalls[0]->getOperand(5));5756  ReduceCalls.clear();5757  findCalls(SecondCallee, omp::RuntimeFunction::OMPRTL___kmpc_reduce,5758            OMPBuilder, ReduceCalls);5759  auto *XorReduction = cast<Function>(ReduceCalls[0]->getOperand(5));5760  EXPECT_NE(AddReduction, XorReduction);5761 5762  // Each reduction function does its own kind of reduction.5763  BasicBlock *FnReductionBB = &AddReduction->getEntryBlock();5764  Value *FirstLHSPtr = findSingleUserInBlock<GetElementPtrInst>(5765      AddReduction->getArg(0), FnReductionBB);5766  ASSERT_NE(FirstLHSPtr, nullptr);5767  Value *Opaque = findSingleUserInBlock<LoadInst>(FirstLHSPtr, FnReductionBB);5768  ASSERT_NE(Opaque, nullptr);5769  Instruction::BinaryOps Opcode = Instruction::FAdd;5770  EXPECT_TRUE(isSimpleBinaryReduction(Opaque, FnReductionBB, &Opcode));5771 5772  FnReductionBB = &XorReduction->getEntryBlock();5773  Value *SecondLHSPtr = findSingleUserInBlock<GetElementPtrInst>(5774      XorReduction->getArg(0), FnReductionBB);5775  ASSERT_NE(FirstLHSPtr, nullptr);5776  Opaque = findSingleUserInBlock<LoadInst>(SecondLHSPtr, FnReductionBB);5777  ASSERT_NE(Opaque, nullptr);5778  Opcode = Instruction::Xor;5779  EXPECT_TRUE(isSimpleBinaryReduction(Opaque, FnReductionBB, &Opcode));5780}5781 5782TEST_F(OpenMPIRBuilderTest, CreateSectionsSimple) {5783  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;5784  using BodyGenCallbackTy = llvm::OpenMPIRBuilder::StorableBodyGenCallbackTy;5785  OpenMPIRBuilder OMPBuilder(*M);5786  OMPBuilder.initialize();5787  F->setName("func");5788  IRBuilder<> Builder(BB);5789 5790  BasicBlock *EnterBB = BasicBlock::Create(Ctx, "sections.enter", F);5791  Builder.CreateBr(EnterBB);5792  Builder.SetInsertPoint(EnterBB);5793  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});5794 5795  llvm::SmallVector<BodyGenCallbackTy, 4> SectionCBVector;5796 5797  auto FiniCB = [&](InsertPointTy IP) { return Error::success(); };5798  auto SectionCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {5799    return Error::success();5800  };5801  SectionCBVector.push_back(SectionCB);5802 5803  auto PrivCB = [](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,5804                   llvm::Value &, llvm::Value &Val,5805                   llvm::Value *&ReplVal) { return CodeGenIP; };5806  IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(),5807                                    F->getEntryBlock().getFirstInsertionPt());5808  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,5809                       OMPBuilder.createSections(Loc, AllocaIP, SectionCBVector,5810                                                 PrivCB, FiniCB, false, false));5811  Builder.restoreIP(AfterIP);5812  Builder.CreateRetVoid(); // Required at the end of the function5813  EXPECT_NE(F->getEntryBlock().getTerminator(), nullptr);5814  EXPECT_FALSE(verifyModule(*M, &errs()));5815}5816 5817TEST_F(OpenMPIRBuilderTest, CreateSections) {5818  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;5819  using BodyGenCallbackTy = llvm::OpenMPIRBuilder::StorableBodyGenCallbackTy;5820  OpenMPIRBuilder OMPBuilder(*M);5821  OMPBuilder.initialize();5822  F->setName("func");5823  IRBuilder<> Builder(BB);5824 5825  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});5826  llvm::SmallVector<BodyGenCallbackTy, 4> SectionCBVector;5827  llvm::SmallVector<BasicBlock *, 4> CaseBBs;5828 5829  BasicBlock *SwitchBB = nullptr;5830  AllocaInst *PrivAI = nullptr;5831  SwitchInst *Switch = nullptr;5832 5833  unsigned NumBodiesGenerated = 0;5834  unsigned NumFiniCBCalls = 0;5835  PrivAI = Builder.CreateAlloca(F->arg_begin()->getType());5836 5837  auto FiniCB = [&](InsertPointTy IP) {5838    ++NumFiniCBCalls;5839    BasicBlock *IPBB = IP.getBlock();5840    EXPECT_NE(IPBB->end(), IP.getPoint());5841  };5842 5843  auto SectionCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {5844    ++NumBodiesGenerated;5845    CaseBBs.push_back(CodeGenIP.getBlock());5846    SwitchBB = CodeGenIP.getBlock()->getSinglePredecessor();5847    Builder.restoreIP(CodeGenIP);5848    Builder.CreateStore(F->arg_begin(), PrivAI);5849    Value *PrivLoad =5850        Builder.CreateLoad(F->arg_begin()->getType(), PrivAI, "local.alloca");5851    Builder.CreateICmpNE(F->arg_begin(), PrivLoad);5852    return Error::success();5853  };5854  auto PrivCB = [](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,5855                   llvm::Value &, llvm::Value &Val, llvm::Value *&ReplVal) {5856    // TODO: Privatization not implemented yet5857    return CodeGenIP;5858  };5859 5860  SectionCBVector.push_back(SectionCB);5861  SectionCBVector.push_back(SectionCB);5862 5863  IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(),5864                                    F->getEntryBlock().getFirstInsertionPt());5865  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,5866                       OMPBuilder.createSections(Loc, AllocaIP, SectionCBVector,5867                                                 PrivCB, FINICB_WRAPPER(FiniCB),5868                                                 false, false));5869  Builder.restoreIP(AfterIP);5870  Builder.CreateRetVoid(); // Required at the end of the function5871 5872  // Switch BB's predecessor is loop condition BB, whose successor at index 1 is5873  // loop's exit BB5874  BasicBlock *ForExitBB =5875      SwitchBB->getSinglePredecessor()->getTerminator()->getSuccessor(1);5876  EXPECT_NE(ForExitBB, nullptr);5877 5878  EXPECT_NE(PrivAI, nullptr);5879  Function *OutlinedFn = PrivAI->getFunction();5880  EXPECT_EQ(F, OutlinedFn);5881  EXPECT_FALSE(verifyModule(*M, &errs()));5882  EXPECT_EQ(OutlinedFn->arg_size(), 1U);5883 5884  BasicBlock *LoopPreheaderBB =5885      OutlinedFn->getEntryBlock().getSingleSuccessor();5886  // loop variables are 5 - lower bound, upper bound, stride, islastiter, and5887  // iterator/counter5888  bool FoundForInit = false;5889  for (Instruction &Inst : *LoopPreheaderBB) {5890    if (isa<CallInst>(Inst)) {5891      if (cast<CallInst>(&Inst)->getCalledFunction()->getName() ==5892          "__kmpc_for_static_init_4u") {5893        FoundForInit = true;5894      }5895    }5896  }5897  EXPECT_EQ(FoundForInit, true);5898 5899  bool FoundForExit = false;5900  bool FoundBarrier = false;5901  for (Instruction &Inst : *ForExitBB) {5902    if (isa<CallInst>(Inst)) {5903      if (cast<CallInst>(&Inst)->getCalledFunction()->getName() ==5904          "__kmpc_for_static_fini") {5905        FoundForExit = true;5906      }5907      if (cast<CallInst>(&Inst)->getCalledFunction()->getName() ==5908          "__kmpc_barrier") {5909        FoundBarrier = true;5910      }5911      if (FoundForExit && FoundBarrier)5912        break;5913    }5914  }5915  EXPECT_EQ(FoundForExit, true);5916  EXPECT_EQ(FoundBarrier, true);5917 5918  EXPECT_NE(SwitchBB, nullptr);5919  EXPECT_NE(SwitchBB->getTerminator(), nullptr);5920  EXPECT_EQ(isa<SwitchInst>(SwitchBB->getTerminator()), true);5921  Switch = cast<SwitchInst>(SwitchBB->getTerminator());5922  EXPECT_EQ(Switch->getNumCases(), 2U);5923 5924  EXPECT_EQ(CaseBBs.size(), 2U);5925  for (auto *&CaseBB : CaseBBs) {5926    EXPECT_EQ(CaseBB->getParent(), OutlinedFn);5927  }5928 5929  ASSERT_EQ(NumBodiesGenerated, 2U);5930  ASSERT_EQ(NumFiniCBCalls, 1U);5931  EXPECT_FALSE(verifyModule(*M, &errs()));5932}5933 5934TEST_F(OpenMPIRBuilderTest, CreateSectionsNoWait) {5935  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;5936  using BodyGenCallbackTy = llvm::OpenMPIRBuilder::StorableBodyGenCallbackTy;5937  OpenMPIRBuilder OMPBuilder(*M);5938  OMPBuilder.initialize();5939  F->setName("func");5940  IRBuilder<> Builder(BB);5941 5942  BasicBlock *EnterBB = BasicBlock::Create(Ctx, "sections.enter", F);5943  Builder.CreateBr(EnterBB);5944  Builder.SetInsertPoint(EnterBB);5945  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});5946 5947  IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(),5948                                    F->getEntryBlock().getFirstInsertionPt());5949  llvm::SmallVector<BodyGenCallbackTy, 4> SectionCBVector;5950  auto PrivCB = [](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,5951                   llvm::Value &, llvm::Value &Val,5952                   llvm::Value *&ReplVal) { return CodeGenIP; };5953  auto FiniCB = [&](InsertPointTy IP) { return Error::success(); };5954 5955  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,5956                       OMPBuilder.createSections(Loc, AllocaIP, SectionCBVector,5957                                                 PrivCB, FiniCB, false, true));5958  Builder.restoreIP(AfterIP);5959  Builder.CreateRetVoid(); // Required at the end of the function5960  for (auto &Inst : instructions(*F)) {5961    EXPECT_FALSE(isa<CallInst>(Inst) &&5962                 cast<CallInst>(&Inst)->getCalledFunction()->getName() ==5963                     "__kmpc_barrier" &&5964                 "call to function __kmpc_barrier found with nowait");5965  }5966}5967 5968TEST_F(OpenMPIRBuilderTest, CreateOffloadMaptypes) {5969  OpenMPIRBuilder OMPBuilder(*M);5970  OMPBuilder.initialize();5971 5972  IRBuilder<> Builder(BB);5973 5974  SmallVector<uint64_t> Mappings = {0, 1};5975  GlobalVariable *OffloadMaptypesGlobal =5976      OMPBuilder.createOffloadMaptypes(Mappings, "offload_maptypes");5977  EXPECT_FALSE(M->global_empty());5978  EXPECT_EQ(OffloadMaptypesGlobal->getName(), "offload_maptypes");5979  EXPECT_TRUE(OffloadMaptypesGlobal->isConstant());5980  EXPECT_TRUE(OffloadMaptypesGlobal->hasGlobalUnnamedAddr());5981  EXPECT_TRUE(OffloadMaptypesGlobal->hasPrivateLinkage());5982  EXPECT_TRUE(OffloadMaptypesGlobal->hasInitializer());5983  Constant *Initializer = OffloadMaptypesGlobal->getInitializer();5984  EXPECT_TRUE(isa<ConstantDataArray>(Initializer));5985  ConstantDataArray *MappingInit = dyn_cast<ConstantDataArray>(Initializer);5986  EXPECT_EQ(MappingInit->getNumElements(), Mappings.size());5987  EXPECT_TRUE(MappingInit->getType()->getElementType()->isIntegerTy(64));5988  Constant *CA = ConstantDataArray::get(Builder.getContext(), Mappings);5989  EXPECT_EQ(MappingInit, CA);5990}5991 5992TEST_F(OpenMPIRBuilderTest, CreateOffloadMapnames) {5993  OpenMPIRBuilder OMPBuilder(*M);5994  OMPBuilder.initialize();5995 5996  IRBuilder<> Builder(BB);5997 5998  uint32_t StrSize;5999  Constant *Cst1 =6000      OMPBuilder.getOrCreateSrcLocStr("array1", "file1", 2, 5, StrSize);6001  Constant *Cst2 =6002      OMPBuilder.getOrCreateSrcLocStr("array2", "file1", 3, 5, StrSize);6003  SmallVector<llvm::Constant *> Names = {Cst1, Cst2};6004 6005  GlobalVariable *OffloadMaptypesGlobal =6006      OMPBuilder.createOffloadMapnames(Names, "offload_mapnames");6007  EXPECT_FALSE(M->global_empty());6008  EXPECT_EQ(OffloadMaptypesGlobal->getName(), "offload_mapnames");6009  EXPECT_TRUE(OffloadMaptypesGlobal->isConstant());6010  EXPECT_FALSE(OffloadMaptypesGlobal->hasGlobalUnnamedAddr());6011  EXPECT_TRUE(OffloadMaptypesGlobal->hasPrivateLinkage());6012  EXPECT_TRUE(OffloadMaptypesGlobal->hasInitializer());6013  Constant *Initializer = OffloadMaptypesGlobal->getInitializer();6014  EXPECT_TRUE(isa<Constant>(Initializer->getOperand(0)->stripPointerCasts()));6015  EXPECT_TRUE(isa<Constant>(Initializer->getOperand(1)->stripPointerCasts()));6016 6017  GlobalVariable *Name1Gbl =6018      cast<GlobalVariable>(Initializer->getOperand(0)->stripPointerCasts());6019  EXPECT_TRUE(isa<ConstantDataArray>(Name1Gbl->getInitializer()));6020  ConstantDataArray *Name1GblCA =6021      dyn_cast<ConstantDataArray>(Name1Gbl->getInitializer());6022  EXPECT_EQ(Name1GblCA->getAsCString(), ";file1;array1;2;5;;");6023 6024  GlobalVariable *Name2Gbl =6025      cast<GlobalVariable>(Initializer->getOperand(1)->stripPointerCasts());6026  EXPECT_TRUE(isa<ConstantDataArray>(Name2Gbl->getInitializer()));6027  ConstantDataArray *Name2GblCA =6028      dyn_cast<ConstantDataArray>(Name2Gbl->getInitializer());6029  EXPECT_EQ(Name2GblCA->getAsCString(), ";file1;array2;3;5;;");6030 6031  EXPECT_TRUE(Initializer->getType()->getArrayElementType()->isPointerTy());6032  EXPECT_EQ(Initializer->getType()->getArrayNumElements(), Names.size());6033}6034 6035TEST_F(OpenMPIRBuilderTest, CreateMapperAllocas) {6036  OpenMPIRBuilder OMPBuilder(*M);6037  OMPBuilder.initialize();6038  F->setName("func");6039  IRBuilder<> Builder(BB);6040 6041  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});6042 6043  unsigned TotalNbOperand = 2;6044 6045  OpenMPIRBuilder::MapperAllocas MapperAllocas;6046  IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(),6047                                    F->getEntryBlock().getFirstInsertionPt());6048  OMPBuilder.createMapperAllocas(Loc, AllocaIP, TotalNbOperand, MapperAllocas);6049  EXPECT_NE(MapperAllocas.ArgsBase, nullptr);6050  EXPECT_NE(MapperAllocas.Args, nullptr);6051  EXPECT_NE(MapperAllocas.ArgSizes, nullptr);6052  EXPECT_TRUE(MapperAllocas.ArgsBase->getAllocatedType()->isArrayTy());6053  ArrayType *ArrType =6054      dyn_cast<ArrayType>(MapperAllocas.ArgsBase->getAllocatedType());6055  EXPECT_EQ(ArrType->getNumElements(), TotalNbOperand);6056  EXPECT_TRUE(MapperAllocas.ArgsBase->getAllocatedType()6057                  ->getArrayElementType()6058                  ->isPointerTy());6059 6060  EXPECT_TRUE(MapperAllocas.Args->getAllocatedType()->isArrayTy());6061  ArrType = dyn_cast<ArrayType>(MapperAllocas.Args->getAllocatedType());6062  EXPECT_EQ(ArrType->getNumElements(), TotalNbOperand);6063  EXPECT_TRUE(MapperAllocas.Args->getAllocatedType()6064                  ->getArrayElementType()6065                  ->isPointerTy());6066 6067  EXPECT_TRUE(MapperAllocas.ArgSizes->getAllocatedType()->isArrayTy());6068  ArrType = dyn_cast<ArrayType>(MapperAllocas.ArgSizes->getAllocatedType());6069  EXPECT_EQ(ArrType->getNumElements(), TotalNbOperand);6070  EXPECT_TRUE(MapperAllocas.ArgSizes->getAllocatedType()6071                  ->getArrayElementType()6072                  ->isIntegerTy(64));6073}6074 6075TEST_F(OpenMPIRBuilderTest, EmitMapperCall) {6076  OpenMPIRBuilder OMPBuilder(*M);6077  OMPBuilder.initialize();6078  F->setName("func");6079  IRBuilder<> Builder(BB);6080  LLVMContext &Ctx = M->getContext();6081 6082  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});6083 6084  unsigned TotalNbOperand = 2;6085 6086  OpenMPIRBuilder::MapperAllocas MapperAllocas;6087  IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(),6088                                    F->getEntryBlock().getFirstInsertionPt());6089  OMPBuilder.createMapperAllocas(Loc, AllocaIP, TotalNbOperand, MapperAllocas);6090 6091  auto *BeginMapperFunc = OMPBuilder.getOrCreateRuntimeFunctionPtr(6092      omp::OMPRTL___tgt_target_data_begin_mapper);6093 6094  SmallVector<uint64_t> Flags = {0, 2};6095 6096  uint32_t StrSize;6097  Constant *SrcLocCst =6098      OMPBuilder.getOrCreateSrcLocStr("", "file1", 2, 5, StrSize);6099  Value *SrcLocInfo = OMPBuilder.getOrCreateIdent(SrcLocCst, StrSize);6100 6101  Constant *Cst1 =6102      OMPBuilder.getOrCreateSrcLocStr("array1", "file1", 2, 5, StrSize);6103  Constant *Cst2 =6104      OMPBuilder.getOrCreateSrcLocStr("array2", "file1", 3, 5, StrSize);6105  SmallVector<llvm::Constant *> Names = {Cst1, Cst2};6106 6107  GlobalVariable *Maptypes =6108      OMPBuilder.createOffloadMaptypes(Flags, ".offload_maptypes");6109  Value *MaptypesArg = Builder.CreateConstInBoundsGEP2_32(6110      ArrayType::get(Type::getInt64Ty(Ctx), TotalNbOperand), Maptypes,6111      /*Idx0=*/0, /*Idx1=*/0);6112 6113  GlobalVariable *Mapnames =6114      OMPBuilder.createOffloadMapnames(Names, ".offload_mapnames");6115  Value *MapnamesArg = Builder.CreateConstInBoundsGEP2_32(6116      ArrayType::get(PointerType::getUnqual(Ctx), TotalNbOperand), Mapnames,6117      /*Idx0=*/0, /*Idx1=*/0);6118 6119  OMPBuilder.emitMapperCall(Builder.saveIP(), BeginMapperFunc, SrcLocInfo,6120                            MaptypesArg, MapnamesArg, MapperAllocas, -1,6121                            TotalNbOperand);6122 6123  CallInst *MapperCall = dyn_cast<CallInst>(&BB->back());6124  EXPECT_NE(MapperCall, nullptr);6125  EXPECT_EQ(MapperCall->arg_size(), 9U);6126  EXPECT_EQ(MapperCall->getCalledFunction()->getName(),6127            "__tgt_target_data_begin_mapper");6128  EXPECT_EQ(MapperCall->getOperand(0), SrcLocInfo);6129  EXPECT_TRUE(MapperCall->getOperand(1)->getType()->isIntegerTy(64));6130  EXPECT_TRUE(MapperCall->getOperand(2)->getType()->isIntegerTy(32));6131 6132  EXPECT_EQ(MapperCall->getOperand(6), MaptypesArg);6133  EXPECT_EQ(MapperCall->getOperand(7), MapnamesArg);6134  EXPECT_TRUE(MapperCall->getOperand(8)->getType()->isPointerTy());6135}6136 6137TEST_F(OpenMPIRBuilderTest, TargetEnterData) {6138  OpenMPIRBuilder OMPBuilder(*M);6139  OMPBuilder.initialize();6140  F->setName("func");6141  IRBuilder<> Builder(BB);6142  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});6143 6144  int64_t DeviceID = 2;6145 6146  AllocaInst *Val1 =6147      Builder.CreateAlloca(Builder.getInt32Ty(), Builder.getInt64(1));6148  ASSERT_NE(Val1, nullptr);6149 6150  IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(),6151                                    F->getEntryBlock().getFirstInsertionPt());6152 6153  llvm::OpenMPIRBuilder::MapInfosTy CombinedInfo;6154  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;6155  auto GenMapInfoCB =6156      [&](InsertPointTy codeGenIP) -> llvm::OpenMPIRBuilder::MapInfosTy & {6157    // Get map clause information.6158    Builder.restoreIP(codeGenIP);6159 6160    CombinedInfo.BasePointers.emplace_back(Val1);6161    CombinedInfo.Pointers.emplace_back(Val1);6162    CombinedInfo.DevicePointers.emplace_back(6163        llvm::OpenMPIRBuilder::DeviceInfoTy::None);6164    CombinedInfo.Sizes.emplace_back(Builder.getInt64(4));6165    CombinedInfo.Types.emplace_back(llvm::omp::OpenMPOffloadMappingFlags(1));6166    uint32_t temp;6167    CombinedInfo.Names.emplace_back(6168        OMPBuilder.getOrCreateSrcLocStr("unknown", temp));6169    return CombinedInfo;6170  };6171 6172  auto CustomMapperCB = [&](unsigned int I) { return nullptr; };6173  llvm::OpenMPIRBuilder::TargetDataInfo Info(6174      /*RequiresDevicePointerInfo=*/false,6175      /*SeparateBeginEndCalls=*/true);6176 6177  OMPBuilder.Config.setIsGPU(true);6178 6179  llvm::omp::RuntimeFunction RTLFunc = OMPRTL___tgt_target_data_begin_mapper;6180  ASSERT_EXPECTED_INIT(6181      OpenMPIRBuilder::InsertPointTy, AfterIP,6182      OMPBuilder.createTargetData(6183          Loc, AllocaIP, Builder.saveIP(), Builder.getInt64(DeviceID),6184          /* IfCond= */ nullptr, Info, GenMapInfoCB, CustomMapperCB, &RTLFunc));6185  Builder.restoreIP(AfterIP);6186 6187  CallInst *TargetDataCall = dyn_cast<CallInst>(&BB->back());6188  EXPECT_NE(TargetDataCall, nullptr);6189  EXPECT_EQ(TargetDataCall->arg_size(), 9U);6190  EXPECT_EQ(TargetDataCall->getCalledFunction()->getName(),6191            "__tgt_target_data_begin_mapper");6192  EXPECT_TRUE(TargetDataCall->getOperand(1)->getType()->isIntegerTy(64));6193  EXPECT_TRUE(TargetDataCall->getOperand(2)->getType()->isIntegerTy(32));6194  EXPECT_TRUE(TargetDataCall->getOperand(8)->getType()->isPointerTy());6195 6196  Builder.CreateRetVoid();6197  EXPECT_FALSE(verifyModule(*M, &errs()));6198}6199 6200TEST_F(OpenMPIRBuilderTest, TargetExitData) {6201  OpenMPIRBuilder OMPBuilder(*M);6202  OMPBuilder.initialize();6203  F->setName("func");6204  IRBuilder<> Builder(BB);6205  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});6206 6207  int64_t DeviceID = 2;6208 6209  AllocaInst *Val1 =6210      Builder.CreateAlloca(Builder.getInt32Ty(), Builder.getInt64(1));6211  ASSERT_NE(Val1, nullptr);6212 6213  IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(),6214                                    F->getEntryBlock().getFirstInsertionPt());6215 6216  llvm::OpenMPIRBuilder::MapInfosTy CombinedInfo;6217  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;6218  auto GenMapInfoCB =6219      [&](InsertPointTy codeGenIP) -> llvm::OpenMPIRBuilder::MapInfosTy & {6220    // Get map clause information.6221    Builder.restoreIP(codeGenIP);6222 6223    CombinedInfo.BasePointers.emplace_back(Val1);6224    CombinedInfo.Pointers.emplace_back(Val1);6225    CombinedInfo.DevicePointers.emplace_back(6226        llvm::OpenMPIRBuilder::DeviceInfoTy::None);6227    CombinedInfo.Sizes.emplace_back(Builder.getInt64(4));6228    CombinedInfo.Types.emplace_back(llvm::omp::OpenMPOffloadMappingFlags(2));6229    uint32_t temp;6230    CombinedInfo.Names.emplace_back(6231        OMPBuilder.getOrCreateSrcLocStr("unknown", temp));6232    return CombinedInfo;6233  };6234 6235  auto CustomMapperCB = [&](unsigned int I) { return nullptr; };6236  llvm::OpenMPIRBuilder::TargetDataInfo Info(6237      /*RequiresDevicePointerInfo=*/false,6238      /*SeparateBeginEndCalls=*/true);6239 6240  OMPBuilder.Config.setIsGPU(true);6241 6242  llvm::omp::RuntimeFunction RTLFunc = OMPRTL___tgt_target_data_end_mapper;6243  ASSERT_EXPECTED_INIT(6244      OpenMPIRBuilder::InsertPointTy, AfterIP,6245      OMPBuilder.createTargetData(6246          Loc, AllocaIP, Builder.saveIP(), Builder.getInt64(DeviceID),6247          /* IfCond= */ nullptr, Info, GenMapInfoCB, CustomMapperCB, &RTLFunc));6248  Builder.restoreIP(AfterIP);6249 6250  CallInst *TargetDataCall = dyn_cast<CallInst>(&BB->back());6251  EXPECT_NE(TargetDataCall, nullptr);6252  EXPECT_EQ(TargetDataCall->arg_size(), 9U);6253  EXPECT_EQ(TargetDataCall->getCalledFunction()->getName(),6254            "__tgt_target_data_end_mapper");6255  EXPECT_TRUE(TargetDataCall->getOperand(1)->getType()->isIntegerTy(64));6256  EXPECT_TRUE(TargetDataCall->getOperand(2)->getType()->isIntegerTy(32));6257  EXPECT_TRUE(TargetDataCall->getOperand(8)->getType()->isPointerTy());6258 6259  Builder.CreateRetVoid();6260  EXPECT_FALSE(verifyModule(*M, &errs()));6261}6262 6263TEST_F(OpenMPIRBuilderTest, TargetDataRegion) {6264  OpenMPIRBuilder OMPBuilder(*M);6265  OMPBuilder.initialize();6266  F->setName("func");6267  IRBuilder<> Builder(BB);6268  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});6269 6270  int64_t DeviceID = 2;6271 6272  AllocaInst *Val1 =6273      Builder.CreateAlloca(Builder.getInt32Ty(), Builder.getInt64(1));6274  ASSERT_NE(Val1, nullptr);6275 6276  AllocaInst *Val2 = Builder.CreateAlloca(Builder.getPtrTy());6277  ASSERT_NE(Val2, nullptr);6278 6279  AllocaInst *Val3 = Builder.CreateAlloca(Builder.getPtrTy());6280  ASSERT_NE(Val3, nullptr);6281 6282  IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(),6283                                    F->getEntryBlock().getFirstInsertionPt());6284 6285  using DeviceInfoTy = llvm::OpenMPIRBuilder::DeviceInfoTy;6286  llvm::OpenMPIRBuilder::MapInfosTy CombinedInfo;6287  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;6288  auto GenMapInfoCB =6289      [&](InsertPointTy codeGenIP) -> llvm::OpenMPIRBuilder::MapInfosTy & {6290    // Get map clause information.6291    Builder.restoreIP(codeGenIP);6292    uint32_t temp;6293 6294    CombinedInfo.BasePointers.emplace_back(Val1);6295    CombinedInfo.Pointers.emplace_back(Val1);6296    CombinedInfo.DevicePointers.emplace_back(DeviceInfoTy::None);6297    CombinedInfo.Sizes.emplace_back(Builder.getInt64(4));6298    CombinedInfo.Types.emplace_back(llvm::omp::OpenMPOffloadMappingFlags(3));6299    CombinedInfo.Names.emplace_back(6300        OMPBuilder.getOrCreateSrcLocStr("unknown", temp));6301 6302    CombinedInfo.BasePointers.emplace_back(Val2);6303    CombinedInfo.Pointers.emplace_back(Val2);6304    CombinedInfo.DevicePointers.emplace_back(DeviceInfoTy::Pointer);6305    CombinedInfo.Sizes.emplace_back(Builder.getInt64(8));6306    CombinedInfo.Types.emplace_back(llvm::omp::OpenMPOffloadMappingFlags(67));6307    CombinedInfo.Names.emplace_back(6308        OMPBuilder.getOrCreateSrcLocStr("unknown", temp));6309 6310    CombinedInfo.BasePointers.emplace_back(Val3);6311    CombinedInfo.Pointers.emplace_back(Val3);6312    CombinedInfo.DevicePointers.emplace_back(DeviceInfoTy::Address);6313    CombinedInfo.Sizes.emplace_back(Builder.getInt64(8));6314    CombinedInfo.Types.emplace_back(llvm::omp::OpenMPOffloadMappingFlags(67));6315    CombinedInfo.Names.emplace_back(6316        OMPBuilder.getOrCreateSrcLocStr("unknown", temp));6317    return CombinedInfo;6318  };6319 6320  auto CustomMapperCB = [&](unsigned int I) { return nullptr; };6321  llvm::OpenMPIRBuilder::TargetDataInfo Info(6322      /*RequiresDevicePointerInfo=*/true,6323      /*SeparateBeginEndCalls=*/true);6324 6325  OMPBuilder.Config.setIsGPU(true);6326 6327  using BodyGenTy = llvm::OpenMPIRBuilder::BodyGenTy;6328  auto BodyCB = [&](InsertPointTy CodeGenIP, BodyGenTy BodyGenType) {6329    if (BodyGenType == BodyGenTy::Priv) {6330      EXPECT_EQ(Info.DevicePtrInfoMap.size(), 2u);6331      Builder.restoreIP(CodeGenIP);6332      CallInst *TargetDataCall =6333          dyn_cast<CallInst>(BB->back().getPrevNode()->getPrevNode());6334      EXPECT_NE(TargetDataCall, nullptr);6335      EXPECT_EQ(TargetDataCall->arg_size(), 9U);6336      EXPECT_EQ(TargetDataCall->getCalledFunction()->getName(),6337                "__tgt_target_data_begin_mapper");6338      EXPECT_TRUE(TargetDataCall->getOperand(1)->getType()->isIntegerTy(64));6339      EXPECT_TRUE(TargetDataCall->getOperand(2)->getType()->isIntegerTy(32));6340      EXPECT_TRUE(TargetDataCall->getOperand(8)->getType()->isPointerTy());6341 6342      LoadInst *LI = dyn_cast<LoadInst>(BB->back().getPrevNode());6343      EXPECT_NE(LI, nullptr);6344      StoreInst *SI = dyn_cast<StoreInst>(&BB->back());6345      EXPECT_NE(SI, nullptr);6346      EXPECT_EQ(SI->getValueOperand(), LI);6347      EXPECT_EQ(SI->getPointerOperand(), Info.DevicePtrInfoMap[Val2].second);6348      EXPECT_TRUE(isa<AllocaInst>(Info.DevicePtrInfoMap[Val2].second));6349      EXPECT_TRUE(isa<GetElementPtrInst>(Info.DevicePtrInfoMap[Val3].second));6350      Builder.CreateStore(Builder.getInt32(99), Val1);6351    }6352    return Builder.saveIP();6353  };6354 6355  ASSERT_EXPECTED_INIT(6356      OpenMPIRBuilder::InsertPointTy, TargetDataIP1,6357      OMPBuilder.createTargetData(Loc, AllocaIP, Builder.saveIP(),6358                                  Builder.getInt64(DeviceID),6359                                  /* IfCond= */ nullptr, Info, GenMapInfoCB,6360                                  CustomMapperCB, nullptr, BodyCB));6361  Builder.restoreIP(TargetDataIP1);6362 6363  CallInst *TargetDataCall = dyn_cast<CallInst>(&BB->back());6364  EXPECT_NE(TargetDataCall, nullptr);6365  EXPECT_EQ(TargetDataCall->arg_size(), 9U);6366  EXPECT_EQ(TargetDataCall->getCalledFunction()->getName(),6367            "__tgt_target_data_end_mapper");6368  EXPECT_TRUE(TargetDataCall->getOperand(1)->getType()->isIntegerTy(64));6369  EXPECT_TRUE(TargetDataCall->getOperand(2)->getType()->isIntegerTy(32));6370  EXPECT_TRUE(TargetDataCall->getOperand(8)->getType()->isPointerTy());6371 6372  // Check that BodyGenCB is still made when IsTargetDevice is set to true.6373  OMPBuilder.Config.setIsTargetDevice(true);6374  bool CheckDevicePassBodyGen = false;6375  auto BodyTargetCB = [&](InsertPointTy CodeGenIP, BodyGenTy BodyGenType) {6376    CheckDevicePassBodyGen = true;6377    Builder.restoreIP(CodeGenIP);6378    CallInst *TargetDataCall =6379        dyn_cast<CallInst>(BB->back().getPrevNode()->getPrevNode());6380    // Make sure no begin_mapper call is present for device pass.6381    EXPECT_EQ(TargetDataCall, nullptr);6382    return Builder.saveIP();6383  };6384  ASSERT_EXPECTED_INIT(6385      OpenMPIRBuilder::InsertPointTy, TargetDataIP2,6386      OMPBuilder.createTargetData(Loc, AllocaIP, Builder.saveIP(),6387                                  Builder.getInt64(DeviceID),6388                                  /* IfCond= */ nullptr, Info, GenMapInfoCB,6389                                  CustomMapperCB, nullptr, BodyTargetCB));6390  Builder.restoreIP(TargetDataIP2);6391  EXPECT_TRUE(CheckDevicePassBodyGen);6392 6393  Builder.CreateRetVoid();6394  EXPECT_FALSE(verifyModule(*M, &errs()));6395}6396 6397namespace {6398// Some basic handling of argument mapping for the moment6399void CreateDefaultMapInfos(llvm::OpenMPIRBuilder &OmpBuilder,6400                           llvm::SmallVectorImpl<llvm::Value *> &Args,6401                           llvm::OpenMPIRBuilder::MapInfosTy &CombinedInfo) {6402  for (auto Arg : Args) {6403    CombinedInfo.BasePointers.emplace_back(Arg);6404    CombinedInfo.Pointers.emplace_back(Arg);6405    uint32_t SrcLocStrSize;6406    CombinedInfo.Names.emplace_back(OmpBuilder.getOrCreateSrcLocStr(6407        "Unknown loc - stub implementation", SrcLocStrSize));6408    CombinedInfo.Types.emplace_back(llvm::omp::OpenMPOffloadMappingFlags(6409        llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO |6410        llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM |6411        llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM));6412    CombinedInfo.Sizes.emplace_back(OmpBuilder.Builder.getInt64(6413        OmpBuilder.M.getDataLayout().getTypeAllocSize(Arg->getType())));6414  }6415}6416} // namespace6417 6418TEST_F(OpenMPIRBuilderTest, TargetRegion) {6419  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;6420  OpenMPIRBuilder OMPBuilder(*M);6421  OMPBuilder.initialize();6422  OpenMPIRBuilderConfig Config(false, false, false, false, false, false, false);6423  OMPBuilder.setConfig(Config);6424  F->setName("func");6425  F->addFnAttr("target-cpu", "x86-64");6426  F->addFnAttr("target-features", "+mmx,+sse");6427  IRBuilder<> Builder(BB);6428  auto *Int32Ty = Builder.getInt32Ty();6429  Builder.SetCurrentDebugLocation(DL);6430 6431  AllocaInst *APtr = Builder.CreateAlloca(Int32Ty, nullptr, "a_ptr");6432  AllocaInst *BPtr = Builder.CreateAlloca(Int32Ty, nullptr, "b_ptr");6433  AllocaInst *CPtr = Builder.CreateAlloca(Int32Ty, nullptr, "c_ptr");6434 6435  Builder.CreateStore(Builder.getInt32(10), APtr);6436  Builder.CreateStore(Builder.getInt32(20), BPtr);6437  auto BodyGenCB = [&](InsertPointTy AllocaIP,6438                       InsertPointTy CodeGenIP) -> InsertPointTy {6439    IRBuilderBase::InsertPointGuard guard(Builder);6440    Builder.SetCurrentDebugLocation(llvm::DebugLoc());6441    Builder.restoreIP(CodeGenIP);6442    LoadInst *AVal = Builder.CreateLoad(Int32Ty, APtr);6443    LoadInst *BVal = Builder.CreateLoad(Int32Ty, BPtr);6444    Value *Sum = Builder.CreateAdd(AVal, BVal);6445    Builder.CreateStore(Sum, CPtr);6446    return Builder.saveIP();6447  };6448 6449  llvm::SmallVector<llvm::Value *> Inputs;6450  Inputs.push_back(APtr);6451  Inputs.push_back(BPtr);6452  Inputs.push_back(CPtr);6453 6454  auto SimpleArgAccessorCB =6455      [&](llvm::Argument &Arg, llvm::Value *Input, llvm::Value *&RetVal,6456          llvm::OpenMPIRBuilder::InsertPointTy AllocaIP,6457          llvm::OpenMPIRBuilder::InsertPointTy CodeGenIP) {6458        IRBuilderBase::InsertPointGuard guard(Builder);6459        Builder.SetCurrentDebugLocation(llvm::DebugLoc());6460        if (!OMPBuilder.Config.isTargetDevice()) {6461          RetVal = cast<llvm::Value>(&Arg);6462          return CodeGenIP;6463        }6464 6465        Builder.restoreIP(AllocaIP);6466 6467        llvm::Value *Addr = Builder.CreateAlloca(6468            Arg.getType()->isPointerTy()6469                ? Arg.getType()6470                : Type::getInt64Ty(Builder.getContext()),6471            OMPBuilder.M.getDataLayout().getAllocaAddrSpace());6472        llvm::Value *AddrAscast =6473            Builder.CreatePointerBitCastOrAddrSpaceCast(Addr, Input->getType());6474        Builder.CreateStore(&Arg, AddrAscast);6475 6476        Builder.restoreIP(CodeGenIP);6477 6478        RetVal = Builder.CreateLoad(Arg.getType(), AddrAscast);6479 6480        return Builder.saveIP();6481      };6482 6483  llvm::OpenMPIRBuilder::MapInfosTy CombinedInfos;6484  auto GenMapInfoCB = [&](llvm::OpenMPIRBuilder::InsertPointTy codeGenIP)6485      -> llvm::OpenMPIRBuilder::MapInfosTy & {6486    CreateDefaultMapInfos(OMPBuilder, Inputs, CombinedInfos);6487    return CombinedInfos;6488  };6489 6490  auto CustomMapperCB = [&](unsigned int I) { return nullptr; };6491  llvm::OpenMPIRBuilder::TargetDataInfo Info(6492      /*RequiresDevicePointerInfo=*/false,6493      /*SeparateBeginEndCalls=*/true);6494 6495  TargetRegionEntryInfo EntryInfo("func", 42, 4711, 17);6496  OpenMPIRBuilder::LocationDescription OmpLoc({Builder.saveIP(), DL});6497  OpenMPIRBuilder::TargetKernelRuntimeAttrs RuntimeAttrs;6498  OpenMPIRBuilder::TargetKernelDefaultAttrs DefaultAttrs = {6499      /*ExecFlags=*/omp::OMPTgtExecModeFlags::OMP_TGT_EXEC_MODE_GENERIC,6500      /*MaxTeams=*/{10}, /*MinTeams=*/0, /*MaxThreads=*/{0}, /*MinThreads=*/0};6501  RuntimeAttrs.TargetThreadLimit[0] = Builder.getInt32(20);6502  RuntimeAttrs.TeamsThreadLimit[0] = Builder.getInt32(30);6503  RuntimeAttrs.MaxThreads = Builder.getInt32(40);6504 6505  ASSERT_EXPECTED_INIT(6506      OpenMPIRBuilder::InsertPointTy, AfterIP,6507      OMPBuilder.createTarget(OmpLoc, /*IsOffloadEntry=*/true, Builder.saveIP(),6508                              Builder.saveIP(), Info, EntryInfo, DefaultAttrs,6509                              RuntimeAttrs, /*IfCond=*/nullptr, Inputs,6510                              GenMapInfoCB, BodyGenCB, SimpleArgAccessorCB,6511                              CustomMapperCB, {}, false));6512  EXPECT_EQ(DL, Builder.getCurrentDebugLocation());6513  Builder.restoreIP(AfterIP);6514 6515  OMPBuilder.finalize();6516  Builder.CreateRetVoid();6517 6518  // Check the kernel launch sequence6519  auto Iter = F->getEntryBlock().rbegin();6520  EXPECT_TRUE(isa<BranchInst>(&*(Iter)));6521  BranchInst *Branch = dyn_cast<BranchInst>(&*(Iter));6522  EXPECT_TRUE(isa<CmpInst>(&*(++Iter)));6523  EXPECT_TRUE(isa<CallInst>(&*(++Iter)));6524  CallInst *Call = dyn_cast<CallInst>(&*(Iter));6525 6526  // Check that the kernel launch function is called6527  Function *KernelLaunchFunc = Call->getCalledFunction();6528  EXPECT_NE(KernelLaunchFunc, nullptr);6529  StringRef FunctionName = KernelLaunchFunc->getName();6530  EXPECT_TRUE(FunctionName.starts_with("__tgt_target_kernel"));6531 6532  // Check num_teams and num_threads in call arguments6533  EXPECT_TRUE(Call->arg_size() >= 4);6534  Value *NumTeamsArg = Call->getArgOperand(2);6535  EXPECT_TRUE(isa<ConstantInt>(NumTeamsArg));6536  EXPECT_EQ(10U, cast<ConstantInt>(NumTeamsArg)->getZExtValue());6537  Value *NumThreadsArg = Call->getArgOperand(3);6538  EXPECT_TRUE(isa<ConstantInt>(NumThreadsArg));6539  EXPECT_EQ(20U, cast<ConstantInt>(NumThreadsArg)->getZExtValue());6540 6541  // Check num_teams and num_threads kernel arguments (use number 5 starting6542  // from the end and counting the call to __tgt_target_kernel as the first use)6543  Value *KernelArgs = Call->getArgOperand(Call->arg_size() - 1);6544  EXPECT_TRUE(KernelArgs->hasNUsesOrMore(4));6545  Value *NumTeamsGetElemPtr = *std::next(KernelArgs->user_begin(), 3);6546  EXPECT_TRUE(isa<GetElementPtrInst>(NumTeamsGetElemPtr));6547  Value *NumTeamsStore = NumTeamsGetElemPtr->getUniqueUndroppableUser();6548  EXPECT_TRUE(isa<StoreInst>(NumTeamsStore));6549  Value *NumTeamsStoreArg = cast<StoreInst>(NumTeamsStore)->getValueOperand();6550  EXPECT_TRUE(isa<ConstantDataSequential>(NumTeamsStoreArg));6551  auto *NumTeamsStoreValue = cast<ConstantDataSequential>(NumTeamsStoreArg);6552  EXPECT_EQ(3U, NumTeamsStoreValue->getNumElements());6553  EXPECT_EQ(10U, NumTeamsStoreValue->getElementAsInteger(0));6554  EXPECT_EQ(0U, NumTeamsStoreValue->getElementAsInteger(1));6555  EXPECT_EQ(0U, NumTeamsStoreValue->getElementAsInteger(2));6556  Value *NumThreadsGetElemPtr = *std::next(KernelArgs->user_begin(), 2);6557  EXPECT_TRUE(isa<GetElementPtrInst>(NumThreadsGetElemPtr));6558  Value *NumThreadsStore = NumThreadsGetElemPtr->getUniqueUndroppableUser();6559  EXPECT_TRUE(isa<StoreInst>(NumThreadsStore));6560  Value *NumThreadsStoreArg =6561      cast<StoreInst>(NumThreadsStore)->getValueOperand();6562  EXPECT_TRUE(isa<ConstantDataSequential>(NumThreadsStoreArg));6563  auto *NumThreadsStoreValue = cast<ConstantDataSequential>(NumThreadsStoreArg);6564  EXPECT_EQ(3U, NumThreadsStoreValue->getNumElements());6565  EXPECT_EQ(20U, NumThreadsStoreValue->getElementAsInteger(0));6566  EXPECT_EQ(0U, NumThreadsStoreValue->getElementAsInteger(1));6567  EXPECT_EQ(0U, NumThreadsStoreValue->getElementAsInteger(2));6568 6569  // Check the fallback call6570  BasicBlock *FallbackBlock = Branch->getSuccessor(0);6571  Iter = FallbackBlock->rbegin();6572  CallInst *FCall = dyn_cast<CallInst>(&*(++Iter));6573  // 'F' has a dummy DISubprogram which causes OutlinedFunc to also6574  // have a DISubprogram. In this case, the call to OutlinedFunc needs6575  // to have a debug loc, otherwise verifier will complain.6576  FCall->setDebugLoc(DL);6577  EXPECT_NE(FCall, nullptr);6578 6579  // Check that the correct aguments are passed in6580  for (auto ArgInput : zip(FCall->args(), Inputs)) {6581    EXPECT_EQ(std::get<0>(ArgInput), std::get<1>(ArgInput));6582  }6583 6584  // Check that the outlined function exists with the expected prefix6585  Function *OutlinedFunc = FCall->getCalledFunction();6586  EXPECT_NE(OutlinedFunc, nullptr);6587  StringRef FunctionName2 = OutlinedFunc->getName();6588  EXPECT_TRUE(FunctionName2.starts_with("__omp_offloading"));6589 6590  // Check that target-cpu and target-features were propagated to the outlined6591  // function6592  EXPECT_EQ(OutlinedFunc->getFnAttribute("target-cpu"),6593            F->getFnAttribute("target-cpu"));6594  EXPECT_EQ(OutlinedFunc->getFnAttribute("target-features"),6595            F->getFnAttribute("target-features"));6596 6597  EXPECT_FALSE(verifyModule(*M, &errs()));6598}6599 6600TEST_F(OpenMPIRBuilderTest, TargetRegionDevice) {6601  OpenMPIRBuilder OMPBuilder(*M);6602  OMPBuilder.setConfig(6603      OpenMPIRBuilderConfig(true, false, false, false, false, false, false));6604  OMPBuilder.initialize();6605 6606  F->setName("func");6607  F->addFnAttr("target-cpu", "gfx90a");6608  F->addFnAttr("target-features", "+gfx9-insts,+wavefrontsize64");6609  IRBuilder<> Builder(BB);6610  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});6611  Builder.SetCurrentDebugLocation(DL);6612 6613  LoadInst *Value = nullptr;6614  StoreInst *TargetStore = nullptr;6615  llvm::SmallVector<llvm::Value *, 2> CapturedArgs = {6616      Constant::getNullValue(PointerType::get(Ctx, 0)),6617      Constant::getNullValue(PointerType::get(Ctx, 0))};6618 6619  auto SimpleArgAccessorCB =6620      [&](llvm::Argument &Arg, llvm::Value *Input, llvm::Value *&RetVal,6621          llvm::OpenMPIRBuilder::InsertPointTy AllocaIP,6622          llvm::OpenMPIRBuilder::InsertPointTy CodeGenIP) {6623        IRBuilderBase::InsertPointGuard guard(Builder);6624        Builder.SetCurrentDebugLocation(llvm::DebugLoc());6625        if (!OMPBuilder.Config.isTargetDevice()) {6626          RetVal = cast<llvm::Value>(&Arg);6627          return CodeGenIP;6628        }6629 6630        Builder.restoreIP(AllocaIP);6631 6632        llvm::Value *Addr = Builder.CreateAlloca(6633            Arg.getType()->isPointerTy()6634                ? Arg.getType()6635                : Type::getInt64Ty(Builder.getContext()),6636            OMPBuilder.M.getDataLayout().getAllocaAddrSpace());6637        llvm::Value *AddrAscast =6638            Builder.CreatePointerBitCastOrAddrSpaceCast(Addr, Input->getType());6639        Builder.CreateStore(&Arg, AddrAscast);6640 6641        Builder.restoreIP(CodeGenIP);6642 6643        RetVal = Builder.CreateLoad(Arg.getType(), AddrAscast);6644 6645        return Builder.saveIP();6646      };6647 6648  llvm::OpenMPIRBuilder::MapInfosTy CombinedInfos;6649  auto GenMapInfoCB = [&](llvm::OpenMPIRBuilder::InsertPointTy codeGenIP)6650      -> llvm::OpenMPIRBuilder::MapInfosTy & {6651    CreateDefaultMapInfos(OMPBuilder, CapturedArgs, CombinedInfos);6652    return CombinedInfos;6653  };6654 6655  auto CustomMapperCB = [&](unsigned int I) { return nullptr; };6656  auto BodyGenCB = [&](OpenMPIRBuilder::InsertPointTy AllocaIP,6657                       OpenMPIRBuilder::InsertPointTy CodeGenIP)6658      -> OpenMPIRBuilder::InsertPointTy {6659    IRBuilderBase::InsertPointGuard guard(Builder);6660    Builder.SetCurrentDebugLocation(llvm::DebugLoc());6661    Builder.restoreIP(CodeGenIP);6662    Value = Builder.CreateLoad(Type::getInt32Ty(Ctx), CapturedArgs[0]);6663    TargetStore = Builder.CreateStore(Value, CapturedArgs[1]);6664    return Builder.saveIP();6665  };6666 6667  IRBuilder<>::InsertPoint EntryIP(&F->getEntryBlock(),6668                                   F->getEntryBlock().getFirstInsertionPt());6669  TargetRegionEntryInfo EntryInfo("parent", /*DeviceID=*/1, /*FileID=*/2,6670                                  /*Line=*/3, /*Count=*/0);6671  OpenMPIRBuilder::TargetKernelRuntimeAttrs RuntimeAttrs;6672  OpenMPIRBuilder::TargetKernelDefaultAttrs DefaultAttrs = {6673      /*ExecFlags=*/omp::OMPTgtExecModeFlags::OMP_TGT_EXEC_MODE_GENERIC,6674      /*MaxTeams=*/{-1}, /*MinTeams=*/0, /*MaxThreads=*/{0}, /*MinThreads=*/0};6675  llvm::OpenMPIRBuilder::TargetDataInfo Info(6676      /*RequiresDevicePointerInfo=*/false,6677      /*SeparateBeginEndCalls=*/true);6678 6679  ASSERT_EXPECTED_INIT(6680      OpenMPIRBuilder::InsertPointTy, AfterIP,6681      OMPBuilder.createTarget(Loc, /*IsOffloadEntry=*/true, EntryIP, EntryIP,6682                              Info, EntryInfo, DefaultAttrs, RuntimeAttrs,6683                              /*IfCond=*/nullptr, CapturedArgs, GenMapInfoCB,6684                              BodyGenCB, SimpleArgAccessorCB, CustomMapperCB,6685                              {}, false));6686  EXPECT_EQ(DL, Builder.getCurrentDebugLocation());6687  Builder.restoreIP(AfterIP);6688 6689  Builder.CreateRetVoid();6690  OMPBuilder.finalize();6691 6692  // Check outlined function6693  EXPECT_FALSE(verifyModule(*M, &errs()));6694  EXPECT_NE(TargetStore, nullptr);6695  Function *OutlinedFn = TargetStore->getFunction();6696  EXPECT_NE(F, OutlinedFn);6697 6698  // Check that target-cpu and target-features were propagated to the outlined6699  // function6700  EXPECT_EQ(OutlinedFn->getFnAttribute("target-cpu"),6701            F->getFnAttribute("target-cpu"));6702  EXPECT_EQ(OutlinedFn->getFnAttribute("target-features"),6703            F->getFnAttribute("target-features"));6704 6705  EXPECT_TRUE(OutlinedFn->hasWeakODRLinkage());6706  // Account for the "implicit" first argument.6707  EXPECT_EQ(OutlinedFn->getName(), "__omp_offloading_1_2_parent_l3");6708  EXPECT_EQ(OutlinedFn->arg_size(), 3U);6709  EXPECT_TRUE(OutlinedFn->getArg(1)->getType()->isPointerTy());6710  EXPECT_TRUE(OutlinedFn->getArg(2)->getType()->isPointerTy());6711 6712  // Check entry block6713  auto &EntryBlock = OutlinedFn->getEntryBlock();6714  Instruction *Alloca1 = &*EntryBlock.getFirstNonPHIIt();6715  EXPECT_NE(Alloca1, nullptr);6716 6717  EXPECT_TRUE(isa<AllocaInst>(Alloca1));6718  auto *Store1 = Alloca1->getNextNode();6719  EXPECT_TRUE(isa<StoreInst>(Store1));6720  auto *Alloca2 = Store1->getNextNode();6721  EXPECT_TRUE(isa<AllocaInst>(Alloca2));6722  auto *Store2 = Alloca2->getNextNode();6723  EXPECT_TRUE(isa<StoreInst>(Store2));6724 6725  auto *InitCall = dyn_cast<CallInst>(Store2->getNextNode());6726  EXPECT_NE(InitCall, nullptr);6727  EXPECT_EQ(InitCall->getCalledFunction()->getName(), "__kmpc_target_init");6728  EXPECT_EQ(InitCall->arg_size(), 2U);6729  EXPECT_TRUE(isa<GlobalVariable>(InitCall->getArgOperand(0)));6730  auto *KernelEnvGV = cast<GlobalVariable>(InitCall->getArgOperand(0));6731  EXPECT_TRUE(isa<ConstantStruct>(KernelEnvGV->getInitializer()));6732  auto *KernelEnvC = cast<ConstantStruct>(KernelEnvGV->getInitializer());6733  EXPECT_TRUE(isa<ConstantStruct>(KernelEnvC->getAggregateElement(0U)));6734  auto ConfigC = cast<ConstantStruct>(KernelEnvC->getAggregateElement(0U));6735  EXPECT_EQ(ConfigC->getAggregateElement(0U),6736            ConstantInt::get(Type::getInt8Ty(Ctx), true));6737  EXPECT_EQ(ConfigC->getAggregateElement(1U),6738            ConstantInt::get(Type::getInt8Ty(Ctx), true));6739  EXPECT_EQ(ConfigC->getAggregateElement(2U),6740            ConstantInt::get(Type::getInt8Ty(Ctx), OMP_TGT_EXEC_MODE_GENERIC));6741 6742  auto *EntryBlockBranch = EntryBlock.getTerminator();6743  EXPECT_NE(EntryBlockBranch, nullptr);6744  EXPECT_EQ(EntryBlockBranch->getNumSuccessors(), 2U);6745 6746  // Check user code block6747  auto *UserCodeBlock = EntryBlockBranch->getSuccessor(0);6748  EXPECT_EQ(UserCodeBlock->getName(), "user_code.entry");6749  Instruction *Load1 = &*UserCodeBlock->getFirstNonPHIIt();6750  EXPECT_TRUE(isa<LoadInst>(Load1));6751  auto *Load2 = Load1->getNextNode();6752  EXPECT_TRUE(isa<LoadInst>(Load2));6753 6754  auto *OutlinedBlockBr = Load2->getNextNode();6755  EXPECT_TRUE(isa<BranchInst>(OutlinedBlockBr));6756 6757  auto *OutlinedBlock = OutlinedBlockBr->getSuccessor(0);6758  EXPECT_EQ(OutlinedBlock->getName(), "outlined.body");6759 6760  Instruction *Value1 = &*OutlinedBlock->getFirstNonPHIIt();6761  EXPECT_EQ(Value1, Value);6762  EXPECT_EQ(Value1->getNextNode(), TargetStore);6763  auto *Deinit = TargetStore->getNextNode();6764  EXPECT_NE(Deinit, nullptr);6765 6766  auto *DeinitCall = dyn_cast<CallInst>(Deinit);6767  EXPECT_NE(DeinitCall, nullptr);6768  EXPECT_EQ(DeinitCall->getCalledFunction()->getName(), "__kmpc_target_deinit");6769  EXPECT_EQ(DeinitCall->arg_size(), 0U);6770 6771  EXPECT_TRUE(isa<ReturnInst>(DeinitCall->getNextNode()));6772 6773  // Check exit block6774  auto *ExitBlock = EntryBlockBranch->getSuccessor(1);6775  EXPECT_EQ(ExitBlock->getName(), "worker.exit");6776  EXPECT_TRUE(isa<ReturnInst>(ExitBlock->getFirstNonPHIIt()));6777 6778  // Check global exec_mode.6779  GlobalVariable *Used = M->getGlobalVariable("llvm.compiler.used");6780  EXPECT_NE(Used, nullptr);6781  Constant *UsedInit = Used->getInitializer();6782  EXPECT_NE(UsedInit, nullptr);6783  EXPECT_TRUE(isa<ConstantArray>(UsedInit));6784  auto *UsedInitData = cast<ConstantArray>(UsedInit);6785  EXPECT_EQ(1U, UsedInitData->getNumOperands());6786  Constant *ExecMode = UsedInitData->getOperand(0);6787  EXPECT_TRUE(isa<GlobalVariable>(ExecMode));6788  Constant *ExecModeValue = cast<GlobalVariable>(ExecMode)->getInitializer();6789  EXPECT_NE(ExecModeValue, nullptr);6790  EXPECT_TRUE(isa<ConstantInt>(ExecModeValue));6791  EXPECT_EQ(OMP_TGT_EXEC_MODE_GENERIC,6792            cast<ConstantInt>(ExecModeValue)->getZExtValue());6793}6794 6795TEST_F(OpenMPIRBuilderTest, TargetRegionSPMD) {6796  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;6797  OpenMPIRBuilder OMPBuilder(*M);6798  OMPBuilder.initialize();6799  OpenMPIRBuilderConfig Config(/*IsTargetDevice=*/false, /*IsGPU=*/false,6800                               /*OpenMPOffloadMandatory=*/false,6801                               /*HasRequiresReverseOffload=*/false,6802                               /*HasRequiresUnifiedAddress=*/false,6803                               /*HasRequiresUnifiedSharedMemory=*/false,6804                               /*HasRequiresDynamicAllocators=*/false);6805  OMPBuilder.setConfig(Config);6806  F->setName("func");6807  IRBuilder<> Builder(BB);6808 6809  auto CustomMapperCB = [&](unsigned int I) { return nullptr; };6810  auto BodyGenCB = [&](InsertPointTy,6811                       InsertPointTy CodeGenIP) -> InsertPointTy {6812    Builder.restoreIP(CodeGenIP);6813    return Builder.saveIP();6814  };6815 6816  auto SimpleArgAccessorCB = [&](Argument &, Value *, Value *&,6817                                 OpenMPIRBuilder::InsertPointTy,6818                                 OpenMPIRBuilder::InsertPointTy CodeGenIP) {6819    Builder.restoreIP(CodeGenIP);6820    return Builder.saveIP();6821  };6822 6823  SmallVector<Value *> Inputs;6824  OpenMPIRBuilder::MapInfosTy CombinedInfos;6825  auto GenMapInfoCB =6826      [&](OpenMPIRBuilder::InsertPointTy) -> OpenMPIRBuilder::MapInfosTy & {6827    return CombinedInfos;6828  };6829 6830  TargetRegionEntryInfo EntryInfo("func", 42, 4711, 17);6831  OpenMPIRBuilder::LocationDescription OmpLoc({Builder.saveIP(), DL});6832  OpenMPIRBuilder::TargetKernelRuntimeAttrs RuntimeAttrs;6833  OpenMPIRBuilder::TargetKernelDefaultAttrs DefaultAttrs = {6834      /*ExecFlags=*/omp::OMPTgtExecModeFlags::OMP_TGT_EXEC_MODE_SPMD,6835      /*MaxTeams=*/{-1}, /*MinTeams=*/0, /*MaxThreads=*/{0}, /*MinThreads=*/0};6836  RuntimeAttrs.LoopTripCount = Builder.getInt64(1000);6837  llvm::OpenMPIRBuilder::TargetDataInfo Info(6838      /*RequiresDevicePointerInfo=*/false,6839      /*SeparateBeginEndCalls=*/true);6840 6841  ASSERT_EXPECTED_INIT(6842      OpenMPIRBuilder::InsertPointTy, AfterIP,6843      OMPBuilder.createTarget(OmpLoc, /*IsOffloadEntry=*/true, Builder.saveIP(),6844                              Builder.saveIP(), Info, EntryInfo, DefaultAttrs,6845                              RuntimeAttrs, /*IfCond=*/nullptr, Inputs,6846                              GenMapInfoCB, BodyGenCB, SimpleArgAccessorCB,6847                              CustomMapperCB, {}));6848  Builder.restoreIP(AfterIP);6849 6850  OMPBuilder.finalize();6851  Builder.CreateRetVoid();6852 6853  // Check the kernel launch sequence6854  auto Iter = F->getEntryBlock().rbegin();6855  EXPECT_TRUE(isa<BranchInst>(&*(Iter)));6856  BranchInst *Branch = dyn_cast<BranchInst>(&*(Iter));6857  EXPECT_TRUE(isa<CmpInst>(&*(++Iter)));6858  EXPECT_TRUE(isa<CallInst>(&*(++Iter)));6859  CallInst *Call = dyn_cast<CallInst>(&*(Iter));6860 6861  // Check that the kernel launch function is called6862  Function *KernelLaunchFunc = Call->getCalledFunction();6863  EXPECT_NE(KernelLaunchFunc, nullptr);6864  StringRef FunctionName = KernelLaunchFunc->getName();6865  EXPECT_TRUE(FunctionName.starts_with("__tgt_target_kernel"));6866 6867  // Check the trip count kernel argument (use number 5 starting from the end6868  // and counting the call to __tgt_target_kernel as the first use)6869  Value *KernelArgs = Call->getArgOperand(Call->arg_size() - 1);6870  EXPECT_TRUE(KernelArgs->hasNUsesOrMore(6));6871  Value *TripCountGetElemPtr = *std::next(KernelArgs->user_begin(), 5);6872  EXPECT_TRUE(isa<GetElementPtrInst>(TripCountGetElemPtr));6873  Value *TripCountStore = TripCountGetElemPtr->getUniqueUndroppableUser();6874  EXPECT_TRUE(isa<StoreInst>(TripCountStore));6875  Value *TripCountStoreArg = cast<StoreInst>(TripCountStore)->getValueOperand();6876  EXPECT_TRUE(isa<ConstantInt>(TripCountStoreArg));6877  EXPECT_EQ(1000U, cast<ConstantInt>(TripCountStoreArg)->getZExtValue());6878 6879  // Check the fallback call6880  BasicBlock *FallbackBlock = Branch->getSuccessor(0);6881  Iter = FallbackBlock->rbegin();6882  CallInst *FCall = dyn_cast<CallInst>(&*(++Iter));6883  // 'F' has a dummy DISubprogram which causes OutlinedFunc to also6884  // have a DISubprogram. In this case, the call to OutlinedFunc needs6885  // to have a debug loc, otherwise verifier will complain.6886  FCall->setDebugLoc(DL);6887  EXPECT_NE(FCall, nullptr);6888 6889  // Check that the outlined function exists with the expected prefix6890  Function *OutlinedFunc = FCall->getCalledFunction();6891  EXPECT_NE(OutlinedFunc, nullptr);6892  StringRef FunctionName2 = OutlinedFunc->getName();6893  EXPECT_TRUE(FunctionName2.starts_with("__omp_offloading"));6894 6895  EXPECT_FALSE(verifyModule(*M, &errs()));6896}6897 6898TEST_F(OpenMPIRBuilderTest, TargetRegionDeviceSPMD) {6899  OpenMPIRBuilder OMPBuilder(*M);6900  OMPBuilder.setConfig(6901      OpenMPIRBuilderConfig(/*IsTargetDevice=*/true, /*IsGPU=*/false,6902                            /*OpenMPOffloadMandatory=*/false,6903                            /*HasRequiresReverseOffload=*/false,6904                            /*HasRequiresUnifiedAddress=*/false,6905                            /*HasRequiresUnifiedSharedMemory=*/false,6906                            /*HasRequiresDynamicAllocators=*/false));6907  OMPBuilder.initialize();6908  F->setName("func");6909  IRBuilder<> Builder(BB);6910  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});6911 6912  Function *OutlinedFn = nullptr;6913  SmallVector<Value *> CapturedArgs;6914 6915  auto SimpleArgAccessorCB = [&](Argument &, Value *, Value *&,6916                                 OpenMPIRBuilder::InsertPointTy,6917                                 OpenMPIRBuilder::InsertPointTy CodeGenIP) {6918    Builder.restoreIP(CodeGenIP);6919    return Builder.saveIP();6920  };6921 6922  OpenMPIRBuilder::MapInfosTy CombinedInfos;6923  auto GenMapInfoCB =6924      [&](OpenMPIRBuilder::InsertPointTy) -> OpenMPIRBuilder::MapInfosTy & {6925    return CombinedInfos;6926  };6927 6928  auto CustomMapperCB = [&](unsigned int I) { return nullptr; };6929  auto BodyGenCB = [&](OpenMPIRBuilder::InsertPointTy,6930                       OpenMPIRBuilder::InsertPointTy CodeGenIP)6931      -> OpenMPIRBuilder::InsertPointTy {6932    Builder.restoreIP(CodeGenIP);6933    OutlinedFn = CodeGenIP.getBlock()->getParent();6934    return Builder.saveIP();6935  };6936 6937  IRBuilder<>::InsertPoint EntryIP(&F->getEntryBlock(),6938                                   F->getEntryBlock().getFirstInsertionPt());6939  TargetRegionEntryInfo EntryInfo("parent", /*DeviceID=*/1, /*FileID=*/2,6940                                  /*Line=*/3, /*Count=*/0);6941  OpenMPIRBuilder::TargetKernelRuntimeAttrs RuntimeAttrs;6942  OpenMPIRBuilder::TargetKernelDefaultAttrs DefaultAttrs = {6943      /*ExecFlags=*/omp::OMPTgtExecModeFlags::OMP_TGT_EXEC_MODE_SPMD,6944      /*MaxTeams=*/{-1}, /*MinTeams=*/0, /*MaxThreads=*/{0}, /*MinThreads=*/0};6945  llvm::OpenMPIRBuilder::TargetDataInfo Info(6946      /*RequiresDevicePointerInfo=*/false,6947      /*SeparateBeginEndCalls=*/true);6948 6949  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,6950                       OMPBuilder.createTarget(6951                           Loc, /*IsOffloadEntry=*/true, EntryIP, EntryIP, Info,6952                           EntryInfo, DefaultAttrs, RuntimeAttrs,6953                           /*IfCond=*/nullptr, CapturedArgs, GenMapInfoCB,6954                           BodyGenCB, SimpleArgAccessorCB, CustomMapperCB, {}));6955  Builder.restoreIP(AfterIP);6956 6957  Builder.CreateRetVoid();6958  OMPBuilder.finalize();6959 6960  // Check outlined function6961  EXPECT_FALSE(verifyModule(*M, &errs()));6962  EXPECT_NE(OutlinedFn, nullptr);6963  EXPECT_NE(F, OutlinedFn);6964 6965  // Check that target-cpu and target-features were propagated to the outlined6966  // function6967  EXPECT_EQ(OutlinedFn->getFnAttribute("target-cpu"),6968            F->getFnAttribute("target-cpu"));6969  EXPECT_EQ(OutlinedFn->getFnAttribute("target-features"),6970            F->getFnAttribute("target-features"));6971 6972  EXPECT_TRUE(OutlinedFn->hasWeakODRLinkage());6973  // Account for the "implicit" first argument.6974  EXPECT_EQ(OutlinedFn->getName(), "__omp_offloading_1_2_parent_l3");6975  EXPECT_EQ(OutlinedFn->arg_size(), 1U);6976 6977  // Check global exec_mode.6978  GlobalVariable *Used = M->getGlobalVariable("llvm.compiler.used");6979  EXPECT_NE(Used, nullptr);6980  Constant *UsedInit = Used->getInitializer();6981  EXPECT_NE(UsedInit, nullptr);6982  EXPECT_TRUE(isa<ConstantArray>(UsedInit));6983  auto *UsedInitData = cast<ConstantArray>(UsedInit);6984  EXPECT_EQ(1U, UsedInitData->getNumOperands());6985  Constant *ExecMode = UsedInitData->getOperand(0);6986  EXPECT_TRUE(isa<GlobalVariable>(ExecMode));6987  Constant *ExecModeValue = cast<GlobalVariable>(ExecMode)->getInitializer();6988  EXPECT_NE(ExecModeValue, nullptr);6989  EXPECT_TRUE(isa<ConstantInt>(ExecModeValue));6990  EXPECT_EQ(OMP_TGT_EXEC_MODE_SPMD,6991            cast<ConstantInt>(ExecModeValue)->getZExtValue());6992}6993 6994TEST_F(OpenMPIRBuilderTest, ConstantAllocaRaise) {6995  OpenMPIRBuilder OMPBuilder(*M);6996  OMPBuilder.setConfig(6997      OpenMPIRBuilderConfig(true, false, false, false, false, false, false));6998  OMPBuilder.initialize();6999 7000  F->setName("func");7001  IRBuilder<> Builder(BB);7002  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});7003  Builder.SetCurrentDebugLocation(DL);7004 7005  LoadInst *Value = nullptr;7006  StoreInst *TargetStore = nullptr;7007  llvm::SmallVector<llvm::Value *, 1> CapturedArgs = {7008      Constant::getNullValue(PointerType::get(Ctx, 0))};7009 7010  auto SimpleArgAccessorCB =7011      [&](llvm::Argument &Arg, llvm::Value *Input, llvm::Value *&RetVal,7012          llvm::OpenMPIRBuilder::InsertPointTy AllocaIP,7013          llvm::OpenMPIRBuilder::InsertPointTy CodeGenIP) {7014        IRBuilderBase::InsertPointGuard guard(Builder);7015        Builder.SetCurrentDebugLocation(llvm::DebugLoc());7016        if (!OMPBuilder.Config.isTargetDevice()) {7017          RetVal = cast<llvm::Value>(&Arg);7018          return CodeGenIP;7019        }7020 7021        Builder.restoreIP(AllocaIP);7022 7023        llvm::Value *Addr = Builder.CreateAlloca(7024            Arg.getType()->isPointerTy()7025                ? Arg.getType()7026                : Type::getInt64Ty(Builder.getContext()),7027            OMPBuilder.M.getDataLayout().getAllocaAddrSpace());7028        llvm::Value *AddrAscast =7029            Builder.CreatePointerBitCastOrAddrSpaceCast(Addr, Input->getType());7030        Builder.CreateStore(&Arg, AddrAscast);7031 7032        Builder.restoreIP(CodeGenIP);7033 7034        RetVal = Builder.CreateLoad(Arg.getType(), AddrAscast);7035 7036        return Builder.saveIP();7037      };7038 7039  llvm::OpenMPIRBuilder::MapInfosTy CombinedInfos;7040  auto GenMapInfoCB = [&](llvm::OpenMPIRBuilder::InsertPointTy codeGenIP)7041      -> llvm::OpenMPIRBuilder::MapInfosTy & {7042    CreateDefaultMapInfos(OMPBuilder, CapturedArgs, CombinedInfos);7043    return CombinedInfos;7044  };7045 7046  llvm::Value *RaiseAlloca = nullptr;7047 7048  auto CustomMapperCB = [&](unsigned int I) { return nullptr; };7049  auto BodyGenCB = [&](OpenMPIRBuilder::InsertPointTy AllocaIP,7050                       OpenMPIRBuilder::InsertPointTy CodeGenIP)7051      -> OpenMPIRBuilder::InsertPointTy {7052    IRBuilderBase::InsertPointGuard guard(Builder);7053    Builder.SetCurrentDebugLocation(llvm::DebugLoc());7054    Builder.restoreIP(CodeGenIP);7055    RaiseAlloca = Builder.CreateAlloca(Builder.getInt32Ty());7056    Value = Builder.CreateLoad(Type::getInt32Ty(Ctx), CapturedArgs[0]);7057    TargetStore = Builder.CreateStore(Value, RaiseAlloca);7058    return Builder.saveIP();7059  };7060 7061  IRBuilder<>::InsertPoint EntryIP(&F->getEntryBlock(),7062                                   F->getEntryBlock().getFirstInsertionPt());7063  TargetRegionEntryInfo EntryInfo("parent", /*DeviceID=*/1, /*FileID=*/2,7064                                  /*Line=*/3, /*Count=*/0);7065  OpenMPIRBuilder::TargetKernelRuntimeAttrs RuntimeAttrs;7066  OpenMPIRBuilder::TargetKernelDefaultAttrs DefaultAttrs = {7067      /*ExecFlags=*/omp::OMPTgtExecModeFlags::OMP_TGT_EXEC_MODE_GENERIC,7068      /*MaxTeams=*/{-1}, /*MinTeams=*/0, /*MaxThreads=*/{0}, /*MinThreads=*/0};7069  llvm::OpenMPIRBuilder::TargetDataInfo Info(7070      /*RequiresDevicePointerInfo=*/false,7071      /*SeparateBeginEndCalls=*/true);7072 7073  ASSERT_EXPECTED_INIT(7074      OpenMPIRBuilder::InsertPointTy, AfterIP,7075      OMPBuilder.createTarget(Loc, /*IsOffloadEntry=*/true, EntryIP, EntryIP,7076                              Info, EntryInfo, DefaultAttrs, RuntimeAttrs,7077                              /*IfCond=*/nullptr, CapturedArgs, GenMapInfoCB,7078                              BodyGenCB, SimpleArgAccessorCB, CustomMapperCB,7079                              {}, false));7080  EXPECT_EQ(DL, Builder.getCurrentDebugLocation());7081  Builder.restoreIP(AfterIP);7082 7083  Builder.CreateRetVoid();7084  OMPBuilder.finalize();7085 7086  // Check outlined function7087  EXPECT_FALSE(verifyModule(*M, &errs()));7088  EXPECT_NE(TargetStore, nullptr);7089  Function *OutlinedFn = TargetStore->getFunction();7090  EXPECT_NE(F, OutlinedFn);7091 7092  EXPECT_TRUE(OutlinedFn->hasWeakODRLinkage());7093  // Account for the "implicit" first argument.7094  EXPECT_EQ(OutlinedFn->getName(), "__omp_offloading_1_2_parent_l3");7095  EXPECT_EQ(OutlinedFn->arg_size(), 2U);7096  EXPECT_TRUE(OutlinedFn->getArg(1)->getType()->isPointerTy());7097 7098  // Check entry block, to see if we have raised our alloca7099  // from the body to the entry block.7100  auto &EntryBlock = OutlinedFn->getEntryBlock();7101 7102  // Check that we have moved our alloca created in the7103  // BodyGenCB function, to the top of the function.7104  Instruction *Alloca1 = &*EntryBlock.getFirstNonPHIIt();7105  EXPECT_NE(Alloca1, nullptr);7106  EXPECT_TRUE(isa<AllocaInst>(Alloca1));7107  EXPECT_EQ(Alloca1, RaiseAlloca);7108 7109  // Verify we have not altered the rest of the function7110  // inappropriately with our alloca movement.7111  auto *Alloca2 = Alloca1->getNextNode();7112  EXPECT_TRUE(isa<AllocaInst>(Alloca2));7113  auto *Store2 = Alloca2->getNextNode();7114  EXPECT_TRUE(isa<StoreInst>(Store2));7115 7116  auto *InitCall = dyn_cast<CallInst>(Store2->getNextNode());7117  EXPECT_NE(InitCall, nullptr);7118  EXPECT_EQ(InitCall->getCalledFunction()->getName(), "__kmpc_target_init");7119  EXPECT_EQ(InitCall->arg_size(), 2U);7120  EXPECT_TRUE(isa<GlobalVariable>(InitCall->getArgOperand(0)));7121  auto *KernelEnvGV = cast<GlobalVariable>(InitCall->getArgOperand(0));7122  EXPECT_TRUE(isa<ConstantStruct>(KernelEnvGV->getInitializer()));7123  auto *KernelEnvC = cast<ConstantStruct>(KernelEnvGV->getInitializer());7124  EXPECT_TRUE(isa<ConstantStruct>(KernelEnvC->getAggregateElement(0U)));7125  auto *ConfigC = cast<ConstantStruct>(KernelEnvC->getAggregateElement(0U));7126  EXPECT_EQ(ConfigC->getAggregateElement(0U),7127            ConstantInt::get(Type::getInt8Ty(Ctx), true));7128  EXPECT_EQ(ConfigC->getAggregateElement(1U),7129            ConstantInt::get(Type::getInt8Ty(Ctx), true));7130  EXPECT_EQ(ConfigC->getAggregateElement(2U),7131            ConstantInt::get(Type::getInt8Ty(Ctx), OMP_TGT_EXEC_MODE_GENERIC));7132 7133  auto *EntryBlockBranch = EntryBlock.getTerminator();7134  EXPECT_NE(EntryBlockBranch, nullptr);7135  EXPECT_EQ(EntryBlockBranch->getNumSuccessors(), 2U);7136 7137  // Check user code block7138  auto *UserCodeBlock = EntryBlockBranch->getSuccessor(0);7139  EXPECT_EQ(UserCodeBlock->getName(), "user_code.entry");7140  BasicBlock::iterator Load1 = UserCodeBlock->getFirstNonPHIIt();7141  EXPECT_TRUE(isa<LoadInst>(Load1));7142 7143  auto *OutlinedBlockBr = Load1->getNextNode();7144  EXPECT_TRUE(isa<BranchInst>(OutlinedBlockBr));7145 7146  auto *OutlinedBlock = OutlinedBlockBr->getSuccessor(0);7147  EXPECT_EQ(OutlinedBlock->getName(), "outlined.body");7148 7149  Instruction *Load2 = &*OutlinedBlock->getFirstNonPHIIt();7150  EXPECT_TRUE(isa<LoadInst>(Load2));7151  EXPECT_EQ(Load2, Value);7152  EXPECT_EQ(Load2->getNextNode(), TargetStore);7153  auto *Deinit = TargetStore->getNextNode();7154  EXPECT_NE(Deinit, nullptr);7155 7156  auto *DeinitCall = dyn_cast<CallInst>(Deinit);7157  EXPECT_NE(DeinitCall, nullptr);7158  EXPECT_EQ(DeinitCall->getCalledFunction()->getName(), "__kmpc_target_deinit");7159  EXPECT_EQ(DeinitCall->arg_size(), 0U);7160 7161  EXPECT_TRUE(isa<ReturnInst>(DeinitCall->getNextNode()));7162 7163  // Check exit block7164  auto *ExitBlock = EntryBlockBranch->getSuccessor(1);7165  EXPECT_EQ(ExitBlock->getName(), "worker.exit");7166  EXPECT_TRUE(isa<ReturnInst>(ExitBlock->getFirstNonPHIIt()));7167}7168 7169TEST_F(OpenMPIRBuilderTest, CreateTask) {7170  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;7171  OpenMPIRBuilder OMPBuilder(*M);7172  OMPBuilder.Config.IsTargetDevice = false;7173  OMPBuilder.initialize();7174  F->setName("func");7175  IRBuilder<> Builder(BB);7176 7177  AllocaInst *ValPtr32 = Builder.CreateAlloca(Builder.getInt32Ty());7178  AllocaInst *ValPtr128 = Builder.CreateAlloca(Builder.getInt128Ty());7179  Value *Val128 =7180      Builder.CreateLoad(Builder.getInt128Ty(), ValPtr128, "bodygen.load");7181 7182  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {7183    Builder.restoreIP(AllocaIP);7184    AllocaInst *Local128 = Builder.CreateAlloca(Builder.getInt128Ty(), nullptr,7185                                                "bodygen.alloca128");7186 7187    Builder.restoreIP(CodeGenIP);7188    // Loading and storing captured pointer and values7189    Builder.CreateStore(Val128, Local128);7190    Value *Val32 = Builder.CreateLoad(ValPtr32->getAllocatedType(), ValPtr32,7191                                      "bodygen.load32");7192 7193    LoadInst *PrivLoad128 = Builder.CreateLoad(7194        Local128->getAllocatedType(), Local128, "bodygen.local.load128");7195    Value *Cmp = Builder.CreateICmpNE(7196        Val32, Builder.CreateTrunc(PrivLoad128, Val32->getType()));7197    Instruction *ThenTerm, *ElseTerm;7198    SplitBlockAndInsertIfThenElse(Cmp, CodeGenIP.getBlock()->getTerminator(),7199                                  &ThenTerm, &ElseTerm);7200    return Error::success();7201  };7202 7203  BasicBlock *AllocaBB = Builder.GetInsertBlock();7204  BasicBlock *BodyBB = splitBB(Builder, /*CreateBranch=*/true, "alloca.split");7205  OpenMPIRBuilder::LocationDescription Loc(7206      InsertPointTy(BodyBB, BodyBB->getFirstInsertionPt()), DL);7207  ASSERT_EXPECTED_INIT(7208      OpenMPIRBuilder::InsertPointTy, AfterIP,7209      OMPBuilder.createTask(7210          Loc, InsertPointTy(AllocaBB, AllocaBB->getFirstInsertionPt()),7211          BodyGenCB));7212  Builder.restoreIP(AfterIP);7213  OMPBuilder.finalize();7214  Builder.CreateRetVoid();7215 7216  EXPECT_FALSE(verifyModule(*M, &errs()));7217 7218  CallInst *TaskAllocCall = dyn_cast<CallInst>(7219      OMPBuilder.getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_omp_task_alloc)7220          ->user_back());7221 7222  // Verify the Ident argument7223  GlobalVariable *Ident = cast<GlobalVariable>(TaskAllocCall->getArgOperand(0));7224  ASSERT_NE(Ident, nullptr);7225  EXPECT_TRUE(Ident->hasInitializer());7226  Constant *Initializer = Ident->getInitializer();7227  GlobalVariable *SrcStrGlob =7228      cast<GlobalVariable>(Initializer->getOperand(4)->stripPointerCasts());7229  ASSERT_NE(SrcStrGlob, nullptr);7230  ConstantDataArray *SrcSrc =7231      dyn_cast<ConstantDataArray>(SrcStrGlob->getInitializer());7232  ASSERT_NE(SrcSrc, nullptr);7233 7234  // Verify the num_threads argument.7235  CallInst *GTID = dyn_cast<CallInst>(TaskAllocCall->getArgOperand(1));7236  ASSERT_NE(GTID, nullptr);7237  EXPECT_EQ(GTID->arg_size(), 1U);7238  EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num");7239 7240  // Verify the flags7241  // TODO: Check for others flags. Currently testing only for tiedness.7242  ConstantInt *Flags = dyn_cast<ConstantInt>(TaskAllocCall->getArgOperand(2));7243  ASSERT_NE(Flags, nullptr);7244  EXPECT_EQ(Flags->getSExtValue(), 1);7245 7246  // Verify the data size7247  ConstantInt *DataSize =7248      dyn_cast<ConstantInt>(TaskAllocCall->getArgOperand(3));7249  ASSERT_NE(DataSize, nullptr);7250  EXPECT_EQ(DataSize->getSExtValue(), 40);7251 7252  ConstantInt *SharedsSize =7253      dyn_cast<ConstantInt>(TaskAllocCall->getOperand(4));7254  EXPECT_EQ(SharedsSize->getSExtValue(),7255            24); // 64-bit pointer + 128-bit integer7256 7257  // Verify Wrapper function7258  Function *OutlinedFn =7259      dyn_cast<Function>(TaskAllocCall->getArgOperand(5)->stripPointerCasts());7260  ASSERT_NE(OutlinedFn, nullptr);7261 7262  LoadInst *SharedsLoad = dyn_cast<LoadInst>(OutlinedFn->begin()->begin());7263  ASSERT_NE(SharedsLoad, nullptr);7264  EXPECT_EQ(SharedsLoad->getPointerOperand(), OutlinedFn->getArg(1));7265 7266  EXPECT_FALSE(OutlinedFn->isDeclaration());7267  EXPECT_EQ(OutlinedFn->getArg(0)->getType(), Builder.getInt32Ty());7268 7269  // Verify that the data argument is used only once, and that too in the load7270  // instruction that is then used for accessing shared data.7271  Value *DataPtr = OutlinedFn->getArg(1);7272  EXPECT_TRUE(DataPtr->hasOneUse());7273  EXPECT_TRUE(isa<LoadInst>(DataPtr->uses().begin()->getUser()));7274  Value *Data = DataPtr->uses().begin()->getUser();7275  EXPECT_TRUE(all_of(Data->uses(), [](Use &U) {7276    return isa<GetElementPtrInst>(U.getUser());7277  }));7278 7279  // Verify the presence of `trunc` and `icmp` instructions in Outlined function7280  EXPECT_TRUE(any_of(instructions(OutlinedFn),7281                     [](Instruction &inst) { return isa<TruncInst>(&inst); }));7282  EXPECT_TRUE(any_of(instructions(OutlinedFn),7283                     [](Instruction &inst) { return isa<ICmpInst>(&inst); }));7284 7285  // Verify the execution of the task7286  CallInst *TaskCall = dyn_cast<CallInst>(7287      OMPBuilder.getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_omp_task)7288          ->user_back());7289  ASSERT_NE(TaskCall, nullptr);7290  EXPECT_EQ(TaskCall->getArgOperand(0), Ident);7291  EXPECT_EQ(TaskCall->getArgOperand(1), GTID);7292  EXPECT_EQ(TaskCall->getArgOperand(2), TaskAllocCall);7293 7294  // Verify that the argument data has been copied7295  for (User *in : TaskAllocCall->users()) {7296    if (MemCpyInst *memCpyInst = dyn_cast<MemCpyInst>(in)) {7297      EXPECT_EQ(memCpyInst->getDest(), TaskAllocCall);7298    }7299  }7300}7301 7302TEST_F(OpenMPIRBuilderTest, CreateTaskNoArgs) {7303  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;7304  OpenMPIRBuilder OMPBuilder(*M);7305  OMPBuilder.Config.IsTargetDevice = false;7306  OMPBuilder.initialize();7307  F->setName("func");7308  IRBuilder<> Builder(BB);7309 7310  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {7311    return Error::success();7312  };7313 7314  BasicBlock *AllocaBB = Builder.GetInsertBlock();7315  BasicBlock *BodyBB = splitBB(Builder, /*CreateBranch=*/true, "alloca.split");7316  OpenMPIRBuilder::LocationDescription Loc(7317      InsertPointTy(BodyBB, BodyBB->getFirstInsertionPt()), DL);7318  ASSERT_EXPECTED_INIT(7319      OpenMPIRBuilder::InsertPointTy, AfterIP,7320      OMPBuilder.createTask(7321          Loc, InsertPointTy(AllocaBB, AllocaBB->getFirstInsertionPt()),7322          BodyGenCB));7323  Builder.restoreIP(AfterIP);7324  OMPBuilder.finalize();7325  Builder.CreateRetVoid();7326 7327  EXPECT_FALSE(verifyModule(*M, &errs()));7328 7329  // Check that the outlined function has only one argument.7330  CallInst *TaskAllocCall = dyn_cast<CallInst>(7331      OMPBuilder.getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_omp_task_alloc)7332          ->user_back());7333  Function *OutlinedFn = dyn_cast<Function>(TaskAllocCall->getArgOperand(5));7334  ASSERT_NE(OutlinedFn, nullptr);7335  ASSERT_EQ(OutlinedFn->arg_size(), 1U);7336}7337 7338TEST_F(OpenMPIRBuilderTest, CreateTaskUntied) {7339  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;7340  OpenMPIRBuilder OMPBuilder(*M);7341  OMPBuilder.Config.IsTargetDevice = false;7342  OMPBuilder.initialize();7343  F->setName("func");7344  IRBuilder<> Builder(BB);7345  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {7346    return Error::success();7347  };7348  BasicBlock *AllocaBB = Builder.GetInsertBlock();7349  BasicBlock *BodyBB = splitBB(Builder, /*CreateBranch=*/true, "alloca.split");7350  OpenMPIRBuilder::LocationDescription Loc(7351      InsertPointTy(BodyBB, BodyBB->getFirstInsertionPt()), DL);7352  ASSERT_EXPECTED_INIT(7353      OpenMPIRBuilder::InsertPointTy, AfterIP,7354      OMPBuilder.createTask(7355          Loc, InsertPointTy(AllocaBB, AllocaBB->getFirstInsertionPt()),7356          BodyGenCB,7357          /*Tied=*/false));7358  Builder.restoreIP(AfterIP);7359  OMPBuilder.finalize();7360  Builder.CreateRetVoid();7361 7362  // Check for the `Tied` argument7363  CallInst *TaskAllocCall = dyn_cast<CallInst>(7364      OMPBuilder.getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_omp_task_alloc)7365          ->user_back());7366  ASSERT_NE(TaskAllocCall, nullptr);7367  ConstantInt *Flags = dyn_cast<ConstantInt>(TaskAllocCall->getArgOperand(2));7368  ASSERT_NE(Flags, nullptr);7369  EXPECT_EQ(Flags->getZExtValue() & 1U, 0U);7370 7371  EXPECT_FALSE(verifyModule(*M, &errs()));7372}7373 7374TEST_F(OpenMPIRBuilderTest, CreateTaskDepend) {7375  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;7376  OpenMPIRBuilder OMPBuilder(*M);7377  OMPBuilder.Config.IsTargetDevice = false;7378  OMPBuilder.initialize();7379  F->setName("func");7380  IRBuilder<> Builder(BB);7381  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {7382    return Error::success();7383  };7384  BasicBlock *AllocaBB = Builder.GetInsertBlock();7385  BasicBlock *BodyBB = splitBB(Builder, /*CreateBranch=*/true, "alloca.split");7386  OpenMPIRBuilder::LocationDescription Loc(7387      InsertPointTy(BodyBB, BodyBB->getFirstInsertionPt()), DL);7388  AllocaInst *InDep = Builder.CreateAlloca(Type::getInt32Ty(M->getContext()));7389  SmallVector<OpenMPIRBuilder::DependData> DDS;7390  {7391    OpenMPIRBuilder::DependData DDIn(RTLDependenceKindTy::DepIn,7392                                     Type::getInt32Ty(M->getContext()), InDep);7393    DDS.push_back(DDIn);7394  }7395  ASSERT_EXPECTED_INIT(7396      OpenMPIRBuilder::InsertPointTy, AfterIP,7397      OMPBuilder.createTask(7398          Loc, InsertPointTy(AllocaBB, AllocaBB->getFirstInsertionPt()),7399          BodyGenCB,7400          /*Tied=*/false, /*Final*/ nullptr, /*IfCondition*/ nullptr, DDS));7401  Builder.restoreIP(AfterIP);7402  OMPBuilder.finalize();7403  Builder.CreateRetVoid();7404 7405  // Check for the `NumDeps` argument7406  CallInst *TaskAllocCall = dyn_cast<CallInst>(7407      OMPBuilder7408          .getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_omp_task_with_deps)7409          ->user_back());7410  ASSERT_NE(TaskAllocCall, nullptr);7411  ConstantInt *NumDeps = dyn_cast<ConstantInt>(TaskAllocCall->getArgOperand(3));7412  ASSERT_NE(NumDeps, nullptr);7413  EXPECT_EQ(NumDeps->getZExtValue(), 1U);7414 7415  // Check for the `DepInfo` array argument7416  AllocaInst *DepArray = dyn_cast<AllocaInst>(TaskAllocCall->getOperand(4));7417  ASSERT_NE(DepArray, nullptr);7418  Value::user_iterator DepArrayI = DepArray->user_begin();7419  ++DepArrayI;7420  Value::user_iterator DepInfoI = DepArrayI->user_begin();7421  // Check for the `DependKind` flag in the `DepInfo` array7422  Value *Flag = findStoredValue<GetElementPtrInst>(*DepInfoI);7423  ASSERT_NE(Flag, nullptr);7424  ConstantInt *FlagInt = dyn_cast<ConstantInt>(Flag);7425  ASSERT_NE(FlagInt, nullptr);7426  EXPECT_EQ(FlagInt->getZExtValue(),7427            static_cast<unsigned int>(RTLDependenceKindTy::DepIn));7428  ++DepInfoI;7429  // Check for the size in the `DepInfo` array7430  Value *Size = findStoredValue<GetElementPtrInst>(*DepInfoI);7431  ASSERT_NE(Size, nullptr);7432  ConstantInt *SizeInt = dyn_cast<ConstantInt>(Size);7433  ASSERT_NE(SizeInt, nullptr);7434  EXPECT_EQ(SizeInt->getZExtValue(), 4U);7435  ++DepInfoI;7436  // Check for the variable address in the `DepInfo` array7437  Value *AddrStored = findStoredValue<GetElementPtrInst>(*DepInfoI);7438  ASSERT_NE(AddrStored, nullptr);7439  PtrToIntInst *AddrInt = dyn_cast<PtrToIntInst>(AddrStored);7440  ASSERT_NE(AddrInt, nullptr);7441  Value *Addr = AddrInt->getPointerOperand();7442  EXPECT_EQ(Addr, InDep);7443 7444  ConstantInt *NumDepsNoAlias =7445      dyn_cast<ConstantInt>(TaskAllocCall->getArgOperand(5));7446  ASSERT_NE(NumDepsNoAlias, nullptr);7447  EXPECT_EQ(NumDepsNoAlias->getZExtValue(), 0U);7448  EXPECT_EQ(TaskAllocCall->getOperand(6),7449            ConstantPointerNull::get(PointerType::getUnqual(M->getContext())));7450 7451  EXPECT_FALSE(verifyModule(*M, &errs()));7452}7453 7454TEST_F(OpenMPIRBuilderTest, CreateTaskFinal) {7455  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;7456  OpenMPIRBuilder OMPBuilder(*M);7457  OMPBuilder.Config.IsTargetDevice = false;7458  OMPBuilder.initialize();7459  F->setName("func");7460  IRBuilder<> Builder(BB);7461  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {7462    return Error::success();7463  };7464  BasicBlock *BodyBB = splitBB(Builder, /*CreateBranch=*/true, "alloca.split");7465  IRBuilderBase::InsertPoint AllocaIP = Builder.saveIP();7466  Builder.SetInsertPoint(BodyBB);7467  Value *Final = Builder.CreateICmp(7468      CmpInst::Predicate::ICMP_EQ, F->getArg(0),7469      ConstantInt::get(Type::getInt32Ty(M->getContext()), 0U));7470  OpenMPIRBuilder::LocationDescription Loc(Builder.saveIP(), DL);7471  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,7472                       OMPBuilder.createTask(Loc, AllocaIP, BodyGenCB,7473                                             /*Tied=*/false, Final));7474  Builder.restoreIP(AfterIP);7475  OMPBuilder.finalize();7476  Builder.CreateRetVoid();7477 7478  // Check for the `Tied` argument7479  CallInst *TaskAllocCall = dyn_cast<CallInst>(7480      OMPBuilder.getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_omp_task_alloc)7481          ->user_back());7482  ASSERT_NE(TaskAllocCall, nullptr);7483  BinaryOperator *OrInst =7484      dyn_cast<BinaryOperator>(TaskAllocCall->getArgOperand(2));7485  ASSERT_NE(OrInst, nullptr);7486  EXPECT_EQ(OrInst->getOpcode(), BinaryOperator::BinaryOps::Or);7487 7488  // One of the arguments to `or` instruction is the tied flag, which is equal7489  // to zero.7490  EXPECT_TRUE(any_of(OrInst->operands(), [](Value *op) {7491    if (ConstantInt *TiedValue = dyn_cast<ConstantInt>(op))7492      return TiedValue->getSExtValue() == 0;7493    return false;7494  }));7495 7496  // One of the arguments to `or` instruction is the final condition.7497  EXPECT_TRUE(any_of(OrInst->operands(), [Final](Value *op) {7498    if (SelectInst *Select = dyn_cast<SelectInst>(op)) {7499      ConstantInt *TrueValue = dyn_cast<ConstantInt>(Select->getTrueValue());7500      ConstantInt *FalseValue = dyn_cast<ConstantInt>(Select->getFalseValue());7501      if (!TrueValue || !FalseValue)7502        return false;7503      return Select->getCondition() == Final &&7504             TrueValue->getSExtValue() == 2 && FalseValue->getSExtValue() == 0;7505    }7506    return false;7507  }));7508 7509  EXPECT_FALSE(verifyModule(*M, &errs()));7510}7511 7512TEST_F(OpenMPIRBuilderTest, CreateTaskIfCondition) {7513  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;7514  OpenMPIRBuilder OMPBuilder(*M);7515  OMPBuilder.Config.IsTargetDevice = false;7516  OMPBuilder.initialize();7517  F->setName("func");7518  IRBuilder<> Builder(BB);7519  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {7520    return Error::success();7521  };7522  BasicBlock *BodyBB = splitBB(Builder, /*CreateBranch=*/true, "alloca.split");7523  IRBuilderBase::InsertPoint AllocaIP = Builder.saveIP();7524  Builder.SetInsertPoint(BodyBB);7525  Value *IfCondition = Builder.CreateICmp(7526      CmpInst::Predicate::ICMP_EQ, F->getArg(0),7527      ConstantInt::get(Type::getInt32Ty(M->getContext()), 0U));7528  OpenMPIRBuilder::LocationDescription Loc(Builder.saveIP(), DL);7529  ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, AfterIP,7530                       OMPBuilder.createTask(Loc, AllocaIP, BodyGenCB,7531                                             /*Tied=*/false, /*Final=*/nullptr,7532                                             IfCondition));7533  Builder.restoreIP(AfterIP);7534  OMPBuilder.finalize();7535  Builder.CreateRetVoid();7536 7537  EXPECT_FALSE(verifyModule(*M, &errs()));7538 7539  CallInst *TaskAllocCall = dyn_cast<CallInst>(7540      OMPBuilder.getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_omp_task_alloc)7541          ->user_back());7542  ASSERT_NE(TaskAllocCall, nullptr);7543 7544  // Check the branching is based on the if condition argument.7545  BranchInst *IfConditionBranchInst =7546      dyn_cast<BranchInst>(TaskAllocCall->getParent()->getTerminator());7547  ASSERT_NE(IfConditionBranchInst, nullptr);7548  ASSERT_TRUE(IfConditionBranchInst->isConditional());7549  EXPECT_EQ(IfConditionBranchInst->getCondition(), IfCondition);7550 7551  // Check that the `__kmpc_omp_task` executes only in the then branch.7552  CallInst *TaskCall = dyn_cast<CallInst>(7553      OMPBuilder.getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_omp_task)7554          ->user_back());7555  ASSERT_NE(TaskCall, nullptr);7556  EXPECT_EQ(TaskCall->getParent(), IfConditionBranchInst->getSuccessor(0));7557 7558  // Check that the OpenMP Runtime Functions specific to `if` clause execute7559  // only in the else branch. Also check that the function call is between the7560  // `__kmpc_omp_task_begin_if0` and `__kmpc_omp_task_complete_if0` calls.7561  CallInst *TaskBeginIfCall = dyn_cast<CallInst>(7562      OMPBuilder7563          .getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_omp_task_begin_if0)7564          ->user_back());7565  CallInst *TaskCompleteCall = dyn_cast<CallInst>(7566      OMPBuilder7567          .getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_omp_task_complete_if0)7568          ->user_back());7569  ASSERT_NE(TaskBeginIfCall, nullptr);7570  ASSERT_NE(TaskCompleteCall, nullptr);7571  Function *OulinedFn =7572      dyn_cast<Function>(TaskAllocCall->getArgOperand(5)->stripPointerCasts());7573  ASSERT_NE(OulinedFn, nullptr);7574  CallInst *OulinedFnCall = dyn_cast<CallInst>(OulinedFn->user_back());7575  ASSERT_NE(OulinedFnCall, nullptr);7576  EXPECT_EQ(TaskBeginIfCall->getParent(),7577            IfConditionBranchInst->getSuccessor(1));7578 7579  EXPECT_EQ(TaskBeginIfCall->getNextNode(), OulinedFnCall);7580  EXPECT_EQ(OulinedFnCall->getNextNode(), TaskCompleteCall);7581}7582 7583TEST_F(OpenMPIRBuilderTest, CreateTaskgroup) {7584  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;7585  OpenMPIRBuilder OMPBuilder(*M);7586  OMPBuilder.initialize();7587  F->setName("func");7588  IRBuilder<> Builder(BB);7589 7590  AllocaInst *ValPtr32 = Builder.CreateAlloca(Builder.getInt32Ty());7591  AllocaInst *ValPtr128 = Builder.CreateAlloca(Builder.getInt128Ty());7592  Value *Val128 =7593      Builder.CreateLoad(Builder.getInt128Ty(), ValPtr128, "bodygen.load");7594  Instruction *ThenTerm, *ElseTerm;7595 7596  Value *InternalStoreInst, *InternalLoad32, *InternalLoad128, *InternalIfCmp;7597 7598  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {7599    Builder.restoreIP(AllocaIP);7600    AllocaInst *Local128 = Builder.CreateAlloca(Builder.getInt128Ty(), nullptr,7601                                                "bodygen.alloca128");7602 7603    Builder.restoreIP(CodeGenIP);7604    // Loading and storing captured pointer and values7605    InternalStoreInst = Builder.CreateStore(Val128, Local128);7606    InternalLoad32 = Builder.CreateLoad(ValPtr32->getAllocatedType(), ValPtr32,7607                                        "bodygen.load32");7608 7609    InternalLoad128 = Builder.CreateLoad(Local128->getAllocatedType(), Local128,7610                                         "bodygen.local.load128");7611    InternalIfCmp = Builder.CreateICmpNE(7612        InternalLoad32,7613        Builder.CreateTrunc(InternalLoad128, InternalLoad32->getType()));7614    SplitBlockAndInsertIfThenElse(InternalIfCmp,7615                                  CodeGenIP.getBlock()->getTerminator(),7616                                  &ThenTerm, &ElseTerm);7617    return Error::success();7618  };7619 7620  BasicBlock *AllocaBB = Builder.GetInsertBlock();7621  BasicBlock *BodyBB = splitBB(Builder, /*CreateBranch=*/true, "alloca.split");7622  OpenMPIRBuilder::LocationDescription Loc(7623      InsertPointTy(BodyBB, BodyBB->getFirstInsertionPt()), DL);7624  ASSERT_EXPECTED_INIT(7625      OpenMPIRBuilder::InsertPointTy, AfterIP,7626      OMPBuilder.createTaskgroup(7627          Loc, InsertPointTy(AllocaBB, AllocaBB->getFirstInsertionPt()),7628          BodyGenCB));7629  Builder.restoreIP(AfterIP);7630  OMPBuilder.finalize();7631  Builder.CreateRetVoid();7632 7633  EXPECT_FALSE(verifyModule(*M, &errs()));7634 7635  CallInst *TaskgroupCall = dyn_cast<CallInst>(7636      OMPBuilder.getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_taskgroup)7637          ->user_back());7638  ASSERT_NE(TaskgroupCall, nullptr);7639  CallInst *EndTaskgroupCall = dyn_cast<CallInst>(7640      OMPBuilder.getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_end_taskgroup)7641          ->user_back());7642  ASSERT_NE(EndTaskgroupCall, nullptr);7643 7644  // Verify the Ident argument7645  GlobalVariable *Ident = cast<GlobalVariable>(TaskgroupCall->getArgOperand(0));7646  ASSERT_NE(Ident, nullptr);7647  EXPECT_TRUE(Ident->hasInitializer());7648  Constant *Initializer = Ident->getInitializer();7649  GlobalVariable *SrcStrGlob =7650      cast<GlobalVariable>(Initializer->getOperand(4)->stripPointerCasts());7651  ASSERT_NE(SrcStrGlob, nullptr);7652  ConstantDataArray *SrcSrc =7653      dyn_cast<ConstantDataArray>(SrcStrGlob->getInitializer());7654  ASSERT_NE(SrcSrc, nullptr);7655 7656  // Verify the num_threads argument.7657  CallInst *GTID = dyn_cast<CallInst>(TaskgroupCall->getArgOperand(1));7658  ASSERT_NE(GTID, nullptr);7659  EXPECT_EQ(GTID->arg_size(), 1U);7660  EXPECT_EQ(GTID->getCalledFunction(), OMPBuilder.getOrCreateRuntimeFunctionPtr(7661                                           OMPRTL___kmpc_global_thread_num));7662 7663  // Checking the general structure of the IR generated is same as expected.7664  Instruction *GeneratedStoreInst = TaskgroupCall->getNextNode();7665  EXPECT_EQ(GeneratedStoreInst, InternalStoreInst);7666  Instruction *GeneratedLoad32 = GeneratedStoreInst->getNextNode();7667  EXPECT_EQ(GeneratedLoad32, InternalLoad32);7668  Instruction *GeneratedLoad128 = GeneratedLoad32->getNextNode();7669  EXPECT_EQ(GeneratedLoad128, InternalLoad128);7670 7671  // Checking the ordering because of the if statements and that7672  // `__kmp_end_taskgroup` call is after the if branching.7673  BasicBlock *RefOrder[] = {TaskgroupCall->getParent(), ThenTerm->getParent(),7674                            ThenTerm->getSuccessor(0),7675                            EndTaskgroupCall->getParent(),7676                            ElseTerm->getParent()};7677  verifyDFSOrder(F, RefOrder);7678}7679 7680TEST_F(OpenMPIRBuilderTest, CreateTaskgroupWithTasks) {7681  using InsertPointTy = OpenMPIRBuilder::InsertPointTy;7682  OpenMPIRBuilder OMPBuilder(*M);7683  OMPBuilder.Config.IsTargetDevice = false;7684  OMPBuilder.initialize();7685  F->setName("func");7686  IRBuilder<> Builder(BB);7687 7688  auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {7689    Builder.restoreIP(AllocaIP);7690    AllocaInst *Alloca32 =7691        Builder.CreateAlloca(Builder.getInt32Ty(), nullptr, "bodygen.alloca32");7692    AllocaInst *Alloca64 =7693        Builder.CreateAlloca(Builder.getInt64Ty(), nullptr, "bodygen.alloca64");7694    Builder.restoreIP(CodeGenIP);7695    auto TaskBodyGenCB1 = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {7696      Builder.restoreIP(CodeGenIP);7697      LoadInst *LoadValue =7698          Builder.CreateLoad(Alloca64->getAllocatedType(), Alloca64);7699      Value *AddInst = Builder.CreateAdd(LoadValue, Builder.getInt64(64));7700      Builder.CreateStore(AddInst, Alloca64);7701      return Error::success();7702    };7703    OpenMPIRBuilder::LocationDescription Loc(Builder.saveIP(), DL);7704    ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, TaskIP1,7705                         OMPBuilder.createTask(Loc, AllocaIP, TaskBodyGenCB1));7706    Builder.restoreIP(TaskIP1);7707 7708    auto TaskBodyGenCB2 = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {7709      Builder.restoreIP(CodeGenIP);7710      LoadInst *LoadValue =7711          Builder.CreateLoad(Alloca32->getAllocatedType(), Alloca32);7712      Value *AddInst = Builder.CreateAdd(LoadValue, Builder.getInt32(32));7713      Builder.CreateStore(AddInst, Alloca32);7714      return Error::success();7715    };7716    OpenMPIRBuilder::LocationDescription Loc2(Builder.saveIP(), DL);7717    ASSERT_EXPECTED_INIT(OpenMPIRBuilder::InsertPointTy, TaskIP2,7718                         OMPBuilder.createTask(Loc2, AllocaIP, TaskBodyGenCB2));7719    Builder.restoreIP(TaskIP2);7720  };7721 7722  BasicBlock *AllocaBB = Builder.GetInsertBlock();7723  BasicBlock *BodyBB = splitBB(Builder, /*CreateBranch=*/true, "alloca.split");7724  OpenMPIRBuilder::LocationDescription Loc(7725      InsertPointTy(BodyBB, BodyBB->getFirstInsertionPt()), DL);7726  ASSERT_EXPECTED_INIT(7727      OpenMPIRBuilder::InsertPointTy, AfterIP,7728      OMPBuilder.createTaskgroup(7729          Loc, InsertPointTy(AllocaBB, AllocaBB->getFirstInsertionPt()),7730          BODYGENCB_WRAPPER(BodyGenCB)));7731  Builder.restoreIP(AfterIP);7732  OMPBuilder.finalize();7733  Builder.CreateRetVoid();7734 7735  EXPECT_FALSE(verifyModule(*M, &errs()));7736 7737  CallInst *TaskgroupCall = dyn_cast<CallInst>(7738      OMPBuilder.getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_taskgroup)7739          ->user_back());7740  ASSERT_NE(TaskgroupCall, nullptr);7741  CallInst *EndTaskgroupCall = dyn_cast<CallInst>(7742      OMPBuilder.getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_end_taskgroup)7743          ->user_back());7744  ASSERT_NE(EndTaskgroupCall, nullptr);7745 7746  Function *TaskAllocFn =7747      OMPBuilder.getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_omp_task_alloc);7748  ASSERT_TRUE(TaskAllocFn->hasNUses(2));7749 7750  CallInst *FirstTaskAllocCall =7751      dyn_cast_or_null<CallInst>(*TaskAllocFn->users().begin());7752  CallInst *SecondTaskAllocCall =7753      dyn_cast_or_null<CallInst>(*TaskAllocFn->users().begin()++);7754  ASSERT_NE(FirstTaskAllocCall, nullptr);7755  ASSERT_NE(SecondTaskAllocCall, nullptr);7756 7757  // Verify that the tasks have been generated in order and inside taskgroup7758  // construct.7759  BasicBlock *RefOrder[] = {7760      TaskgroupCall->getParent(), FirstTaskAllocCall->getParent(),7761      SecondTaskAllocCall->getParent(), EndTaskgroupCall->getParent()};7762  verifyDFSOrder(F, RefOrder);7763}7764 7765TEST_F(OpenMPIRBuilderTest, EmitOffloadingArraysArguments) {7766  OpenMPIRBuilder OMPBuilder(*M);7767  OMPBuilder.initialize();7768 7769  IRBuilder<> Builder(BB);7770 7771  OpenMPIRBuilder::TargetDataRTArgs RTArgs;7772  OpenMPIRBuilder::TargetDataInfo Info(true, false);7773 7774  auto VoidPtrPtrTy = PointerType::getUnqual(Builder.getContext());7775  auto Int64PtrTy = PointerType::getUnqual(Builder.getContext());7776 7777  Info.RTArgs.BasePointersArray = ConstantPointerNull::get(Builder.getPtrTy(0));7778  Info.RTArgs.PointersArray = ConstantPointerNull::get(Builder.getPtrTy(0));7779  Info.RTArgs.SizesArray = ConstantPointerNull::get(Builder.getPtrTy(0));7780  Info.RTArgs.MapTypesArray = ConstantPointerNull::get(Builder.getPtrTy(0));7781  Info.RTArgs.MapNamesArray = ConstantPointerNull::get(Builder.getPtrTy(0));7782  Info.RTArgs.MappersArray = ConstantPointerNull::get(Builder.getPtrTy(0));7783  Info.NumberOfPtrs = 4;7784  Info.EmitDebug = false;7785  OMPBuilder.emitOffloadingArraysArgument(Builder, RTArgs, Info, false);7786 7787  EXPECT_NE(RTArgs.BasePointersArray, nullptr);7788  EXPECT_NE(RTArgs.PointersArray, nullptr);7789  EXPECT_NE(RTArgs.SizesArray, nullptr);7790  EXPECT_NE(RTArgs.MapTypesArray, nullptr);7791  EXPECT_NE(RTArgs.MappersArray, nullptr);7792  EXPECT_NE(RTArgs.MapNamesArray, nullptr);7793  EXPECT_EQ(RTArgs.MapTypesArrayEnd, nullptr);7794 7795  EXPECT_EQ(RTArgs.BasePointersArray->getType(), VoidPtrPtrTy);7796  EXPECT_EQ(RTArgs.PointersArray->getType(), VoidPtrPtrTy);7797  EXPECT_EQ(RTArgs.SizesArray->getType(), Int64PtrTy);7798  EXPECT_EQ(RTArgs.MapTypesArray->getType(), Int64PtrTy);7799  EXPECT_EQ(RTArgs.MappersArray->getType(), VoidPtrPtrTy);7800  EXPECT_EQ(RTArgs.MapNamesArray->getType(), VoidPtrPtrTy);7801}7802 7803TEST_F(OpenMPIRBuilderTest, OffloadEntriesInfoManager) {7804  OpenMPIRBuilder OMPBuilder(*M);7805  OMPBuilder.setConfig(7806      OpenMPIRBuilderConfig(true, false, false, false, false, false, false));7807  OffloadEntriesInfoManager &InfoManager = OMPBuilder.OffloadInfoManager;7808  TargetRegionEntryInfo EntryInfo("parent", 1, 2, 4, 0);7809  InfoManager.initializeTargetRegionEntryInfo(EntryInfo, 0);7810  EXPECT_TRUE(InfoManager.hasTargetRegionEntryInfo(EntryInfo));7811  InfoManager.initializeDeviceGlobalVarEntryInfo(7812      "gvar", OffloadEntriesInfoManager::OMPTargetGlobalVarEntryTo, 0);7813  InfoManager.registerTargetRegionEntryInfo(7814      EntryInfo, nullptr, nullptr,7815      OffloadEntriesInfoManager::OMPTargetRegionEntryTargetRegion);7816  InfoManager.registerDeviceGlobalVarEntryInfo(7817      "gvar", 0x0, 8, OffloadEntriesInfoManager::OMPTargetGlobalVarEntryTo,7818      GlobalValue::WeakAnyLinkage);7819  EXPECT_TRUE(InfoManager.hasDeviceGlobalVarEntryInfo("gvar"));7820}7821 7822// Tests both registerTargetGlobalVariable and getAddrOfDeclareTargetVar as they7823// call each other (recursively in some cases). The test case test these7824// functions by utilising them for host code generation for declare target7825// global variables7826TEST_F(OpenMPIRBuilderTest, registerTargetGlobalVariable) {7827  OpenMPIRBuilder OMPBuilder(*M);7828  OMPBuilder.initialize();7829  OpenMPIRBuilderConfig Config(false, false, false, false, false, false, false);7830  OMPBuilder.setConfig(Config);7831 7832  std::vector<llvm::Triple> TargetTriple;7833  TargetTriple.emplace_back("amdgcn-amd-amdhsa");7834 7835  TargetRegionEntryInfo EntryInfo("", 42, 4711, 17);7836  std::vector<GlobalVariable *> RefsGathered;7837 7838  std::vector<Constant *> Globals;7839  auto *IntTy = Type::getInt32Ty(Ctx);7840  for (int I = 0; I < 2; ++I) {7841    Globals.push_back(M->getOrInsertGlobal(7842        "test_data_int_" + std::to_string(I), IntTy, [&]() -> GlobalVariable * {7843          return new GlobalVariable(7844              *M, IntTy, false, GlobalValue::LinkageTypes::WeakAnyLinkage,7845              ConstantInt::get(IntTy, I), "test_data_int_" + std::to_string(I));7846        }));7847  }7848 7849  OMPBuilder.registerTargetGlobalVariable(7850      OffloadEntriesInfoManager::OMPTargetGlobalVarEntryTo,7851      OffloadEntriesInfoManager::OMPTargetDeviceClauseAny, false, true,7852      EntryInfo, Globals[0]->getName(), RefsGathered, false, TargetTriple,7853      nullptr, nullptr, Globals[0]->getType(), Globals[0]);7854 7855  OMPBuilder.registerTargetGlobalVariable(7856      OffloadEntriesInfoManager::OMPTargetGlobalVarEntryLink,7857      OffloadEntriesInfoManager::OMPTargetDeviceClauseAny, false, true,7858      EntryInfo, Globals[1]->getName(), RefsGathered, false, TargetTriple,7859      nullptr, nullptr, Globals[1]->getType(), Globals[1]);7860 7861  llvm::OpenMPIRBuilder::EmitMetadataErrorReportFunctionTy &&ErrorReportfn =7862      [](llvm::OpenMPIRBuilder::EmitMetadataErrorKind Kind,7863         const llvm::TargetRegionEntryInfo &EntryInfo) -> void {7864    // If this is invoked, then we want to emit an error, even if it is not7865    // neccesarily the most readable, as something has went wrong. The7866    // test-suite unfortunately eats up all error output7867    ASSERT_EQ(Kind, Kind);7868  };7869 7870  OMPBuilder.createOffloadEntriesAndInfoMetadata(ErrorReportfn);7871 7872  // Clauses for data_int_0 with To + Any clauses for the host7873  std::vector<GlobalVariable *> OffloadEntries;7874  OffloadEntries.push_back(M->getNamedGlobal(".offloading.entry_name"));7875  OffloadEntries.push_back(7876      M->getNamedGlobal(".offloading.entry.test_data_int_0"));7877 7878  // Clauses for data_int_1 with Link + Any clauses for the host7879  OffloadEntries.push_back(7880      M->getNamedGlobal("test_data_int_1_decl_tgt_ref_ptr"));7881  OffloadEntries.push_back(M->getNamedGlobal(".offloading.entry_name.1"));7882  OffloadEntries.push_back(7883      M->getNamedGlobal(".offloading.entry.test_data_int_1_decl_tgt_ref_ptr"));7884 7885  for (unsigned I = 0; I < OffloadEntries.size(); ++I)7886    EXPECT_NE(OffloadEntries[I], nullptr);7887 7888  // Metadata generated for the host offload module7889  NamedMDNode *OffloadMetadata = M->getNamedMetadata("omp_offload.info");7890  ASSERT_THAT(OffloadMetadata, testing::NotNull());7891  StringRef Nodes[2] = {7892      cast<MDString>(OffloadMetadata->getOperand(0)->getOperand(1))7893          ->getString(),7894      cast<MDString>(OffloadMetadata->getOperand(1)->getOperand(1))7895          ->getString()};7896  EXPECT_THAT(7897      Nodes, testing::UnorderedElementsAre("test_data_int_0",7898                                           "test_data_int_1_decl_tgt_ref_ptr"));7899}7900 7901TEST_F(OpenMPIRBuilderTest, createGPUOffloadEntry) {7902  OpenMPIRBuilder OMPBuilder(*M);7903  OMPBuilder.initialize();7904  OpenMPIRBuilderConfig Config(/* IsTargetDevice = */ true,7905                               /* IsGPU = */ true,7906                               /* OpenMPOffloadMandatory = */ false,7907                               /* HasRequiresReverseOffload = */ false,7908                               /* HasRequiresUnifiedAddress = */ false,7909                               /* HasRequiresUnifiedSharedMemory = */ false,7910                               /* HasRequiresDynamicAllocators = */ false);7911  OMPBuilder.setConfig(Config);7912 7913  FunctionCallee FnTypeAndCallee =7914      M->getOrInsertFunction("test_kernel", Type::getVoidTy(Ctx));7915 7916  auto *Fn = cast<Function>(FnTypeAndCallee.getCallee());7917  OMPBuilder.createOffloadEntry(/* ID = */ nullptr, Fn,7918                                /* Size = */ 0,7919                                /* Flags = */ 0, GlobalValue::WeakAnyLinkage);7920 7921  // Check kernel attributes7922  EXPECT_TRUE(Fn->hasFnAttribute("kernel"));7923  EXPECT_TRUE(Fn->hasFnAttribute(Attribute::MustProgress));7924}7925 7926TEST_F(OpenMPIRBuilderTest, splitBB) {7927  OpenMPIRBuilder OMPBuilder(*M);7928  OMPBuilder.Config.IsTargetDevice = false;7929  OMPBuilder.initialize();7930  F->setName("func");7931  IRBuilder<> Builder(BB);7932 7933  Builder.SetCurrentDebugLocation(DL);7934  AllocaInst *alloc = Builder.CreateAlloca(Builder.getInt32Ty());7935  EXPECT_TRUE(DL == alloc->getStableDebugLoc());7936  BasicBlock *AllocaBB = Builder.GetInsertBlock();7937  splitBB(Builder, /*CreateBranch=*/true, "test");7938  if (AllocaBB->getTerminator())7939    EXPECT_TRUE(DL == AllocaBB->getTerminator()->getStableDebugLoc());7940}7941 7942TEST_F(OpenMPIRBuilderTest, spliceBBWithEmptyBB) {7943  OpenMPIRBuilder OMPBuilder(*M);7944  OMPBuilder.Config.IsTargetDevice = false;7945  OMPBuilder.initialize();7946  F->setName("func");7947  IRBuilder<> Builder(BB);7948 7949  // Test calling spliceBB with an empty Block (but having trailing debug7950  // records).7951  DIBuilder DIB(*M);7952  DISubprogram *SP = F->getSubprogram();7953  DIType *VoidPtrTy =7954      DIB.createQualifiedType(dwarf::DW_TAG_pointer_type, nullptr);7955  DILocalVariable *Var = DIB.createParameterVariable(7956      SP, "test", /*ArgNo*/ 1, SP->getFile(), /*LineNo=*/0, VoidPtrTy);7957  DIB.insertDeclare(F->getArg(0), Var, DIB.createExpression(), DL,7958                    Builder.GetInsertPoint());7959  BasicBlock *New = BasicBlock::Create(Ctx, "", F);7960  spliceBB(Builder.saveIP(), New, true, DL);7961  Instruction *Terminator = BB->getTerminator();7962  EXPECT_NE(Terminator, nullptr);7963  EXPECT_FALSE(Terminator->getDbgRecordRange().empty());7964}7965 7966} // namespace7967