Index: llvm/include/llvm/Analysis/Directives.h =================================================================== --- /dev/null +++ llvm/include/llvm/Analysis/Directives.h @@ -0,0 +1,59 @@ +//===------------- Directives.h - Class definition -*- 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 +// +// ===--------------------------------------------------------------------=== // +/// +/// \file +/// Contains the enumerations for unroll/parallel/vector directives and +/// clauses. The enums are automatically generated by TableGen. +/// +// ===--------------------------------------------------------------------=== // + +#ifndef LLVM_ANALYSIS_DIRECTIVES_H +#define LLVM_ANALYSIS_DIRECTIVES_H + + +#include "llvm/Support/Debug.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringMap.h" +#include + +using namespace llvm; + +namespace llvm { + +typedef enum DIRECTIVES { +#define GET_DIRECTIVES_ENUM_VALUES +#include "llvm/IR/Directives.gen" +#undef GET_DIRECTIVES_ENUM_VALUES +} DIRECTIVES; + +typedef enum CLAUSES { +#define GET_CLAUSES_ENUM_VALUES +#include "llvm/IR/Directives.gen" +#undef GET_CLAUSES_ENUM_VALUES +} CLAUSES; + +class Directives { + +public: +// Map DIRECTIVES to StringRefs +static std::unordered_map DirectiveStrings; + +// Map CLAUSES to StringRefs +static std::unordered_map ClauseStrings; + +// Map Strings to DIRECTIVES +static StringMap DirectiveIDs; + +// Map Strings to CLAUSES +static StringMap ClauseIDs; + +}; + +} // end llvm namespace + +#endif // LLVM_ANALYSIS_DIRECTIVES_H Index: llvm/include/llvm/IR/CMakeLists.txt =================================================================== --- llvm/include/llvm/IR/CMakeLists.txt +++ llvm/include/llvm/IR/CMakeLists.txt @@ -5,3 +5,7 @@ tablegen(LLVM IntrinsicEnums.inc -gen-intrinsic-enums) tablegen(LLVM IntrinsicImpl.inc -gen-intrinsic-impl) add_public_tablegen_target(intrinsics_gen) + +set(LLVM_TARGET_DEFINITIONS Directives.td) +tablegen(LLVM Directives.gen -gen-directives) +add_public_tablegen_target(directives_gen) Index: llvm/include/llvm/IR/Directives.td =================================================================== --- /dev/null +++ llvm/include/llvm/IR/Directives.td @@ -0,0 +1,265 @@ +//==---- Directives.td - Defines all parallelization and -*- tablegen -*----==// +// vectorization directives and clauses. +// +// 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 defines the classes used to represent parallelization and +/// vectorization directives and clauses. Each different type of directive and +/// clause is then instantiated accordingly. TableGen parses these records and +/// generates enums for both classes, as well as tables which provide an +/// enum->string and string->enum mapping. The enums and tables are used to +/// generate Metadata strings that are used as arguments to llvm.directive +/// intrinsics. These intrinsics are used to mark parallel/vector constructs +/// and behavior. +/// +// ===--------------------------------------------------------------------=== // + +// The Directive class represents all ivdep/unroll/parallel/vector constructs +// that can be represented within LLVM IR. For example, the "#pragma ivdep +// directive. +class Directive; + +// The Clause class represents additional information provided to Directives +// that can be used to control parallel/vector execution. For example, +// "#pragma omp parallel" could be modified to include the "if (expr)" clause +// to determine if the region should be executed in parallel or not. +class Clause; + +// For additional information on the supported Directives and Clauses, please +// refer to the following documentation. Currently, this file defines only +// the directives and clauses associated with OpenMP, but will be extended in +// the future for other parallel/vector programming models and APIs. +// +// http://openmp.org/wp/openmp-specifications + +// *** Begin OpenMP Directives *** + +def "DIR.OMP.PARALLEL" : Directive; +def "DIR.OMP.END.PARALLEL" : Directive; + +def "DIR.OMP.LOOP" : Directive; +def "DIR.OMP.END.LOOP" : Directive; + +def "DIR.OMP.PARALLEL.LOOP" : Directive; +def "DIR.OMP.END.PARALLEL.LOOP" : Directive; + +def "DIR.OMP.SECTIONS" : Directive; +def "DIR.OMP.END.SECTIONS" : Directive; + +def "DIR.OMP.PARALLEL.SECTIONS" : Directive; +def "DIR.OMP.END.PARALLEL.SECTIONS" : Directive; + +def "DIR.OMP.WORKSHARE" : Directive; +def "DIR.OMP.END.WORKSHARE" : Directive; + +def "DIR.OMP.PARALLEL.WORKSHARE" : Directive; +def "DIR.OMP.END.PARALLEL.WORKSHARE" : Directive; + +def "DIR.OMP.SECTION" : Directive; +def "DIR.OMP.END.SECTION" : Directive; + +def "DIR.OMP.SINGLE" : Directive; +def "DIR.OMP.END.SINGLE" : Directive; + +def "DIR.OMP.TASK" : Directive; +def "DIR.OMP.END.TASK" : Directive; + +def "DIR.OMP.MASTER" : Directive; +def "DIR.OMP.END.MASTER" : Directive; + +def "DIR.OMP.CRITICAL" : Directive; +def "DIR.OMP.END.CRITICAL" : Directive; + +def "DIR.OMP.BARRIER" : Directive; +def "DIR.OMP.END.BARRIER" : Directive; + +def "DIR.OMP.TASKWAIT" : Directive; +def "DIR.OMP.END.TASKWAIT" : Directive; + +def "DIR.OMP.TASKYIELD" : Directive; +def "DIR.OMP.END.TASKYIELD" : Directive; + +def "DIR.OMP.ATOMIC" : Directive; +def "DIR.OMP.END.ATOMIC" : Directive; + +def "DIR.OMP.FLUSH" : Directive; +def "DIR.OMP.END.FLUSH" : Directive; + +def "DIR.OMP.THREADPRIVATE" : Directive; + +def "DIR.OMP.ORDERED" : Directive; +def "DIR.OMP.END.ORDERED" : Directive; + +def "DIR.OMP.SIMD" : Directive; +def "DIR.OMP.END.SIMD" : Directive; + +def "DIR.OMP.TASKGROUP" : Directive; +def "DIR.OMP.END.TASKGROUP" : Directive; + +def "DIR.OMP.TASKLOOP" : Directive; +def "DIR.OMP.END.TASKLOOP" : Directive; + +def "DIR.OMP.TARGET" : Directive; +def "DIR.OMP.END.TARGET" : Directive; + +def "DIR.OMP.TARGET.DATA" : Directive; +def "DIR.OMP.END.TARGET.DATA" : Directive; + +def "DIR.OMP.TARGET.UPDATE" : Directive; +def "DIR.OMP.END.TARGET.UPDATE" : Directive; + +def "DIR.OMP.TEAMS" : Directive; +def "DIR.OMP.END.TEAMS" : Directive; + +def "DIR.OMP.DISTRIBUTE" : Directive; +def "DIR.OMP.END.DISTRIBUTE" : Directive; + +def "DIR.OMP.DISTRIBUTE.PARLOOP" : Directive; +def "DIR.OMP.END.DISTRIBUTE.PARLOOP" : Directive; + +def "DIR.OMP.TARGET.ENTER.DATA" : Directive; +def "DIR.OMP.END.TARGET.ENTER.DATA" : Directive; + +def "DIR.OMP.TARGET.EXIT.DATA" : Directive; +def "DIR.OMP.END.TARGET.EXIT.DATA" : Directive; + +def "DIR.OMP.CANCEL" : Directive; +def "DIR.OMP.END.CANCEL" : Directive; + +def "DIR.OMP.CANCELLATION.POINT" : Directive; +def "DIR.OMP.END.CANCELLATION.POINT" : Directive; + +// *** Begin non-OpenMP Directives *** + +// Directives used to mark begin/end of a loop determined by VPO vectorizer +// legality analysis to be legal to vectorize. +def "DIR.VPO.AUTO.VEC" : Directive; +def "DIR.VPO.END.AUTO.VEC" : Directive; + +def "DIR.PRAGMA.IVDEP" : Directive; +def "DIR.PRAGMA.END.IVDEP" : Directive; + +def "DIR.PRAGMA.UNROLL" : Directive; +def "DIR.PRAGMA.END.UNROLL" : Directive; + +// *** Begin OpenMP Clauses *** + +def "QUAL.OMP.DEFAULT.NONE" : Clause; +def "QUAL.OMP.DEFAULT.SHARED" : Clause; +def "QUAL.OMP.DEFAULT.PRIVATE" : Clause; +def "QUAL.OMP.DEFAULT.FIRSTPRIVATE" : Clause; +def "QUAL.OMP.MERGEABLE" : Clause; +def "QUAL.OMP.NOWAIT" : Clause; +def "QUAL.OMP.NOGROUP" : Clause; +def "QUAL.OMP.UNTIED" : Clause; +def "QUAL.OMP.READ" : Clause; +def "QUAL.OMP.READ.SEQ_CST" : Clause; +def "QUAL.OMP.WRITE" : Clause; +def "QUAL.OMP.WRITE.SEQ_CST" : Clause; +def "QUAL.OMP.UPDATE" : Clause; +def "QUAL.OMP.UPDATE.SEQ_CST" : Clause; +def "QUAL.OMP.CAPTURE" : Clause; +def "QUAL.OMP.CAPTURE.SEQ_CST" : Clause; +def "QUAL.OMP.PROC.BIND.MASTER" : Clause; +def "QUAL.OMP.PROC.BIND.CLOSE" : Clause; +def "QUAL.OMP.PROC.BIND.SPREAD" : Clause; +def "QUAL.OMP.IF" : Clause; +def "QUAL.OMP.COLLAPSE" : Clause; +def "QUAL.OMP.NUM_THREADS" : Clause; +def "QUAL.OMP.ORDERED" : Clause; +def "QUAL.OMP.SAFELEN" : Clause; +def "QUAL.OMP.SIMDLEN" : Clause; +def "QUAL.OMP.FINAL" : Clause; +def "QUAL.OMP.GRAINSIZE" : Clause; +def "QUAL.OMP.NUM_TASKS" : Clause; +def "QUAL.OMP.PRIORITY" : Clause; +def "QUAL.OMP.NUM_TEAMS" : Clause; +def "QUAL.OMP.THREAD_LIMIT" : Clause; +def "QUAL.OMP.DIST_SCHEDULE.STATIC" : Clause; +def "QUAL.OMP.SCHEDULE.STATIC" : Clause; +def "QUAL.OMP.SCHEDULE.DYNAMIC" : Clause; +def "QUAL.OMP.SCHEDULE.GUIDED" : Clause; +def "QUAL.OMP.SCHEDULE.AUTO" : Clause; +def "QUAL.OMP.SCHEDULE.RUNTIME" : Clause; +def "QUAL.OMP.SHARED" : Clause; +def "QUAL.OMP.PRIVATE" : Clause; +def "QUAL.OMP.FIRSTPRIVATE" : Clause; +def "QUAL.OMP.LASTPRIVATE" : Clause; +def "QUAL.OMP.COPYIN" : Clause; +def "QUAL.OMP.COPYPRIVATE" : Clause; +def "QUAL.OMP.REDUCTION.ADD" : Clause; +def "QUAL.OMP.REDUCTION.SUB" : Clause; +def "QUAL.OMP.REDUCTION.MUL" : Clause; +def "QUAL.OMP.REDUCTION.AND" : Clause; +def "QUAL.OMP.REDUCTION.OR" : Clause; +def "QUAL.OMP.REDUCTION.BXOR" : Clause; +def "QUAL.OMP.REDUCTION.BAND" : Clause; +def "QUAL.OMP.REDUCTION.BOR" : Clause; +def "QUAL.OMP.REDUCTION.MAX" : Clause; +def "QUAL.OMP.REDUCTION.MIN" : Clause; +def "QUAL.OMP.REDUCTION.UDR" : Clause; +def "QUAL.OMP.INREDUCTION.ADD" : Clause; +def "QUAL.OMP.INREDUCTION.SUB" : Clause; +def "QUAL.OMP.INREDUCTION.MUL" : Clause; +def "QUAL.OMP.INREDUCTION.AND" : Clause; +def "QUAL.OMP.INREDUCTION.OR" : Clause; +def "QUAL.OMP.INREDUCTION.BXOR" : Clause; +def "QUAL.OMP.INREDUCTION.BAND" : Clause; +def "QUAL.OMP.INREDUCTION.BOR" : Clause; +def "QUAL.OMP.INREDUCTION.MAX" : Clause; +def "QUAL.OMP.INREDUCTION.MIN" : Clause; +def "QUAL.OMP.INREDUCTION.UDR" : Clause; +def "QUAL.OMP.TO" : Clause; +def "QUAL.OMP.FROM" : Clause; +def "QUAL.OMP.LINEAR" : Clause; +def "QUAL.OMP.UNIFORM" : Clause; +def "QUAL.OMP.ALIGNED" : Clause; +def "QUAL.OMP.FLUSH" : Clause; +def "QUAL.OMP.THREADPRIVATE" : Clause; +def "QUAL.OMP.DEVICE" : Clause; +def "QUAL.OMP.IS_DEVICE_PTR" : Clause; +def "QUAL.OMP.USE_DEVICE_PTR" : Clause; +def "QUAL.OMP.DEFAULTMAP.TOFROM.SCALAR" : Clause; +def "QUAL.OMP.MAP.TO" : Clause; +def "QUAL.OMP.MAP.FROM" : Clause; +def "QUAL.OMP.MAP.TOFROM" : Clause; +def "QUAL.OMP.MAP.ALLOC" : Clause; +def "QUAL.OMP.MAP.RELEASE" : Clause; +def "QUAL.OMP.MAP.DELETE" : Clause; +def "QUAL.OMP.MAP.ALWAYS.TO" : Clause; +def "QUAL.OMP.MAP.ALWAYS.FROM" : Clause; +def "QUAL.OMP.MAP.ALWAYS.TOFROM" : Clause; +def "QUAL.OMP.MAP.ALWAYS.ALLOC" : Clause; +def "QUAL.OMP.MAP.ALWAYS.RELEASE" : Clause; +def "QUAL.OMP.MAP.ALWAYS.DELETE" : Clause; +def "QUAL.OMP.DEPEND.IN" : Clause; +def "QUAL.OMP.DEPEND.OUT" : Clause; +def "QUAL.OMP.DEPEND.INOUT" : Clause; +def "QUAL.OMP.DEPEND.SOURCE" : Clause; +def "QUAL.OMP.DEPEND.SINK" : Clause; +def "QUAL.OMP.ORDERED.THREADS" : Clause; +def "QUAL.OMP.ORDERED.SIMD" : Clause; +def "QUAL.OMP.CANCEL.PARALLEL" : Clause; +def "QUAL.OMP.CANCEL.LOOP" : Clause; +def "QUAL.OMP.CANCEL.SECTIONS" : Clause; +def "QUAL.OMP.CANCEL.TASKGROUP" : Clause; +def "QUAL.OMP.HINT" : Clause; +def "QUAL.OMP.NAME" : Clause; + +// *** Begin Auxiliary Clauses *** +// These "clauses" don't correspond to actual OpenMP clauses, but are used +// to carry additional information + +def "QUAL.OMP.TARGET.TASK" : Clause; +def "QUAL.OMP.NORMALIZED.IV" : Clause; +def "QUAL.OMP.NORMALIZED.UB" : Clause; +def "QUAL.OMP.CANCELLATION.POINTS" : Clause; +def "QUAL.OMP.OPERAND.ADDR" : Clause; +def "QUAL.OMP.OFFLOAD.ENTRY.IDX" : Clause; + +def "QUAL.PRAGMA.ARRAY" : Clause; Index: llvm/include/llvm/IR/Intrinsics.td =================================================================== --- llvm/include/llvm/IR/Intrinsics.td +++ llvm/include/llvm/IR/Intrinsics.td @@ -952,6 +952,12 @@ [llvm_token_ty, llvm_i32_ty, llvm_i32_ty], [IntrReadMem, ImmArg<1>, ImmArg<2>]>; +//===------------------------ Directive Intrinsics ------------------------===// +// +def int_directive_region_entry : Intrinsic<[llvm_token_ty], [], []>; +def int_directive_region_exit : Intrinsic<[], [llvm_token_ty], []>; +def int_directive_marker : Intrinsic<[], [], []>; + //===------------------------ Coroutine Intrinsics ---------------===// // These are documented in docs/Coroutines.rst Index: llvm/include/llvm/Transforms/Utils/IntrinsicUtils.h =================================================================== --- /dev/null +++ llvm/include/llvm/Transforms/Utils/IntrinsicUtils.h @@ -0,0 +1,39 @@ +//===----------- IntrinsicUtils.h - Class definition -*- 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 +// +// ===--------------------------------------------------------------------=== // +/// +/// \file +/// Set of utilities that operate on intrinsics introduced by using OpenMP and +/// SIMD directives. They are also used by auto parallelization/vectorization +/// to generate parallel/vector code. +/// +// ===--------------------------------------------------------------------=== // + +#ifndef LLVM_TRANSFORM_UTILS_INTRINSICUTILS_H +#define LLVM_TRANSFORM_UTILS_INTRINSICUTILS_H + +namespace llvm { + +/// \brief This class provides a set of utility functions that operate on +/// intrinsics introduced for directives. +class IntrinsicUtils { + +public: + /// \brief Returns strings corresponding to directives. + static StringRef getDirectiveString(int Id); + + /// \brief Returns strings corresponding to clauses. + static StringRef getClauseString(int Id); + + /// \brief Return true if the instruction is an directive + /// represented as a directive.region.entry/exit intrinsic call + static bool isDirective(Instruction *I); +}; + +} // namespace llvm + +#endif // LLVM_TRANSFORM_UTILS_INTRINSICUTILS_H Index: llvm/lib/Analysis/CMakeLists.txt =================================================================== --- llvm/lib/Analysis/CMakeLists.txt +++ llvm/lib/Analysis/CMakeLists.txt @@ -39,6 +39,7 @@ InstCount.cpp InstructionPrecedenceTracking.cpp InstructionSimplify.cpp + Directives.cpp Interval.cpp IntervalPartition.cpp IteratedDominanceFrontier.cpp @@ -101,4 +102,5 @@ DEPENDS intrinsics_gen + directives_gen ) Index: llvm/lib/Analysis/Directives.cpp =================================================================== --- /dev/null +++ llvm/lib/Analysis/Directives.cpp @@ -0,0 +1,51 @@ +//==------ Directives.cpp - Table of directives and clauses -*- 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 +// +// ===--------------------------------------------------------------------=== // +/// +/// \file +/// This file builds tables of directives and clauses used for parallelization +/// and vectorization. The enums/tables are used to create Metadata that are +/// passed as call arguments to intrinsics. These intrinsics represent things +/// like the beginning and end of vector/parallel regions, specifying variable +/// attributes like private, shared, etc. The enumerations and tables are +/// automatically generated by a TableGen backend. +/// +/// See llvm/utils/TableGen/DirectivesEmitter.cpp +/// +// ===--------------------------------------------------------------------=== // + +#include "llvm/Analysis/Directives.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Debug.h" +#include + +using namespace llvm; + +std::unordered_map Directives::DirectiveStrings = { +#define GET_DIRECTIVES_STRINGS_TABLE +#include "llvm/IR/Directives.gen" + }; +#undef GET_DIRECTIVES_STRINGS_TABLE + +std::unordered_map Directives::ClauseStrings = { +#define GET_CLAUSES_STRINGS_TABLE +#include "llvm/IR/Directives.gen" + }; +#undef GET_CLAUSES_STRINGS_TABLE + +StringMap Directives::DirectiveIDs = { +#define GET_DIRECTIVES_IDS_TABLE +#include "llvm/IR/Directives.gen" + }; +#undef GET_DIRECTIVES_IDS_TABLE + +StringMap Directives::ClauseIDs = { +#define GET_CLAUSES_IDS_TABLE +#include "llvm/IR/Directives.gen" + }; +#undef GET_CLAUSES_IDS_TABLE Index: llvm/lib/Passes/CMakeLists.txt =================================================================== --- llvm/lib/Passes/CMakeLists.txt +++ llvm/lib/Passes/CMakeLists.txt @@ -12,4 +12,5 @@ DEPENDS intrinsics_gen + directives_gen ) Index: llvm/lib/Transforms/Scalar/CMakeLists.txt =================================================================== --- llvm/lib/Transforms/Scalar/CMakeLists.txt +++ llvm/lib/Transforms/Scalar/CMakeLists.txt @@ -79,4 +79,5 @@ DEPENDS intrinsics_gen + directives_gen ) Index: llvm/lib/Transforms/Utils/CMakeLists.txt =================================================================== --- llvm/lib/Transforms/Utils/CMakeLists.txt +++ llvm/lib/Transforms/Utils/CMakeLists.txt @@ -24,6 +24,7 @@ ImportedFunctionsInliningStatistics.cpp InstructionNamer.cpp IntegerDivision.cpp + IntrinsicUtils.cpp LCSSA.cpp LibCallsShrinkWrap.cpp Local.cpp Index: llvm/lib/Transforms/Utils/IntrinsicUtils.cpp =================================================================== --- /dev/null +++ llvm/lib/Transforms/Utils/IntrinsicUtils.cpp @@ -0,0 +1,61 @@ +//==---- IntrinsicUtils.cpp - Utilities for directives-based intrinsics ----==// +// +// 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 provides a set of utilities for VPO-based intrinsic function +/// calls. E.g., directives that mark the beginning and end of SIMD and +/// parallel regions. +/// +// ===--------------------------------------------------------------------=== // + +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Metadata.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Debug.h" +#include "llvm/Transforms/Utils/IntrinsicUtils.h" +#include "llvm/Analysis/Directives.h" + +#define DEBUG_TYPE "IntrinsicUtils" + +using namespace llvm; + +StringRef IntrinsicUtils::getDirectiveString(int Id) { + assert(Directives::DirectiveStrings.count(Id) && + "Can't find a string for directive id"); + return Directives::DirectiveStrings[Id]; +} + +StringRef IntrinsicUtils::getClauseString(int Id) { + assert(Directives::ClauseStrings.count(Id) && + "Can't find a string for clause id"); + return Directives::ClauseStrings[Id]; +} + +bool IntrinsicUtils::isDirective(Instruction *I) { + if (I == nullptr) + return false; + IntrinsicInst *Call = dyn_cast(I); + if (Call) { + Intrinsic::ID Id = Call->getIntrinsicID(); + if (Id == Intrinsic::directive_region_entry || + Id == Intrinsic::directive_region_exit) + if (Call->getNumOperandBundles() > 0) { + // First operand bundle has the directive name + OperandBundleUse BU = Call->getOperandBundleAt(0); + // Check if the TagName corresponds to an OpenMP directive name + return Directives::DirectiveIDs.count(BU.getTagName()); + } + } + return false; +} Index: llvm/utils/TableGen/CMakeLists.txt =================================================================== --- llvm/utils/TableGen/CMakeLists.txt +++ llvm/utils/TableGen/CMakeLists.txt @@ -29,6 +29,7 @@ InstrInfoEmitter.cpp InstrDocsEmitter.cpp IntrinsicEmitter.cpp + DirectivesEmitter.cpp OptParserEmitter.cpp PredicateExpander.cpp PseudoLoweringEmitter.cpp Index: llvm/utils/TableGen/DirectivesEmitter.cpp =================================================================== --- /dev/null +++ llvm/utils/TableGen/DirectivesEmitter.cpp @@ -0,0 +1,209 @@ +// +// 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 tablegen backend is responsible for emitting the enums and tables for +/// the directives and clauses that support parallelization/vectorization. +/// These tables are used to look up strings for use as arguments to intrinsics +/// that define vector/parallel regions and constructs. +/// +/// External interfaces: +/// void EmitDirectives(RecordKeeper &RK, raw_ostream &OS); +/// +// ===--------------------------------------------------------------------=== // + +#include "CodeGenTarget.h" +#include "llvm/Support/Format.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" + +using namespace llvm; + +#define DEBUG_TYPE "Directives" +#include "llvm/Support/Debug.h" + +namespace { + +class DirectivesEmitter { + + RecordKeeper &Records; + +private: + void emitDirectivesEnums(raw_ostream &OS); + void emitClausesEnums(raw_ostream &OS); + void emitDirectivesStringsTable(raw_ostream &OS); + void emitClausesStringsTable(raw_ostream &OS); + void emitDirectivesIdsTable(raw_ostream &OS); + void emitClausesIdsTable(raw_ostream &OS); + std::string genDirectiveClauseEnumString(StringRef DCString); + +public: + DirectivesEmitter(RecordKeeper &R) : Records(R) {} + + // Output the directives and clauses to an enum and enum to string map. + void run(raw_ostream &OS); +}; +} // End anonymous namespace + +/// \brief Generate the enum string for directives and clauses. +std::string +DirectivesEmitter::genDirectiveClauseEnumString(StringRef DCString) { + SmallVector StringParts; + DCString.split(StringParts, '.'); + std::string DCEnum = StringParts[0]; + for (unsigned Idx = 1; Idx < StringParts.size(); Idx++) { + DCEnum = DCEnum + "_" + StringParts[Idx].str(); + } + return DCEnum; +} + +/// \brief Emit the enumerations for parallel/vector directives. +/// E.g., things like the begin/end of a simd loop, parallel region, etc. +void DirectivesEmitter::emitDirectivesEnums(raw_ostream &OS) { + + Record *DirectiveClass = Records.getClass("Directive"); + assert(DirectiveClass && + "Directive class not found in target description file!"); + + OS << "#ifdef GET_DIRECTIVES_ENUM_VALUES\n"; + + for (const auto &D : Records.getDefs()) { + if (D.second->isSubClassOf(DirectiveClass)) { + std::string DirectiveName = D.first; + StringRef DirectiveString = StringRef(DirectiveName); + std::string DirectiveEnum = genDirectiveClauseEnumString(DirectiveString); + OS << " " << DirectiveEnum << ",\n"; + } + } + + OS << "#endif // GET_DIRECTIVES_ENUM_VALUES\n\n"; +} + +/// \brief Emit the enumerations for parallel/vector clauses. +/// E.g., things like the shared clause for OpenMP. +void DirectivesEmitter::emitClausesEnums(raw_ostream &OS) { + + Record *ClauseClass = Records.getClass("Clause"); + assert(ClauseClass && "Clause class not found in target description file!"); + + OS << "#ifdef GET_CLAUSES_ENUM_VALUES\n"; + + for (const auto &D : Records.getDefs()) { + if (D.second->isSubClassOf(ClauseClass)) { + std::string ClauseName = D.first; + StringRef ClauseString = StringRef(ClauseName); + std::string ClauseEnum = genDirectiveClauseEnumString(ClauseString); + OS << " " << ClauseEnum << ",\n"; + } + } + + OS << "#endif // GET_CLAUSES_ENUM_VALUES\n\n"; +} + +/// \brief emit the enum to string mapping for the vector/parallel directives. +void DirectivesEmitter::emitDirectivesStringsTable(raw_ostream &OS) { + + Record *DirectiveClass = Records.getClass("Directive"); + assert(DirectiveClass && + "Directive class not found in target description file!"); + + OS << "#ifdef GET_DIRECTIVES_STRINGS_TABLE\n"; + + for (const auto &D : Records.getDefs()) { + if (D.second->isSubClassOf(DirectiveClass)) { + std::string DirectiveName = D.first; + StringRef DirectiveString = StringRef(DirectiveName); + std::string DirectiveEnum = genDirectiveClauseEnumString(DirectiveString); + OS << " { " << DirectiveEnum << ",\n"; + OS << " \"" << DirectiveString << "\" },\n"; + } + } + + OS << "#endif // GET_DIRECTIVES_STRINGS_TABLE\n\n"; +} + +/// \brief emit the string to enum mapping for the vector/parallel directives. +void DirectivesEmitter::emitDirectivesIdsTable(raw_ostream &OS) { + + Record *DirectiveClass = Records.getClass("Directive"); + assert(DirectiveClass && + "Directive class not found in target description file!"); + + OS << "#ifdef GET_DIRECTIVES_IDS_TABLE\n"; + + for (const auto &D : Records.getDefs()) { + if (D.second->isSubClassOf(DirectiveClass)) { + std::string DirectiveName = D.first; + StringRef DirectiveString = StringRef(DirectiveName); + std::string DirectiveEnum = genDirectiveClauseEnumString(DirectiveString); + OS << " { \"" << DirectiveString << "\",\n"; + OS << " " << DirectiveEnum << " },\n"; + } + } + + OS << "#endif // GET_DIRECTIVES_IDS_TABLE\n\n"; +} + +/// \brief emit the enum to string mapping for the vector/parallel clauses. +void DirectivesEmitter::emitClausesStringsTable(raw_ostream &OS) { + + Record *ClauseClass = Records.getClass("Clause"); + assert(ClauseClass && "Clause class not found in target description file!"); + + OS << "#ifdef GET_CLAUSES_STRINGS_TABLE\n"; + + for (const auto &D : Records.getDefs()) { + if (D.second->isSubClassOf(ClauseClass)) { + std::string ClauseName = D.first; + StringRef ClauseString = StringRef(ClauseName); + std::string ClauseEnum = genDirectiveClauseEnumString(ClauseString); + OS << " { " << ClauseEnum << ",\n"; + OS << " \"" << ClauseString << "\" },\n"; + } + } + + OS << "#endif // GET_CLAUSES_STRINGS_TABLE\n\n"; +} + +/// \brief emit the string to enum mapping for the vector/parallel clauses. +void DirectivesEmitter::emitClausesIdsTable(raw_ostream &OS) { + + Record *ClauseClass = Records.getClass("Clause"); + assert(ClauseClass && "Clause class not found in target description file!"); + + OS << "#ifdef GET_CLAUSES_IDS_TABLE\n"; + + for (const auto &D : Records.getDefs()) { + if (D.second->isSubClassOf(ClauseClass)) { + std::string ClauseName = D.first; + StringRef ClauseString = StringRef(ClauseName); + std::string ClauseEnum = genDirectiveClauseEnumString(ClauseString); + OS << " { \"" << ClauseString << "\",\n"; + OS << " " << ClauseEnum << " },\n"; + } + } + + OS << "#endif // GET_CLAUSES_IDS_TABLE\n\n"; +} + +void DirectivesEmitter::run(raw_ostream &OS) { + emitDirectivesEnums(OS); + emitClausesEnums(OS); + emitDirectivesStringsTable(OS); + emitClausesStringsTable(OS); + emitDirectivesIdsTable(OS); + emitClausesIdsTable(OS); +} + +namespace llvm { + +void EmitDirectives(RecordKeeper &RK, raw_ostream &OS) { + DirectivesEmitter(RK).run(OS); +} + +} // End llvm namespace Index: llvm/utils/TableGen/TableGen.cpp =================================================================== --- llvm/utils/TableGen/TableGen.cpp +++ llvm/utils/TableGen/TableGen.cpp @@ -46,6 +46,7 @@ PrintSets, GenOptParserDefs, GenCTags, + GenDirectives, GenAttributes, GenSearchableTables, GenGlobalISel, @@ -114,6 +115,9 @@ "Generate ctags-compatible index"), clEnumValN(GenAttributes, "gen-attrs", "Generate attributes"), + clEnumValN(GenDirectives, "gen-directives", + "Generate directive enums and tables for \ + unroll/parallel/vector constructs and regions"), clEnumValN(GenSearchableTables, "gen-searchable-tables", "Generate generic binary-searchable table"), clEnumValN(GenGlobalISel, "gen-global-isel", @@ -229,6 +233,9 @@ case GenAttributes: EmitAttributes(Records, OS); break; + case GenDirectives: + EmitDirectives(Records, OS); + break; case GenSearchableTables: EmitSearchableTables(Records, OS); break; Index: llvm/utils/TableGen/TableGenBackends.h =================================================================== --- llvm/utils/TableGen/TableGenBackends.h +++ llvm/utils/TableGen/TableGenBackends.h @@ -83,6 +83,7 @@ void EmitOptParser(RecordKeeper &RK, raw_ostream &OS); void EmitCTags(RecordKeeper &RK, raw_ostream &OS); void EmitAttributes(RecordKeeper &RK, raw_ostream &OS); +void EmitDirectives(RecordKeeper &RK, raw_ostream &OS); void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS); void EmitGlobalISel(RecordKeeper &RK, raw_ostream &OS); void EmitX86EVEX2VEXTables(RecordKeeper &RK, raw_ostream &OS);