// RUN: cir-opt %s -cir-flatten-cfg -o - | FileCheck %s !s32i = !cir.int module { cir.func @foo(%arg0: !s32i) -> !s32i { %0 = cir.alloca !s32i, !cir.ptr, ["y", init] {alignment = 4 : i64} %1 = cir.alloca !s32i, !cir.ptr, ["__retval"] {alignment = 4 : i64} cir.store %arg0, %0 : !s32i, !cir.ptr %2 = cir.load %0 : !cir.ptr, !s32i %3 = cir.const #cir.int<0> : !s32i %4 = cir.cmp gt %2, %3 : !s32i %5 = cir.ternary(%4, true { %7 = cir.const #cir.int<3> : !s32i cir.yield %7 : !s32i }, false { %7 = cir.const #cir.int<5> : !s32i cir.yield %7 : !s32i }) : (!cir.bool) -> !s32i cir.store %5, %1 : !s32i, !cir.ptr %6 = cir.load %1 : !cir.ptr, !s32i cir.return %6 : !s32i } // CHECK: cir.func{{.*}} @foo(%arg0: !s32i) -> !s32i { // CHECK: %0 = cir.alloca !s32i, !cir.ptr, ["y", init] {alignment = 4 : i64} // CHECK: %1 = cir.alloca !s32i, !cir.ptr, ["__retval"] {alignment = 4 : i64} // CHECK: cir.store %arg0, %0 : !s32i, !cir.ptr // CHECK: %2 = cir.load %0 : !cir.ptr, !s32i // CHECK: %3 = cir.const #cir.int<0> : !s32i // CHECK: %4 = cir.cmp gt %2, %3 : !s32i // CHECK: cir.brcond %4 ^bb1, ^bb2 // CHECK: ^bb1: // pred: ^bb0 // CHECK: %5 = cir.const #cir.int<3> : !s32i // CHECK: cir.br ^bb3(%5 : !s32i) // CHECK: ^bb2: // pred: ^bb0 // CHECK: %6 = cir.const #cir.int<5> : !s32i // CHECK: cir.br ^bb3(%6 : !s32i) // CHECK: ^bb3(%7: !s32i): // 2 preds: ^bb1, ^bb2 // CHECK: cir.br ^bb4 // CHECK: ^bb4: // pred: ^bb3 // CHECK: cir.store %7, %1 : !s32i, !cir.ptr // CHECK: %8 = cir.load %1 : !cir.ptr, !s32i // CHECK: cir.return %8 : !s32i // CHECK: } cir.func @foo2(%arg0: !cir.bool) { cir.ternary(%arg0, true { cir.yield }, false { cir.yield }) : (!cir.bool) -> () cir.return } // CHECK: cir.func{{.*}} @foo2(%arg0: !cir.bool) { // CHECK: cir.brcond %arg0 ^bb1, ^bb2 // CHECK: ^bb1: // pred: ^bb0 // CHECK: cir.br ^bb3 // CHECK: ^bb2: // pred: ^bb0 // CHECK: cir.br ^bb3 // CHECK: ^bb3: // 2 preds: ^bb1, ^bb2 // CHECK: cir.br ^bb4 // CHECK: ^bb4: // pred: ^bb3 // CHECK: cir.return // CHECK: } // Ternary with cir.trap as the false-region terminator. This pattern is // emitted by libc++ assertion macros that expand to // `cond ? (void)0 : __builtin_trap()`. The flatten-cfg pass must accept // cir.trap (a non-returning Terminator) as a valid region terminator and // leave it in place rather than rewriting it into a branch. cir.func @ternary_trap_false(%arg0: !cir.bool) { cir.ternary(%arg0, true { cir.yield }, false { cir.trap }) : (!cir.bool) -> () cir.return } // CHECK: cir.func{{.*}} @ternary_trap_false(%arg0: !cir.bool) { // CHECK: cir.brcond %arg0 ^bb1, ^bb2 // CHECK: ^bb1: // pred: ^bb0 // CHECK: cir.br ^bb3 // CHECK: ^bb2: // pred: ^bb0 // CHECK: cir.trap // CHECK: ^bb3: // pred: ^bb1 // CHECK: cir.br ^bb4 // CHECK: ^bb4: // pred: ^bb3 // CHECK: cir.return // CHECK: } // Mirror case: cir.trap in the true region. cir.func @ternary_trap_true(%arg0: !cir.bool) { cir.ternary(%arg0, true { cir.trap }, false { cir.yield }) : (!cir.bool) -> () cir.return } // CHECK: cir.func{{.*}} @ternary_trap_true(%arg0: !cir.bool) { // CHECK: cir.brcond %arg0 ^bb1, ^bb2 // CHECK: ^bb1: // pred: ^bb0 // CHECK: cir.trap // CHECK: ^bb2: // pred: ^bb0 // CHECK: cir.br ^bb3 // CHECK: ^bb3: // pred: ^bb2 // CHECK: cir.br ^bb4 // CHECK: ^bb4: // pred: ^bb3 // CHECK: cir.return // CHECK: } // cir.unreachable as the false-region terminator (e.g. throw expressions). cir.func @ternary_unreachable_false(%arg0: !cir.bool) { cir.ternary(%arg0, true { cir.yield }, false { cir.unreachable }) : (!cir.bool) -> () cir.return } // CHECK: cir.func{{.*}} @ternary_unreachable_false(%arg0: !cir.bool) { // CHECK: cir.brcond %arg0 ^bb1, ^bb2 // CHECK: ^bb1: // pred: ^bb0 // CHECK: cir.br ^bb3 // CHECK: ^bb2: // pred: ^bb0 // CHECK: cir.unreachable // CHECK: ^bb3: // pred: ^bb1 // CHECK: cir.br ^bb4 // CHECK: ^bb4: // pred: ^bb3 // CHECK: cir.return // CHECK: } }