llvm/mlir/test/Interfaces/LoopLikeInterface/test-block-loop.mlir

// RUN: mlir-opt %s --mlir-disable-threading -test-block-is-in-loop 2>&1 | FileCheck %s

module {
  // Test function with only one bb
  func.func @simple() {
    func.return
  }
// CHECK: Block is not in a loop
// CHECK-NEXT: ^bb0:

  // Test simple loop bb0 -> bb0
  func.func @loopForever() {
  ^bb0:
    cf.br ^bb1
  ^bb1:
    cf.br ^bb1
  }
// CHECK: Block is not in a loop
// CHECK-NEXT: ^bb0:
// CHECK: Block is in a loop
// CHECK-NEXT: ^bb1:

  // Test bb0 -> bb1 -> bb2 -> bb1
  func.func @loopForever2() {
  ^bb0:
    cf.br ^bb1
  ^bb1:
    cf.br ^bb2
  ^bb2:
    cf.br ^bb1
  }
// CHECK: Block is not in a loop
// CHECK-NEXT: ^bb0:
// CHECK: Block is in a loop
// CHECK-NEXT: ^bb1:
// CHECK: Block is in a loop
// CHECK-NEXT: ^bb2:

  // Test conditional branch without loop
  // bb0 -> bb1 -> {bb2, bb3}
  func.func @noLoop(%arg0: i1) {
    cf.br ^bb1
  ^bb1:
    cf.cond_br %arg0, ^bb2, ^bb3
  ^bb2:
    func.return
  ^bb3:
    func.return
  }
// CHECK: Block is not in a loop
// CHECK-NEXT: ^bb0(%arg0: i1)
// CHECK: Block is not in a loop
// CHECK-NEXT: ^bb1:
// CHECK: Block is not in a loop
// CHECK-NEXT: ^bb2:
// CHECK: Block is not in a loop
// CHECK-NEXT: ^bb3:

  // test multiple loops
  // bb0 -> bb1 -> bb2 -> bb3 { -> bb2} -> bb4 { -> bb1 } -> bb5
  func.func @multipleLoops(%arg0: i1, %arg1: i1) {
    cf.br ^bb1
  ^bb1:
    cf.br ^bb2
  ^bb2:
    cf.br ^bb3
  ^bb3:
    cf.cond_br %arg0, ^bb4, ^bb2
  ^bb4:
    cf.cond_br %arg1, ^bb1, ^bb5
  ^bb5:
    return
  }
// CHECK: Block is not in a loop
// CHECK-NEXT: ^bb0(%arg0: i1, %arg1: i1)
// CHECK: Block is in a loop
// CHECK-NEXT: ^bb1:
// CHECK: Block is in a loop
// CHECK-NEXT: ^bb2:
// CHECK: Block is in a loop
// CHECK-NEXT: ^bb3:
// CHECK: Block is in a loop
// CHECK-NEXT: ^bb4:
// CHECK: Block is not in a loop
// CHECK-NEXT: ^bb5:

  // test derived from real Flang output
  func.func @_QPblockTest0(%arg0: i1, %arg1: i1) {
    cf.br ^bb1
  ^bb1:  // 2 preds: ^bb0, ^bb4
    cf.cond_br %arg0, ^bb2, ^bb5
  ^bb2:  // pred: ^bb1
    cf.cond_br %arg1, ^bb3, ^bb4
  ^bb3:  // pred: ^bb2
    return
  ^bb4:  // pred: ^bb2
    cf.br ^bb1
  ^bb5:  // pred: ^bb1
    return
  }
// CHECK: Block is not in a loop
// CHECK-NEXT: ^bb0(%arg0: i1, %arg1: i1)
// CHECK: Block is in a loop
// CHECK-NEXT: ^bb1:
// CHECK: Block is in a loop
// CHECK-NEXT: ^bb2:
// CHECK: Block is not in a loop
// CHECK-NEXT: ^bb3:
// CHECK: Block is in a loop
// CHECK-NEXT: ^bb4:
// CHECK: Block is not in a loop
// CHECK-NEXT: ^bb5:

// check nested blocks
  func.func @check_alloc_in_loop(%counter : i64) {
    cf.br ^bb1(%counter: i64)
    ^bb1(%lv : i64):
      %cm1 = arith.constant -1 : i64
      %rem = arith.addi %lv, %cm1 : i64
      %zero = arith.constant 0 : i64
      %p = arith.cmpi eq, %rem, %zero : i64
      cf.cond_br %p, ^bb3, ^bb2
    ^bb2:
      scf.execute_region -> () {
        %c1 = arith.constant 1 : i64
        scf.yield
      }
      cf.br ^bb1(%rem: i64)
    ^bb3:
      return
  }
// CHECK: Block is not in a loop
// CHECK-NEXT: ^bb0(%arg0: i64):
// CHECK: Block is in a loop
// CHECK-NEXT: ^bb1(%0: i64)
// CHECK: Block is in a loop
// CHECK-NEXT: ^bb0:
// CHECK-NEXT: %c1_i64
// CHECK: Block is in a loop
// CHECK-NEXT: ^bb2:
// CHECK: Block is not in a loop
// CHECK-NEXT: ^bb3:
}