/// Verification hook for PossibleTopLevelTransformOpTrait.
LogicalResult verifyPossibleTopLevelTransformOpTrait(Operation *op);
+
+/// Verification hook for TransformOpInterface.
+LogicalResult verifyTransformOpInterface(Operation *op);
} // namespace detail
/// This trait is supposed to be attached to Transform dialect operations that
return diag;
}
}];
+
+ let verify = [{
+ return ::mlir::transform::detail::verifyTransformOpInterface($_op);
+ }];
}
class TransformTypeInterfaceBase<string cppClass, string cppObjectType>
consumesHandle(getTarget(), effects);
onlyReadsHandle(getTileSizes(), effects);
onlyReadsHandle(getNumThreads(), effects);
+ onlyReadsHandle(getPackedNumThreads(), effects);
+ onlyReadsHandle(getPackedTileSizes(), effects);
producesHandle(getResults(), effects);
}
/// Returns `true` if the given list of effects instances contains an instance
/// with the effect type specified as template parameter.
-template <typename EffectTy, typename ResourceTy = SideEffects::DefaultResource>
-static bool hasEffect(ArrayRef<MemoryEffects::EffectInstance> effects) {
+template <typename EffectTy, typename ResourceTy, typename Range>
+static bool hasEffect(Range &&effects) {
return llvm::any_of(effects, [](const MemoryEffects::EffectInstance &effect) {
return isa<EffectTy>(effect.getEffect()) &&
isa<ResourceTy>(effect.getResource());
}
//===----------------------------------------------------------------------===//
+// Utilities for TransformOpInterface.
+//===----------------------------------------------------------------------===//
+
+LogicalResult transform::detail::verifyTransformOpInterface(Operation *op) {
+ auto iface = cast<MemoryEffectOpInterface>(op);
+ SmallVector<MemoryEffects::EffectInstance> effects;
+ iface.getEffects(effects);
+
+ auto effectsOn = [&](Value value) {
+ return llvm::make_filter_range(
+ effects, [value](const MemoryEffects::EffectInstance &instance) {
+ return instance.getValue() == value;
+ });
+ };
+
+ for (OpOperand &operand : op->getOpOperands()) {
+ auto range = effectsOn(operand.get());
+ if (range.empty()) {
+ InFlightDiagnostic diag =
+ op->emitError() << "TransformOpInterface requires memory effects "
+ "on operands to be specified";
+ diag.attachNote() << "no effects specified for operand #"
+ << operand.getOperandNumber();
+ return diag;
+ }
+ }
+ for (OpResult result : op->getResults()) {
+ auto range = effectsOn(result);
+ if (!::hasEffect<MemoryEffects::Allocate, TransformMappingResource>(
+ range)) {
+ InFlightDiagnostic diag =
+ op->emitError() << "TransformOpInterface requires 'allocate' memory "
+ "effect to be specified for results";
+ diag.attachNote() << "no 'allocate' effect specified for result #"
+ << result.getResultNumber();
+ return diag;
+ }
+ }
+ return success();
+}
+
+//===----------------------------------------------------------------------===//
// Entry point.
//===----------------------------------------------------------------------===//
// expected-note @below {{used here as operand #0}}
transform.test_consume_operand %0
}
+
+// -----
+
+transform.sequence failures(suppress) {
+^bb0(%arg0: !transform.any_op):
+ // expected-error @below {{TransformOpInterface requires memory effects on operands to be specified}}
+ // expected-note @below {{no effects specified for operand #0}}
+ transform.test_required_memory_effects %arg0 : (!transform.any_op) -> !transform.any_op
+}
+
+// -----
+
+transform.sequence failures(suppress) {
+^bb0(%arg0: !transform.any_op):
+ // expected-error @below {{TransformOpInterface requires 'allocate' memory effect to be specified for results}}
+ // expected-note @below {{no 'allocate' effect specified for result #0}}
+ transform.test_required_memory_effects %arg0 {has_operand_effect} : (!transform.any_op) -> !transform.any_op
+}
}
void mlir::test::TestProduceNullParamOp::getEffects(
- SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {}
+ SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
+ transform::producesHandle(getOut(), effects);
+}
DiagnosedSilenceableFailure
mlir::test::TestProduceNullParamOp::apply(transform::TransformResults &results,
return DiagnosedSilenceableFailure::success();
}
+void mlir::test::TestRequiredMemoryEffectsOp::getEffects(
+ SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
+ if (getHasOperandEffect())
+ transform::consumesHandle(getIn(), effects);
+
+ if (getHasResultEffect())
+ transform::producesHandle(getOut(), effects);
+ else
+ transform::onlyReadsHandle(getOut(), effects);
+}
+
+DiagnosedSilenceableFailure mlir::test::TestRequiredMemoryEffectsOp::apply(
+ transform::TransformResults &results, transform::TransformState &state) {
+ results.set(getOut().cast<OpResult>(), state.getPayloadOps(getIn()));
+ return DiagnosedSilenceableFailure::success();
+}
+
namespace {
/// Test extension of the Transform dialect. Registers additional ops and
/// declares PDL as dependent dialect since the additional ops are using PDL
let cppNamespace = "::mlir::test";
}
+def TestRequiredMemoryEffectsOp
+ : Op<Transform_Dialect, "test_required_memory_effects",
+ [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
+ DeclareOpInterfaceMethods<TransformOpInterface>]> {
+ let arguments = (ins TransformHandleTypeInterface:$in,
+ UnitAttr:$has_operand_effect,
+ UnitAttr:$has_result_effect);
+ let results = (outs TransformHandleTypeInterface:$out);
+ let assemblyFormat = "$in attr-dict `:` functional-type(operands, results)";
+ let cppNamespace = "::mlir::test";
+}
+
#endif // MLIR_TESTTRANSFORMDIALECTEXTENSION_TD