def F32Tensor : TypedTensor<F32>;
def F64Tensor : TypedTensor<F64>;
+// This represents a generic tuple without any constraints on elemental type,
+// ranks, or size. As Tuples can contain tensors, vectors, or scalar values
+// there is not only a single elemental type.
+def Tuple : Type<IsTupleTypePred, "tuple">;
+
+//===----------------------------------------------------------------------===//
+// Common type constraints
+//===----------------------------------------------------------------------===//
+
// Type constraint for integer-like types: integers, indices, vectors of
// integers, tensors of integers.
def IntegerLike : TypeConstraint<AnyOf<[Integer.predicate, Index.predicate,
def FloatLike : TypeConstraint<AnyOf<[Float.predicate,
TypedVector<Float>.predicate, TypedTensor<Float>.predicate]>,
"floating-point-like">;
-
-// This represents a generic tuple without any constraints on elemental type,
-// ranks, or size. As Tuples can contain tensors, vectors, or scalar values
-// there is not only a single elemental type.
-def Tuple : Type<IsTupleTypePred, "tuple">;
//===----------------------------------------------------------------------===//
class ConstF32Attr<string val> : ConstantAttr<F32Attr, val>;
//===----------------------------------------------------------------------===//
+// Common attribute constraints
+//===----------------------------------------------------------------------===//
+
+// A general mechanism to further confine the given `attr` with all the
+// `constraints`. This allows to compose complex constraints out of a series
+// of more primitive ones.
+class Confined<Attr attr, list<AttrConstraint> constraints> : Attr<
+ AllOf<!listconcat([attr.predicate],
+ !foreach(pred, constraints, pred.predicate))>,
+ !foldl(/*init*/attr.description, /*list*/constraints,
+ prev, cur, prev # " " # cur.description)> {
+ let storageType = attr.storageType;
+ let returnType = attr.returnType;
+ let convertFromStorage = attr.convertFromStorage;
+ let constBuilderCall = attr.constBuilderCall;
+ let defaultValue = attr.defaultValue;
+ let isOptional = attr.isOptional;
+}
+
+class IntMinValue<int n> : AttrConstraint<
+ CPred<"{0}.cast<IntegerAttr>().getInt() >= " # n>,
+ "whose minimal value is " # n>;
+
+class ArrayMinCount<int n> : AttrConstraint<
+ CPred<"{0}.cast<ArrayAttr>().size() >= " # n>,
+ "with at least " # n # " elements">;
+
+//===----------------------------------------------------------------------===//
// OpTrait definitions
//===----------------------------------------------------------------------===//
}
//===----------------------------------------------------------------------===//
-// Common type constraint predicates
+// Common op type constraints
//===----------------------------------------------------------------------===//
// Type Constraint operand `idx`'s Vector or Tensor Element type is `type`.
SubstLeaves<"{0}", "{0}.getOperand(" # j # ")->getType()",
IsVectorOrTensorTypePred>,
// TODO: This could be made into C++ function instead.
- CPred<"{0}.getOperand(" # i # ")->getType().cast<VectorOrTensorType>().getElementType() == {0}.getOperand(" # j # ")->getType().cast<VectorOrTensorType>().getElementType()">]>;
+ CPred<"{0}.getOperand(" # i # ")->getType().cast<VectorOrTensorType>()."
+ "getElementType() == {0}.getOperand(" # j # ")->getType()."
+ "cast<VectorOrTensorType>().getElementType()">]>;
// Predicate to verify that the i'th result and the j'th operand have the same
// elemental type.
SubstLeaves<"{0}", "{0}.getOperand(" # j # ")->getType()",
IsVectorOrTensorTypePred>,
// TODO: This could be made into C++ function instead.
- CPred<"{0}.getResult(" # i # ")->getType().cast<VectorOrTensorType>().getElementType() == {0}.getOperand(" # j # ")->getType().cast<VectorOrTensorType>().getElementType()">]>;
+ CPred<"{0}.getResult(" # i # ")->getType().cast<VectorOrTensorType>()."
+ "getElementType() == {0}.getOperand(" # j # ")->getType()."
+ "cast<VectorOrTensorType>().getElementType()">]>;
//===----------------------------------------------------------------------===//
// Pattern definitions
// CHECK-LABEL: IdentityI32::verify
// CHECK: if (!((((*this->getOperation()).getNumOperands() > 0)) && (((*this->getOperation()).getOperand(0)->getType().isa<VectorOrTensorType>())) && (((*this->getOperation()).getOperand(0)->getType().cast<VectorOrTensorType>().getElementType().isInteger(32)))))
// CHECK-NEXT: return emitOpError("failed to verify that first operand has i32 element type");
+
+def OpA : Op<"op_for_int_min_val", []> {
+ let arguments = (ins Confined<I32Attr, [IntMinValue<10>]>:$attr);
+}
+
+// CHECK-LABEL: OpA::verify()
+// CHECK: if (!(((true)) && ((this->getAttr("attr").cast<IntegerAttr>().getInt() >= 10))))
+// CHECK-SAME: return emitOpError("attribute 'attr' failed to satisfy 32-bit integer whose minimal value is 10 attribute constraints");
+
+def OpB : Op<"op_for_arr_min_count", []> {
+ let arguments = (ins Confined<ArrayAttr, [ArrayMinCount<8>]>:$attr);
+}
+
+// CHECK-LABEL: OpB::verify()
+// CHECK: if (!(((true)) && ((this->getAttr("attr").cast<ArrayAttr>().size() >= 8))))
+// CHECK-SAME: return emitOpError("attribute 'attr' failed to satisfy array with at least 8 elements attribute constraints");
+