Error: failed to legalize operation XXX marked as erased

Hi, I’m trying defining and lowering a few dialects that were created by myself, in the c++ interface.
But seems it cannot get converted to mlir code, and keeps saying failed to legalize one of the operations.
Based on the dialect and error message, could you give a hint as where could the problem be to prevent the lowering?

Dialect code:

module {
  func.func @main() {
    %alloc_2 = memref.alloc() : memref<239071xi64>
    %alloc_3 = memref.alloc() : memref<239071xi64>
    %1:2 = myToy.readData {arg1=1000,arg2=2000}, %alloc_2, %alloc_3 : memref<239071xi64>, memref<239071xi64> -> memref<239071xi64>, memref<239071xi64>
    %alloc_4 = memref.alloc() : memref<1xindex>
    %c239071 = arith.constant 239071 : index
    memref.store %c239071, %alloc_4[%c239071] : memref<1xindex>
    %c1_i64_5 = arith.constant 1 : i64
    %2:6 = myToy.traverse {map = "$1"}, %c1_i64_5, %alloc_2, %alloc_4 : i64, memref<239071xi64>, memref<1xindex> -> i64, memref<239071xi64>, memref<1xindex>
    return
  }
}

Error:

error: failed to legalize operation 'myToy.traverse' marked as erased

Many thanks.

This means that during your usage of dialect conversion, you tried to erase the operation without providing a replacement for the results, which are still used.

2 Likes

Hi Mehdi,
Thanks for replying.
When having the error, I was trying to replace that myToy::Traverse with two other operations, using codes below.
I was declaring two passes here to replace the myToy::Traverse with myToy::Rep1 and myToy::Rep2.
Does it look like there’s something wrong in the replacement?

void ConversionNo1Pass::runOnOperation() {
  RewritePatternSet patterns(&getContext());
  patterns.add<TraverseOpLowering>(patterns.getContext());
  ConversionTarget target(getContext());
  target.addIllegalOp<mlir::myToy::Traverse>();
  target.markUnknownOpDynamicallyLegal([](Operation *){return true; });

  if (failed(
          applyPartialConversion(getOperation(), target, std::move(patterns))))
    signalPassFailure();
}

Here the Rep1 and Rep2 operations are supposed to replace the Traverse one:

void ConversionNo2Pass::runOnOperation() {
  RewritePatternSet patterns(&getContext());
  patterns.add<Rep1OpLowering, Rep2OpLowering,Test01OpLowering, Test02OpLowering, Test03OpLowering>(patterns.getContext());
  ConversionTarget target(getContext());
  target.addIllegalOp<mlir::myToy::Rep1Op, mlir::myToy::Rep2Op, mlir::myToy::Test01Op, mlir::myToy::Test02Op, mlir::myToy::Test03Op>();
  target.markUnknownOpDynamicallyLegal([](Operation *){return true; });

  if (failed(
          applyPartialConversion(getOperation(), target, std::move(patterns))))
    signalPassFailure();
}

At the end of TraverseLowering, I had let it create the Rep1 and Rep2 operations:

    auto rep1 = rewriter.create<myToy::Rep1Op>(loc, rep1_dict, ValueRange{});
    auto rep2 = rewriter.create<myToy::Rep2Op>(loc, rep2_dict, ValueRange{});
    rewriter.eraseOp(traverseOp);
    return success();
  }
};

With some inspection, I found that the “Failed to legalize…” error was produced at following step:

    mlir::PassManager pm(module.get()->getName());
    if (mlir::failed(mlir::applyPassManagerCLOptions(pm)))
        return 4;
    pm.addPass(mlir::myToy::createConversionPass());
    if (mlir::failed(pm.run(*module)))
        return 4;

However my program eventually produced segment fault and stopped at the pm.run(*module) step here:

mlir::PassManager pm(module.get()->getName());
    if (mlir::failed(mlir::applyPassManagerCLOptions(pm)))
        return FAIL;
    pm.addPass(mlir::myToy::createConversionNo2ConversionPass());
    pm.addPass(mlir::myToy::createLowerToStdPass());
 
    pm.addNestedPass<mlir::LLVM::LLVMFuncOp>(mlir::LLVM::createDIScopeForLLVMFuncOpPass());
    if (mlir::failed(pm.run(*module)))
        return FAIL;

You’re calling rewriter.eraseOp here, but have you first replaced the traverseOp with something else? I see you’re creating two new operations, but that does not create a replacement in itself.

1 Like

Thank you for the advice.
Following this hint, I found that there were some trivial operations at the end of the operations I have mentioned in last reply.
After removing those operations, it seems the mlir code could be generated now.

However now I am facing a problem that part of the generated mlir code seems not taking effect.
The mlir code is pasted below. The two @printEnd() external calls are able to be executed, however the scf.for loop in between seems not. The vector.print cannot print anything…

    %c0_6 = arith.constant 0 : index
    %c0_7 = arith.constant 0 : index
    %c1 = arith.constant 1 : index
    %3 = memref.load %alloc_1[%c0_7] : memref<1xindex>
    vector.print %c0_7 : index
    vector.print %3 : index
    scf.for %arg0 = %c0_7 to %3 step %c1 {
      %5 = memref.load %alloc[%arg0] : memref<1000xi64>
      %6 = memref.load %alloc[%arg0] : memref<1000xi64>
      vector.print %6 : i64
    }
    call @printEnd() : () -> ()

I understand this piece of mlir code may not be able to provide enough information to analyze. But OTOH I feel it kinda weird that only some operations are executed while others aren’t.
Could you kindly provide any hint that what kind of problem could led to such situation?
Many thanks.

It’s hard to say just looking at this code, in general you should be able to figure out by printing the IR after each pass down to the LLVM IR. If you’re using mlir-opt try adding --mlir-print-ir-after-all.

Thank you, I did checked into it and found that one of the loop boundaries was having some problem. The code seems working now after some fix.