llvm::interleaveComma(potentialAncestors, DBGS() << "--ancestors: ",
[](Operation *op) { llvm::dbgs() << *op; });
llvm::dbgs() << "\n");
+
+ Operation *owner = consumingHandle.getOwner();
+ unsigned operandNo = consumingHandle.getOperandNumber();
for (Operation *ancestor : potentialAncestors) {
// clang-format off
DEBUG_WITH_TYPE(DEBUG_TYPE_FULL,
// deleted before the lambda gets called.
Location ancestorLoc = ancestor->getLoc();
Location opLoc = payloadOp->getLoc();
- Operation *owner = consumingHandle.getOwner();
- unsigned operandNo = consumingHandle.getOperandNumber();
std::optional<Location> throughValueLoc =
throughValue ? std::make_optional(throughValue.getLoc()) : std::nullopt;
invalidatedHandles[otherHandle] = [ancestorLoc, opLoc, owner, operandNo,
void transform::TransformState::recordOpHandleInvalidation(
OpOperand &handle, ArrayRef<Operation *> potentialAncestors,
Value throughValue) {
+
+ if (potentialAncestors.empty()) {
+ DEBUG_WITH_TYPE(DEBUG_TYPE_FULL, {
+ (DBGS() << "----recording invalidation for empty handle: " << handle.get()
+ << "\n");
+ });
+
+ Operation *owner = handle.getOwner();
+ unsigned operandNo = handle.getOperandNumber();
+ invalidatedHandles[handle.get()] = [owner, operandNo](Location currentLoc) {
+ InFlightDiagnostic diag = emitError(currentLoc)
+ << "op uses a handle associated with empty "
+ "payload and invalidated by a "
+ "previously executed transform op";
+ diag.attachNote(owner->getLoc())
+ << "invalidated by this transform op that consumes its operand #"
+ << operandNo;
+ };
+ return;
+ }
+
// Iterate over the mapping and invalidate aliasing handles. This is quite
// expensive and only necessary for error reporting in case of transform
// dialect misuse with dangling handles. Iteration over the handles is based
test_consume_operand %3 : !transform.any_value
test_consume_operand %2 : !transform.any_op
}
+
+// -----
+
+transform.sequence failures(propagate) {
+^bb0(%arg0: !transform.any_op):
+ %0 = transform.test_produce_empty_payload : !transform.any_op
+ // expected-note @below {{invalidated by this transform op that consumes its operand #0}}
+ transform.test_consume_operand %0 : !transform.any_op
+ // expected-error @below {{uses a handle associated with empty payload and invalidated by a previously executed transform op}}
+ transform.test_print_remark_at_operand %0, "remark" : !transform.any_op
+}
return DiagnosedSilenceableFailure::success();
}
+DiagnosedSilenceableFailure mlir::test::TestProduceEmptyPayloadOp::apply(
+ transform::TransformResults &results, transform::TransformState &state) {
+ results.set(cast<OpResult>(getOut()), {});
+ return DiagnosedSilenceableFailure::success();
+}
+
void mlir::test::TestProduceNullParamOp::getEffects(
SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
transform::producesHandle(getOut(), effects);
let cppNamespace = "::mlir::test";
}
+def TestProduceEmptyPayloadOp
+ : Op<Transform_Dialect, "test_produce_empty_payload",
+ [DeclareOpInterfaceMethods<TransformOpInterface>,
+ MemoryEffectsOpInterface, FunctionalStyleTransformOpTrait]> {
+ let results = (outs TransformHandleTypeInterface:$out);
+ let assemblyFormat = "attr-dict `:` type($out)";
+ let cppNamespace = "::mlir::test";
+}
+
def TestProduceNullParamOp
: Op<Transform_Dialect, "test_produce_null_param",
[DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,