def NVVM_MMA_OPS : NVVM_MMA_OPS;
-// Returns [1] if this combination of layout/satf is supported, [] otherwise.
+// Returns true if this combination of layout/satf is supported; false otherwise.
// MMA ops must provide all parameters. Loads and stores -- only frags and layout_a.
// The class is used to prevent generation of records for the unsupported variants.
// E.g.
-// foreach _ = NVVM_MMA_SUPPORTED<...>.ret in =
+// if NVVM_MMA_SUPPORTED<...>.ret then
// def : FOO<>; // The record will only be defined for supported ops.
//
class NVVM_MMA_SUPPORTED<list<WMMA_REGS> frags, string layout_a, string layout_b="-", int satf=-1> {
# !if(!eq(!size(frags), 4),
frags[2].ptx_elt_type # frags[3].ptx_elt_type,
"?");
- list<int> ret = !cond(
+ bit ret = !cond(
// Sub-int MMA only supports fixed A/B layout.
// b1 does not support .satf.
- !eq(mma#":"#satf, "b1:row:col:0") : [1],
+ !eq(mma#":"#satf, "b1:row:col:0") : true,
// mma.m8n8k4 has no .satf modifier.
!and(!eq(frags[0].geom, "m8n8k4"),
- !ne(satf, 0)): [],
+ !ne(satf, 0)): false,
// mma.m8n8k4 has no C=f32 D=f16 variant.
- !eq(gcd, "m8n8k4:f32f16"): [],
- !eq(mma, "s4:row:col") : [1],
- !eq(mma, "u4:row:col") : [1],
- !eq(mma, "s4:row:col") : [1],
- !eq(mma, "u4:row:col") : [1],
+ !eq(gcd, "m8n8k4:f32f16"): false,
+ !eq(mma, "s4:row:col") : true,
+ !eq(mma, "u4:row:col") : true,
+ !eq(mma, "s4:row:col") : true,
+ !eq(mma, "u4:row:col") : true,
// Sub-int load/stores have fixed layout for A and B.
!and(!eq(layout_b, "-"), // It's a Load or Store op
!or(!eq(ld, "b1:a:row"),
!eq(ld, "u4:a:row"),
!eq(ld, "u4:b:col"),
!eq(ldf, "u4:c"),
- !eq(ldf, "u4:d"))) : [1],
+ !eq(ldf, "u4:d"))) : true,
// All other sub-int ops are not supported.
- !eq(t, "b1") : [],
- !eq(t, "s4") : [],
- !eq(t, "u4") : [],
+ !eq(t, "b1") : false,
+ !eq(t, "s4") : false,
+ !eq(t, "u4") : false,
// All other (non sub-int) are OK.
- true: [1]
+ true: true
);
}
foreach layout = ["row", "col"] in {
foreach stride = [0, 1] in {
foreach frag = NVVM_MMA_OPS.all_ld_ops in
- foreach _ = NVVM_MMA_SUPPORTED<[frag], layout>.ret in
+ if NVVM_MMA_SUPPORTED<[frag], layout>.ret then
def WMMA_NAME_LDST<"load", frag, layout, stride>.record
: NVVM_WMMA_LD<frag, layout, stride>;
foreach frag = NVVM_MMA_OPS.all_st_ops in
- foreach _ = NVVM_MMA_SUPPORTED<[frag], layout>.ret in
+ if NVVM_MMA_SUPPORTED<[frag], layout>.ret then
def WMMA_NAME_LDST<"store", frag, layout, stride>.record
: NVVM_WMMA_ST<frag, layout, stride>;
}
foreach layout_b = ["row", "col"] in {
foreach satf = [0, 1] in {
foreach op = NVVM_MMA_OPS.all_mma_ops in {
- foreach _ = NVVM_MMA_SUPPORTED<op, layout_a, layout_b, satf>.ret in {
+ if NVVM_MMA_SUPPORTED<op, layout_a, layout_b, satf>.ret then {
def WMMA_NAME_MMA<layout_a, layout_b, satf,
op[0], op[1], op[2], op[3]>.record
: NVVM_WMMA_MMA<layout_a, layout_b, satf,
string result = r;
}
-// TODO: Use !interleave() directly rather than through StrJoin/StrJoinInt.
-
-// Concatenates a list of strings with a separator (default ", ")
-class StrJoin<list<string> strings, string sep = ", "> :
- StrFunc<!interleave(strings, sep)>;
-
-// Concatenates a list of integers into a string with a separator (default ", ")
-class StrJoinInt<list<int> integers, string sep = ", "> :
- StrFunc<!interleave(integers, sep)>;
-
//===----------------------------------------------------------------------===//
// Predicate definitions
//===----------------------------------------------------------------------===//
// Satisfy any of the allowed type's condition
Or<!foreach(allowedtype, allowedTypes, allowedtype.predicate)>,
!if(!eq(description, ""),
- StrJoin<!foreach(t, allowedTypes, t.description), " or ">.result,
+ !interleave(!foreach(t, allowedTypes, t.description), " or "),
description)>;
// Integer types.
class AnyIntOfWidths<list<int> widths> :
AnyTypeOf<!foreach(w, widths, AnyI<w>),
- StrJoinInt<widths, "/">.result # "-bit integer",
+ !interleave(widths, "/") # "-bit integer",
"::mlir::IntegerType">;
def AnyI1 : AnyI<1>;
class SignlessIntOfWidths<list<int> widths> :
AnyTypeOf<!foreach(w, widths, I<w>),
- StrJoinInt<widths, "/">.result # "-bit signless integer">;
+ !interleave(widths, "/") # "-bit signless integer">;
def I1 : I<1>;
def I8 : I<8>;
class SignedIntOfWidths<list<int> widths> :
AnyTypeOf<!foreach(w, widths, SI<w>),
- StrJoinInt<widths, "/">.result # "-bit signed integer">;
+ !interleave(widths, "/") # "-bit signed integer">;
def SI1 : SI<1>;
def SI8 : SI<8>;
class UnsignedIntOfWidths<list<int> widths> :
AnyTypeOf<!foreach(w, widths, UI<w>),
- StrJoinInt<widths, "/">.result # "-bit unsigned integer">;
+ !interleave(widths, "/") # "-bit unsigned integer">;
def UI1 : UI<1>;
def UI8 : UI<8>;
class FloatOfWidths<list<int> widths> :
AnyTypeOf<!foreach(w, widths, F<w>),
- StrJoinInt<widths, "/">.result # "-bit float">;
+ !interleave(widths, "/") # "-bit float">;
def F16 : F<16>;
def F32 : F<32>;
// Any vector where the rank is from the given `allowedRanks` list
class VectorOfRank<list<int> allowedRanks> : Type<
IsVectorOfRankPred<allowedRanks>,
- " of ranks " # StrJoinInt<allowedRanks, "/">.result, "::mlir::VectorType">;
+ " of ranks " # !interleave(allowedRanks, "/"), "::mlir::VectorType">;
// Any vector where the rank is from the given `allowedRanks` list and the type
// is from the given `allowedTypes` list
// `allowedLengths` list
class VectorOfLength<list<int> allowedLengths> : Type<
IsVectorOfLengthPred<allowedLengths>,
- " of length " # StrJoinInt<allowedLengths, "/">.result,
+ " of length " # !interleave(allowedLengths, "/"),
"::mlir::VectorType">;
-
// Any vector where the number of elements is from the given
// `allowedLengths` list and the type is from the given `allowedTypes`
// list
// Ranked tensor type with one of the specified types and ranks.
class TensorRankOf<list<Type> allowedTypes, list<int> ranks> :
Type<And<[TensorOf<allowedTypes>.predicate, HasAnyRankOfPred<ranks>]>,
- StrJoin<!foreach(rank, ranks, rank # "D"), "/">.result # " " #
+ !interleave(!foreach(rank, ranks, rank # "D"), "/") # " " #
TensorOf<allowedTypes>.description, "::mlir::TensorType">;
class 0DTensorOf<list<Type> allowedTypes> : TensorRankOf<allowedTypes, [0]>;
// TODO: Have an easy way to add another constraint to a type.
class MemRefRankOf<list<Type> allowedTypes, list<int> ranks> :
Type<And<[MemRefOf<allowedTypes>.predicate, HasAnyRankOfPred<ranks>]>,
- StrJoin<!foreach(rank, ranks, rank # "D"), "/">.result # " " #
+ !interleave(!foreach(rank, ranks, rank # "D"), "/") # " " #
MemRefOf<allowedTypes>.description>;
class StaticShapeMemRefOf<list<Type> allowedTypes>
class StridedMemRefRankOf<list<Type> allowedTypes, list<int> ranks> :
Type<And<[MemRefOf<allowedTypes>.predicate, HasAnyRankOfPred<ranks>]>,
- StrJoin<!foreach(rank, ranks, rank # "D"), "/">.result # " " #
+ !interleave(!foreach(rank, ranks, rank # "D"), "/") # " " #
MemRefOf<allowedTypes>.description>;
// This represents a generic tuple without any constraints on element type.
StringBasedAttr<
And<[StrAttr.predicate, Or<!foreach(case, cases, case.predicate)>]>,
!if(!empty(description), "allowed string cases: " #
- StrJoin<!foreach(case, cases, "'" # case.symbol # "'")>.result,
+ !interleave(!foreach(case, cases, "'" # case.symbol # "'"), ", "),
description)>;
// An enum attribute backed by IntegerAttr.
EnumAttrInfo<name, cases>,
SignlessIntegerAttrBase<intType,
!if(!empty(description), "allowed " # intType.description # " cases: " #
- StrJoinInt<!foreach(case, cases, case.value)>.result, description)> {
+ !interleave(!foreach(case, cases, case.value), ", "), description)> {
let predicate = And<[
SignlessIntegerAttrBase<intType, "">.predicate,
Or<!foreach(case, cases, case.predicate)>]>;
I32Attr.predicate,
// Make sure we don't have unknown bit set.
CPred<"!($_self.cast<::mlir::IntegerAttr>().getValue().getZExtValue() & (~("
- # StrJoin<!foreach(case, cases, case.value # "u"), "|">.result #
+ # !interleave(!foreach(case, cases, case.value # "u"), "|") #
")))">
]>;
let predicate = And<[
SignlessIntElementsAttr<width>.predicate,
CPred<"$_self.cast<::mlir::DenseIntElementsAttr>().getType().getShape() == "
- "::mlir::ArrayRef<int64_t>({" # StrJoinInt<dims>.result # "})">]>;
+ "::mlir::ArrayRef<int64_t>({" # !interleave(dims, ", ") # "})">]>;
let description = width # "-bit signless int elements attribute of shape [" #
- StrJoinInt<dims>.result # "]";
+ !interleave(dims, ", ") # "]";
let constBuilderCall = "::mlir::DenseIntElementsAttr::get("
- "::mlir::RankedTensorType::get({" # StrJoinInt<dims>.result #
+ "::mlir::RankedTensorType::get({" # !interleave(dims, ", ") #
"}, $_builder.getIntegerType(" # width # ")), ::llvm::makeArrayRef($0))";
}
// Check that this is ranked and has the specified shape.
"$_self.cast<::mlir::DenseFPElementsAttr>().getType().hasRank() && "
"$_self.cast<::mlir::DenseFPElementsAttr>().getType().getShape() == "
- "::mlir::ArrayRef<int64_t>({" # StrJoinInt<dims>.result # "})">,
+ "::mlir::ArrayRef<int64_t>({" # !interleave(dims, ", ") # "})">,
width # "-bit float elements attribute of shape [" #
- StrJoinInt<dims>.result # "]"> {
+ !interleave(dims, ", ") # "]"> {
let storageType = [{ ::mlir::DenseFPElementsAttr }];
let returnType = [{ ::mlir::DenseFPElementsAttr }];
let constBuilderCall = "::mlir::DenseElementsAttr::get("
- "::mlir::RankedTensorType::get({" # StrJoinInt<dims>.result #
+ "::mlir::RankedTensorType::get({" # !interleave(dims, ", ") #
"}, $_builder.getF" # width # "Type()), "
"::llvm::makeArrayRef($0)).cast<::mlir::DenseFPElementsAttr>()";
let convertFromStorage = "$_self";
DictionaryAttrBase<CPred<"$_self.isa<" # d.cppNamespace
# "::" # name # ">()">,
"DictionaryAttr with field(s): " #
- StrJoin<!foreach(a, attributes, "'" # a.name # "'"), ", ">.result #
+ !interleave(!foreach(a, attributes, "'" # a.name # "'"), ", ") #
" (each field having its own constraints)"> {
// Name for this StructAttr.
string className = name;
: ParamNativeOpTrait<"HasParent", op>;
class ParentOneOf<list<string> ops>
- : ParamNativeOpTrait<"HasParent", StrJoin<ops>.result>;
+ : ParamNativeOpTrait<"HasParent", !interleave(ops, ", ")>;
// Op result type is derived from the first attribute. If the attribute is an
// subclass of `TypeAttrBase`, its value is used, otherwise, the type of the
class AllMatchPred<list<string> values> :
CPred<"::llvm::is_splat(::llvm::makeArrayRef({"
- # StrJoin<values>.result #"}))">;
+ # !interleave(values, ", ") #"}))">;
class AllMatch<list<string> values, string description> :
PredOpTrait<description, AllMatchPred<values>>;
class AllMatchSameOperatorTrait<list<string> names, string operator,
string description> :
PredOpTrait<
- "all of {" # StrJoin<names>.result # "} have same " # description,
+ "all of {" # !interleave(names, ", ") # "} have same " # description,
AllMatchSameOperatorPred<names, operator>> {
list<string> values = names;
}
// 2) the indices are not out of range.
class TCopVTEtAreSameAt<list<int> indices> : CPred<
"::llvm::is_splat(::llvm::map_range("
- "::mlir::ArrayRef<unsigned>({" # StrJoinInt<indices>.result # "}), "
+ "::mlir::ArrayRef<unsigned>({" # !interleave(indices, ", ") # "}), "
"[this](unsigned i) { return getElementTypeOrSelf(this->getOperand(i)); "
"}))">;