Index: mlir/lib/IR/AsmPrinter.cpp =================================================================== --- mlir/lib/IR/AsmPrinter.cpp +++ mlir/lib/IR/AsmPrinter.cpp @@ -25,6 +25,7 @@ #include "mlir/IR/OpImplementation.h" #include "mlir/IR/Operation.h" #include "mlir/IR/SubElementInterfaces.h" +#include "mlir/IR/Verifier.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/MapVector.h" @@ -2885,7 +2886,12 @@ print(os, state, printerFlags); } void Operation::print(raw_ostream &os, AsmState &state, - const OpPrintingFlags &flags) { + const OpPrintingFlags &originalFlags) { + OpPrintingFlags flags = originalFlags; + // First verify the operation. If the operation fails to verify then custom + // print functions may fail and we have to use generic operation printing. + if (!flags.shouldPrintGenericOpForm() && failed(verify(this))) + flags.printGenericOpForm(); OperationPrinter printer(os, flags, state.getImpl()); if (!getParent() && !flags.shouldUseLocalScope()) printer.printTopLevelOperation(this); @@ -2912,7 +2918,19 @@ print(os, state); } void Block::print(raw_ostream &os, AsmState &state) { - OperationPrinter(os, /*flags=*/llvm::None, state.getImpl()).print(this); + OpPrintingFlags flags; + // First verify operations in the block. If an operation fails to verify then + // custom print functions may fail and we have to use generic operation + // printing. + if (!empty()) { + for (Operation &op : *this) { + if (failed(verify(&op))) { + flags.printGenericOpForm(); + break; + } + } + } + OperationPrinter(os, /*flags=*/flags, state.getImpl()).print(this); } void Block::dump() { print(llvm::errs()); } Index: mlir/lib/IR/Operation.cpp =================================================================== --- mlir/lib/IR/Operation.cpp +++ mlir/lib/IR/Operation.cpp @@ -1097,6 +1097,8 @@ // Check that any value that is used by an operation is defined in the // same region as either an operation result. auto *operandRegion = operand.getParentRegion(); + if (!operandRegion) + return op.emitError("operation's operand is unlinked"); if (!region.isAncestor(operandRegion)) { return op.emitOpError("using value defined outside the region") .attachNote(isolatedOp->getLoc()) Index: mlir/test/Conversion/AffineToStandard/lower-affine.mlir =================================================================== --- mlir/test/Conversion/AffineToStandard/lower-affine.mlir +++ mlir/test/Conversion/AffineToStandard/lower-affine.mlir @@ -1,4 +1,5 @@ -// RUN: mlir-opt -lower-affine %s | FileCheck %s +// `-debug` is used here to check that we don't crash when it's specified. +// RUN: mlir-opt -lower-affine -debug %s | FileCheck %s // CHECK-LABEL: func @empty() { func @empty() { Index: mlir/test/Conversion/SCFToControlFlow/convert-to-cfg.mlir =================================================================== --- mlir/test/Conversion/SCFToControlFlow/convert-to-cfg.mlir +++ mlir/test/Conversion/SCFToControlFlow/convert-to-cfg.mlir @@ -1,4 +1,5 @@ -// RUN: mlir-opt -allow-unregistered-dialect -convert-scf-to-cf %s | FileCheck %s +// `-debug` is used here to check that we don't crash when it's specified. +// RUN: mlir-opt -allow-unregistered-dialect -convert-scf-to-cf -debug %s | FileCheck %s // CHECK-LABEL: func @simple_std_for_loop(%{{.*}}: index, %{{.*}}: index, %{{.*}}: index) { // CHECK-NEXT: cf.br ^bb1(%{{.*}} : index)