-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[MLIR][OpenMP] Automate operand structure definition #99508
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-flang-fir-hlfir @llvm/pr-subscribers-mlir-ods Author: Sergio Afonso (skatrak) ChangesThis patch adds the "gen-openmp-clause-ops" Changes introduced to the The original header is maintained to enable the definition of similar structures that are not directly related to any single Patch is 23.55 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/99508.diff 5 Files Affected:
diff --git a/mlir/include/mlir/Dialect/OpenMP/CMakeLists.txt b/mlir/include/mlir/Dialect/OpenMP/CMakeLists.txt
index d3422f6e48b06..23ccba3067bcb 100644
--- a/mlir/include/mlir/Dialect/OpenMP/CMakeLists.txt
+++ b/mlir/include/mlir/Dialect/OpenMP/CMakeLists.txt
@@ -17,6 +17,7 @@ mlir_tablegen(OpenMPOpsDialect.h.inc -gen-dialect-decls -dialect=omp)
mlir_tablegen(OpenMPOpsDialect.cpp.inc -gen-dialect-defs -dialect=omp)
mlir_tablegen(OpenMPOps.h.inc -gen-op-decls)
mlir_tablegen(OpenMPOps.cpp.inc -gen-op-defs)
+mlir_tablegen(OpenMPClauseOps.h.inc -gen-openmp-clause-ops)
mlir_tablegen(OpenMPOpsTypes.h.inc -gen-typedef-decls -typedefs-dialect=omp)
mlir_tablegen(OpenMPOpsTypes.cpp.inc -gen-typedef-defs -typedefs-dialect=omp)
mlir_tablegen(OpenMPOpsEnums.h.inc -gen-enum-decls)
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h
index f4a87d52a172e..e5b4de4908966 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h
@@ -23,303 +23,31 @@
#define GET_ATTRDEF_CLASSES
#include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.h.inc"
+#include "mlir/Dialect/OpenMP/OpenMPClauseOps.h.inc"
+
namespace mlir {
namespace omp {
//===----------------------------------------------------------------------===//
-// Mixin structures defining MLIR operands associated with each OpenMP clause.
+// Extra clause operand structures.
//===----------------------------------------------------------------------===//
-struct AlignedClauseOps {
- llvm::SmallVector<Value> alignedVars;
- llvm::SmallVector<Attribute> alignments;
-};
-
-struct AllocateClauseOps {
- llvm::SmallVector<Value> allocateVars, allocatorVars;
-};
-
-struct CancelDirectiveNameClauseOps {
- ClauseCancellationConstructTypeAttr cancelDirective;
-};
-
-struct CollapseClauseOps {
- llvm::SmallVector<Value> collapseLowerBound, collapseUpperBound, collapseStep;
-};
-
-struct CopyprivateClauseOps {
- llvm::SmallVector<Value> copyprivateVars;
- llvm::SmallVector<Attribute> copyprivateSyms;
-};
-
-struct CriticalNameClauseOps {
- StringAttr symName;
-};
-
-struct DependClauseOps {
- llvm::SmallVector<Attribute> dependKinds;
- llvm::SmallVector<Value> dependVars;
-};
-
-struct DeviceClauseOps {
- Value device;
-};
-
struct DeviceTypeClauseOps {
// The default capture type.
DeclareTargetDeviceType deviceType = DeclareTargetDeviceType::any;
};
-struct DistScheduleClauseOps {
- UnitAttr distScheduleStatic;
- Value distScheduleChunkSize;
-};
-
-struct DoacrossClauseOps {
- ClauseDependAttr doacrossDependType;
- IntegerAttr doacrossNumLoops;
- llvm::SmallVector<Value> doacrossDependVars;
-};
-
-struct FilterClauseOps {
- Value filteredThreadId;
-};
-
-struct FinalClauseOps {
- Value final;
-};
-
-struct GrainsizeClauseOps {
- Value grainsize;
-};
-
-struct HasDeviceAddrClauseOps {
- llvm::SmallVector<Value> hasDeviceAddrVars;
-};
-
-struct HintClauseOps {
- IntegerAttr hint;
-};
-
-struct IfClauseOps {
- Value ifVar;
-};
-
-struct InReductionClauseOps {
- llvm::SmallVector<Value> inReductionVars;
- llvm::SmallVector<bool> inReductionByref;
- llvm::SmallVector<Attribute> inReductionSyms;
-};
-
-struct IsDevicePtrClauseOps {
- llvm::SmallVector<Value> isDevicePtrVars;
-};
-
-struct LinearClauseOps {
- llvm::SmallVector<Value> linearVars, linearStepVars;
-};
-
-struct LoopRelatedOps {
- UnitAttr loopInclusive;
-};
-
-struct MapClauseOps {
- llvm::SmallVector<Value> mapVars;
-};
-
-struct MergeableClauseOps {
- UnitAttr mergeable;
-};
-
-struct NogroupClauseOps {
- UnitAttr nogroup;
-};
-
-struct NontemporalClauseOps {
- llvm::SmallVector<Value> nontemporalVars;
-};
-
-struct NowaitClauseOps {
- UnitAttr nowait;
-};
-
-struct NumTasksClauseOps {
- Value numTasks;
-};
-
-struct NumTeamsClauseOps {
- Value numTeamsLower, numTeamsUpper;
-};
-
-struct NumThreadsClauseOps {
- Value numThreads;
-};
-
-struct OrderClauseOps {
- ClauseOrderKindAttr order;
- OrderModifierAttr orderMod;
-};
-
-struct OrderedClauseOps {
- IntegerAttr ordered;
-};
-
-struct ParallelizationLevelClauseOps {
- UnitAttr parLevelSimd;
-};
-
-struct PriorityClauseOps {
- Value priority;
-};
-
-struct PrivateClauseOps {
- // SSA values that correspond to "original" values being privatized.
- // They refer to the SSA value outside the OpenMP region from which a clone is
- // created inside the region.
- llvm::SmallVector<Value> privateVars;
- // The list of symbols referring to delayed privatizer ops (i.e. `omp.private`
- // ops).
- llvm::SmallVector<Attribute> privateSyms;
-};
-
-struct ProcBindClauseOps {
- ClauseProcBindKindAttr procBindKind;
-};
-
-struct ReductionClauseOps {
- llvm::SmallVector<Value> reductionVars;
- llvm::SmallVector<bool> reductionByref;
- llvm::SmallVector<Attribute> reductionSyms;
-};
-
-struct SafelenClauseOps {
- IntegerAttr safelen;
-};
-
-struct ScheduleClauseOps {
- ClauseScheduleKindAttr scheduleKind;
- Value scheduleChunk;
- ScheduleModifierAttr scheduleMod;
- UnitAttr scheduleSimd;
-};
-
-struct SimdlenClauseOps {
- IntegerAttr simdlen;
-};
-
-struct TaskReductionClauseOps {
- llvm::SmallVector<Value> taskReductionVars;
- llvm::SmallVector<bool> taskReductionByref;
- llvm::SmallVector<Attribute> taskReductionSyms;
-};
-
-struct ThreadLimitClauseOps {
- Value threadLimit;
-};
-
-struct UntiedClauseOps {
- UnitAttr untied;
-};
-
-struct UseDeviceAddrClauseOps {
- llvm::SmallVector<Value> useDeviceAddrVars;
-};
-
-struct UseDevicePtrClauseOps {
- llvm::SmallVector<Value> useDevicePtrVars;
-};
-
//===----------------------------------------------------------------------===//
-// Structures defining clause operands associated with each OpenMP leaf
-// construct.
-//
-// These mirror the arguments expected by the corresponding OpenMP MLIR ops.
+// Extra operation operand structures.
//===----------------------------------------------------------------------===//
-namespace detail {
-template <typename... Mixins>
-struct Clauses : public Mixins... {};
-} // namespace detail
-
-using CancelOperands =
- detail::Clauses<CancelDirectiveNameClauseOps, IfClauseOps>;
-
-using CancellationPointOperands = detail::Clauses<CancelDirectiveNameClauseOps>;
-
-using CriticalDeclareOperands =
- detail::Clauses<CriticalNameClauseOps, HintClauseOps>;
-
-// TODO `indirect` clause.
+// TODO: Add `indirect` clause.
using DeclareTargetOperands = detail::Clauses<DeviceTypeClauseOps>;
-using DistributeOperands =
- detail::Clauses<AllocateClauseOps, DistScheduleClauseOps, OrderClauseOps,
- PrivateClauseOps>;
-
-using LoopNestOperands = detail::Clauses<CollapseClauseOps, LoopRelatedOps>;
-
-using MaskedOperands = detail::Clauses<FilterClauseOps>;
-
-using OrderedOperands = detail::Clauses<DoacrossClauseOps>;
-
-using OrderedRegionOperands = detail::Clauses<ParallelizationLevelClauseOps>;
-
-using ParallelOperands =
- detail::Clauses<AllocateClauseOps, IfClauseOps, NumThreadsClauseOps,
- PrivateClauseOps, ProcBindClauseOps, ReductionClauseOps>;
-
-using SectionsOperands = detail::Clauses<AllocateClauseOps, NowaitClauseOps,
- PrivateClauseOps, ReductionClauseOps>;
-
-// TODO `linear` clause.
-using SimdOperands =
- detail::Clauses<AlignedClauseOps, IfClauseOps, NontemporalClauseOps,
- OrderClauseOps, PrivateClauseOps, ReductionClauseOps,
- SafelenClauseOps, SimdlenClauseOps>;
-
-using SingleOperands = detail::Clauses<AllocateClauseOps, CopyprivateClauseOps,
- NowaitClauseOps, PrivateClauseOps>;
-
-// TODO `defaultmap`, `uses_allocators` clauses.
-using TargetOperands =
- detail::Clauses<AllocateClauseOps, DependClauseOps, DeviceClauseOps,
- HasDeviceAddrClauseOps, IfClauseOps, InReductionClauseOps,
- IsDevicePtrClauseOps, MapClauseOps, NowaitClauseOps,
- PrivateClauseOps, ThreadLimitClauseOps>;
-
-using TargetDataOperands =
- detail::Clauses<DeviceClauseOps, IfClauseOps, MapClauseOps,
- UseDeviceAddrClauseOps, UseDevicePtrClauseOps>;
-
-using TargetEnterExitUpdateDataOperands =
- detail::Clauses<DependClauseOps, DeviceClauseOps, IfClauseOps, MapClauseOps,
- NowaitClauseOps>;
-
-// TODO `affinity`, `detach` clauses.
-using TaskOperands =
- detail::Clauses<AllocateClauseOps, DependClauseOps, FinalClauseOps,
- IfClauseOps, InReductionClauseOps, MergeableClauseOps,
- PriorityClauseOps, PrivateClauseOps, UntiedClauseOps>;
-
-using TaskgroupOperands =
- detail::Clauses<AllocateClauseOps, TaskReductionClauseOps>;
-
-using TaskloopOperands =
- detail::Clauses<AllocateClauseOps, FinalClauseOps, GrainsizeClauseOps,
- IfClauseOps, InReductionClauseOps, MergeableClauseOps,
- NogroupClauseOps, NumTasksClauseOps, PriorityClauseOps,
- PrivateClauseOps, ReductionClauseOps, UntiedClauseOps>;
-
-using TaskwaitOperands = detail::Clauses<DependClauseOps, NowaitClauseOps>;
-
-using TeamsOperands =
- detail::Clauses<AllocateClauseOps, IfClauseOps, NumTeamsClauseOps,
- PrivateClauseOps, ReductionClauseOps, ThreadLimitClauseOps>;
-
-using WsloopOperands =
- detail::Clauses<AllocateClauseOps, LinearClauseOps, NowaitClauseOps,
- OrderClauseOps, OrderedClauseOps, PrivateClauseOps,
- ReductionClauseOps, ScheduleClauseOps>;
+// omp.target_enter_data, omp.target_exit_data and omp.target_update take the
+// same clauses, so we give the structure to be shared by all of them a
+// representative name.
+using TargetEnterExitUpdateDataOperands = TargetEnterDataOperands;
} // namespace omp
} // namespace mlir
diff --git a/mlir/include/mlir/IR/CommonAttrConstraints.td b/mlir/include/mlir/IR/CommonAttrConstraints.td
index d99bde1f87ef0..f9dcfedfee105 100644
--- a/mlir/include/mlir/IR/CommonAttrConstraints.td
+++ b/mlir/include/mlir/IR/CommonAttrConstraints.td
@@ -408,10 +408,18 @@ class ElementsAttrBase<Pred condition, string summary> :
let storageType = [{ ::mlir::ElementsAttr }];
let returnType = [{ ::mlir::ElementsAttr }];
let convertFromStorage = "$_self";
+
+ // The underlying C++ value type of each element.
+ string elementReturnType = ?;
+
+ // The number of dimensions represented by the element collection.
+ int rank = 1;
}
def ElementsAttr : ElementsAttrBase<CPred<"::llvm::isa<::mlir::ElementsAttr>($_self)">,
- "constant vector/tensor attribute">;
+ "constant vector/tensor attribute"> {
+ let elementReturnType = [{ ::mlir::Attribute }];
+}
class IntElementsAttrBase<Pred condition, string summary> :
ElementsAttrBase<And<[CPred<"::llvm::isa<::mlir::DenseIntElementsAttr>($_self)">,
@@ -419,6 +427,7 @@ class IntElementsAttrBase<Pred condition, string summary> :
summary> {
let storageType = [{ ::mlir::DenseIntElementsAttr }];
let returnType = [{ ::mlir::DenseIntElementsAttr }];
+ let elementReturnType = [{ ::llvm::APInt }];
let convertFromStorage = "$_self";
}
@@ -428,6 +437,7 @@ class DenseArrayAttrBase<string denseAttrName, string cppType, string summaryNam
summaryName # " dense array attribute"> {
let storageType = "::mlir::" # denseAttrName;
let returnType = "::llvm::ArrayRef<" # cppType # ">";
+ let elementReturnType = cppType;
let constBuilderCall = "$_builder.get" # denseAttrName # "($0)";
}
def DenseBoolArrayAttr : DenseArrayAttrBase<"DenseBoolArrayAttr", "bool", "i1">;
@@ -486,6 +496,8 @@ class RankedSignlessIntElementsAttr<int width, list<int> dims> :
let constBuilderCall = "::mlir::DenseIntElementsAttr::get("
"::mlir::RankedTensorType::get({" # !interleave(dims, ", ") #
"}, $_builder.getIntegerType(" # width # ")), ::llvm::ArrayRef($0))";
+
+ let rank = !size(dims);
}
class RankedI32ElementsAttr<list<int> dims> :
@@ -501,6 +513,7 @@ class FloatElementsAttr<int width> : ElementsAttrBase<
let storageType = [{ ::mlir::DenseElementsAttr }];
let returnType = [{ ::mlir::DenseElementsAttr }];
+ let elementReturnType = [{ ::llvm::APFloat }];
// Note that this is only constructing scalar elements attribute.
let constBuilderCall = "::mlir::DenseElementsAttr::get("
@@ -526,6 +539,8 @@ class RankedFloatElementsAttr<int width, list<int> dims> : ElementsAttrBase<
let storageType = [{ ::mlir::DenseFPElementsAttr }];
let returnType = [{ ::mlir::DenseFPElementsAttr }];
+ let elementReturnType = [{ ::llvm::APFloat }];
+ let rank = !size(dims);
let constBuilderCall = "::llvm::cast<::mlir::DenseFPElementsAttr>("
"::mlir::DenseElementsAttr::get("
@@ -544,6 +559,7 @@ def StringElementsAttr : ElementsAttrBase<
let storageType = [{ ::mlir::DenseElementsAttr }];
let returnType = [{ ::mlir::DenseElementsAttr }];
+ let elementReturnType = [{ ::llvm::SmallString }];
let convertFromStorage = "$_self";
}
diff --git a/mlir/test/mlir-tblgen/openmp-clause-ops.td b/mlir/test/mlir-tblgen/openmp-clause-ops.td
new file mode 100644
index 0000000000000..b0139eb546e1b
--- /dev/null
+++ b/mlir/test/mlir-tblgen/openmp-clause-ops.td
@@ -0,0 +1,78 @@
+// Tablegen tests for the automatic generation of OpenMP clause operand
+// structure definitions.
+
+// Run tablegen to generate OmpCommon.td in temp directory first.
+// RUN: mkdir -p %t/mlir/Dialect/OpenMP
+// RUN: mlir-tblgen --gen-directive-decl --directives-dialect=OpenMP \
+// RUN: %S/../../../llvm/include/llvm/Frontend/OpenMP/OMP.td \
+// RUN: -I %S/../../../llvm/include > %t/mlir/Dialect/OpenMP/OmpCommon.td
+
+// RUN: mlir-tblgen -gen-openmp-clause-ops -I %S/../../include -I %t %s | FileCheck %s
+
+include "mlir/Dialect/OpenMP/OpenMPOpBase.td"
+
+
+def OpenMP_MyFirstClause : OpenMP_Clause<
+ /*isRequired=*/false, /*skipTraits=*/false, /*skipArguments=*/false,
+ /*skipAssemblyFormat=*/false, /*skipDescription=*/false,
+ /*skipExtraClassDeclaration=*/false> {
+ let arguments = (ins
+ // Simple attributes
+ I32Attr:$int_attr,
+ TypeAttr:$type_attr,
+ DeclareTargetAttr:$omp_attr,
+
+ // Array attributes
+ F32ArrayAttr:$float_array_attr,
+ StrArrayAttr:$str_array_attr,
+ AnyIntElementsAttr:$anyint_elems_attr,
+ RankedF32ElementsAttr<[3, 4, 5]>:$float_nd_elems_attr,
+
+ // Optional attributes
+ OptionalAttr<BoolAttr>:$opt_bool_attr,
+ OptionalAttr<I64ArrayAttr>:$opt_int_array_attr,
+ OptionalAttr<DenseI8ArrayAttr>:$opt_int_elems_attr,
+
+ // Multi-level composition
+ ConfinedAttr<OptionalAttr<I64Attr>, [IntMinValue<0>]>:$complex_opt_int_attr
+ );
+}
+// CHECK: struct MyFirstClauseOps {
+// CHECK-NEXT: ::mlir::IntegerAttr intAttr;
+// CHECK-NEXT: ::mlir::TypeAttr typeAttr;
+// CHECK-NEXT: ::mlir::omp::DeclareTargetAttr ompAttr;
+
+// CHECK-NEXT: ::llvm::SmallVector<::mlir::Attribute> floatArrayAttr;
+// CHECK-NEXT: ::llvm::SmallVector<::mlir::Attribute> strArrayAttr;
+// CHECK-NEXT: ::llvm::SmallVector<::llvm::APInt> anyintElemsAttr;
+// CHECK-NEXT: ::llvm::SmallVector<::llvm::APFloat> floatNdElemsAttr;
+// CHECK-NEXT: int floatNdElemsAttrDims[3];
+
+// CHECK-NEXT: ::mlir::BoolAttr optBoolAttr;
+// CHECK-NEXT: ::llvm::SmallVector<::mlir::Attribute> optIntArrayAttr;
+// CHECK-NEXT: ::llvm::SmallVector<int8_t> optIntElemsAttr;
+
+// CHECK-NEXT: ::mlir::IntegerAttr complexOptIntAttr;
+// CHECK-NEXT: }
+
+def OpenMP_MySecondClause : OpenMP_Clause<
+ /*isRequired=*/false, /*skipTraits=*/false, /*skipArguments=*/false,
+ /*skipAssemblyFormat=*/false, /*skipDescription=*/false,
+ /*skipExtraClassDeclaration=*/false> {
+ let arguments = (ins
+ I32:$int_val,
+ Optional<AnyType>:$opt_any_val,
+ Variadic<Index>:$variadic_index_val
+ );
+}
+// CHECK: struct MySecondClauseOps {
+// CHECK-NEXT: ::mlir::Value intVal;
+// CHECK-NEXT: ::mlir::Value optAnyVal;
+// CHECK-NEXT: ::llvm::SmallVector<::mlir::Value> variadicIndexVal;
+// CHECK-NEXT: }
+
+def OpenMP_MyFirstOp : OpenMP_Op<"op", clauses=[OpenMP_MyFirstClause]>;
+// CHECK: using MyFirstOperands = detail::Clauses<MyFirstClauseOps>;
+
+def OpenMP_MySecondOp : OpenMP_Op<"op", clauses=[OpenMP_MyFirstClause, OpenMP_MySecondClause]>;
+// CHECK: using MySecondOperands = detail::Clauses<MyFirstClauseOps, MySecondClauseOps>;
diff --git a/mlir/tools/mlir-tblgen/OmpOpGen.cpp b/mlir/tools/mlir-tblgen/OmpOpGen.cpp
index 51eb43f322e6a..d4c2cd48e891f 100644
--- a/mlir/tools/mlir-tblgen/OmpOpGen.cpp
+++ b/mlir/tools/mlir-tblgen/OmpOpGen.cpp
@@ -12,11 +12,43 @@
#include "mlir/TableGen/GenInfo.h"
+#include "mlir/TableGen/CodeGenHelpers.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/TypeSwitch.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
using namespace llvm;
+/// The code block defining the base mixin class for combining clause operand
+/// structures.
+static const char *const baseMixinClass = R"(
+namespace detail {
+template <typename... Mixins>
+struct Clauses : public Mixins... {};
+} // namespace detail
+)";
+
+/// The code block defining operation argument structures.
+static const char *const operationArgStruct = R"(
+using {0}Operands = detail::Clauses<{1}>;
+)";
+
+/// Remove multiple optional prefixes and suffixes from \c str.
+static StringRef stripPrefixAndSuffix(StringRef str,
+ llvm::ArrayRef<StringRef> prefixes,
+ llvm::ArrayRef<StringRef> suffixes) {
+ for (StringRef prefix : prefixes)
+ if (str.starts_with(prefix))
+ str = str.substr(prefix.size());
+
+ for (StringRef suffix : suffixes)
+ if (str.ends_with(suffix))
+ str = str.substr(0, str.size() - suffix.size());
+
+ return str;
+}
+
/// Obtain the name of the OpenMP clause a given record inheriting
/// `OpenMP_Clause` refers to.
///
@@ -53,19 +85,8 @@ static StringRef extractOmpClauseName(Record *clause) {
assert(!clauseClassName.empty() && "clause name must be found");
// Keep only the OpenMP clause name itself for reporting purposes.
- StringRef prefix = "OpenMP_";
- StringRef suffixes[] = {"Skip", "Clause"};
-
- if (clauseClassName.starts_with(prefix))
- clauseClassName = clauseClassName.substr(prefix.size());
-
- for (StringRef suffix : suffixes) {
- if (clauseClassName.ends_with(suffix))
- clauseClassName =
- clauseClassName.substr(0, clauseClassName.size() - suffix.size());
- }
-
- return clauseClassName;
+ return stripPrefixAndSuffix(clauseClassName, /*prefixes=*/{"OpenMP_"},
+ /*suffixes=*/{"Skip", "Clause"});
}
/// Check that the given argument, identified by its name and initialization
@@ -148,6 +169,110 @@ static void verifyClause(Record *op, Record *clause) {
"or explicitly skipping this field.");
}
+/// Translate the type of an OpenMP clause's argument to its corresponding
+/// representation for clause operand structures.
+///
+/// All kinds of values are represented as `mlir::Value` fields, whereas
+/// attributes are represented based on their `storageType`.
+///
+/// \param[in] init The `DefInit` object representing the argument.
+/// \param[out] rank Number of levels of array nesting associated with the
+/// type.
+///
+/// \return the name of the base type to represent elements of the argument
+/// type.
+static StringRef translateArgumentType(Init *init, int &rank) {
+ Record *def = cast<DefInit>(init)->getDef();
+ bool isAttr = false, isValue = false;
+
+ for (auto [sc, _] : def->getSuperClasses()) {
+ std::string scName = sc->getNameInitAsString();
+ if (scName == "OptionalAttr")
+ return translateArgumentType(def->getValue("baseAttr")->getValue(), rank);
+
+ if (scName == "TypedArrayAttrBase") {
+ ++rank;
+ return translateArgumentType(def->getValue("elementAttr")->getValue(),
+ rank);
+ }
+
+ if (scName == "ElementsAttrBase") {
+ rank += def->getValueAsInt("rank");
+ return def->getValueAsString("elementReturnType").trim();
+ }
+
+ if (scName == "Attr")
+ isAttr = true;
+ else if (scName == "TypeConstraint")
+ isValue = true;
+ else if (scName == "Variadic")
+ ...
[truncated]
|
@llvm/pr-subscribers-mlir-core Author: Sergio Afonso (skatrak) ChangesThis patch adds the "gen-openmp-clause-ops" Changes introduced to the The original header is maintained to enable the definition of similar structures that are not directly related to any single Patch is 23.55 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/99508.diff 5 Files Affected:
diff --git a/mlir/include/mlir/Dialect/OpenMP/CMakeLists.txt b/mlir/include/mlir/Dialect/OpenMP/CMakeLists.txt
index d3422f6e48b06..23ccba3067bcb 100644
--- a/mlir/include/mlir/Dialect/OpenMP/CMakeLists.txt
+++ b/mlir/include/mlir/Dialect/OpenMP/CMakeLists.txt
@@ -17,6 +17,7 @@ mlir_tablegen(OpenMPOpsDialect.h.inc -gen-dialect-decls -dialect=omp)
mlir_tablegen(OpenMPOpsDialect.cpp.inc -gen-dialect-defs -dialect=omp)
mlir_tablegen(OpenMPOps.h.inc -gen-op-decls)
mlir_tablegen(OpenMPOps.cpp.inc -gen-op-defs)
+mlir_tablegen(OpenMPClauseOps.h.inc -gen-openmp-clause-ops)
mlir_tablegen(OpenMPOpsTypes.h.inc -gen-typedef-decls -typedefs-dialect=omp)
mlir_tablegen(OpenMPOpsTypes.cpp.inc -gen-typedef-defs -typedefs-dialect=omp)
mlir_tablegen(OpenMPOpsEnums.h.inc -gen-enum-decls)
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h
index f4a87d52a172e..e5b4de4908966 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h
@@ -23,303 +23,31 @@
#define GET_ATTRDEF_CLASSES
#include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.h.inc"
+#include "mlir/Dialect/OpenMP/OpenMPClauseOps.h.inc"
+
namespace mlir {
namespace omp {
//===----------------------------------------------------------------------===//
-// Mixin structures defining MLIR operands associated with each OpenMP clause.
+// Extra clause operand structures.
//===----------------------------------------------------------------------===//
-struct AlignedClauseOps {
- llvm::SmallVector<Value> alignedVars;
- llvm::SmallVector<Attribute> alignments;
-};
-
-struct AllocateClauseOps {
- llvm::SmallVector<Value> allocateVars, allocatorVars;
-};
-
-struct CancelDirectiveNameClauseOps {
- ClauseCancellationConstructTypeAttr cancelDirective;
-};
-
-struct CollapseClauseOps {
- llvm::SmallVector<Value> collapseLowerBound, collapseUpperBound, collapseStep;
-};
-
-struct CopyprivateClauseOps {
- llvm::SmallVector<Value> copyprivateVars;
- llvm::SmallVector<Attribute> copyprivateSyms;
-};
-
-struct CriticalNameClauseOps {
- StringAttr symName;
-};
-
-struct DependClauseOps {
- llvm::SmallVector<Attribute> dependKinds;
- llvm::SmallVector<Value> dependVars;
-};
-
-struct DeviceClauseOps {
- Value device;
-};
-
struct DeviceTypeClauseOps {
// The default capture type.
DeclareTargetDeviceType deviceType = DeclareTargetDeviceType::any;
};
-struct DistScheduleClauseOps {
- UnitAttr distScheduleStatic;
- Value distScheduleChunkSize;
-};
-
-struct DoacrossClauseOps {
- ClauseDependAttr doacrossDependType;
- IntegerAttr doacrossNumLoops;
- llvm::SmallVector<Value> doacrossDependVars;
-};
-
-struct FilterClauseOps {
- Value filteredThreadId;
-};
-
-struct FinalClauseOps {
- Value final;
-};
-
-struct GrainsizeClauseOps {
- Value grainsize;
-};
-
-struct HasDeviceAddrClauseOps {
- llvm::SmallVector<Value> hasDeviceAddrVars;
-};
-
-struct HintClauseOps {
- IntegerAttr hint;
-};
-
-struct IfClauseOps {
- Value ifVar;
-};
-
-struct InReductionClauseOps {
- llvm::SmallVector<Value> inReductionVars;
- llvm::SmallVector<bool> inReductionByref;
- llvm::SmallVector<Attribute> inReductionSyms;
-};
-
-struct IsDevicePtrClauseOps {
- llvm::SmallVector<Value> isDevicePtrVars;
-};
-
-struct LinearClauseOps {
- llvm::SmallVector<Value> linearVars, linearStepVars;
-};
-
-struct LoopRelatedOps {
- UnitAttr loopInclusive;
-};
-
-struct MapClauseOps {
- llvm::SmallVector<Value> mapVars;
-};
-
-struct MergeableClauseOps {
- UnitAttr mergeable;
-};
-
-struct NogroupClauseOps {
- UnitAttr nogroup;
-};
-
-struct NontemporalClauseOps {
- llvm::SmallVector<Value> nontemporalVars;
-};
-
-struct NowaitClauseOps {
- UnitAttr nowait;
-};
-
-struct NumTasksClauseOps {
- Value numTasks;
-};
-
-struct NumTeamsClauseOps {
- Value numTeamsLower, numTeamsUpper;
-};
-
-struct NumThreadsClauseOps {
- Value numThreads;
-};
-
-struct OrderClauseOps {
- ClauseOrderKindAttr order;
- OrderModifierAttr orderMod;
-};
-
-struct OrderedClauseOps {
- IntegerAttr ordered;
-};
-
-struct ParallelizationLevelClauseOps {
- UnitAttr parLevelSimd;
-};
-
-struct PriorityClauseOps {
- Value priority;
-};
-
-struct PrivateClauseOps {
- // SSA values that correspond to "original" values being privatized.
- // They refer to the SSA value outside the OpenMP region from which a clone is
- // created inside the region.
- llvm::SmallVector<Value> privateVars;
- // The list of symbols referring to delayed privatizer ops (i.e. `omp.private`
- // ops).
- llvm::SmallVector<Attribute> privateSyms;
-};
-
-struct ProcBindClauseOps {
- ClauseProcBindKindAttr procBindKind;
-};
-
-struct ReductionClauseOps {
- llvm::SmallVector<Value> reductionVars;
- llvm::SmallVector<bool> reductionByref;
- llvm::SmallVector<Attribute> reductionSyms;
-};
-
-struct SafelenClauseOps {
- IntegerAttr safelen;
-};
-
-struct ScheduleClauseOps {
- ClauseScheduleKindAttr scheduleKind;
- Value scheduleChunk;
- ScheduleModifierAttr scheduleMod;
- UnitAttr scheduleSimd;
-};
-
-struct SimdlenClauseOps {
- IntegerAttr simdlen;
-};
-
-struct TaskReductionClauseOps {
- llvm::SmallVector<Value> taskReductionVars;
- llvm::SmallVector<bool> taskReductionByref;
- llvm::SmallVector<Attribute> taskReductionSyms;
-};
-
-struct ThreadLimitClauseOps {
- Value threadLimit;
-};
-
-struct UntiedClauseOps {
- UnitAttr untied;
-};
-
-struct UseDeviceAddrClauseOps {
- llvm::SmallVector<Value> useDeviceAddrVars;
-};
-
-struct UseDevicePtrClauseOps {
- llvm::SmallVector<Value> useDevicePtrVars;
-};
-
//===----------------------------------------------------------------------===//
-// Structures defining clause operands associated with each OpenMP leaf
-// construct.
-//
-// These mirror the arguments expected by the corresponding OpenMP MLIR ops.
+// Extra operation operand structures.
//===----------------------------------------------------------------------===//
-namespace detail {
-template <typename... Mixins>
-struct Clauses : public Mixins... {};
-} // namespace detail
-
-using CancelOperands =
- detail::Clauses<CancelDirectiveNameClauseOps, IfClauseOps>;
-
-using CancellationPointOperands = detail::Clauses<CancelDirectiveNameClauseOps>;
-
-using CriticalDeclareOperands =
- detail::Clauses<CriticalNameClauseOps, HintClauseOps>;
-
-// TODO `indirect` clause.
+// TODO: Add `indirect` clause.
using DeclareTargetOperands = detail::Clauses<DeviceTypeClauseOps>;
-using DistributeOperands =
- detail::Clauses<AllocateClauseOps, DistScheduleClauseOps, OrderClauseOps,
- PrivateClauseOps>;
-
-using LoopNestOperands = detail::Clauses<CollapseClauseOps, LoopRelatedOps>;
-
-using MaskedOperands = detail::Clauses<FilterClauseOps>;
-
-using OrderedOperands = detail::Clauses<DoacrossClauseOps>;
-
-using OrderedRegionOperands = detail::Clauses<ParallelizationLevelClauseOps>;
-
-using ParallelOperands =
- detail::Clauses<AllocateClauseOps, IfClauseOps, NumThreadsClauseOps,
- PrivateClauseOps, ProcBindClauseOps, ReductionClauseOps>;
-
-using SectionsOperands = detail::Clauses<AllocateClauseOps, NowaitClauseOps,
- PrivateClauseOps, ReductionClauseOps>;
-
-// TODO `linear` clause.
-using SimdOperands =
- detail::Clauses<AlignedClauseOps, IfClauseOps, NontemporalClauseOps,
- OrderClauseOps, PrivateClauseOps, ReductionClauseOps,
- SafelenClauseOps, SimdlenClauseOps>;
-
-using SingleOperands = detail::Clauses<AllocateClauseOps, CopyprivateClauseOps,
- NowaitClauseOps, PrivateClauseOps>;
-
-// TODO `defaultmap`, `uses_allocators` clauses.
-using TargetOperands =
- detail::Clauses<AllocateClauseOps, DependClauseOps, DeviceClauseOps,
- HasDeviceAddrClauseOps, IfClauseOps, InReductionClauseOps,
- IsDevicePtrClauseOps, MapClauseOps, NowaitClauseOps,
- PrivateClauseOps, ThreadLimitClauseOps>;
-
-using TargetDataOperands =
- detail::Clauses<DeviceClauseOps, IfClauseOps, MapClauseOps,
- UseDeviceAddrClauseOps, UseDevicePtrClauseOps>;
-
-using TargetEnterExitUpdateDataOperands =
- detail::Clauses<DependClauseOps, DeviceClauseOps, IfClauseOps, MapClauseOps,
- NowaitClauseOps>;
-
-// TODO `affinity`, `detach` clauses.
-using TaskOperands =
- detail::Clauses<AllocateClauseOps, DependClauseOps, FinalClauseOps,
- IfClauseOps, InReductionClauseOps, MergeableClauseOps,
- PriorityClauseOps, PrivateClauseOps, UntiedClauseOps>;
-
-using TaskgroupOperands =
- detail::Clauses<AllocateClauseOps, TaskReductionClauseOps>;
-
-using TaskloopOperands =
- detail::Clauses<AllocateClauseOps, FinalClauseOps, GrainsizeClauseOps,
- IfClauseOps, InReductionClauseOps, MergeableClauseOps,
- NogroupClauseOps, NumTasksClauseOps, PriorityClauseOps,
- PrivateClauseOps, ReductionClauseOps, UntiedClauseOps>;
-
-using TaskwaitOperands = detail::Clauses<DependClauseOps, NowaitClauseOps>;
-
-using TeamsOperands =
- detail::Clauses<AllocateClauseOps, IfClauseOps, NumTeamsClauseOps,
- PrivateClauseOps, ReductionClauseOps, ThreadLimitClauseOps>;
-
-using WsloopOperands =
- detail::Clauses<AllocateClauseOps, LinearClauseOps, NowaitClauseOps,
- OrderClauseOps, OrderedClauseOps, PrivateClauseOps,
- ReductionClauseOps, ScheduleClauseOps>;
+// omp.target_enter_data, omp.target_exit_data and omp.target_update take the
+// same clauses, so we give the structure to be shared by all of them a
+// representative name.
+using TargetEnterExitUpdateDataOperands = TargetEnterDataOperands;
} // namespace omp
} // namespace mlir
diff --git a/mlir/include/mlir/IR/CommonAttrConstraints.td b/mlir/include/mlir/IR/CommonAttrConstraints.td
index d99bde1f87ef0..f9dcfedfee105 100644
--- a/mlir/include/mlir/IR/CommonAttrConstraints.td
+++ b/mlir/include/mlir/IR/CommonAttrConstraints.td
@@ -408,10 +408,18 @@ class ElementsAttrBase<Pred condition, string summary> :
let storageType = [{ ::mlir::ElementsAttr }];
let returnType = [{ ::mlir::ElementsAttr }];
let convertFromStorage = "$_self";
+
+ // The underlying C++ value type of each element.
+ string elementReturnType = ?;
+
+ // The number of dimensions represented by the element collection.
+ int rank = 1;
}
def ElementsAttr : ElementsAttrBase<CPred<"::llvm::isa<::mlir::ElementsAttr>($_self)">,
- "constant vector/tensor attribute">;
+ "constant vector/tensor attribute"> {
+ let elementReturnType = [{ ::mlir::Attribute }];
+}
class IntElementsAttrBase<Pred condition, string summary> :
ElementsAttrBase<And<[CPred<"::llvm::isa<::mlir::DenseIntElementsAttr>($_self)">,
@@ -419,6 +427,7 @@ class IntElementsAttrBase<Pred condition, string summary> :
summary> {
let storageType = [{ ::mlir::DenseIntElementsAttr }];
let returnType = [{ ::mlir::DenseIntElementsAttr }];
+ let elementReturnType = [{ ::llvm::APInt }];
let convertFromStorage = "$_self";
}
@@ -428,6 +437,7 @@ class DenseArrayAttrBase<string denseAttrName, string cppType, string summaryNam
summaryName # " dense array attribute"> {
let storageType = "::mlir::" # denseAttrName;
let returnType = "::llvm::ArrayRef<" # cppType # ">";
+ let elementReturnType = cppType;
let constBuilderCall = "$_builder.get" # denseAttrName # "($0)";
}
def DenseBoolArrayAttr : DenseArrayAttrBase<"DenseBoolArrayAttr", "bool", "i1">;
@@ -486,6 +496,8 @@ class RankedSignlessIntElementsAttr<int width, list<int> dims> :
let constBuilderCall = "::mlir::DenseIntElementsAttr::get("
"::mlir::RankedTensorType::get({" # !interleave(dims, ", ") #
"}, $_builder.getIntegerType(" # width # ")), ::llvm::ArrayRef($0))";
+
+ let rank = !size(dims);
}
class RankedI32ElementsAttr<list<int> dims> :
@@ -501,6 +513,7 @@ class FloatElementsAttr<int width> : ElementsAttrBase<
let storageType = [{ ::mlir::DenseElementsAttr }];
let returnType = [{ ::mlir::DenseElementsAttr }];
+ let elementReturnType = [{ ::llvm::APFloat }];
// Note that this is only constructing scalar elements attribute.
let constBuilderCall = "::mlir::DenseElementsAttr::get("
@@ -526,6 +539,8 @@ class RankedFloatElementsAttr<int width, list<int> dims> : ElementsAttrBase<
let storageType = [{ ::mlir::DenseFPElementsAttr }];
let returnType = [{ ::mlir::DenseFPElementsAttr }];
+ let elementReturnType = [{ ::llvm::APFloat }];
+ let rank = !size(dims);
let constBuilderCall = "::llvm::cast<::mlir::DenseFPElementsAttr>("
"::mlir::DenseElementsAttr::get("
@@ -544,6 +559,7 @@ def StringElementsAttr : ElementsAttrBase<
let storageType = [{ ::mlir::DenseElementsAttr }];
let returnType = [{ ::mlir::DenseElementsAttr }];
+ let elementReturnType = [{ ::llvm::SmallString }];
let convertFromStorage = "$_self";
}
diff --git a/mlir/test/mlir-tblgen/openmp-clause-ops.td b/mlir/test/mlir-tblgen/openmp-clause-ops.td
new file mode 100644
index 0000000000000..b0139eb546e1b
--- /dev/null
+++ b/mlir/test/mlir-tblgen/openmp-clause-ops.td
@@ -0,0 +1,78 @@
+// Tablegen tests for the automatic generation of OpenMP clause operand
+// structure definitions.
+
+// Run tablegen to generate OmpCommon.td in temp directory first.
+// RUN: mkdir -p %t/mlir/Dialect/OpenMP
+// RUN: mlir-tblgen --gen-directive-decl --directives-dialect=OpenMP \
+// RUN: %S/../../../llvm/include/llvm/Frontend/OpenMP/OMP.td \
+// RUN: -I %S/../../../llvm/include > %t/mlir/Dialect/OpenMP/OmpCommon.td
+
+// RUN: mlir-tblgen -gen-openmp-clause-ops -I %S/../../include -I %t %s | FileCheck %s
+
+include "mlir/Dialect/OpenMP/OpenMPOpBase.td"
+
+
+def OpenMP_MyFirstClause : OpenMP_Clause<
+ /*isRequired=*/false, /*skipTraits=*/false, /*skipArguments=*/false,
+ /*skipAssemblyFormat=*/false, /*skipDescription=*/false,
+ /*skipExtraClassDeclaration=*/false> {
+ let arguments = (ins
+ // Simple attributes
+ I32Attr:$int_attr,
+ TypeAttr:$type_attr,
+ DeclareTargetAttr:$omp_attr,
+
+ // Array attributes
+ F32ArrayAttr:$float_array_attr,
+ StrArrayAttr:$str_array_attr,
+ AnyIntElementsAttr:$anyint_elems_attr,
+ RankedF32ElementsAttr<[3, 4, 5]>:$float_nd_elems_attr,
+
+ // Optional attributes
+ OptionalAttr<BoolAttr>:$opt_bool_attr,
+ OptionalAttr<I64ArrayAttr>:$opt_int_array_attr,
+ OptionalAttr<DenseI8ArrayAttr>:$opt_int_elems_attr,
+
+ // Multi-level composition
+ ConfinedAttr<OptionalAttr<I64Attr>, [IntMinValue<0>]>:$complex_opt_int_attr
+ );
+}
+// CHECK: struct MyFirstClauseOps {
+// CHECK-NEXT: ::mlir::IntegerAttr intAttr;
+// CHECK-NEXT: ::mlir::TypeAttr typeAttr;
+// CHECK-NEXT: ::mlir::omp::DeclareTargetAttr ompAttr;
+
+// CHECK-NEXT: ::llvm::SmallVector<::mlir::Attribute> floatArrayAttr;
+// CHECK-NEXT: ::llvm::SmallVector<::mlir::Attribute> strArrayAttr;
+// CHECK-NEXT: ::llvm::SmallVector<::llvm::APInt> anyintElemsAttr;
+// CHECK-NEXT: ::llvm::SmallVector<::llvm::APFloat> floatNdElemsAttr;
+// CHECK-NEXT: int floatNdElemsAttrDims[3];
+
+// CHECK-NEXT: ::mlir::BoolAttr optBoolAttr;
+// CHECK-NEXT: ::llvm::SmallVector<::mlir::Attribute> optIntArrayAttr;
+// CHECK-NEXT: ::llvm::SmallVector<int8_t> optIntElemsAttr;
+
+// CHECK-NEXT: ::mlir::IntegerAttr complexOptIntAttr;
+// CHECK-NEXT: }
+
+def OpenMP_MySecondClause : OpenMP_Clause<
+ /*isRequired=*/false, /*skipTraits=*/false, /*skipArguments=*/false,
+ /*skipAssemblyFormat=*/false, /*skipDescription=*/false,
+ /*skipExtraClassDeclaration=*/false> {
+ let arguments = (ins
+ I32:$int_val,
+ Optional<AnyType>:$opt_any_val,
+ Variadic<Index>:$variadic_index_val
+ );
+}
+// CHECK: struct MySecondClauseOps {
+// CHECK-NEXT: ::mlir::Value intVal;
+// CHECK-NEXT: ::mlir::Value optAnyVal;
+// CHECK-NEXT: ::llvm::SmallVector<::mlir::Value> variadicIndexVal;
+// CHECK-NEXT: }
+
+def OpenMP_MyFirstOp : OpenMP_Op<"op", clauses=[OpenMP_MyFirstClause]>;
+// CHECK: using MyFirstOperands = detail::Clauses<MyFirstClauseOps>;
+
+def OpenMP_MySecondOp : OpenMP_Op<"op", clauses=[OpenMP_MyFirstClause, OpenMP_MySecondClause]>;
+// CHECK: using MySecondOperands = detail::Clauses<MyFirstClauseOps, MySecondClauseOps>;
diff --git a/mlir/tools/mlir-tblgen/OmpOpGen.cpp b/mlir/tools/mlir-tblgen/OmpOpGen.cpp
index 51eb43f322e6a..d4c2cd48e891f 100644
--- a/mlir/tools/mlir-tblgen/OmpOpGen.cpp
+++ b/mlir/tools/mlir-tblgen/OmpOpGen.cpp
@@ -12,11 +12,43 @@
#include "mlir/TableGen/GenInfo.h"
+#include "mlir/TableGen/CodeGenHelpers.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/TypeSwitch.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
using namespace llvm;
+/// The code block defining the base mixin class for combining clause operand
+/// structures.
+static const char *const baseMixinClass = R"(
+namespace detail {
+template <typename... Mixins>
+struct Clauses : public Mixins... {};
+} // namespace detail
+)";
+
+/// The code block defining operation argument structures.
+static const char *const operationArgStruct = R"(
+using {0}Operands = detail::Clauses<{1}>;
+)";
+
+/// Remove multiple optional prefixes and suffixes from \c str.
+static StringRef stripPrefixAndSuffix(StringRef str,
+ llvm::ArrayRef<StringRef> prefixes,
+ llvm::ArrayRef<StringRef> suffixes) {
+ for (StringRef prefix : prefixes)
+ if (str.starts_with(prefix))
+ str = str.substr(prefix.size());
+
+ for (StringRef suffix : suffixes)
+ if (str.ends_with(suffix))
+ str = str.substr(0, str.size() - suffix.size());
+
+ return str;
+}
+
/// Obtain the name of the OpenMP clause a given record inheriting
/// `OpenMP_Clause` refers to.
///
@@ -53,19 +85,8 @@ static StringRef extractOmpClauseName(Record *clause) {
assert(!clauseClassName.empty() && "clause name must be found");
// Keep only the OpenMP clause name itself for reporting purposes.
- StringRef prefix = "OpenMP_";
- StringRef suffixes[] = {"Skip", "Clause"};
-
- if (clauseClassName.starts_with(prefix))
- clauseClassName = clauseClassName.substr(prefix.size());
-
- for (StringRef suffix : suffixes) {
- if (clauseClassName.ends_with(suffix))
- clauseClassName =
- clauseClassName.substr(0, clauseClassName.size() - suffix.size());
- }
-
- return clauseClassName;
+ return stripPrefixAndSuffix(clauseClassName, /*prefixes=*/{"OpenMP_"},
+ /*suffixes=*/{"Skip", "Clause"});
}
/// Check that the given argument, identified by its name and initialization
@@ -148,6 +169,110 @@ static void verifyClause(Record *op, Record *clause) {
"or explicitly skipping this field.");
}
+/// Translate the type of an OpenMP clause's argument to its corresponding
+/// representation for clause operand structures.
+///
+/// All kinds of values are represented as `mlir::Value` fields, whereas
+/// attributes are represented based on their `storageType`.
+///
+/// \param[in] init The `DefInit` object representing the argument.
+/// \param[out] rank Number of levels of array nesting associated with the
+/// type.
+///
+/// \return the name of the base type to represent elements of the argument
+/// type.
+static StringRef translateArgumentType(Init *init, int &rank) {
+ Record *def = cast<DefInit>(init)->getDef();
+ bool isAttr = false, isValue = false;
+
+ for (auto [sc, _] : def->getSuperClasses()) {
+ std::string scName = sc->getNameInitAsString();
+ if (scName == "OptionalAttr")
+ return translateArgumentType(def->getValue("baseAttr")->getValue(), rank);
+
+ if (scName == "TypedArrayAttrBase") {
+ ++rank;
+ return translateArgumentType(def->getValue("elementAttr")->getValue(),
+ rank);
+ }
+
+ if (scName == "ElementsAttrBase") {
+ rank += def->getValueAsInt("rank");
+ return def->getValueAsString("elementReturnType").trim();
+ }
+
+ if (scName == "Attr")
+ isAttr = true;
+ else if (scName == "TypeConstraint")
+ isValue = true;
+ else if (scName == "Variadic")
+ ...
[truncated]
|
@llvm/pr-subscribers-mlir Author: Sergio Afonso (skatrak) ChangesThis patch adds the "gen-openmp-clause-ops" Changes introduced to the The original header is maintained to enable the definition of similar structures that are not directly related to any single Patch is 23.55 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/99508.diff 5 Files Affected:
diff --git a/mlir/include/mlir/Dialect/OpenMP/CMakeLists.txt b/mlir/include/mlir/Dialect/OpenMP/CMakeLists.txt
index d3422f6e48b06..23ccba3067bcb 100644
--- a/mlir/include/mlir/Dialect/OpenMP/CMakeLists.txt
+++ b/mlir/include/mlir/Dialect/OpenMP/CMakeLists.txt
@@ -17,6 +17,7 @@ mlir_tablegen(OpenMPOpsDialect.h.inc -gen-dialect-decls -dialect=omp)
mlir_tablegen(OpenMPOpsDialect.cpp.inc -gen-dialect-defs -dialect=omp)
mlir_tablegen(OpenMPOps.h.inc -gen-op-decls)
mlir_tablegen(OpenMPOps.cpp.inc -gen-op-defs)
+mlir_tablegen(OpenMPClauseOps.h.inc -gen-openmp-clause-ops)
mlir_tablegen(OpenMPOpsTypes.h.inc -gen-typedef-decls -typedefs-dialect=omp)
mlir_tablegen(OpenMPOpsTypes.cpp.inc -gen-typedef-defs -typedefs-dialect=omp)
mlir_tablegen(OpenMPOpsEnums.h.inc -gen-enum-decls)
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h
index f4a87d52a172e..e5b4de4908966 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauseOperands.h
@@ -23,303 +23,31 @@
#define GET_ATTRDEF_CLASSES
#include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.h.inc"
+#include "mlir/Dialect/OpenMP/OpenMPClauseOps.h.inc"
+
namespace mlir {
namespace omp {
//===----------------------------------------------------------------------===//
-// Mixin structures defining MLIR operands associated with each OpenMP clause.
+// Extra clause operand structures.
//===----------------------------------------------------------------------===//
-struct AlignedClauseOps {
- llvm::SmallVector<Value> alignedVars;
- llvm::SmallVector<Attribute> alignments;
-};
-
-struct AllocateClauseOps {
- llvm::SmallVector<Value> allocateVars, allocatorVars;
-};
-
-struct CancelDirectiveNameClauseOps {
- ClauseCancellationConstructTypeAttr cancelDirective;
-};
-
-struct CollapseClauseOps {
- llvm::SmallVector<Value> collapseLowerBound, collapseUpperBound, collapseStep;
-};
-
-struct CopyprivateClauseOps {
- llvm::SmallVector<Value> copyprivateVars;
- llvm::SmallVector<Attribute> copyprivateSyms;
-};
-
-struct CriticalNameClauseOps {
- StringAttr symName;
-};
-
-struct DependClauseOps {
- llvm::SmallVector<Attribute> dependKinds;
- llvm::SmallVector<Value> dependVars;
-};
-
-struct DeviceClauseOps {
- Value device;
-};
-
struct DeviceTypeClauseOps {
// The default capture type.
DeclareTargetDeviceType deviceType = DeclareTargetDeviceType::any;
};
-struct DistScheduleClauseOps {
- UnitAttr distScheduleStatic;
- Value distScheduleChunkSize;
-};
-
-struct DoacrossClauseOps {
- ClauseDependAttr doacrossDependType;
- IntegerAttr doacrossNumLoops;
- llvm::SmallVector<Value> doacrossDependVars;
-};
-
-struct FilterClauseOps {
- Value filteredThreadId;
-};
-
-struct FinalClauseOps {
- Value final;
-};
-
-struct GrainsizeClauseOps {
- Value grainsize;
-};
-
-struct HasDeviceAddrClauseOps {
- llvm::SmallVector<Value> hasDeviceAddrVars;
-};
-
-struct HintClauseOps {
- IntegerAttr hint;
-};
-
-struct IfClauseOps {
- Value ifVar;
-};
-
-struct InReductionClauseOps {
- llvm::SmallVector<Value> inReductionVars;
- llvm::SmallVector<bool> inReductionByref;
- llvm::SmallVector<Attribute> inReductionSyms;
-};
-
-struct IsDevicePtrClauseOps {
- llvm::SmallVector<Value> isDevicePtrVars;
-};
-
-struct LinearClauseOps {
- llvm::SmallVector<Value> linearVars, linearStepVars;
-};
-
-struct LoopRelatedOps {
- UnitAttr loopInclusive;
-};
-
-struct MapClauseOps {
- llvm::SmallVector<Value> mapVars;
-};
-
-struct MergeableClauseOps {
- UnitAttr mergeable;
-};
-
-struct NogroupClauseOps {
- UnitAttr nogroup;
-};
-
-struct NontemporalClauseOps {
- llvm::SmallVector<Value> nontemporalVars;
-};
-
-struct NowaitClauseOps {
- UnitAttr nowait;
-};
-
-struct NumTasksClauseOps {
- Value numTasks;
-};
-
-struct NumTeamsClauseOps {
- Value numTeamsLower, numTeamsUpper;
-};
-
-struct NumThreadsClauseOps {
- Value numThreads;
-};
-
-struct OrderClauseOps {
- ClauseOrderKindAttr order;
- OrderModifierAttr orderMod;
-};
-
-struct OrderedClauseOps {
- IntegerAttr ordered;
-};
-
-struct ParallelizationLevelClauseOps {
- UnitAttr parLevelSimd;
-};
-
-struct PriorityClauseOps {
- Value priority;
-};
-
-struct PrivateClauseOps {
- // SSA values that correspond to "original" values being privatized.
- // They refer to the SSA value outside the OpenMP region from which a clone is
- // created inside the region.
- llvm::SmallVector<Value> privateVars;
- // The list of symbols referring to delayed privatizer ops (i.e. `omp.private`
- // ops).
- llvm::SmallVector<Attribute> privateSyms;
-};
-
-struct ProcBindClauseOps {
- ClauseProcBindKindAttr procBindKind;
-};
-
-struct ReductionClauseOps {
- llvm::SmallVector<Value> reductionVars;
- llvm::SmallVector<bool> reductionByref;
- llvm::SmallVector<Attribute> reductionSyms;
-};
-
-struct SafelenClauseOps {
- IntegerAttr safelen;
-};
-
-struct ScheduleClauseOps {
- ClauseScheduleKindAttr scheduleKind;
- Value scheduleChunk;
- ScheduleModifierAttr scheduleMod;
- UnitAttr scheduleSimd;
-};
-
-struct SimdlenClauseOps {
- IntegerAttr simdlen;
-};
-
-struct TaskReductionClauseOps {
- llvm::SmallVector<Value> taskReductionVars;
- llvm::SmallVector<bool> taskReductionByref;
- llvm::SmallVector<Attribute> taskReductionSyms;
-};
-
-struct ThreadLimitClauseOps {
- Value threadLimit;
-};
-
-struct UntiedClauseOps {
- UnitAttr untied;
-};
-
-struct UseDeviceAddrClauseOps {
- llvm::SmallVector<Value> useDeviceAddrVars;
-};
-
-struct UseDevicePtrClauseOps {
- llvm::SmallVector<Value> useDevicePtrVars;
-};
-
//===----------------------------------------------------------------------===//
-// Structures defining clause operands associated with each OpenMP leaf
-// construct.
-//
-// These mirror the arguments expected by the corresponding OpenMP MLIR ops.
+// Extra operation operand structures.
//===----------------------------------------------------------------------===//
-namespace detail {
-template <typename... Mixins>
-struct Clauses : public Mixins... {};
-} // namespace detail
-
-using CancelOperands =
- detail::Clauses<CancelDirectiveNameClauseOps, IfClauseOps>;
-
-using CancellationPointOperands = detail::Clauses<CancelDirectiveNameClauseOps>;
-
-using CriticalDeclareOperands =
- detail::Clauses<CriticalNameClauseOps, HintClauseOps>;
-
-// TODO `indirect` clause.
+// TODO: Add `indirect` clause.
using DeclareTargetOperands = detail::Clauses<DeviceTypeClauseOps>;
-using DistributeOperands =
- detail::Clauses<AllocateClauseOps, DistScheduleClauseOps, OrderClauseOps,
- PrivateClauseOps>;
-
-using LoopNestOperands = detail::Clauses<CollapseClauseOps, LoopRelatedOps>;
-
-using MaskedOperands = detail::Clauses<FilterClauseOps>;
-
-using OrderedOperands = detail::Clauses<DoacrossClauseOps>;
-
-using OrderedRegionOperands = detail::Clauses<ParallelizationLevelClauseOps>;
-
-using ParallelOperands =
- detail::Clauses<AllocateClauseOps, IfClauseOps, NumThreadsClauseOps,
- PrivateClauseOps, ProcBindClauseOps, ReductionClauseOps>;
-
-using SectionsOperands = detail::Clauses<AllocateClauseOps, NowaitClauseOps,
- PrivateClauseOps, ReductionClauseOps>;
-
-// TODO `linear` clause.
-using SimdOperands =
- detail::Clauses<AlignedClauseOps, IfClauseOps, NontemporalClauseOps,
- OrderClauseOps, PrivateClauseOps, ReductionClauseOps,
- SafelenClauseOps, SimdlenClauseOps>;
-
-using SingleOperands = detail::Clauses<AllocateClauseOps, CopyprivateClauseOps,
- NowaitClauseOps, PrivateClauseOps>;
-
-// TODO `defaultmap`, `uses_allocators` clauses.
-using TargetOperands =
- detail::Clauses<AllocateClauseOps, DependClauseOps, DeviceClauseOps,
- HasDeviceAddrClauseOps, IfClauseOps, InReductionClauseOps,
- IsDevicePtrClauseOps, MapClauseOps, NowaitClauseOps,
- PrivateClauseOps, ThreadLimitClauseOps>;
-
-using TargetDataOperands =
- detail::Clauses<DeviceClauseOps, IfClauseOps, MapClauseOps,
- UseDeviceAddrClauseOps, UseDevicePtrClauseOps>;
-
-using TargetEnterExitUpdateDataOperands =
- detail::Clauses<DependClauseOps, DeviceClauseOps, IfClauseOps, MapClauseOps,
- NowaitClauseOps>;
-
-// TODO `affinity`, `detach` clauses.
-using TaskOperands =
- detail::Clauses<AllocateClauseOps, DependClauseOps, FinalClauseOps,
- IfClauseOps, InReductionClauseOps, MergeableClauseOps,
- PriorityClauseOps, PrivateClauseOps, UntiedClauseOps>;
-
-using TaskgroupOperands =
- detail::Clauses<AllocateClauseOps, TaskReductionClauseOps>;
-
-using TaskloopOperands =
- detail::Clauses<AllocateClauseOps, FinalClauseOps, GrainsizeClauseOps,
- IfClauseOps, InReductionClauseOps, MergeableClauseOps,
- NogroupClauseOps, NumTasksClauseOps, PriorityClauseOps,
- PrivateClauseOps, ReductionClauseOps, UntiedClauseOps>;
-
-using TaskwaitOperands = detail::Clauses<DependClauseOps, NowaitClauseOps>;
-
-using TeamsOperands =
- detail::Clauses<AllocateClauseOps, IfClauseOps, NumTeamsClauseOps,
- PrivateClauseOps, ReductionClauseOps, ThreadLimitClauseOps>;
-
-using WsloopOperands =
- detail::Clauses<AllocateClauseOps, LinearClauseOps, NowaitClauseOps,
- OrderClauseOps, OrderedClauseOps, PrivateClauseOps,
- ReductionClauseOps, ScheduleClauseOps>;
+// omp.target_enter_data, omp.target_exit_data and omp.target_update take the
+// same clauses, so we give the structure to be shared by all of them a
+// representative name.
+using TargetEnterExitUpdateDataOperands = TargetEnterDataOperands;
} // namespace omp
} // namespace mlir
diff --git a/mlir/include/mlir/IR/CommonAttrConstraints.td b/mlir/include/mlir/IR/CommonAttrConstraints.td
index d99bde1f87ef0..f9dcfedfee105 100644
--- a/mlir/include/mlir/IR/CommonAttrConstraints.td
+++ b/mlir/include/mlir/IR/CommonAttrConstraints.td
@@ -408,10 +408,18 @@ class ElementsAttrBase<Pred condition, string summary> :
let storageType = [{ ::mlir::ElementsAttr }];
let returnType = [{ ::mlir::ElementsAttr }];
let convertFromStorage = "$_self";
+
+ // The underlying C++ value type of each element.
+ string elementReturnType = ?;
+
+ // The number of dimensions represented by the element collection.
+ int rank = 1;
}
def ElementsAttr : ElementsAttrBase<CPred<"::llvm::isa<::mlir::ElementsAttr>($_self)">,
- "constant vector/tensor attribute">;
+ "constant vector/tensor attribute"> {
+ let elementReturnType = [{ ::mlir::Attribute }];
+}
class IntElementsAttrBase<Pred condition, string summary> :
ElementsAttrBase<And<[CPred<"::llvm::isa<::mlir::DenseIntElementsAttr>($_self)">,
@@ -419,6 +427,7 @@ class IntElementsAttrBase<Pred condition, string summary> :
summary> {
let storageType = [{ ::mlir::DenseIntElementsAttr }];
let returnType = [{ ::mlir::DenseIntElementsAttr }];
+ let elementReturnType = [{ ::llvm::APInt }];
let convertFromStorage = "$_self";
}
@@ -428,6 +437,7 @@ class DenseArrayAttrBase<string denseAttrName, string cppType, string summaryNam
summaryName # " dense array attribute"> {
let storageType = "::mlir::" # denseAttrName;
let returnType = "::llvm::ArrayRef<" # cppType # ">";
+ let elementReturnType = cppType;
let constBuilderCall = "$_builder.get" # denseAttrName # "($0)";
}
def DenseBoolArrayAttr : DenseArrayAttrBase<"DenseBoolArrayAttr", "bool", "i1">;
@@ -486,6 +496,8 @@ class RankedSignlessIntElementsAttr<int width, list<int> dims> :
let constBuilderCall = "::mlir::DenseIntElementsAttr::get("
"::mlir::RankedTensorType::get({" # !interleave(dims, ", ") #
"}, $_builder.getIntegerType(" # width # ")), ::llvm::ArrayRef($0))";
+
+ let rank = !size(dims);
}
class RankedI32ElementsAttr<list<int> dims> :
@@ -501,6 +513,7 @@ class FloatElementsAttr<int width> : ElementsAttrBase<
let storageType = [{ ::mlir::DenseElementsAttr }];
let returnType = [{ ::mlir::DenseElementsAttr }];
+ let elementReturnType = [{ ::llvm::APFloat }];
// Note that this is only constructing scalar elements attribute.
let constBuilderCall = "::mlir::DenseElementsAttr::get("
@@ -526,6 +539,8 @@ class RankedFloatElementsAttr<int width, list<int> dims> : ElementsAttrBase<
let storageType = [{ ::mlir::DenseFPElementsAttr }];
let returnType = [{ ::mlir::DenseFPElementsAttr }];
+ let elementReturnType = [{ ::llvm::APFloat }];
+ let rank = !size(dims);
let constBuilderCall = "::llvm::cast<::mlir::DenseFPElementsAttr>("
"::mlir::DenseElementsAttr::get("
@@ -544,6 +559,7 @@ def StringElementsAttr : ElementsAttrBase<
let storageType = [{ ::mlir::DenseElementsAttr }];
let returnType = [{ ::mlir::DenseElementsAttr }];
+ let elementReturnType = [{ ::llvm::SmallString }];
let convertFromStorage = "$_self";
}
diff --git a/mlir/test/mlir-tblgen/openmp-clause-ops.td b/mlir/test/mlir-tblgen/openmp-clause-ops.td
new file mode 100644
index 0000000000000..b0139eb546e1b
--- /dev/null
+++ b/mlir/test/mlir-tblgen/openmp-clause-ops.td
@@ -0,0 +1,78 @@
+// Tablegen tests for the automatic generation of OpenMP clause operand
+// structure definitions.
+
+// Run tablegen to generate OmpCommon.td in temp directory first.
+// RUN: mkdir -p %t/mlir/Dialect/OpenMP
+// RUN: mlir-tblgen --gen-directive-decl --directives-dialect=OpenMP \
+// RUN: %S/../../../llvm/include/llvm/Frontend/OpenMP/OMP.td \
+// RUN: -I %S/../../../llvm/include > %t/mlir/Dialect/OpenMP/OmpCommon.td
+
+// RUN: mlir-tblgen -gen-openmp-clause-ops -I %S/../../include -I %t %s | FileCheck %s
+
+include "mlir/Dialect/OpenMP/OpenMPOpBase.td"
+
+
+def OpenMP_MyFirstClause : OpenMP_Clause<
+ /*isRequired=*/false, /*skipTraits=*/false, /*skipArguments=*/false,
+ /*skipAssemblyFormat=*/false, /*skipDescription=*/false,
+ /*skipExtraClassDeclaration=*/false> {
+ let arguments = (ins
+ // Simple attributes
+ I32Attr:$int_attr,
+ TypeAttr:$type_attr,
+ DeclareTargetAttr:$omp_attr,
+
+ // Array attributes
+ F32ArrayAttr:$float_array_attr,
+ StrArrayAttr:$str_array_attr,
+ AnyIntElementsAttr:$anyint_elems_attr,
+ RankedF32ElementsAttr<[3, 4, 5]>:$float_nd_elems_attr,
+
+ // Optional attributes
+ OptionalAttr<BoolAttr>:$opt_bool_attr,
+ OptionalAttr<I64ArrayAttr>:$opt_int_array_attr,
+ OptionalAttr<DenseI8ArrayAttr>:$opt_int_elems_attr,
+
+ // Multi-level composition
+ ConfinedAttr<OptionalAttr<I64Attr>, [IntMinValue<0>]>:$complex_opt_int_attr
+ );
+}
+// CHECK: struct MyFirstClauseOps {
+// CHECK-NEXT: ::mlir::IntegerAttr intAttr;
+// CHECK-NEXT: ::mlir::TypeAttr typeAttr;
+// CHECK-NEXT: ::mlir::omp::DeclareTargetAttr ompAttr;
+
+// CHECK-NEXT: ::llvm::SmallVector<::mlir::Attribute> floatArrayAttr;
+// CHECK-NEXT: ::llvm::SmallVector<::mlir::Attribute> strArrayAttr;
+// CHECK-NEXT: ::llvm::SmallVector<::llvm::APInt> anyintElemsAttr;
+// CHECK-NEXT: ::llvm::SmallVector<::llvm::APFloat> floatNdElemsAttr;
+// CHECK-NEXT: int floatNdElemsAttrDims[3];
+
+// CHECK-NEXT: ::mlir::BoolAttr optBoolAttr;
+// CHECK-NEXT: ::llvm::SmallVector<::mlir::Attribute> optIntArrayAttr;
+// CHECK-NEXT: ::llvm::SmallVector<int8_t> optIntElemsAttr;
+
+// CHECK-NEXT: ::mlir::IntegerAttr complexOptIntAttr;
+// CHECK-NEXT: }
+
+def OpenMP_MySecondClause : OpenMP_Clause<
+ /*isRequired=*/false, /*skipTraits=*/false, /*skipArguments=*/false,
+ /*skipAssemblyFormat=*/false, /*skipDescription=*/false,
+ /*skipExtraClassDeclaration=*/false> {
+ let arguments = (ins
+ I32:$int_val,
+ Optional<AnyType>:$opt_any_val,
+ Variadic<Index>:$variadic_index_val
+ );
+}
+// CHECK: struct MySecondClauseOps {
+// CHECK-NEXT: ::mlir::Value intVal;
+// CHECK-NEXT: ::mlir::Value optAnyVal;
+// CHECK-NEXT: ::llvm::SmallVector<::mlir::Value> variadicIndexVal;
+// CHECK-NEXT: }
+
+def OpenMP_MyFirstOp : OpenMP_Op<"op", clauses=[OpenMP_MyFirstClause]>;
+// CHECK: using MyFirstOperands = detail::Clauses<MyFirstClauseOps>;
+
+def OpenMP_MySecondOp : OpenMP_Op<"op", clauses=[OpenMP_MyFirstClause, OpenMP_MySecondClause]>;
+// CHECK: using MySecondOperands = detail::Clauses<MyFirstClauseOps, MySecondClauseOps>;
diff --git a/mlir/tools/mlir-tblgen/OmpOpGen.cpp b/mlir/tools/mlir-tblgen/OmpOpGen.cpp
index 51eb43f322e6a..d4c2cd48e891f 100644
--- a/mlir/tools/mlir-tblgen/OmpOpGen.cpp
+++ b/mlir/tools/mlir-tblgen/OmpOpGen.cpp
@@ -12,11 +12,43 @@
#include "mlir/TableGen/GenInfo.h"
+#include "mlir/TableGen/CodeGenHelpers.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/TypeSwitch.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
using namespace llvm;
+/// The code block defining the base mixin class for combining clause operand
+/// structures.
+static const char *const baseMixinClass = R"(
+namespace detail {
+template <typename... Mixins>
+struct Clauses : public Mixins... {};
+} // namespace detail
+)";
+
+/// The code block defining operation argument structures.
+static const char *const operationArgStruct = R"(
+using {0}Operands = detail::Clauses<{1}>;
+)";
+
+/// Remove multiple optional prefixes and suffixes from \c str.
+static StringRef stripPrefixAndSuffix(StringRef str,
+ llvm::ArrayRef<StringRef> prefixes,
+ llvm::ArrayRef<StringRef> suffixes) {
+ for (StringRef prefix : prefixes)
+ if (str.starts_with(prefix))
+ str = str.substr(prefix.size());
+
+ for (StringRef suffix : suffixes)
+ if (str.ends_with(suffix))
+ str = str.substr(0, str.size() - suffix.size());
+
+ return str;
+}
+
/// Obtain the name of the OpenMP clause a given record inheriting
/// `OpenMP_Clause` refers to.
///
@@ -53,19 +85,8 @@ static StringRef extractOmpClauseName(Record *clause) {
assert(!clauseClassName.empty() && "clause name must be found");
// Keep only the OpenMP clause name itself for reporting purposes.
- StringRef prefix = "OpenMP_";
- StringRef suffixes[] = {"Skip", "Clause"};
-
- if (clauseClassName.starts_with(prefix))
- clauseClassName = clauseClassName.substr(prefix.size());
-
- for (StringRef suffix : suffixes) {
- if (clauseClassName.ends_with(suffix))
- clauseClassName =
- clauseClassName.substr(0, clauseClassName.size() - suffix.size());
- }
-
- return clauseClassName;
+ return stripPrefixAndSuffix(clauseClassName, /*prefixes=*/{"OpenMP_"},
+ /*suffixes=*/{"Skip", "Clause"});
}
/// Check that the given argument, identified by its name and initialization
@@ -148,6 +169,110 @@ static void verifyClause(Record *op, Record *clause) {
"or explicitly skipping this field.");
}
+/// Translate the type of an OpenMP clause's argument to its corresponding
+/// representation for clause operand structures.
+///
+/// All kinds of values are represented as `mlir::Value` fields, whereas
+/// attributes are represented based on their `storageType`.
+///
+/// \param[in] init The `DefInit` object representing the argument.
+/// \param[out] rank Number of levels of array nesting associated with the
+/// type.
+///
+/// \return the name of the base type to represent elements of the argument
+/// type.
+static StringRef translateArgumentType(Init *init, int &rank) {
+ Record *def = cast<DefInit>(init)->getDef();
+ bool isAttr = false, isValue = false;
+
+ for (auto [sc, _] : def->getSuperClasses()) {
+ std::string scName = sc->getNameInitAsString();
+ if (scName == "OptionalAttr")
+ return translateArgumentType(def->getValue("baseAttr")->getValue(), rank);
+
+ if (scName == "TypedArrayAttrBase") {
+ ++rank;
+ return translateArgumentType(def->getValue("elementAttr")->getValue(),
+ rank);
+ }
+
+ if (scName == "ElementsAttrBase") {
+ rank += def->getValueAsInt("rank");
+ return def->getValueAsString("elementReturnType").trim();
+ }
+
+ if (scName == "Attr")
+ isAttr = true;
+ else if (scName == "TypeConstraint")
+ isValue = true;
+ else if (scName == "Variadic")
+ ...
[truncated]
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 for automatically generating this.
@@ -408,17 +408,26 @@ class ElementsAttrBase<Pred condition, string summary> : | |||
let storageType = [{ ::mlir::ElementsAttr }]; | |||
let returnType = [{ ::mlir::ElementsAttr }]; | |||
let convertFromStorage = "$_self"; | |||
|
|||
// The underlying C++ value type of each element. | |||
string elementReturnType = ?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This may need wider support, specifically we may need to generate an accessor function in .h.inc/.cpp.inc. Something like https://github.com/llvm/llvm-project/blob/main/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp#L1204, for example.
I'm wary about making this kind of change in a widely shared file. Maybe we could just handle this in OmpOpGen.cpp? Specifically, infer this information in there based on the type of the attribute?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wary about making this kind of change in a widely shared file. Maybe we could just handle this in OmpOpGen.cpp? Specifically, infer this information in there based on the type of the attribute?
Yes, this is something I tried to avoid as well. The problem is that the only existing attribute we could potentially use to get the element type information is the returnType
inherited from Attr
. We could potentially remove the "::llvm::ArrayRef<>" part of that string in the case of DenseArrayAttrBase
and derived types, which doesn't seem like a very clean solution but it would work (as long as these subclasses/definitions don't override that property). For other subclasses of ElementsAttrBase
we would have to accept having to use array-style attributes (e.g. ::mlir::DenseIntElementsAttr
) instead of lists of elements.
I'd like to avoid hardcoding as many type names as possible in the new tablegen backend, since people could just create new general or OpenMP-specific attribute types and then it would have to be updated. I think it makes sense to specialize it for as few and as generic cases as we can get away with and just make sure they already contain the information we need. In this case, we're just missing the element type and rank of array attributes, which seems like something that could be of general use eventually.
Having said that, this is just the approach that works that made the most sense to me, but I'm very much interested in discussing potentially better alternatives.
This may need wider support, specifically we may need to generate an accessor function in .h.inc/.cpp.inc.
Good point, I'll delay making this change until we decide whether we want to keep these new properties or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tagging people involved in the patch that created the CommonAttrConstraints.td file and reviewers (sorry for the spam, just looking for an expert in this area to comment on these potential additions!): @Groverkss, @River707, @Mogball, @joker-eph.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I would consider it a bit off to make changes to the ODS spec only for OMP purposes. What exactly are you trying to do here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @Mogball for taking a look.
What exactly are you trying to do here?
The main thing for which I added these properties is to be able to translate argument types as defined in tablegen to some corresponding C++ types used to store this information in a way that is useful for us. For example:
OptionalAttr<I32Attr>
->::mlir::IntegerAttr
DeclareTargetAttr
->::mlir::omp::DeclareTargetAttr
DenseI8ArrayAttr
->::llvm::SmallVector<int8_t>
I32
->::mlir::Value
Variadic<Index>
->::llvm::SmallVector<::mlir::Value>
For values, this is not an issue. For attributes, we can generally use already existing properties, such as their storageType
. The issue comes when trying to represent definitions based on ElementsAttrBase
, like DenseI8ArrayAttr
above, because we don't have a general way of knowing what element type we should use for the generated vector. That's what the elementReturnType
(name can most likely be improved) solves, it just holds the cppType
template parameter of DenseArrayAttrBase
definitions and provides some hopefully reasonable types for other tablegen subclasses, so that it can be queried independently.
Then, it made sense to me that we should be able to also have access to the rank of these ElementsAttrBase
definitions and generate some specific code for 2+D arrays, but right now it's not for certain that we would actually need that, so I'm thinking support for this could be postponed to when/if it's needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ping again! Is there anything I can do to unblock progress on this? Thank you for your time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I don't know why my email notifications aren't going through. I got this one now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in a way that is useful for us
This is kind of the crux of the issue. There is a kind of layering inversion here: only the OMP tablegen backend makes use of this information, yet the onus is on the main tablegen definitions to provide this information. No other dialects will realistically ever have to provide these definitions, and it's not clear to them why these are useful if they aren't using OMP.
I don't think there's a way forward for adding this kind of metadata to ODS proper if there is no conceivable use outside of OMP. Since the information has to be specified manually for ODS definitions to be used with OMP, would it be much worse to have a centralized mapping of Attr -> C++ representation
in the OMP backend?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the discussion.
Since the information has to be specified manually for ODS definitions to be used with OMP, would it be much worse to have a centralized mapping of Attr -> C++ representation in the OMP backend?
I will look into creating such a mapping, though my concern about that approach is that it's unlikely to be very general. That is, I think it might be easy to break it by just using some new attribute definition based on ElementsAttrBase
. I think the addition of a field to hold the element type would be more resilient in this regard, since it would always be present regardless of levels of inheritance, etc (except if explicitly overridden to prevent it).
There is a kind of layering inversion here: only the OMP tablegen backend makes use of this information, yet the onus is on the main tablegen definitions to provide this information. No other dialects will realistically ever have to provide these definitions, and it's not clear to them why these are useful if they aren't using OMP.
I don't think there's a way forward for adding this kind of metadata to ODS proper if there is no conceivable use outside of OMP.
I share that concern, but at the same time I feel like what I'm proposing of adding is a property to hold a subset of data that is already defined by DenseArrayAttrBase
(the cppType
template argument). It's adding some flexibility to query that information that initially would only be used by the OpenMP dialect but which is not really specific to it. We don't have any uses for it on other dialects at this point, but I think there is no reason why it couldn't have other use cases later on.
Also, apart from subclasses/definitions based directly on ElementsAttrBase
(of which I can currently see none outside of CommonAttrConstraints.td), no other attribute types defined in a dialect would actually have to initialize that new property, as this is done for all direct subclasses/definitions in this PR. So, in that sense, it would be a transparent addition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just added a commit to undo additions to base MLIR attribute definitions and to update the implementation of the tablegen backend to get the element type information from existing information (hard-coding special handling for a couple more attribute types). Let me know if this approach addresses your concerns and is something we could consider merging @Mogball, @kparzysz, @Meinersbur. Thank you!
8bccd4c
to
c80e6f1
Compare
87e529a
to
893b8de
Compare
c80e6f1
to
ae2de5c
Compare
893b8de
to
8948a6b
Compare
@@ -408,17 +408,26 @@ class ElementsAttrBase<Pred condition, string summary> : | |||
let storageType = [{ ::mlir::ElementsAttr }]; | |||
let returnType = [{ ::mlir::ElementsAttr }]; | |||
let convertFromStorage = "$_self"; | |||
|
|||
// The underlying C++ value type of each element. | |||
string elementReturnType = ?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I would consider it a bit off to make changes to the ODS spec only for OMP purposes. What exactly are you trying to do here?
Ping for review! |
56a445c
to
d9f3b38
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for automating!
This patch adds the "gen-openmp-clause-ops" `mlir-tblgen` generator to produce the structure definitions previously in OpenMPClauseOperands.h automatically from the information contained in OpenMPOps.td and OpenMPClauses.td. The original header is maintained to enable the definition of similar structures that are not directly related to any single `OpenMP_Clause` or `OpenMP_Op` tablegen definition.
d9f3b38
to
0cbfcd4
Compare
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/52/builds/2193 Here is the relevant piece of the build log for the reference
|
This patch adds the "gen-openmp-clause-ops"
mlir-tblgen
generator to produce the structure definitions previously in OpenMPClauseOperands.h automatically from the information contained in OpenMPOps.td and OpenMPClauses.td.The original header is maintained to enable the definition of similar structures that are not directly related to any single
OpenMP_Clause
orOpenMP_Op
tablegen definition.