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
ftynse
January 5, 2021, 10:21am
6
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.