Closed
Description
This example shows the beginnings of algorithmic explosion when run through mlir-opt -canonicalize
module {
llvm.func @foo(%arg0: i64)
llvm.func @rand() -> i1
llvm.func @top(%arg0: i64) {
%0 = llvm.mlir.constant(0 : i64) : i64
%1 = llvm.mlir.constant(8 : i64) : i64
%2 = llvm.mlir.constant(7 : i64) : i64
%3 = llvm.mlir.constant(6 : i64) : i64
%4 = llvm.mlir.constant(5 : i64) : i64
%5 = llvm.mlir.constant(4 : i64) : i64
%6 = llvm.mlir.constant(3 : i64) : i64
%7 = llvm.mlir.constant(1 : i64) : i64
%8 = llvm.mlir.constant(2 : i64) : i64
%10 = llvm.icmp "eq" %arg0, %0 : i64
llvm.cond_br %10, ^bb1, ^bb14
^bb1: // pred: ^bb0
%11 = llvm.call @rand() : () -> i1
llvm.cond_br %11, ^bb2, ^bb3
^bb2: // pred: ^bb1
llvm.call @foo(%7) : (i64) -> ()
llvm.br ^bb4
^bb3: // pred: ^bb1
llvm.call @foo(%8) : (i64) -> ()
llvm.br ^bb4
^bb4: // 2 preds: ^bb2, ^bb3
%14 = llvm.call @rand() : () -> i1
llvm.cond_br %14, ^bb5, ^bb6
^bb5: // pred: ^bb4
llvm.call @foo(%6) : (i64) -> ()
llvm.br ^bb7
^bb6: // pred: ^bb4
llvm.call @foo(%5) : (i64) -> ()
llvm.br ^bb7
^bb7: // 2 preds: ^bb5, ^bb6
%17 = llvm.call @rand() : () -> i1
llvm.cond_br %17, ^bb8, ^bb9
^bb8: // pred: ^bb7
llvm.call @foo(%4) : (i64) -> ()
llvm.br ^bb10
^bb9: // pred: ^bb7
llvm.call @foo(%3) : (i64) -> ()
llvm.br ^bb10
^bb10: // 2 preds: ^bb8, ^bb9
%20 = llvm.call @rand() : () -> i1
llvm.cond_br %20, ^bb11, ^bb12
^bb11: // pred: ^bb10
llvm.call @foo(%2) : (i64) -> ()
llvm.br ^bb13
^bb12: // pred: ^bb10
llvm.call @foo(%1) : (i64) -> ()
llvm.br ^bb13
^bb13: // 2 preds: ^bb11, ^bb12
llvm.br ^bb27
^bb14: // pred: ^bb0
%23 = llvm.call @rand() : () -> i1
llvm.cond_br %23, ^bb15, ^bb16
^bb15: // pred: ^bb14
llvm.call @foo(%8) : (i64) -> ()
llvm.br ^bb17
^bb16: // pred: ^bb14
llvm.call @foo(%7) : (i64) -> ()
llvm.br ^bb17
^bb17: // 2 preds: ^bb15, ^bb16
%26 = llvm.call @rand() : () -> i1
llvm.cond_br %26, ^bb18, ^bb19
^bb18: // pred: ^bb17
llvm.call @foo(%5) : (i64) -> ()
llvm.br ^bb20
^bb19: // pred: ^bb17
llvm.call @foo(%6) : (i64) -> ()
llvm.br ^bb20
^bb20: // 2 preds: ^bb18, ^bb19
%29 = llvm.call @rand() : () -> i1
llvm.cond_br %29, ^bb21, ^bb22
^bb21: // pred: ^bb20
llvm.call @foo(%3) : (i64) -> ()
llvm.br ^bb23
^bb22: // pred: ^bb20
llvm.call @foo(%4) : (i64) -> ()
llvm.br ^bb23
^bb23: // 2 preds: ^bb21, ^bb22
%32 = llvm.call @rand() : () -> i1
llvm.cond_br %32, ^bb24, ^bb25
^bb24: // pred: ^bb23
llvm.call @foo(%1) : (i64) -> ()
llvm.br ^bb26
^bb25: // pred: ^bb23
llvm.call @foo(%2) : (i64) -> ()
llvm.br ^bb26
^bb26: // 2 preds: ^bb24, ^bb25
llvm.br ^bb27
^bb27: // 2 preds: ^bb13, ^bb26
llvm.return
}
}
It corresponds approximately to
if (something) {
foo(1, 2)
foo(3, 4)
foo(5, 6)
foo(7, 8)
} else {
foo(2, 1)
foo(4, 3)
foo(6, 5)
foo(8, 7)
}
The block merger is trying to merge both branches together, since they share similar sub-CFGs, but it's blowing up on the number of block operands. Adding just a few more branches causes 💥