jdoerfert updated this revision to Diff 228754.
jdoerfert marked an inline comment as done.
jdoerfert added a comment.

Make attributes opt-in


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69785/new/

https://reviews.llvm.org/D69785

Files:
  llvm/include/llvm/IR/OpenMPConstants.h
  llvm/include/llvm/IR/OpenMPIRBuilder.h
  llvm/include/llvm/IR/OpenMPKinds.def
  llvm/lib/IR/CMakeLists.txt
  llvm/lib/IR/OpenMPConstants.cpp
  llvm/lib/IR/OpenMPIRBuilder.cpp
  llvm/unittests/IR/CMakeLists.txt
  llvm/unittests/IR/IRBuilderTest.cpp
  llvm/unittests/IR/OpenMPIRBuilderTest.cpp

Index: llvm/unittests/IR/OpenMPIRBuilderTest.cpp
===================================================================
--- /dev/null
+++ llvm/unittests/IR/OpenMPIRBuilderTest.cpp
@@ -0,0 +1,133 @@
+//===- 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/IR/OpenMPIRBuilder.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/IR/OpenMPConstants.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),
+                                          /*isVarArg=*/false);
+    F = Function::Create(FTy, Function::ExternalLinkage, "", M.get());
+    BB = BasicBlock::Create(Ctx, "", F);
+  }
+
+  void TearDown() override {
+    BB = nullptr;
+    M.reset();
+    uninitializeTypes();
+  }
+
+  LLVMContext Ctx;
+  std::unique_ptr<Module> M;
+  Function *F;
+  BasicBlock *BB;
+};
+
+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, DbgLoc) {
+  OpenMPIRBuilder OMPBuilder(*M);
+  OMPBuilder.initialize();
+  F->setName("func");
+
+  IRBuilder<> Builder(BB);
+
+  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();
+
+  DebugLoc DL = DebugLoc::get(3, 7, Scope);
+  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
Index: llvm/unittests/IR/IRBuilderTest.cpp
===================================================================
--- llvm/unittests/IR/IRBuilderTest.cpp
+++ llvm/unittests/IR/IRBuilderTest.cpp
@@ -198,12 +198,12 @@
   ASSERT_TRUE(isa<IntrinsicInst>(V));
   II = cast<IntrinsicInst>(V);
   EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fmul);
-  
+
   V = Builder.CreateFDiv(V, V);
   ASSERT_TRUE(isa<IntrinsicInst>(V));
   II = cast<IntrinsicInst>(V);
   EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fdiv);
-  
+
   V = Builder.CreateFRem(V, V);
   ASSERT_TRUE(isa<IntrinsicInst>(V));
   II = cast<IntrinsicInst>(V);
@@ -467,7 +467,7 @@
   ASSERT_TRUE(isa<Instruction>(F));
   FDiv = cast<Instruction>(F);
   EXPECT_FALSE(FDiv->hasAllowReciprocal());
- 
+
   // Try individual flags.
   FMF.clear();
   FMF.setAllowReciprocal();
@@ -526,7 +526,7 @@
   EXPECT_TRUE(FAdd->hasApproxFunc());
   EXPECT_TRUE(FAdd->hasAllowContract());
   EXPECT_FALSE(FAdd->hasAllowReassoc());
-  
+
   FMF.setAllowReassoc();
   Builder.clearFastMathFlags();
   Builder.setFastMathFlags(FMF);
Index: llvm/unittests/IR/CMakeLists.txt
===================================================================
--- llvm/unittests/IR/CMakeLists.txt
+++ llvm/unittests/IR/CMakeLists.txt
@@ -28,6 +28,7 @@
   ManglerTest.cpp
   MetadataTest.cpp
   ModuleTest.cpp
+  OpenMPIRBuilderTest.cpp
   PassManagerTest.cpp
   PatternMatch.cpp
   TimePassesTest.cpp
Index: llvm/lib/IR/OpenMPIRBuilder.cpp
===================================================================
--- /dev/null
+++ llvm/lib/IR/OpenMPIRBuilder.cpp
@@ -0,0 +1,240 @@
+//===- OpenMPIRBuilder.cpp - Builder for LLVM-IR for OpenMP directives ----===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// This file implements the OpenMPIRBuilder class, which is used as a
+/// convenient way to create LLVM instructions for OpenMP directives.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/IR/OpenMPIRBuilder.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/Support/CommandLine.h"
+
+#define DEBUG_TYPE "openmp-ir-builder"
+
+using namespace llvm;
+using namespace omp;
+using namespace types;
+
+static cl::opt<bool>
+    OptimisticAttributes("openmp-ir-builder-optimistic-attributes", cl::Hidden,
+                         cl::desc("Use optimistic attributes describing "
+                                  "'as-if' properties of runtime calls."),
+                         cl::init(false));
+
+void OpenMPIRBuilder::addAttributes(omp::RuntimeFunction FnID, Function &Fn) {
+  LLVMContext &Ctx = Fn.getContext();
+
+#define OMP_ATTRS_SET(VarName, AttrSet) AttributeSet VarName = AttrSet;
+#include "llvm/IR/OpenMPKinds.def"
+
+  // Add attributes to the new declaration.
+  switch (FnID) {
+#define OMP_RTL_ATTRS(Enum, FnAttrSet, RetAttrSet, ArgAttrSets)                \
+  case Enum:                                                                   \
+    Fn.setAttributes(                                                          \
+        AttributeList::get(Ctx, FnAttrSet, RetAttrSet, ArgAttrSets));          \
+    break;
+#include "llvm/IR/OpenMPKinds.def"
+  default:
+    // Attributes are optional.
+    break;
+  }
+}
+
+Function *OpenMPIRBuilder::getOrCreateRuntimeFunction(RuntimeFunction FnID) {
+  Function *Fn = nullptr;
+
+  // Try to find the declation in the module first.
+  switch (FnID) {
+#define OMP_RTL(Enum, Str, IsVarArg, ReturnType, ...)                          \
+  case Enum:                                                                   \
+    Fn = M.getFunction(Str);                                                   \
+    break;
+#include "llvm/IR/OpenMPKinds.def"
+  }
+
+  if (!Fn) {
+    // Create a new declaration if we need one.
+    switch (FnID) {
+#define OMP_RTL(Enum, Str, IsVarArg, ReturnType, ...)                          \
+  case Enum:                                                                   \
+    Fn = Function::Create(FunctionType::get(ReturnType,                        \
+                                            ArrayRef<Type *>{__VA_ARGS__},     \
+                                            IsVarArg),                         \
+                          GlobalValue::ExternalLinkage, Str, M);               \
+    break;
+#include "llvm/IR/OpenMPKinds.def"
+    }
+
+    addAttributes(FnID, *Fn);
+  }
+
+  assert(Fn && "Failed to create OpenMP runtime function");
+  return Fn;
+}
+
+void OpenMPIRBuilder::initialize() { initializeTypes(M); }
+
+Value *OpenMPIRBuilder::getOrCreateIdent(Constant *SrcLocStr,
+                                         IdentFlag LocFlags) {
+  // Enable "C-mode".
+  LocFlags |= OMP_IDENT_FLAG_KMPC;
+
+  GlobalVariable *&DefaultIdent = IdentMap[{SrcLocStr, uint64_t(LocFlags)}];
+  if (!DefaultIdent) {
+    Constant *I32Null = ConstantInt::getNullValue(Int32);
+    Constant *IdentData[] = {I32Null,
+                             ConstantInt::get(Int32, uint64_t(LocFlags)),
+                             I32Null, I32Null, SrcLocStr};
+    Constant *Initializer = ConstantStruct::get(
+        cast<StructType>(IdentPtr->getPointerElementType()), IdentData);
+
+    // Look for existing encoding of the location + flags, not needed but
+    // minimizes the difference to the existing solution while we transition.
+    for (GlobalVariable &GV : M.getGlobalList())
+      if (GV.getType() == IdentPtr && GV.hasInitializer())
+        if (GV.getInitializer() == Initializer)
+          return DefaultIdent = &GV;
+
+    DefaultIdent = new GlobalVariable(M, IdentPtr->getPointerElementType(),
+                                      /* isConstant = */ false,
+                                      GlobalValue::PrivateLinkage, Initializer);
+    DefaultIdent->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
+    DefaultIdent->setAlignment(Align(8));
+  }
+  return DefaultIdent;
+}
+
+Constant *OpenMPIRBuilder::getOrCreateSrcLocStr(StringRef LocStr) {
+  Constant *&SrcLocStr = SrcLocStrMap[LocStr];
+  if (!SrcLocStr) {
+    Constant *Initializer =
+        ConstantDataArray::getString(M.getContext(), LocStr);
+
+    // Look for existing encoding of the location, not needed but minimizes the
+    // difference to the existing solution while we transition.
+    for (GlobalVariable &GV : M.getGlobalList())
+      if (GV.isConstant() && GV.hasInitializer() &&
+          GV.getInitializer() == Initializer)
+        return SrcLocStr = ConstantExpr::getPointerCast(&GV, Int8Ptr);
+
+    SrcLocStr = Builder.CreateGlobalStringPtr(LocStr);
+  }
+  return SrcLocStr;
+}
+
+Constant *OpenMPIRBuilder::getOrCreateDefaultSrcLocStr() {
+  return getOrCreateSrcLocStr(";unknown;unknown;0;0;;");
+}
+
+Constant *
+OpenMPIRBuilder::getOrCreateSrcLocStr(const LocationDescription &Loc) {
+  DILocation *DIL = Loc.DL.get();
+  if (!DIL)
+    return getOrCreateDefaultSrcLocStr();
+  StringRef Filename =
+      !DIL->getFilename().empty() ? DIL->getFilename() : M.getName();
+  StringRef Function = DIL->getScope()->getSubprogram()->getName();
+  Function =
+      !Function.empty() ? Function : Loc.IP.getBlock()->getParent()->getName();
+  std::string LineStr = std::to_string(DIL->getLine());
+  std::string ColumnStr = std::to_string(DIL->getColumn());
+  std::string SrcLocStr = (";" + Filename + ";" + Function).str() + ";" +
+                          LineStr + ";" + ColumnStr + ";;";
+  return getOrCreateSrcLocStr(SrcLocStr);
+}
+
+Value *OpenMPIRBuilder::getOrCreateThreadID(Value *Ident) {
+  // TODO: It makes only so much sense to actually cache the global_thread_num
+  //       calls in the front-end as we can do a better job later on. Once
+  //       the middle-end combines global_thread_num calls (user calls and
+  //       generated ones!) we can rethink having a caching scheme here.
+  Function *Fn = Builder.GetInsertBlock()->getParent();
+  Value *&TID = ThreadIDMap[Fn];
+  if (!TID) {
+    // Search the entry block, not needed once all thread id calls go through
+    // here and are cached in the OpenMPIRBuilder.
+    for (Instruction &I : Fn->getEntryBlock())
+      if (CallInst *CI = dyn_cast<CallInst>(&I))
+        if (CI->getCalledFunction() &&
+            CI->getCalledFunction()->getName() == "__kmpc_global_thread_num")
+          return TID = CI;
+
+    Function *FnDecl =
+        getOrCreateRuntimeFunction(OMPRTL___kmpc_global_thread_num);
+    Instruction *Call =
+        Builder.CreateCall(FnDecl, Ident, "omp_global_thread_num");
+    if (Instruction *IdentI = dyn_cast<Instruction>(Ident))
+      Call->moveAfter(IdentI);
+    else
+      Call->moveBefore(&*Fn->getEntryBlock().getFirstInsertionPt());
+    TID = Call;
+  }
+  return TID;
+}
+
+void OpenMPIRBuilder::CreateBarrier(const LocationDescription &Loc,
+                                    Directive DK, bool ForceSimpleCall,
+                                    bool CheckCancelFlag) {
+  // TODO: Do we really expect these create calls to happen at an invalid
+  //       location and if so is ignoring them the right thing to do? This
+  //       mimics Clang's behavior for now.
+  if (!Loc.IP.getBlock())
+    return;
+  updateToLocation(Loc);
+  emitBarrierImpl(Loc, DK, ForceSimpleCall, CheckCancelFlag);
+}
+
+void OpenMPIRBuilder::emitBarrierImpl(const LocationDescription &Loc,
+                                      Directive Kind, bool ForceSimpleCall,
+                                      bool CheckCancelFlag) {
+  // Build call __kmpc_cancel_barrier(loc, thread_id) or
+  //            __kmpc_barrier(loc, thread_id);
+
+  IdentFlag BarrierLocFlags;
+  switch (Kind) {
+  case OMPD_for:
+    BarrierLocFlags = OMP_IDENT_FLAG_BARRIER_IMPL_FOR;
+    break;
+  case OMPD_sections:
+    BarrierLocFlags = OMP_IDENT_FLAG_BARRIER_IMPL_SECTIONS;
+    break;
+  case OMPD_single:
+    BarrierLocFlags = OMP_IDENT_FLAG_BARRIER_IMPL_SINGLE;
+    break;
+  case OMPD_barrier:
+    BarrierLocFlags = OMP_IDENT_FLAG_BARRIER_EXPL;
+    break;
+  default:
+    BarrierLocFlags = OMP_IDENT_FLAG_BARRIER_IMPL;
+    break;
+  }
+
+  // Set new insertion point for the internal builder.
+  Constant *SrcLocStr = getOrCreateSrcLocStr(Loc);
+  Value *Args[] = {getOrCreateIdent(SrcLocStr, BarrierLocFlags),
+                   getOrCreateThreadID(getOrCreateIdent(SrcLocStr))};
+  bool UseCancelBarrier = !ForceSimpleCall && CancelationBlock;
+  Value *Result = Builder.CreateCall(
+      getOrCreateRuntimeFunction(UseCancelBarrier ? OMPRTL___kmpc_cancel_barrier
+                                                  : OMPRTL___kmpc_barrier),
+      Args);
+
+  if (UseCancelBarrier && CheckCancelFlag) {
+    Value *Cmp = Builder.CreateIsNotNull(Result);
+    // TODO Reimplement part of llvm::SplitBlockAndInsertIfThen in a helper and
+    // use it here.
+    (void)Cmp;
+  }
+}
Index: llvm/lib/IR/OpenMPConstants.cpp
===================================================================
--- llvm/lib/IR/OpenMPConstants.cpp
+++ llvm/lib/IR/OpenMPConstants.cpp
@@ -12,9 +12,12 @@
 
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringSwitch.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Type.h"
 
 using namespace llvm;
 using namespace omp;
+using namespace types;
 
 Directive llvm::omp::getOpenMPDirectiveKind(StringRef Str) {
   return llvm::StringSwitch<Directive>(Str)
@@ -32,3 +35,53 @@
   }
   llvm_unreachable("Invalid OpenMP directive kind");
 }
+
+/// Declarations for LLVM-IR types (simple, function and structure) are
+/// generated below. Their names are defined and used in OpenMPKinds.def. Here
+/// we provide the declarations, the initializeTypes function will provide the
+/// values.
+///
+///{
+
+#define OMP_TYPE(VarName, InitValue) Type *llvm::omp::types::VarName = nullptr;
+#define OMP_FUNCTION_TYPE(VarName, IsVarArg, ReturnType, ...)                  \
+  FunctionType *llvm::omp::types::VarName = nullptr;                           \
+  PointerType *llvm::omp::types::VarName##Ptr = nullptr;
+#define OMP_STRUCT_TYPE(VarName, StrName, ...)                                 \
+  StructType *llvm::omp::types::VarName = nullptr;                             \
+  PointerType *llvm::omp::types::VarName##Ptr = nullptr;
+#include "llvm/IR/OpenMPKinds.def"
+
+///}
+
+void llvm::omp::types::initializeTypes(Module &M) {
+  if (Void)
+    return;
+
+  LLVMContext &Ctx = M.getContext();
+  // Create all simple and struct types exposed by the runtime and remember
+  // the llvm::PointerTypes of them for easy access later.
+  StructType *T;
+#define OMP_TYPE(VarName, InitValue) VarName = InitValue;
+#define OMP_FUNCTION_TYPE(VarName, IsVarArg, ReturnType, ...)                  \
+  VarName = FunctionType::get(ReturnType, {__VA_ARGS__}, IsVarArg);            \
+  VarName##Ptr = PointerType::getUnqual(T);
+#define OMP_STRUCT_TYPE(VarName, StructName, ...)                              \
+  T = M.getTypeByName(StructName);                                             \
+  if (!T)                                                                      \
+    T = StructType::create(Ctx, {__VA_ARGS__}, StructName);                    \
+  VarName = T;                                                                 \
+  VarName##Ptr = PointerType::getUnqual(T);
+#include "llvm/IR/OpenMPKinds.def"
+}
+
+void llvm::omp::types::uninitializeTypes() {
+#define OMP_TYPE(VarName, InitValue) VarName = nullptr;
+#define OMP_FUNCTION_TYPE(VarName, IsVarArg, ReturnType, ...)                  \
+  VarName = nullptr;                                                           \
+  VarName##Ptr = nullptr;
+#define OMP_STRUCT_TYPE(VarName, StrName, ...)                                 \
+  VarName = nullptr;                                                           \
+  VarName##Ptr = nullptr;
+#include "llvm/IR/OpenMPKinds.def"
+}
Index: llvm/lib/IR/CMakeLists.txt
===================================================================
--- llvm/lib/IR/CMakeLists.txt
+++ llvm/lib/IR/CMakeLists.txt
@@ -40,6 +40,7 @@
   Module.cpp
   ModuleSummaryIndex.cpp
   OpenMPConstants.cpp
+  OpenMPIRBuilder.cpp
   Operator.cpp
   OptBisect.cpp
   Pass.cpp
Index: llvm/include/llvm/IR/OpenMPKinds.def
===================================================================
--- llvm/include/llvm/IR/OpenMPKinds.def
+++ llvm/include/llvm/IR/OpenMPKinds.def
@@ -99,3 +99,137 @@
 #undef OMP_DIRECTIVE
 
 ///}
+
+/// Types used in runtime structs or runtime functions
+///
+///{
+
+#ifndef OMP_TYPE
+#define OMP_TYPE(VarName, InitValue)
+#endif
+
+#define __OMP_TYPE(VarName) OMP_TYPE(VarName, Type::get##VarName##Ty(Ctx))
+
+__OMP_TYPE(Void)
+__OMP_TYPE(Int8)
+__OMP_TYPE(Int32)
+__OMP_TYPE(Int8Ptr)
+__OMP_TYPE(Int32Ptr)
+
+#undef __OMP_TYPE
+#undef OMP_TYPE
+
+///}
+
+/// Struct and function types
+///
+///{
+
+#ifndef OMP_STRUCT_TYPE
+#define OMP_STRUCT_TYPE(VarName, StructName, ...)
+#endif
+
+#define __OMP_STRUCT_TYPE(VarName, Name, ...)                                  \
+  OMP_STRUCT_TYPE(VarName, "struct." #Name, __VA_ARGS__)
+
+__OMP_STRUCT_TYPE(Ident, ident_t, Int32, Int32, Int32, Int32, Int8Ptr)
+
+#undef __OMP_STRUCT_TYPE
+#undef OMP_STRUCT_TYPE
+
+#ifndef OMP_FUNCTION_TYPE
+#define OMP_FUNCTION_TYPE(VarName, IsVarArg, ReturnType, ...)
+#endif
+
+#define __OMP_FUNCTION_TYPE(VarName, IsVarArg, ReturnType, ...)                \
+  OMP_FUNCTION_TYPE(VarName, IsVarArg, ReturnType, __VA_ARGS__)
+
+__OMP_FUNCTION_TYPE(ParallelTask, true, Void, Int32Ptr, Int32Ptr)
+
+#undef __OMP_FUNCTION_TYPE
+#undef OMP_FUNCTION_TYPE
+
+///}
+
+/// Runtime library function (and their attributes)
+///
+///{
+
+#ifndef OMP_RTL
+#define OMP_RTL(Enum, Str, IsVarArg, ReturnType, ...)
+#endif
+
+#define __OMP_RTL(Name, IsVarArg, ReturnType, ...)                             \
+  OMP_RTL(OMPRTL_##Name, #Name, IsVarArg, ReturnType, __VA_ARGS__)
+
+__OMP_RTL(__kmpc_barrier, false, Void, IdentPtr, Int32)
+__OMP_RTL(__kmpc_cancel_barrier, false, Int32, IdentPtr, Int32)
+__OMP_RTL(__kmpc_global_thread_num, false, Int32, IdentPtr)
+__OMP_RTL(__kmpc_fork_call, true, Void, IdentPtr, Int32, ParallelTaskPtr)
+__OMP_RTL(omp_get_thread_num, false, Int32, )
+
+#undef __OMP_RTL
+#undef OMP_RTL
+
+#define EnumAttr(Kind) Attribute::get(Ctx, Attribute::AttrKind::Kind)
+#define AttributeSet(...)                                                      \
+  AttributeSet::get(Ctx, ArrayRef<Attribute>({__VA_ARGS__}))
+
+#ifndef OMP_ATTRS_SET
+#define OMP_ATTRS_SET(VarName, AttrSet)
+#endif
+
+#define __OMP_ATTRS_SET(VarName, AttrSet) OMP_ATTRS_SET(VarName, AttrSet)
+
+__OMP_ATTRS_SET(GetterAttrs,
+                OptimisticAttributes
+                    ? AttributeSet(EnumAttr(NoUnwind), EnumAttr(ReadOnly),
+                                   EnumAttr(NoSync), EnumAttr(NoFree))
+                    : AttributeSet(EnumAttr(NoUnwind)))
+
+#undef __OMP_ATTRS_SET
+#undef OMP_ATTRS_SET
+
+#ifndef OMP_RTL_ATTRS
+#define OMP_RTL_ATTRS(Enum, FnAttrSet, RetAttrSet, ArgAttrSets)
+#endif
+
+#define __OMP_RTL_ATTRS(Name, FnAttrSet, RetAttrSet, ArgAttrSets)              \
+  OMP_RTL_ATTRS(OMPRTL_##Name, FnAttrSet, RetAttrSet, ArgAttrSets)
+
+__OMP_RTL_ATTRS(__kmpc_global_thread_num, GetterAttrs, AttributeSet(), {})
+__OMP_RTL_ATTRS(omp_get_thread_num, GetterAttrs, AttributeSet(), {})
+
+#undef __OMP_RTL_ATTRS
+#undef OMP_RTL_ATTRS
+#undef AttributeSet
+#undef EnumAttr
+
+///}
+
+/// KMP ident_t bit flags
+///
+/// In accordance with the values in `openmp/runtime/src/kmp.h`.
+///
+///{
+
+#ifndef OMP_IDENT_FLAG
+#define OMP_IDENT_FLAG(Enum, Str, Value)
+#endif
+
+#define __OMP_IDENT_FLAG(Name, Value)                                          \
+  OMP_IDENT_FLAG(OMP_IDENT_FLAG_##Name, #Name, Value)
+
+__OMP_IDENT_FLAG(KMPC, 0x02)
+__OMP_IDENT_FLAG(BARRIER_EXPL, 0x20)
+__OMP_IDENT_FLAG(BARRIER_IMPL, 0x0040)
+__OMP_IDENT_FLAG(BARRIER_IMPL_MASK, 0x01C0)
+__OMP_IDENT_FLAG(BARRIER_IMPL_FOR, 0x0040)
+__OMP_IDENT_FLAG(BARRIER_IMPL_SECTIONS, 0x00C0)
+__OMP_IDENT_FLAG(BARRIER_IMPL_SINGLE, 0x0140)
+__OMP_IDENT_FLAG(BARRIER_IMPL_WORKSHARE, 0x01C0)
+
+#undef __OMP_IDENT_FLAG
+#undef OMP_IDENT_FLAG
+
+///}
Index: llvm/include/llvm/IR/OpenMPIRBuilder.h
===================================================================
--- /dev/null
+++ llvm/include/llvm/IR/OpenMPIRBuilder.h
@@ -0,0 +1,125 @@
+//===- IR/OpenMPIRBuilder.h - OpenMP encoding builder for LLVM IR - C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the OpenMPIRBuilder class and helpers used as a convenient
+// way to create LLVM instructions for OpenMP directives.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OPENMP_IR_IRBUILDER_H
+#define LLVM_OPENMP_IR_IRBUILDER_H
+
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/OpenMPConstants.h"
+
+namespace llvm {
+
+/// An interface to create LLVM-IR for OpenMP directives.
+///
+/// Each OpenMP directive has a corresponding public generator method.
+class OpenMPIRBuilder {
+public:
+  /// Create a new OpenMPIRBuilder operating on the given module \p M. This will
+  /// not have an effect on \p M (see initialize).
+  OpenMPIRBuilder(Module &M) : M(M), Builder(M.getContext()) {}
+
+  /// Initialize the internal state, this will put structures types and
+  /// potentially other helpers into the underlying module. Must be called
+  /// before any other method and only once!
+  void initialize();
+
+  /// Add attributes known for \p FnID to \p Fn.
+  void addAttributes(omp::RuntimeFunction FnID, Function &Fn);
+
+  /// Description of a LLVM-IR insertion point (IP) and a debug/source location
+  /// (filename, line, column, ...).
+  struct LocationDescription {
+    LocationDescription(const IRBuilder<>::InsertPoint &IP) : IP(IP) {}
+    LocationDescription(const IRBuilder<>::InsertPoint &IP, const DebugLoc &DL)
+        : IP(IP), DL(DL) {}
+    IRBuilder<>::InsertPoint IP;
+    DebugLoc DL;
+  };
+
+  /// Emitter methods for OpenMP directives.
+  ///
+  ///{
+
+  /// Generator for '#omp barrier'
+  ///
+  /// \param Loc The location where the barrier directive was encountered.
+  /// \param DK The kind of directive that caused the barrier.
+  /// \param ForceSimpleCall Flag to force a simple (=non-cancelation) barrier.
+  /// \param CheckCancelFlag Flag to indicate a cancel barrier return value
+  ///                        should be checked and acted upon.
+  void CreateBarrier(const LocationDescription &Loc, omp::Directive DK,
+                     bool ForceSimpleCall = false, bool CheckCancelFlag = true);
+
+  ///}
+
+private:
+  /// Update the internal location to \p Loc.
+  void updateToLocation(const LocationDescription &Loc) {
+    Builder.restoreIP(Loc.IP);
+    Builder.SetCurrentDebugLocation(Loc.DL);
+  }
+
+  /// Return the function declaration for the runtime function with \p FnID.
+  Function *getOrCreateRuntimeFunction(omp::RuntimeFunction FnID);
+
+  /// Return the (LLVM-IR) string describing the source location \p LocStr.
+  Constant *getOrCreateSrcLocStr(StringRef LocStr);
+
+  /// Return the (LLVM-IR) string describing the default source location.
+  Constant *getOrCreateDefaultSrcLocStr();
+
+  /// Return the (LLVM-IR) string describing the source location \p Loc.
+  Constant *getOrCreateSrcLocStr(const LocationDescription &Loc);
+
+  /// Return an ident_t* encoding the source location \p SrcLocStr and \p Flags.
+  Value *getOrCreateIdent(Constant *SrcLocStr,
+                          omp::IdentFlag Flags = omp::IdentFlag(0));
+
+  /// Generate a barrier runtime call.
+  ///
+  /// \param Loc The location at which the request originated and is fulfilled.
+  /// \param DK The directive which caused the barrier
+  /// \param ForceSimpleCall Flag to force a simple (=non-cancelation) barrier.
+  /// \param CheckCancelFlag Flag to indicate a cancel barrier return value
+  ///                        should be checked and acted upon.
+  void emitBarrierImpl(const LocationDescription &Loc, omp::Directive DK,
+                       bool ForceSimpleCall, bool CheckCancelFlag);
+
+  /// Return the current thread ID.
+  ///
+  /// \param Ident The ident (ident_t*) describing the query origin.
+  Value *getOrCreateThreadID(Value *Ident);
+
+  /// The underlying LLVM-IR module
+  Module &M;
+
+  /// The LLVM-IR Builder used to create IR.
+  IRBuilder<> Builder;
+
+  /// TODO: Stub for a cancelation block stack.
+  BasicBlock *CancelationBlock = nullptr;
+
+  /// Map to remember the thread in a function.
+  DenseMap<Function *, Value *> ThreadIDMap;
+
+  /// Map to remember source location strings
+  StringMap<Constant *> SrcLocStrMap;
+
+  /// Map to remember existing ident_t*.
+  DenseMap<std::pair<Constant *, uint64_t>, GlobalVariable *> IdentMap;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_IR_IRBUILDER_H
Index: llvm/include/llvm/IR/OpenMPConstants.h
===================================================================
--- llvm/include/llvm/IR/OpenMPConstants.h
+++ llvm/include/llvm/IR/OpenMPConstants.h
@@ -14,11 +14,18 @@
 #ifndef LLVM_OPENMP_CONSTANTS_H
 #define LLVM_OPENMP_CONSTANTS_H
 
+#include "llvm/ADT/BitmaskEnum.h"
 #include "llvm/ADT/StringRef.h"
 
 namespace llvm {
+class Type;
+class Module;
+class StructType;
+class PointerType;
+class FunctionType;
 
 namespace omp {
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
 
 /// IDs for all OpenMP directives.
 enum class Directive {
@@ -33,12 +40,58 @@
 #define OMP_DIRECTIVE(Enum, ...) constexpr auto Enum = omp::Directive::Enum;
 #include "llvm/IR/OpenMPKinds.def"
 
+/// IDs for all omp runtime library (RTL) functions.
+enum class RuntimeFunction {
+#define OMP_RTL(Enum, ...) Enum,
+#include "llvm/IR/OpenMPKinds.def"
+};
+
+#define OMP_RTL(Enum, ...) constexpr auto Enum = omp::RuntimeFunction::Enum;
+#include "llvm/IR/OpenMPKinds.def"
+
+/// IDs for all omp runtime library ident_t flag encodings (see
+/// their defintion in openmp/runtime/src/kmp.h).
+enum class IdentFlag {
+#define OMP_IDENT_FLAG(Enum, Str, Value) Enum = Value,
+#include "llvm/IR/OpenMPKinds.def"
+  LLVM_MARK_AS_BITMASK_ENUM(0x7FFFFFFF)
+};
+
+#define OMP_IDENT_FLAG(Enum, ...) constexpr auto Enum = omp::IdentFlag::Enum;
+#include "llvm/IR/OpenMPKinds.def"
+
 /// Parse \p Str and return the directive it matches or OMPD_unknown if none.
 Directive getOpenMPDirectiveKind(StringRef Str);
 
 /// Return a textual representation of the directive \p D.
 StringRef getOpenMPDirectiveName(Directive D);
 
+/// Forward declarations for LLVM-IR types (simple, function and structure) are
+/// generated below. Their names are defined and used in OpenMPKinds.def. Here
+/// we provide the forward declarations, the initializeTypes function will
+/// provide the values.
+///
+///{
+namespace types {
+
+#define OMP_TYPE(VarName, InitValue) extern Type *VarName;
+#define OMP_FUNCTION_TYPE(VarName, IsVarArg, ReturnType, ...)                  \
+  extern FunctionType *VarName;                                                \
+  extern PointerType *VarName##Ptr;
+#define OMP_STRUCT_TYPE(VarName, StrName, ...)                                 \
+  extern StructType *VarName;                                                  \
+  extern PointerType *VarName##Ptr;
+#include "llvm/IR/OpenMPKinds.def"
+
+/// Helper to initialize all types defined in OpenMPKinds.def.
+void initializeTypes(Module &M);
+
+/// Helper to uninitialize all types defined in OpenMPKinds.def.
+void uninitializeTypes();
+
+} // namespace types
+///}
+
 } // end namespace omp
 
 } // end namespace llvm
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to