Changeset View
Changeset View
Standalone View
Standalone View
llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
//===- llvm/unittest/IR/OpenMPIRBuilderTest.cpp - OpenMPIRBuilder tests ---===// | //===- llvm/unittest/IR/OpenMPIRBuilderTest.cpp - OpenMPIRBuilder tests ---===// | ||||
// | // | ||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||
// See https://llvm.org/LICENSE.txt for license information. | // See https://llvm.org/LICENSE.txt for license information. | ||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||
// | // | ||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||
#include "llvm/Frontend/OpenMP/OMPConstants.h" | |||||
#include "llvm/Frontend/OpenMP/OMPIRBuilder.h" | #include "llvm/Frontend/OpenMP/OMPIRBuilder.h" | ||||
#include "llvm/IR/BasicBlock.h" | #include "llvm/IR/BasicBlock.h" | ||||
#include "llvm/IR/DIBuilder.h" | #include "llvm/IR/DIBuilder.h" | ||||
#include "llvm/IR/Function.h" | #include "llvm/IR/Function.h" | ||||
#include "llvm/IR/InstIterator.h" | |||||
#include "llvm/IR/LLVMContext.h" | #include "llvm/IR/LLVMContext.h" | ||||
#include "llvm/IR/Module.h" | #include "llvm/IR/Module.h" | ||||
#include "llvm/Frontend/OpenMP/OMPConstants.h" | |||||
#include "llvm/IR/Verifier.h" | #include "llvm/IR/Verifier.h" | ||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h" | #include "llvm/Transforms/Utils/BasicBlockUtils.h" | ||||
#include "gtest/gtest.h" | #include "gtest/gtest.h" | ||||
using namespace llvm; | using namespace llvm; | ||||
using namespace omp; | using namespace omp; | ||||
namespace { | namespace { | ||||
▲ Show 20 Lines • Show All 331 Lines • ▼ Show 20 Lines | auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, | ||||
ReplacementValue = Builder.CreateAlloca(VTy, 0, VPtr.getName() + ".copy"); | ReplacementValue = Builder.CreateAlloca(VTy, 0, VPtr.getName() + ".copy"); | ||||
Builder.restoreIP(CodeGenIP); | Builder.restoreIP(CodeGenIP); | ||||
Builder.CreateStore(V, ReplacementValue); | Builder.CreateStore(V, ReplacementValue); | ||||
return CodeGenIP; | return CodeGenIP; | ||||
}; | }; | ||||
auto FiniCB = [&](InsertPointTy CodeGenIP) { ++NumFinalizationPoints; }; | auto FiniCB = [&](InsertPointTy CodeGenIP) { ++NumFinalizationPoints; }; | ||||
IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), | |||||
F->getEntryBlock().getFirstInsertionPt()); | |||||
IRBuilder<>::InsertPoint AfterIP = | IRBuilder<>::InsertPoint AfterIP = | ||||
OMPBuilder.CreateParallel(Loc, BodyGenCB, PrivCB, FiniCB, nullptr, | OMPBuilder.CreateParallel(Loc, AllocaIP, BodyGenCB, PrivCB, FiniCB, | ||||
nullptr, OMP_PROC_BIND_default, false); | nullptr, nullptr, OMP_PROC_BIND_default, false); | ||||
EXPECT_EQ(NumBodiesGenerated, 1U); | EXPECT_EQ(NumBodiesGenerated, 1U); | ||||
EXPECT_EQ(NumPrivatizedVars, 1U); | EXPECT_EQ(NumPrivatizedVars, 1U); | ||||
EXPECT_EQ(NumFinalizationPoints, 1U); | EXPECT_EQ(NumFinalizationPoints, 1U); | ||||
Builder.restoreIP(AfterIP); | Builder.restoreIP(AfterIP); | ||||
Builder.CreateRetVoid(); | Builder.CreateRetVoid(); | ||||
OMPBuilder.finalize(); | OMPBuilder.finalize(); | ||||
Show All 21 Lines | TEST_F(OpenMPIRBuilderTest, ParallelSimple) { | ||||
EXPECT_EQ(ForkCI->getNumArgOperands(), 4U); | EXPECT_EQ(ForkCI->getNumArgOperands(), 4U); | ||||
EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0))); | EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0))); | ||||
EXPECT_EQ(ForkCI->getArgOperand(1), | EXPECT_EQ(ForkCI->getArgOperand(1), | ||||
ConstantInt::get(Type::getInt32Ty(Ctx), 1U)); | ConstantInt::get(Type::getInt32Ty(Ctx), 1U)); | ||||
EXPECT_EQ(ForkCI->getArgOperand(2), Usr); | EXPECT_EQ(ForkCI->getArgOperand(2), Usr); | ||||
EXPECT_EQ(ForkCI->getArgOperand(3), F->arg_begin()); | EXPECT_EQ(ForkCI->getArgOperand(3), F->arg_begin()); | ||||
} | } | ||||
TEST_F(OpenMPIRBuilderTest, ParallelNested) { | |||||
using InsertPointTy = OpenMPIRBuilder::InsertPointTy; | |||||
OpenMPIRBuilder OMPBuilder(*M); | |||||
OMPBuilder.initialize(); | |||||
F->setName("func"); | |||||
IRBuilder<> Builder(BB); | |||||
OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); | |||||
unsigned NumInnerBodiesGenerated = 0; | |||||
unsigned NumOuterBodiesGenerated = 0; | |||||
unsigned NumFinalizationPoints = 0; | |||||
auto InnerBodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, | |||||
BasicBlock &ContinuationIP) { | |||||
++NumInnerBodiesGenerated; | |||||
}; | |||||
auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, | |||||
Value &VPtr, Value *&ReplacementValue) -> InsertPointTy { | |||||
// Trivial copy (=firstprivate). | |||||
Builder.restoreIP(AllocaIP); | |||||
Type *VTy = VPtr.getType()->getPointerElementType(); | |||||
Value *V = Builder.CreateLoad(VTy, &VPtr, VPtr.getName() + ".reload"); | |||||
ReplacementValue = Builder.CreateAlloca(VTy, 0, VPtr.getName() + ".copy"); | |||||
Builder.restoreIP(CodeGenIP); | |||||
Builder.CreateStore(V, ReplacementValue); | |||||
return CodeGenIP; | |||||
}; | |||||
auto FiniCB = [&](InsertPointTy CodeGenIP) { ++NumFinalizationPoints; }; | |||||
auto OuterBodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, | |||||
BasicBlock &ContinuationIP) { | |||||
++NumOuterBodiesGenerated; | |||||
Builder.restoreIP(CodeGenIP); | |||||
BasicBlock *CGBB = CodeGenIP.getBlock(); | |||||
BasicBlock *NewBB = SplitBlock(CGBB, &*CodeGenIP.getPoint()); | |||||
CGBB->getTerminator()->eraseFromParent(); | |||||
; | |||||
IRBuilder<>::InsertPoint AfterIP = OMPBuilder.CreateParallel( | |||||
InsertPointTy(CGBB, CGBB->end()), AllocaIP, InnerBodyGenCB, PrivCB, | |||||
FiniCB, nullptr, nullptr, OMP_PROC_BIND_default, false); | |||||
Builder.restoreIP(AfterIP); | |||||
Builder.CreateBr(NewBB); | |||||
}; | |||||
IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), | |||||
F->getEntryBlock().getFirstInsertionPt()); | |||||
IRBuilder<>::InsertPoint AfterIP = | |||||
OMPBuilder.CreateParallel(Loc, AllocaIP, OuterBodyGenCB, PrivCB, FiniCB, | |||||
nullptr, nullptr, OMP_PROC_BIND_default, false); | |||||
EXPECT_EQ(NumInnerBodiesGenerated, 1U); | |||||
EXPECT_EQ(NumOuterBodiesGenerated, 1U); | |||||
EXPECT_EQ(NumFinalizationPoints, 2U); | |||||
Builder.restoreIP(AfterIP); | |||||
Builder.CreateRetVoid(); | |||||
OMPBuilder.finalize(); | |||||
EXPECT_EQ(M->size(), 5U); | |||||
for (Function &OutlinedFn : *M) { | |||||
if (F == &OutlinedFn || OutlinedFn.isDeclaration()) | |||||
continue; | |||||
EXPECT_FALSE(verifyModule(*M, &errs())); | |||||
EXPECT_TRUE(OutlinedFn.hasFnAttribute(Attribute::NoUnwind)); | |||||
EXPECT_TRUE(OutlinedFn.hasFnAttribute(Attribute::NoRecurse)); | |||||
EXPECT_TRUE(OutlinedFn.hasParamAttribute(0, Attribute::NoAlias)); | |||||
EXPECT_TRUE(OutlinedFn.hasParamAttribute(1, Attribute::NoAlias)); | |||||
EXPECT_TRUE(OutlinedFn.hasInternalLinkage()); | |||||
EXPECT_EQ(OutlinedFn.arg_size(), 2U); | |||||
EXPECT_EQ(OutlinedFn.getNumUses(), 1U); | |||||
User *Usr = OutlinedFn.user_back(); | |||||
ASSERT_TRUE(isa<ConstantExpr>(Usr)); | |||||
CallInst *ForkCI = dyn_cast<CallInst>(Usr->user_back()); | |||||
ASSERT_NE(ForkCI, nullptr); | |||||
EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call"); | |||||
EXPECT_EQ(ForkCI->getNumArgOperands(), 3U); | |||||
EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0))); | |||||
EXPECT_EQ(ForkCI->getArgOperand(1), | |||||
ConstantInt::get(Type::getInt32Ty(Ctx), 0U)); | |||||
EXPECT_EQ(ForkCI->getArgOperand(2), Usr); | |||||
} | |||||
} | |||||
TEST_F(OpenMPIRBuilderTest, ParallelNested2Inner) { | |||||
using InsertPointTy = OpenMPIRBuilder::InsertPointTy; | |||||
OpenMPIRBuilder OMPBuilder(*M); | |||||
OMPBuilder.initialize(); | |||||
F->setName("func"); | |||||
IRBuilder<> Builder(BB); | |||||
OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); | |||||
unsigned NumInnerBodiesGenerated = 0; | |||||
unsigned NumOuterBodiesGenerated = 0; | |||||
unsigned NumFinalizationPoints = 0; | |||||
auto InnerBodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, | |||||
BasicBlock &ContinuationIP) { | |||||
++NumInnerBodiesGenerated; | |||||
}; | |||||
auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, | |||||
Value &VPtr, Value *&ReplacementValue) -> InsertPointTy { | |||||
// Trivial copy (=firstprivate). | |||||
Builder.restoreIP(AllocaIP); | |||||
Type *VTy = VPtr.getType()->getPointerElementType(); | |||||
Value *V = Builder.CreateLoad(VTy, &VPtr, VPtr.getName() + ".reload"); | |||||
ReplacementValue = Builder.CreateAlloca(VTy, 0, VPtr.getName() + ".copy"); | |||||
Builder.restoreIP(CodeGenIP); | |||||
Builder.CreateStore(V, ReplacementValue); | |||||
return CodeGenIP; | |||||
}; | |||||
auto FiniCB = [&](InsertPointTy CodeGenIP) { ++NumFinalizationPoints; }; | |||||
auto OuterBodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, | |||||
BasicBlock &ContinuationIP) { | |||||
++NumOuterBodiesGenerated; | |||||
Builder.restoreIP(CodeGenIP); | |||||
BasicBlock *CGBB = CodeGenIP.getBlock(); | |||||
BasicBlock *NewBB1 = SplitBlock(CGBB, &*CodeGenIP.getPoint()); | |||||
BasicBlock *NewBB2 = SplitBlock(NewBB1, &*NewBB1->getFirstInsertionPt()); | |||||
CGBB->getTerminator()->eraseFromParent(); | |||||
; | |||||
NewBB1->getTerminator()->eraseFromParent(); | |||||
; | |||||
IRBuilder<>::InsertPoint AfterIP1 = OMPBuilder.CreateParallel( | |||||
InsertPointTy(CGBB, CGBB->end()), AllocaIP, InnerBodyGenCB, PrivCB, | |||||
FiniCB, nullptr, nullptr, OMP_PROC_BIND_default, false); | |||||
Builder.restoreIP(AfterIP1); | |||||
Builder.CreateBr(NewBB1); | |||||
IRBuilder<>::InsertPoint AfterIP2 = OMPBuilder.CreateParallel( | |||||
InsertPointTy(NewBB1, NewBB1->end()), AllocaIP, InnerBodyGenCB, PrivCB, | |||||
FiniCB, nullptr, nullptr, OMP_PROC_BIND_default, false); | |||||
Builder.restoreIP(AfterIP2); | |||||
Builder.CreateBr(NewBB2); | |||||
}; | |||||
IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), | |||||
F->getEntryBlock().getFirstInsertionPt()); | |||||
IRBuilder<>::InsertPoint AfterIP = | |||||
OMPBuilder.CreateParallel(Loc, AllocaIP, OuterBodyGenCB, PrivCB, FiniCB, | |||||
nullptr, nullptr, OMP_PROC_BIND_default, false); | |||||
EXPECT_EQ(NumInnerBodiesGenerated, 2U); | |||||
EXPECT_EQ(NumOuterBodiesGenerated, 1U); | |||||
EXPECT_EQ(NumFinalizationPoints, 3U); | |||||
Builder.restoreIP(AfterIP); | |||||
Builder.CreateRetVoid(); | |||||
OMPBuilder.finalize(); | |||||
EXPECT_EQ(M->size(), 6U); | |||||
for (Function &OutlinedFn : *M) { | |||||
if (F == &OutlinedFn || OutlinedFn.isDeclaration()) | |||||
continue; | |||||
EXPECT_FALSE(verifyModule(*M, &errs())); | |||||
EXPECT_TRUE(OutlinedFn.hasFnAttribute(Attribute::NoUnwind)); | |||||
EXPECT_TRUE(OutlinedFn.hasFnAttribute(Attribute::NoRecurse)); | |||||
EXPECT_TRUE(OutlinedFn.hasParamAttribute(0, Attribute::NoAlias)); | |||||
EXPECT_TRUE(OutlinedFn.hasParamAttribute(1, Attribute::NoAlias)); | |||||
EXPECT_TRUE(OutlinedFn.hasInternalLinkage()); | |||||
EXPECT_EQ(OutlinedFn.arg_size(), 2U); | |||||
unsigned NumAllocas = 0; | |||||
for (Instruction &I : instructions(OutlinedFn)) | |||||
NumAllocas += isa<AllocaInst>(I); | |||||
EXPECT_EQ(NumAllocas, 1U); | |||||
EXPECT_EQ(OutlinedFn.getNumUses(), 1U); | |||||
User *Usr = OutlinedFn.user_back(); | |||||
ASSERT_TRUE(isa<ConstantExpr>(Usr)); | |||||
CallInst *ForkCI = dyn_cast<CallInst>(Usr->user_back()); | |||||
ASSERT_NE(ForkCI, nullptr); | |||||
EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call"); | |||||
EXPECT_EQ(ForkCI->getNumArgOperands(), 3U); | |||||
EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0))); | |||||
EXPECT_EQ(ForkCI->getArgOperand(1), | |||||
ConstantInt::get(Type::getInt32Ty(Ctx), 0U)); | |||||
EXPECT_EQ(ForkCI->getArgOperand(2), Usr); | |||||
} | |||||
} | |||||
TEST_F(OpenMPIRBuilderTest, ParallelIfCond) { | TEST_F(OpenMPIRBuilderTest, ParallelIfCond) { | ||||
using InsertPointTy = OpenMPIRBuilder::InsertPointTy; | using InsertPointTy = OpenMPIRBuilder::InsertPointTy; | ||||
OpenMPIRBuilder OMPBuilder(*M); | OpenMPIRBuilder OMPBuilder(*M); | ||||
OMPBuilder.initialize(); | OMPBuilder.initialize(); | ||||
F->setName("func"); | F->setName("func"); | ||||
IRBuilder<> Builder(BB); | IRBuilder<> Builder(BB); | ||||
OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); | OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, | ||||
return CodeGenIP; | return CodeGenIP; | ||||
}; | }; | ||||
auto FiniCB = [&](InsertPointTy CodeGenIP) { | auto FiniCB = [&](InsertPointTy CodeGenIP) { | ||||
++NumFinalizationPoints; | ++NumFinalizationPoints; | ||||
// No destructors. | // No destructors. | ||||
}; | }; | ||||
IRBuilder<>::InsertPoint AfterIP = OMPBuilder.CreateParallel( | IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), | ||||
Loc, BodyGenCB, PrivCB, FiniCB, Builder.CreateIsNotNull(F->arg_begin()), | F->getEntryBlock().getFirstInsertionPt()); | ||||
IRBuilder<>::InsertPoint AfterIP = | |||||
OMPBuilder.CreateParallel(Loc, AllocaIP, BodyGenCB, PrivCB, FiniCB, | |||||
Builder.CreateIsNotNull(F->arg_begin()), | |||||
nullptr, OMP_PROC_BIND_default, false); | nullptr, OMP_PROC_BIND_default, false); | ||||
EXPECT_EQ(NumBodiesGenerated, 1U); | EXPECT_EQ(NumBodiesGenerated, 1U); | ||||
EXPECT_EQ(NumPrivatizedVars, 1U); | EXPECT_EQ(NumPrivatizedVars, 1U); | ||||
EXPECT_EQ(NumFinalizationPoints, 1U); | EXPECT_EQ(NumFinalizationPoints, 1U); | ||||
Builder.restoreIP(AfterIP); | Builder.restoreIP(AfterIP); | ||||
Builder.CreateRetVoid(); | Builder.CreateRetVoid(); | ||||
OMPBuilder.finalize(); | OMPBuilder.finalize(); | ||||
▲ Show 20 Lines • Show All 106 Lines • ▼ Show 20 Lines | TEST_F(OpenMPIRBuilderTest, ParallelCancelBarrier) { | ||||
auto FiniCB = [&](InsertPointTy IP) { | auto FiniCB = [&](InsertPointTy IP) { | ||||
++NumFinalizationPoints; | ++NumFinalizationPoints; | ||||
Builder.restoreIP(IP); | Builder.restoreIP(IP); | ||||
Builder.CreateCall(FakeDestructor, | Builder.CreateCall(FakeDestructor, | ||||
{Builder.getInt32(NumFinalizationPoints)}); | {Builder.getInt32(NumFinalizationPoints)}); | ||||
}; | }; | ||||
IRBuilder<>::InsertPoint AfterIP = OMPBuilder.CreateParallel( | IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), | ||||
Loc, BodyGenCB, PrivCB, FiniCB, Builder.CreateIsNotNull(F->arg_begin()), | F->getEntryBlock().getFirstInsertionPt()); | ||||
IRBuilder<>::InsertPoint AfterIP = | |||||
OMPBuilder.CreateParallel(Loc, AllocaIP, BodyGenCB, PrivCB, FiniCB, | |||||
Builder.CreateIsNotNull(F->arg_begin()), | |||||
nullptr, OMP_PROC_BIND_default, true); | nullptr, OMP_PROC_BIND_default, true); | ||||
EXPECT_EQ(NumBodiesGenerated, 1U); | EXPECT_EQ(NumBodiesGenerated, 1U); | ||||
EXPECT_EQ(NumPrivatizedVars, 0U); | EXPECT_EQ(NumPrivatizedVars, 0U); | ||||
EXPECT_EQ(NumFinalizationPoints, 2U); | EXPECT_EQ(NumFinalizationPoints, 2U); | ||||
EXPECT_EQ(FakeDestructor->getNumUses(), 2U); | EXPECT_EQ(FakeDestructor->getNumUses(), 2U); | ||||
Builder.restoreIP(AfterIP); | Builder.restoreIP(AfterIP); | ||||
Builder.CreateRetVoid(); | Builder.CreateRetVoid(); | ||||
▲ Show 20 Lines • Show All 217 Lines • Show Last 20 Lines |