mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-04-01 07:11:45 +00:00
[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
This commit is contained in:
parent
998874b92b
commit
e23e38391a
@ -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
|
||||
|
138
include/llvm/Frontend/OpenMP/OMPIRBuilder.h
Normal file
138
include/llvm/Frontend/OpenMP/OMPIRBuilder.h
Normal file
@ -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
|
@ -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
|
||||
|
||||
///}
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
}
|
||||
|
236
lib/Frontend/OpenMP/OMPIRBuilder.cpp
Normal file
236
lib/Frontend/OpenMP/OMPIRBuilder.cpp
Normal file
@ -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 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::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();
|
||||
}
|
@ -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)
|
||||
|
13
unittests/Frontend/CMakeLists.txt
Normal file
13
unittests/Frontend/CMakeLists.txt
Normal file
@ -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)
|
178
unittests/Frontend/OpenMPIRBuilderTest.cpp
Normal file
178
unittests/Frontend/OpenMPIRBuilderTest.cpp
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user