scf::WhileOp failing on assert

I’m trying to create a WhileOp operation, and here is the very simple code:

SmallVector<mlir::Type, 3> resultTypes;
SmallVector<mlir::Value, 3> operands;
auto whileOp = builder.create<scf::WhileOp>(builder.getUnknownLoc(), resultTypes, operands);
builder.setInsertionPointToStart(&whileOp.before().front());

An assert is failing when calling the .front() method and I really can’t understand why.

 llvm/ADT/ilist_iterator.h:138: llvm::ilist_iterator<OptionsT, IsReverse, IsConst>::reference llvm::ilist_iterator<OptionsT, IsReverse, IsConst>::operator*() const [with OptionsT = llvm::ilist_detail::node_options<mlir::Block, true, false, void>; bool IsReverse = false; bool IsConst = false; llvm::ilist_iterator<OptionsT, IsReverse, IsConst>::reference = mlir::Block&]: Assertion `!NodePtr->isKnownSentinel()' failed.

Am I doing something wrong or is it a bug?

I suspect that after creating the WhileOp using the builder, the regions are empty and don’t contain any block, you need to create the block first:

builder.createBlock(whileOp.before()); // you may have to provide block argument types
builder.setInsertionPointToStart(&whileOp.before().front());

That worked. May I ask why, differently from IfOp, must the blocks be created explicitely?
Anyway I’m encountering a second problem while converting it to the LLVM dialect.

This is part of the code that is being converted:

scf.while : () -> () {
  %false = constant false
  scf.condition(%false)
} do {
  scf.yield
}

The condition is obviously just a temporary one made for test purpose.
I can’t understand why it’s trying to replace the llvm.cast operation with another llvm.cast operation.

Legalizing operation : 'scf.while'(0x7fffc16eb500) {
  * Fold {
  } -> FAILURE : unable to fold

  * Pattern : 'scf.while -> ()' {
    ** Insert  : 'std.br'(0x7fffc16ed990)
    ** Insert  : 'std.cond_br'(0x7fffc1709620)
    ** Replace : 'scf.condition'(0x7fffc16ecb30)
    ** Replace : 'scf.while'(0x7fffc16eb500)

    //===-------------------------------------------===//
    Legalizing operation : 'std.br'(0x7fffc16ed990) {
      "std.br"()[^bb1] : () -> ()

      * Fold {
      } -> FAILURE : unable to fold

      * Pattern : 'std.br -> ()' {
        ** Insert  : 'llvm.br'(0x7fffc1709d30)
        ** Replace : 'std.br'(0x7fffc16ed990)

        //===-------------------------------------------===//
        Legalizing operation : 'llvm.br'(0x7fffc1709d30) {
          "llvm.br"()[^bb1] : () -> ()

        } -> SUCCESS : operation marked legal by the target
        //===-------------------------------------------===//
      } -> SUCCESS : pattern applied successfully
    } -> SUCCESS
    //===-------------------------------------------===//

    //===-------------------------------------------===//
    Legalizing operation : 'std.cond_br'(0x7fffc1709620) {
      "std.cond_br"(%false)[^bb1, ^bb2] {operand_segment_sizes = dense<[1, 0, 0]> : vector<3xi32>} : (i1) -> ()

      * Fold {
      } -> FAILURE : unable to fold

      * Pattern : 'std.cond_br -> ()' {
        ** Insert  : 'llvm.mlir.cast'(0x7fffc17082b8)
        ** Insert  : 'llvm.cond_br'(0x7fffc17097d0)
        ** Replace : 'std.cond_br'(0x7fffc1709620)

        //===-------------------------------------------===//
        Legalizing operation : 'llvm.mlir.cast'(0x7fffc17082b8) {
          %25 = "llvm.mlir.cast"(%false) : (i1) -> !llvm.i1

          * Fold {
          } -> FAILURE : unable to fold

          * Pattern : 'llvm.mlir.cast -> ()' {
            ** Insert  : 'llvm.mlir.cast'(0x7fffc170ca68)
            ** Replace : 'llvm.mlir.cast'(0x7fffc17082b8)

            //===-------------------------------------------===//
            Legalizing operation : 'llvm.mlir.cast'(0x7fffc170ca68) {
              %25 = "llvm.mlir.cast"(%false) : (i1) -> !llvm.i1

              * Fold {
              } -> FAILURE : unable to fold

              * Pattern : 'llvm.mlir.cast -> ()' {
              } -> FAILURE : pattern was already applied
            } -> FAILURE : no matched legalization pattern
            //===-------------------------------------------===//
          } -> FAILURE : generated operation 'llvm.mlir.cast'(0x00007FFFC170CA68) was illegal
        } -> FAILURE : pattern failed to match
      } -> FAILURE : no matched legalization pattern
      //===-------------------------------------------===//
    } -> FAILURE : generated operation 'llvm.mlir.cast'(0x00007FFFC17082B8) was illegal
  } -> FAILURE : pattern failed to match
} -> FAILURE : no matched legalization pattern

When you’re building IfOp you may use one of the manually written builder: http://github.com/llvm/llvm-project/tree/master/mlir/lib/Dialect/SCF/SCF.cpp#L581-L589

I suspect this is possible because IfOp blocks don’t need arguments while for the WhileOp you need to handle it.

Thanks, it makes sense.
I also managed to solve the other problem. By temporarily setting the cast operation as legal, I saw that it was trying to convert a !llvm.i1 into i1 and then the i1 back into !llvm.i1. That was because I was applying the ScfToStd and StdToLLVM conversion patterns together, thus converting first the original i1 into a !llvm.i1 and then passing it to the scf::Condition operation (which instead should receive a i1). I solved it by applying two different passes: the first one to convert from SCF to Std (thus leaving the original i1 untouched) and the second one from Std to LLVM

I just haven’t added a manually-written builder for the WhileOp because there is no upstream user for such a builder, and I am not comfortable adding unexercised/untested code.