[llvm] d23c614 - [OpenMP] Introduce the OpenMP-IR-Builder
Johannes Doerfert via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 11 12:40:15 PST 2019
Author: Johannes Doerfert
Date: 2019-12-11T14:38:49-06:00
New Revision: d23c61490c282a7a8f29aaa5c021cbfdaf87fb6f
URL: https://github.com/llvm/llvm-project/commit/d23c61490c282a7a8f29aaa5c021cbfdaf87fb6f
DIFF: https://github.com/llvm/llvm-project/commit/d23c61490c282a7a8f29aaa5c021cbfdaf87fb6f.diff
LOG: [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
Added:
llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
llvm/unittests/Frontend/CMakeLists.txt
llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
Modified:
llvm/include/llvm/Frontend/OpenMP/OMPConstants.h
llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
llvm/lib/Frontend/OpenMP/CMakeLists.txt
llvm/lib/Frontend/OpenMP/OMPConstants.cpp
llvm/unittests/CMakeLists.txt
Removed:
################################################################################
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPConstants.h b/llvm/include/llvm/Frontend/OpenMP/OMPConstants.h
index 42b19091c14d..9fc949aac790 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMPConstants.h
+++ b/llvm/include/llvm/Frontend/OpenMP/OMPConstants.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 @@ enum class Directive {
#define OMP_DIRECTIVE(Enum, ...) constexpr auto Enum = omp::Directive::Enum;
#include "llvm/Frontend/OpenMP/OMPKinds.def"
+/// IDs for all omp runtime library (RTL) functions.
+enum class RuntimeFunction {
+#define OMP_RTL(Enum, ...) Enum,
+#include "llvm/Frontend/OpenMP/OMPKinds.def"
+};
+
+#define OMP_RTL(Enum, ...) constexpr auto Enum = omp::RuntimeFunction::Enum;
+#include "llvm/Frontend/OpenMP/OMPKinds.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/Frontend/OpenMP/OMPKinds.def"
+ LLVM_MARK_AS_BITMASK_ENUM(0x7FFFFFFF)
+};
+
+#define OMP_IDENT_FLAG(Enum, ...) constexpr auto Enum = omp::IdentFlag::Enum;
+#include "llvm/Frontend/OpenMP/OMPKinds.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/Frontend/OpenMP/OMPKinds.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
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
new file mode 100644
index 000000000000..a8cb3dfb39a6
--- /dev/null
+++ b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
@@ -0,0 +1,138 @@
+//===- 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/Frontend/OpenMP/OMPConstants.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);
+
+ /// Set the cancellation block to \p CBB.
+ void setCancellationBlock(BasicBlock *CBB) { CancellationBlock = CBB; }
+
+ /// Type used throughout for insertion points.
+ using InsertPointTy = IRBuilder<>::InsertPoint;
+
+ /// Description of a LLVM-IR insertion point (IP) and a debug/source location
+ /// (filename, line, column, ...).
+ struct LocationDescription {
+ template <typename T, typename U>
+ LocationDescription(const IRBuilder<T, U> &IRB)
+ : IP(IRB.saveIP()), DL(IRB.getCurrentDebugLocation()) {}
+ LocationDescription(const InsertPointTy &IP) : IP(IP) {}
+ LocationDescription(const InsertPointTy &IP, const DebugLoc &DL)
+ : IP(IP), DL(DL) {}
+ InsertPointTy 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-cancellation) barrier.
+ /// \param CheckCancelFlag Flag to indicate a cancel barrier return value
+ /// should be checked and acted upon.
+ ///
+ /// \returns The insertion point after the barrier.
+ InsertPointTy CreateBarrier(const LocationDescription &Loc, omp::Directive DK,
+ bool ForceSimpleCall = false,
+ bool CheckCancelFlag = true);
+
+ ///}
+
+private:
+ /// Update the internal location to \p Loc.
+ bool updateToLocation(const LocationDescription &Loc) {
+ Builder.restoreIP(Loc.IP);
+ Builder.SetCurrentDebugLocation(Loc.DL);
+ return Loc.IP.getBlock() != nullptr;
+ }
+
+ /// 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-cancellation) barrier.
+ /// \param CheckCancelFlag Flag to indicate a cancel barrier return value
+ /// should be checked and acted upon.
+ ///
+ /// \returns The insertion point after the barrier.
+ InsertPointTy 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 cancellation block stack.
+ BasicBlock *CancellationBlock = nullptr;
+
+ /// 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
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def b/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
index fc84ffb578c5..874d3f91bf31 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
+++ b/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
@@ -100,3 +100,137 @@ __OMP_DIRECTIVE(unknown)
#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
+
+///}
diff --git a/llvm/lib/Frontend/OpenMP/CMakeLists.txt b/llvm/lib/Frontend/OpenMP/CMakeLists.txt
index 5d74bcf3b9fc..e7d1f8e57f62 100644
--- a/llvm/lib/Frontend/OpenMP/CMakeLists.txt
+++ b/llvm/lib/Frontend/OpenMP/CMakeLists.txt
@@ -1,9 +1,10 @@
add_llvm_component_library(LLVMFrontendOpenMP
OMPConstants.cpp
+ OMPIRBuilder.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/Frontend
- ${LLVM_MAIN_INCLUDE_DIR}/llvm/Frontend/OpenMP
+ ${LLVM_MAIN_INCLUDE_DIR}/llvm/Frontend/OpenMP/OMP
DEPENDS
intrinsics_gen
diff --git a/llvm/lib/Frontend/OpenMP/OMPConstants.cpp b/llvm/lib/Frontend/OpenMP/OMPConstants.cpp
index 994fb4e2fa84..67d88ffb17ab 100644
--- a/llvm/lib/Frontend/OpenMP/OMPConstants.cpp
+++ b/llvm/lib/Frontend/OpenMP/OMPConstants.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 @@ StringRef llvm::omp::getOpenMPDirectiveName(Directive Kind) {
}
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/Frontend/OpenMP/OMPKinds.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/Frontend/OpenMP/OMPKinds.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/Frontend/OpenMP/OMPKinds.def"
+}
diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
new file mode 100644
index 000000000000..13733394b073
--- /dev/null
+++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
@@ -0,0 +1,236 @@
+//===- 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/Frontend/OpenMP/OMPIRBuilder.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"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+
+#include <sstream>
+
+#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/Frontend/OpenMP/OMPKinds.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/Frontend/OpenMP/OMPKinds.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/Frontend/OpenMP/OMPKinds.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/Frontend/OpenMP/OMPKinds.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
diff erence 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
+ //
diff erence 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::stringstream SrcLocStr;
+ SrcLocStr << ";" << Filename.data() << ";" << Function.data() << ";"
+ << LineStr << ";" << ColumnStr << ";;";
+ return getOrCreateSrcLocStr(SrcLocStr.str());
+}
+
+Value *OpenMPIRBuilder::getOrCreateThreadID(Value *Ident) {
+ return Builder.CreateCall(
+ getOrCreateRuntimeFunction(OMPRTL___kmpc_global_thread_num), Ident,
+ "omp_global_thread_num");
+}
+
+OpenMPIRBuilder::InsertPointTy
+OpenMPIRBuilder::CreateBarrier(const LocationDescription &Loc, Directive DK,
+ bool ForceSimpleCall, bool CheckCancelFlag) {
+ if (!updateToLocation(Loc))
+ return Loc.IP;
+ return emitBarrierImpl(Loc, DK, ForceSimpleCall, CheckCancelFlag);
+}
+
+OpenMPIRBuilder::InsertPointTy
+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;
+ }
+
+ Constant *SrcLocStr = getOrCreateSrcLocStr(Loc);
+ Value *Args[] = {getOrCreateIdent(SrcLocStr, BarrierLocFlags),
+ getOrCreateThreadID(getOrCreateIdent(SrcLocStr))};
+
+ // If we are in a cancellable parallel region, barriers are cancellation
+ // points.
+ // TODO: Check why we would force simple calls or to ignore the cancel flag.
+ bool UseCancelBarrier = !ForceSimpleCall && CancellationBlock;
+
+ Value *Result = Builder.CreateCall(
+ getOrCreateRuntimeFunction(UseCancelBarrier ? OMPRTL___kmpc_cancel_barrier
+ : OMPRTL___kmpc_barrier),
+ Args);
+
+ if (UseCancelBarrier && CheckCancelFlag) {
+ // For a cancel barrier we create two new blocks.
+ BasicBlock *BB = Builder.GetInsertBlock();
+ BasicBlock *NonCancellationBlock = BasicBlock::Create(
+ BB->getContext(), BB->getName() + ".cont", BB->getParent());
+
+ // Jump to them based on the return value.
+ Value *Cmp = Builder.CreateIsNull(Result);
+ Builder.CreateCondBr(Cmp, NonCancellationBlock, CancellationBlock,
+ /* TODO weight */ nullptr, nullptr);
+
+ Builder.SetInsertPoint(NonCancellationBlock);
+ assert(CancellationBlock->getParent() == BB->getParent() &&
+ "Unexpected cancellation block parent!");
+
+ // TODO: This is a workaround for now, we always reset the cancellation
+ // block until we manage it ourselves here.
+ CancellationBlock = nullptr;
+ }
+
+ return Builder.saveIP();
+}
diff --git a/llvm/unittests/CMakeLists.txt b/llvm/unittests/CMakeLists.txt
index 9384bdad0434..8c51fad45531 100644
--- a/llvm/unittests/CMakeLists.txt
+++ b/llvm/unittests/CMakeLists.txt
@@ -18,6 +18,7 @@ add_subdirectory(CodeGen)
add_subdirectory(DebugInfo)
add_subdirectory(Demangle)
add_subdirectory(ExecutionEngine)
+add_subdirectory(Frontend)
add_subdirectory(FuzzMutate)
add_subdirectory(IR)
add_subdirectory(LineEditor)
diff --git a/llvm/unittests/Frontend/CMakeLists.txt b/llvm/unittests/Frontend/CMakeLists.txt
new file mode 100644
index 000000000000..f63a3f85dd61
--- /dev/null
+++ b/llvm/unittests/Frontend/CMakeLists.txt
@@ -0,0 +1,13 @@
+set(LLVM_LINK_COMPONENTS
+ Analysis
+ Core
+ FrontendOpenMP
+ Support
+ Passes
+ )
+
+add_llvm_unittest(LLVMFrontendTests
+ OpenMPIRBuilderTest.cpp
+ )
+
+target_link_libraries(LLVMFrontendTests PRIVATE LLVMTestingSupport)
diff --git a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
new file mode 100644
index 000000000000..3c960c431b5b
--- /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
More information about the llvm-commits
mailing list