diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPConstants.h b/llvm/include/llvm/Frontend/OpenMP/OMPConstants.h --- a/llvm/include/llvm/Frontend/OpenMP/OMPConstants.h +++ b/llvm/include/llvm/Frontend/OpenMP/OMPConstants.h @@ -48,6 +48,25 @@ #define OMP_CLAUSE(Enum, ...) constexpr auto Enum = omp::Clause::Enum; #include "llvm/Frontend/OpenMP/OMPKinds.def" +/// IDs for all Internal Control Variables (ICVs). +enum class InternalControlVar { +#define ICV_DATA_ENV(Enum, ...) Enum, +#include "llvm/Frontend/OpenMP/OMPKinds.def" +}; + +#define ICV_DATA_ENV(Enum, ...) \ + constexpr auto Enum = omp::InternalControlVar::Enum; +#include "llvm/Frontend/OpenMP/OMPKinds.def" + +enum class ICVInitValue { +#define ICV_DATA_ENV(Enum, Name, EnvVar, Init) Init, +#include "llvm/Frontend/OpenMP/OMPKinds.def" +}; + +#define ICV_DATA_ENV(Enum, Name, EnvVar, Init) \ + constexpr auto Init = omp::ICVInitValue::Init; +#include "llvm/Frontend/OpenMP/OMPKinds.def" + /// IDs for all omp runtime library (RTL) functions. enum class RuntimeFunction { #define OMP_RTL(Enum, ...) Enum, diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def b/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def --- a/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def +++ b/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def @@ -230,6 +230,7 @@ #define __OMP_TYPE(VarName) OMP_TYPE(VarName, Type::get##VarName##Ty(Ctx)) __OMP_TYPE(Void) +__OMP_TYPE(Int1) __OMP_TYPE(Int8) __OMP_TYPE(Int32) __OMP_TYPE(Int64) @@ -310,6 +311,51 @@ ///} +/// Internal Control Variables information +/// +///{ + +#ifndef ICV_DATA_ENV +#define ICV_DATA_ENV(Enum, Name, EnvVarName, Init) +#endif + +#define __ICV_DATA_ENV(Name, EnvVarName, Init) \ + ICV_DATA_ENV(ICV_##Name, #Name, #EnvVarName, Init) + +__ICV_DATA_ENV(nthreads, OMP_NUM_THREADS, IMPLEMENTATION_DEFINED) +__ICV_DATA_ENV(active_levels, NONE, ZERO) +__ICV_DATA_ENV(cancel, OMP_CANCELLATION, FALSE) +__ICV_DATA_ENV(__last, last, LAST) + +#undef __ICV_DATA_ENV +#undef ICV_DATA_ENV + +#ifndef ICV_RT_SET +#define ICV_RT_SET(Name, RTL) +#endif + +#define __ICV_RT_SET(Name, RTL) ICV_RT_SET(ICV_##Name, OMPRTL_##RTL) + +__ICV_RT_SET(nthreads, omp_set_num_threads) + +#undef __ICV_RT_SET +#undef ICV_RT_SET + +#ifndef ICV_RT_GET +#define ICV_RT_GET(Name, RTL) +#endif + +#define __ICV_RT_GET(Name, RTL) ICV_RT_GET(ICV_##Name, OMPRTL_##RTL) + +__ICV_RT_GET(nthreads, omp_get_max_threads) +__ICV_RT_GET(active_levels, omp_get_active_level) +__ICV_RT_GET(cancel, omp_get_cancellation) + +#undef __ICV_RT_GET +#undef ICV_RT_GET + +///} + /// Runtime library function (and their attributes) /// ///{ diff --git a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp --- a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp +++ b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp @@ -38,6 +38,9 @@ cl::desc("Disable OpenMP specific optimizations."), cl::Hidden, cl::init(false)); +static cl::opt PrintICVValues("openmp-print-icv-values", cl::init(false), + cl::Hidden); + STATISTIC(NumOpenMPRuntimeCallsDeduplicated, "Number of OpenMP runtime calls deduplicated"); STATISTIC(NumOpenMPParallelRegionsDeleted, @@ -63,10 +66,38 @@ OMPBuilder(M) { initializeTypes(M); initializeRuntimeFunctions(); + initializeInternalControlVars(); OMPBuilder.initialize(); } + /// Generic information that describes an internal control variable. + struct InternalControlVarInfo { + /// The kind, as described by InternalControlVar enum. + InternalControlVar Kind; + + /// The name of the ICV. + StringRef Name; + + /// Environment variable associated with this ICV. + StringRef EnvVarName; + + /// Initial value kind. + ICVInitValue InitKind; + + /// Initial value. + ConstantInt *InitValue; + + /// Setter RTL function associated with this ICV. + RuntimeFunction Setter; + + /// Getter RTL function associated with this ICV. + RuntimeFunction Getter; + + /// RTL Function corresponding to the override clause of this ICV + RuntimeFunction Clause; + }; + /// Generic information that describes a runtime function struct RuntimeFunctionInfo { @@ -165,6 +196,49 @@ RuntimeFunction::OMPRTL___last> RFIs; + /// Map from ICV kind to the ICV description. + EnumeratedArray + ICVs; + + /// Helper to initialize all internal control variable information for those + /// defined in OMPKinds.def. + void initializeInternalControlVars() { +#define ICV_RT_SET(_Name, RTL) \ + { \ + auto &ICV = ICVs[_Name]; \ + ICV.Setter = RTL; \ + } +#define ICV_RT_GET(Name, RTL) \ + { \ + auto &ICV = ICVs[Name]; \ + ICV.Getter = RTL; \ + } +#define ICV_DATA_ENV(Enum, _Name, _EnvVarName, Init) \ + { \ + auto &ICV = ICVs[Enum]; \ + ICV.Name = _Name; \ + ICV.Kind = Enum; \ + ICV.InitKind = Init; \ + ICV.EnvVarName = _EnvVarName; \ + switch (ICV.InitKind) { \ + case IMPLEMENTATION_DEFINED: \ + ICV.InitValue = nullptr; \ + break; \ + case ZERO: \ + ICV.InitValue = \ + ConstantInt::get(Type::getInt32Ty(Int32->getContext()), 0); \ + break; \ + case FALSE: \ + ICV.InitValue = ConstantInt::getFalse(Int1->getContext()); \ + break; \ + case LAST: \ + break; \ + } \ + } +#include "llvm/Frontend/OpenMP/OMPKinds.def" + } + /// Returns true if the function declaration \p F matches the runtime /// function types, that is, return type \p RTFRetType, and argument types /// \p RTFArgTypes. @@ -271,6 +345,28 @@ << " functions in a slice with " << ModuleSlice.size() << " functions\n"); + /// Print initial ICV values for testing. + /// FIXME: This should be done from the Attributor once it is added. + if (PrintICVValues) { + InternalControlVar ICVs[] = {ICV_nthreads, ICV_active_levels, ICV_cancel}; + + for (Function *F : ModuleSlice) { + for (auto ICV : ICVs) { + auto ICVInfo = OMPInfoCache.ICVs[ICV]; + auto Remark = [&](OptimizationRemark OR) { + return OR << "OpenMP ICV " << ore::NV("OpenMPICV", ICVInfo.Name) + << " Value: " + << (ICVInfo.InitValue + ? ICVInfo.InitValue->getValue().toString(10, true) + : "IMPLEMENTATION_DEFINED"); + }; + + emitRemark(&(F->getEntryBlock().front()), + "OpenMPICVTracker", Remark); + } + } + } + Changed |= deduplicateRuntimeCalls(); Changed |= deleteParallelRegions(); diff --git a/llvm/test/Transforms/OpenMP/icv_tracking.ll b/llvm/test/Transforms/OpenMP/icv_tracking.ll --- a/llvm/test/Transforms/OpenMP/icv_tracking.ll +++ b/llvm/test/Transforms/OpenMP/icv_tracking.ll @@ -2,11 +2,17 @@ ; RUN: opt -S -openmpopt < %s | FileCheck %s ; RUN: opt -S -passes=openmpopt < %s | FileCheck %s +; RUN: opt -passes=openmpopt -pass-remarks=openmp-opt -openmp-print-icv-values -disable-output < %s 2>&1 | FileCheck %s --check-prefix=ICV_REMARKS +; RUN: opt -openmpopt -pass-remarks=openmp-opt -openmp-print-icv-values -disable-output < %s 2>&1 | FileCheck %s --check-prefix=ICV_REMARKS + %struct.ident_t = type { i32, i32, i32, i32, i8* } @.str = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00", align 1 @0 = private unnamed_addr global %struct.ident_t { i32 0, i32 2, i32 0, i32 0, i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.str, i32 0, i32 0) }, align 8 +; ICV_REMARKS: remark: :0:0: OpenMP ICV nthreads Value: IMPLEMENTATION_DEFINED +; ICV_REMARKS: remark: :0:0: OpenMP ICV active_levels Value: 0 +; ICV_REMARKS: remark: :0:0: OpenMP ICV cancel Value: 0 define dso_local i32 @foo(i32 %0, i32 %1) { ; CHECK-LABEL: define {{[^@]+}}@foo ; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) @@ -44,6 +50,9 @@ declare dso_local void @use(i32) +; ICV_REMARKS: remark: :0:0: OpenMP ICV nthreads Value: IMPLEMENTATION_DEFINED +; ICV_REMARKS: remark: :0:0: OpenMP ICV active_levels Value: 0 +; ICV_REMARKS: remark: :0:0: OpenMP ICV cancel Value: 0 define internal void @.omp_outlined.(i32* %0, i32* %1) { ; CHECK-LABEL: define {{[^@]+}}@.omp_outlined. ; CHECK-SAME: (i32* [[TMP0:%.*]], i32* [[TMP1:%.*]]) @@ -68,6 +77,9 @@ declare !callback !0 void @__kmpc_fork_call(%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) +; ICV_REMARKS: remark: :0:0: OpenMP ICV nthreads Value: IMPLEMENTATION_DEFINED +; ICV_REMARKS: remark: :0:0: OpenMP ICV active_levels Value: 0 +; ICV_REMARKS: remark: :0:0: OpenMP ICV cancel Value: 0 define dso_local i32 @bar(i32 %0, i32 %1) { ; CHECK-LABEL: define {{[^@]+}}@bar ; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) @@ -91,6 +103,9 @@ ret i32 0 } +; ICV_REMARKS: remark: :0:0: OpenMP ICV nthreads Value: IMPLEMENTATION_DEFINED +; ICV_REMARKS: remark: :0:0: OpenMP ICV active_levels Value: 0 +; ICV_REMARKS: remark: :0:0: OpenMP ICV cancel Value: 0 define internal void @.omp_outlined..1(i32* %0, i32* %1) { ; CHECK-LABEL: define {{[^@]+}}@.omp_outlined..1 ; CHECK-SAME: (i32* [[TMP0:%.*]], i32* [[TMP1:%.*]])