[OpenMP] Introduce the OpenMP-IR-Builder
This is the initial patch for the OpenMP-IR-Builder, as discussed on the
mailing list ([1] and later) and at the US Dev Meeting'19.
The design is similar to D61953 but:
- in a non-WIP status, with proper documentation and working.
- using a OpenMPKinds.def file to manage lists of directives, runtime
functions, types, ..., similar to the current Clang implementation.
- restricted to handle only (simple) barriers, to implement most
`#pragma omp barrier` directives and most implicit barriers.
- properly hooked into Clang to be used if possible (D69922).
- compatible with the remaining code generation.
Parts have been extracted into D69853.
The plan is to have multiple people working on moving logic from Clang
here once the initial scaffolding (=this patch) landed.
[1] http://lists.flang-compiler.org/pipermail/flang-dev_lists.flang-compiler.org/2019-May/000197.html
Reviewers: kiranchandramohan, ABataev, RaviNarayanaswamy, gtbercea, grokos, sdmitriev, JonChesterfield, hfinkel, fghanim
Subscribers: mgorny, hiraditya, bollu, guansong, jfb, cfe-commits, llvm-commits, penzn, ppenzin
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D69785
diff --git a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
new file mode 100644
index 0000000..3c960c4
--- /dev/null
+++ b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
@@ -0,0 +1,178 @@
+//===- llvm/unittest/IR/OpenMPIRBuilderTest.cpp - OpenMPIRBuilder tests ---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/DIBuilder.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include "llvm/IR/Verifier.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace omp;
+using namespace types;
+
+namespace {
+
+class OpenMPIRBuilderTest : public testing::Test {
+protected:
+ void SetUp() override {
+ M.reset(new Module("MyModule", Ctx));
+ FunctionType *FTy =
+ FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt32Ty(Ctx)},
+ /*isVarArg=*/false);
+ F = Function::Create(FTy, Function::ExternalLinkage, "", M.get());
+ BB = BasicBlock::Create(Ctx, "", F);
+
+ DIBuilder DIB(*M);
+ auto File = DIB.createFile("test.dbg", "/");
+ auto CU =
+ DIB.createCompileUnit(dwarf::DW_LANG_C, File, "llvm-C", true, "", 0);
+ auto Type = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None));
+ auto SP = DIB.createFunction(
+ CU, "foo", "", File, 1, Type, 1, DINode::FlagZero,
+ DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized);
+ F->setSubprogram(SP);
+ auto Scope = DIB.createLexicalBlockFile(SP, File, 0);
+ DIB.finalize();
+ DL = DebugLoc::get(3, 7, Scope);
+ }
+
+ void TearDown() override {
+ BB = nullptr;
+ M.reset();
+ uninitializeTypes();
+ }
+
+ LLVMContext Ctx;
+ std::unique_ptr<Module> M;
+ Function *F;
+ BasicBlock *BB;
+ DebugLoc DL;
+};
+
+TEST_F(OpenMPIRBuilderTest, CreateBarrier) {
+ OpenMPIRBuilder OMPBuilder(*M);
+ OMPBuilder.initialize();
+
+ IRBuilder<> Builder(BB);
+
+ OMPBuilder.CreateBarrier({IRBuilder<>::InsertPoint()}, OMPD_for);
+ EXPECT_TRUE(M->global_empty());
+ EXPECT_EQ(M->size(), 1U);
+ EXPECT_EQ(F->size(), 1U);
+ EXPECT_EQ(BB->size(), 0U);
+
+ OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()});
+ OMPBuilder.CreateBarrier(Loc, OMPD_for);
+ EXPECT_FALSE(M->global_empty());
+ EXPECT_EQ(M->size(), 3U);
+ EXPECT_EQ(F->size(), 1U);
+ EXPECT_EQ(BB->size(), 2U);
+
+ CallInst *GTID = dyn_cast<CallInst>(&BB->front());
+ EXPECT_NE(GTID, nullptr);
+ EXPECT_EQ(GTID->getNumArgOperands(), 1U);
+ EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num");
+ EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory());
+ EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory());
+
+ CallInst *Barrier = dyn_cast<CallInst>(GTID->getNextNode());
+ EXPECT_NE(Barrier, nullptr);
+ EXPECT_EQ(Barrier->getNumArgOperands(), 2U);
+ EXPECT_EQ(Barrier->getCalledFunction()->getName(), "__kmpc_barrier");
+ EXPECT_FALSE(Barrier->getCalledFunction()->doesNotAccessMemory());
+ EXPECT_FALSE(Barrier->getCalledFunction()->doesNotFreeMemory());
+
+ EXPECT_EQ(cast<CallInst>(Barrier)->getArgOperand(1), GTID);
+
+ Builder.CreateUnreachable();
+ EXPECT_FALSE(verifyModule(*M));
+}
+
+TEST_F(OpenMPIRBuilderTest, CreateCancelBarrier) {
+ OpenMPIRBuilder OMPBuilder(*M);
+ OMPBuilder.initialize();
+
+ BasicBlock *CBB = BasicBlock::Create(Ctx, "", F);
+ new UnreachableInst(Ctx, CBB);
+ OMPBuilder.setCancellationBlock(CBB);
+
+ IRBuilder<> Builder(BB);
+
+ OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()});
+ auto NewIP = OMPBuilder.CreateBarrier(Loc, OMPD_for);
+ Builder.restoreIP(NewIP);
+ EXPECT_FALSE(M->global_empty());
+ EXPECT_EQ(M->size(), 3U);
+ EXPECT_EQ(F->size(), 3U);
+ EXPECT_EQ(BB->size(), 4U);
+
+ CallInst *GTID = dyn_cast<CallInst>(&BB->front());
+ EXPECT_NE(GTID, nullptr);
+ EXPECT_EQ(GTID->getNumArgOperands(), 1U);
+ EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num");
+ EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory());
+ EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory());
+
+ CallInst *Barrier = dyn_cast<CallInst>(GTID->getNextNode());
+ EXPECT_NE(Barrier, nullptr);
+ EXPECT_EQ(Barrier->getNumArgOperands(), 2U);
+ EXPECT_EQ(Barrier->getCalledFunction()->getName(), "__kmpc_cancel_barrier");
+ EXPECT_FALSE(Barrier->getCalledFunction()->doesNotAccessMemory());
+ EXPECT_FALSE(Barrier->getCalledFunction()->doesNotFreeMemory());
+ EXPECT_EQ(Barrier->getNumUses(), 1U);
+ Instruction *BarrierBBTI = Barrier->getParent()->getTerminator();
+ EXPECT_EQ(BarrierBBTI->getNumSuccessors(), 2U);
+ EXPECT_EQ(BarrierBBTI->getSuccessor(0), NewIP.getBlock());
+ EXPECT_EQ(BarrierBBTI->getSuccessor(1), CBB);
+
+ EXPECT_EQ(cast<CallInst>(Barrier)->getArgOperand(1), GTID);
+
+ Builder.CreateUnreachable();
+ EXPECT_FALSE(verifyModule(*M));
+}
+
+TEST_F(OpenMPIRBuilderTest, DbgLoc) {
+ OpenMPIRBuilder OMPBuilder(*M);
+ OMPBuilder.initialize();
+ F->setName("func");
+
+ IRBuilder<> Builder(BB);
+
+ OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
+ OMPBuilder.CreateBarrier(Loc, OMPD_for);
+ CallInst *GTID = dyn_cast<CallInst>(&BB->front());
+ CallInst *Barrier = dyn_cast<CallInst>(GTID->getNextNode());
+ EXPECT_EQ(GTID->getDebugLoc(), DL);
+ EXPECT_EQ(Barrier->getDebugLoc(), DL);
+ EXPECT_TRUE(isa<GlobalVariable>(Barrier->getOperand(0)));
+ if (!isa<GlobalVariable>(Barrier->getOperand(0)))
+ return;
+ GlobalVariable *Ident = cast<GlobalVariable>(Barrier->getOperand(0));
+ EXPECT_TRUE(Ident->hasInitializer());
+ if (!Ident->hasInitializer())
+ return;
+ Constant *Initializer = Ident->getInitializer();
+ EXPECT_TRUE(
+ isa<GlobalVariable>(Initializer->getOperand(4)->stripPointerCasts()));
+ GlobalVariable *SrcStrGlob =
+ cast<GlobalVariable>(Initializer->getOperand(4)->stripPointerCasts());
+ if (!SrcStrGlob)
+ return;
+ EXPECT_TRUE(isa<ConstantDataArray>(SrcStrGlob->getInitializer()));
+ ConstantDataArray *SrcSrc =
+ dyn_cast<ConstantDataArray>(SrcStrGlob->getInitializer());
+ if (!SrcSrc)
+ return;
+ EXPECT_EQ(SrcSrc->getAsCString(), ";test.dbg;foo;3;7;;");
+}
+} // namespace