| // RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir |
| /// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR |
| // RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll |
| // RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG |
| void sw1(int a) { |
| switch (int b = 1; a) { |
| case 0: |
| b = b + 1; |
| break; |
| case 1: |
| break; |
| case 2: { |
| b = b + 1; |
| int yolo = 100; |
| break; |
| } |
| } |
| } |
| // CIR: cir.func @_Z3sw1i |
| // CIR: cir.switch (%3 : !s32i) { |
| // CIR-NEXT: cir.case(equal, [#cir.int<0> : !s32i]) { |
| // CIR: cir.break |
| // CIR: cir.case(equal, [#cir.int<1> : !s32i]) { |
| // CIR-NEXT: cir.break |
| // CIR: cir.case(equal, [#cir.int<2> : !s32i]) { |
| // CIR: cir.scope { |
| // CIR: cir.alloca !s32i, !cir.ptr<!s32i>, ["yolo", init] |
| // CIR: cir.break |
| |
| // OGCG: define dso_local void @_Z3sw1i |
| // OGCG: entry: |
| // OGCG: %[[A_ADDR:.*]] = alloca i32, align 4 |
| // OGCG: %[[B:.*]] = alloca i32, align 4 |
| // OGCG: %[[YOLO:.*]] = alloca i32, align 4 |
| // OGCG: %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4 |
| // OGCG: switch i32 %[[A_VAL]], label %[[SW_EPILOG:.*]] [ |
| // OGCG: i32 0, label %[[SW0:.*]] |
| // OGCG: i32 1, label %[[SW1:.*]] |
| // OGCG: i32 2, label %[[SW2:.*]] |
| // OGCG: ] |
| // OGCG: [[SW0]]: |
| // OGCG: %[[B_LOAD0:.*]] = load i32, ptr %[[B]], align 4 |
| // OGCG: %[[B_INC0:.*]] = add nsw i32 %[[B_LOAD0]], 1 |
| // OGCG: store i32 %[[B_INC0]], ptr %[[B]], align 4 |
| // OGCG: br label %[[SW_EPILOG]] |
| // OGCG: [[SW1]]: |
| // OGCG: br label %[[SW_EPILOG]] |
| // OGCG: [[SW2]]: |
| // OGCG: %[[B_LOAD2:.*]] = load i32, ptr %[[B]], align 4 |
| // OGCG: %[[B_INC2:.*]] = add nsw i32 %[[B_LOAD2]], 1 |
| // OGCG: store i32 %[[B_INC2]], ptr %[[B]], align 4 |
| // OGCG: store i32 100, ptr %[[YOLO]], align 4 |
| // OGCG: br label %[[SW_EPILOG]] |
| // OGCG: [[SW_EPILOG]]: |
| // OGCG: ret void |
| |
| void sw2(int a) { |
| switch (int yolo = 2; a) { |
| case 3: |
| // "fomo" has the same lifetime as "yolo" |
| int fomo = 0; |
| yolo = yolo + fomo; |
| break; |
| } |
| } |
| |
| // CIR: cir.func @_Z3sw2i |
| // CIR: cir.scope { |
| // CIR-NEXT: %1 = cir.alloca !s32i, !cir.ptr<!s32i>, ["yolo", init] |
| // CIR-NEXT: %2 = cir.alloca !s32i, !cir.ptr<!s32i>, ["fomo", init] |
| // CIR: cir.switch (%4 : !s32i) { |
| // CIR-NEXT: cir.case(equal, [#cir.int<3> : !s32i]) { |
| // CIR-NEXT: %5 = cir.const #cir.int<0> : !s32i |
| // CIR-NEXT: cir.store %5, %2 : !s32i, !cir.ptr<!s32i> |
| |
| // OGCG: define dso_local void @_Z3sw2i |
| // OGCG: entry: |
| // OGCG: %[[A_ADDR:.*]] = alloca i32, align 4 |
| // OGCG: %[[YOLO:.*]] = alloca i32, align 4 |
| // OGCG: %[[FOMO:.*]] = alloca i32, align 4 |
| // OGCG: %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4 |
| // OGCG: switch i32 %[[A_VAL]], label %[[SW_EPILOG:.*]] [ |
| // OGCG: i32 3, label %[[SW3:.*]] |
| // OGCG: ] |
| // OGCG: [[SW3]]: |
| // OGCG: %[[Y:.*]] = load i32, ptr %[[YOLO]], align 4 |
| // OGCG: %[[F:.*]] = load i32, ptr %[[FOMO]], align 4 |
| // OGCG: %[[SUM:.*]] = add nsw i32 %[[Y]], %[[F]] |
| // OGCG: store i32 %[[SUM]], ptr %[[YOLO]], align 4 |
| // OGCG: br label %[[SW_EPILOG]] |
| // OGCG: [[SW_EPILOG]]: |
| // OGCG: ret void |
| |
| int sw4(int a) { |
| switch (a) { |
| case 42: { |
| return 3; |
| } |
| // TODO: add default case when it is upstreamed |
| } |
| return 0; |
| } |
| |
| // CIR: cir.func @_Z3sw4i |
| // CIR: cir.switch (%4 : !s32i) { |
| // CIR-NEXT: cir.case(equal, [#cir.int<42> : !s32i]) { |
| // CIR-NEXT: cir.scope { |
| // CIR-NEXT: %5 = cir.const #cir.int<3> : !s32i |
| // CIR-NEXT: cir.store %5, %1 : !s32i, !cir.ptr<!s32i> |
| // CIR-NEXT: %6 = cir.load %1 : !cir.ptr<!s32i>, !s32i |
| // CIR-NEXT: cir.return %6 : !s32i |
| // CIR-NEXT: } |
| // CIR-NEXT: cir.yield |
| // CIR-NEXT: } |
| |
| // OGCG: define dso_local noundef i32 @_Z3sw4i |
| // OGCG: entry: |
| // OGCG: %[[RETVAL:.*]] = alloca i32, align 4 |
| // OGCG: %[[A_ADDR:.*]] = alloca i32, align 4 |
| // OGCG: %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4 |
| // OGCG: switch i32 %[[A_VAL]], label %[[EPILOG:.*]] [ |
| // OGCG: i32 42, label %[[SW42:.*]] |
| // OGCG: ] |
| // OGCG: [[SW42]]: |
| // OGCG: br label %[[RETURN:.*]] |
| // OGCG: [[EPILOG]]: |
| // OGCG: br label %[[RETURN]] |
| // OGCG: [[RETURN]]: |
| // OGCG: %[[RETVAL_LOAD:.*]] = load i32, ptr %[[RETVAL]], align 4 |
| // OGCG: ret i32 %[[RETVAL_LOAD]] |
| |
| |
| void sw5(int a) { |
| switch (a) { |
| case 1:; |
| } |
| } |
| |
| // CIR: cir.func @_Z3sw5i |
| // CIR: cir.switch (%1 : !s32i) { |
| // CIR-NEXT: cir.case(equal, [#cir.int<1> : !s32i]) { |
| // CIR-NEXT: cir.yield |
| // CIR-NEXT: } |
| // CIR-NEXT: cir.yield |
| // CIR-NEXT: } |
| |
| // OGCG: define dso_local void @_Z3sw5i |
| // OGCG: entry: |
| // OGCG: %[[A_ADDR:.*]] = alloca i32, align 4 |
| // OGCG: %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4 |
| // OGCG: switch i32 %[[A_VAL]], label %[[SW_EPILOG:.*]] [ |
| // OGCG: i32 1, label %[[SW1:.*]] |
| // OGCG: ] |
| // OGCG: [[SW1]]: |
| // OGCG: br label %[[SW_EPILOG]] |
| // OGCG: [[SW_EPILOG]]: |
| // OGCG: ret void |
| |
| void sw8(int a) { |
| switch (a) |
| { |
| case 3: |
| break; |
| case 4: |
| // TODO: add default case when it is upstreamed |
| break; |
| } |
| } |
| |
| // CIR: cir.func @_Z3sw8i |
| // CIR: cir.case(equal, [#cir.int<3> : !s32i]) { |
| // CIR-NEXT: cir.break |
| // CIR-NEXT: } |
| // CIR-NEXT: cir.case(equal, [#cir.int<4> : !s32i]) { |
| // CIR-NEXT: cir.break |
| // CIR-NEXT: } |
| |
| |
| // OGCG: define dso_local void @_Z3sw8i |
| // OGCG: entry: |
| // OGCG: %[[A_ADDR:.*]] = alloca i32, align 4 |
| // OGCG: %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4 |
| // OGCG: switch i32 %[[A_VAL]], label %[[EPILOG:.*]] [ |
| // OGCG: i32 3, label %[[SW3:.*]] |
| // OGCG: i32 4, label %[[SW4:.*]] |
| // OGCG: ] |
| // OGCG: [[SW3]]: |
| // OGCG: br label %[[EPILOG]] |
| // OGCG: [[SW4]]: |
| // OGCG: br label %[[EPILOG]] |
| // OGCG: [[EPILOG]]: |
| // OGCG: ret void |
| |
| |
| void sw9(int a) { |
| switch (a) |
| { |
| case 3: |
| break; |
| // TODO: add default case when it is upstreamed |
| case 4: |
| break; |
| } |
| } |
| |
| // CIR: cir.func @_Z3sw9i |
| // CIR: cir.case(equal, [#cir.int<3> : !s32i]) { |
| // CIR-NEXT: cir.break |
| // CIR-NEXT: } |
| // CIR-NEXT: cir.case(equal, [#cir.int<4> : !s32i]) { |
| // CIR-NEXT: cir.break |
| // CIR-NEXT: } |
| |
| // OGCG: define dso_local void @_Z3sw9i |
| // OGCG: entry: |
| // OGCG: %[[A_ADDR:.*]] = alloca i32, align 4 |
| // OGCG: %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4 |
| // OGCG: switch i32 %[[A_VAL]], label %[[EPILOG:.*]] [ |
| // OGCG: i32 3, label %[[SW3:.*]] |
| // OGCG: i32 4, label %[[SW4:.*]] |
| // OGCG: ] |
| // OGCG: [[SW3]]: |
| // OGCG: br label %[[EPILOG]] |
| // OGCG: [[SW4]]: |
| // OGCG: br label %[[EPILOG]] |
| // OGCG: [[EPILOG]]: |
| // OGCG: ret void |
| |
| void sw12(int a) { |
| switch (a) |
| { |
| case 3: |
| return; |
| break; |
| } |
| } |
| |
| // CIR: cir.func @_Z4sw12i |
| // CIR: cir.scope { |
| // CIR: cir.switch |
| // CIR-NEXT: cir.case(equal, [#cir.int<3> : !s32i]) { |
| // CIR-NEXT: cir.return |
| // CIR-NEXT: ^bb1: // no predecessors |
| // CIR-NEXT: cir.break |
| // CIR-NEXT: } |
| |
| // OGCG: define dso_local void @_Z4sw12i |
| // OGCG: entry: |
| // OGCG: %[[A_ADDR:.*]] = alloca i32, align 4 |
| // OGCG: %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4 |
| // OGCG: switch i32 %[[A_VAL]], label %[[SW_DEFAULT:.*]] [ |
| // OGCG: i32 3, label %[[SW3:.*]] |
| // OGCG: ] |
| // OGCG: [[SW3]]: |
| // OGCG: br label %[[SW_DEFAULT]] |
| // OGCG: [[SW_DEFAULT]]: |
| // OGCG: ret void |
| |
| void sw13(int a, int b) { |
| switch (a) { |
| case 1: |
| switch (b) { |
| case 2: |
| break; |
| } |
| } |
| } |
| |
| // CIR: cir.func @_Z4sw13ii |
| // CIR: cir.scope { |
| // CIR: cir.switch |
| // CIR-NEXT: cir.case(equal, [#cir.int<1> : !s32i]) { |
| // CIR-NEXT: cir.scope { |
| // CIR: cir.switch |
| // CIR-NEXT: cir.case(equal, [#cir.int<2> : !s32i]) { |
| // CIR-NEXT: cir.break |
| // CIR-NEXT: } |
| // CIR-NEXT: cir.yield |
| // CIR-NEXT: } |
| // CIR-NEXT: } |
| // CIR: cir.yield |
| // CIR: } |
| // CIR: cir.return |
| |
| // OGCG: define dso_local void @_Z4sw13ii |
| // OGCG: entry: |
| // OGCG: %[[A_ADDR:.*]] = alloca i32, align 4 |
| // OGCG: %[[B_ADDR:.*]] = alloca i32, align 4 |
| // OGCG: %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4 |
| // OGCG: switch i32 %[[A_VAL]], label %[[EPILOG2:.*]] [ |
| // OGCG: i32 1, label %[[SW1:.*]] |
| // OGCG: ] |
| // OGCG: [[SW1]]: |
| // OGCG: %[[B_VAL:.*]] = load i32, ptr %[[B_ADDR]], align 4 |
| // OGCG: switch i32 %[[B_VAL]], label %[[EPILOG:.*]] [ |
| // OGCG: i32 2, label %[[SW12:.*]] |
| // OGCG: ] |
| // OGCG: [[SW12]]: |
| // OGCG: br label %[[EPILOG]] |
| // OGCG: [[EPILOG]]: |
| // OGCG: br label %[[EPILOG2]] |
| // OGCG: [[EPILOG2]]: |
| // OGCG: ret void |
| |
| int nested_switch(int a) { |
| switch (int b = 1; a) { |
| case 0: |
| b = b + 1; |
| case 1: |
| return b; |
| case 2: { |
| b = b + 1; |
| if (a > 1000) { |
| case 9: |
| b = a + b; |
| } |
| if (a > 500) { |
| case 7: |
| return a + b; |
| } |
| break; |
| } |
| } |
| |
| return 0; |
| } |
| |
| // CIR: cir.switch (%6 : !s32i) { |
| // CIR: cir.case(equal, [#cir.int<0> : !s32i]) { |
| // CIR: cir.yield |
| // CIR: } |
| // CIR: cir.case(equal, [#cir.int<1> : !s32i]) { |
| // CIR: cir.return |
| // CIR: } |
| // CIR: cir.case(equal, [#cir.int<2> : !s32i]) { |
| // CIR: cir.scope { |
| // CIR: cir.scope { |
| // CIR: cir.if |
| // CIR: cir.case(equal, [#cir.int<9> : !s32i]) { |
| // CIR: cir.yield |
| // CIR: cir.scope { |
| // CIR: cir.if |
| // CIR: cir.case(equal, [#cir.int<7> : !s32i]) { |
| // CIR: cir.return |
| |
| // OGCG: define dso_local noundef i32 @_Z13nested_switchi |
| // OGCG: entry: |
| // OGCG: %[[RETVAL:.*]] = alloca i32, align 4 |
| // OGCG: %[[A_ADDR:.*]] = alloca i32, align 4 |
| // OGCG: %[[B:.*]] = alloca i32, align 4 |
| // OGCG: %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4 |
| // OGCG: switch i32 %[[A_VAL]], label %[[EPILOG:.*]] [ |
| // OGCG: i32 0, label %[[SW0:.*]] |
| // OGCG: i32 1, label %[[SW1:.*]] |
| // OGCG: i32 2, label %[[SW2:.*]] |
| // OGCG: i32 9, label %[[SW4:.*]] |
| // OGCG: i32 7, label %[[SW8:.*]] |
| // OGCG: ] |
| // OGCG: [[SW0]]: |
| // OGCG: %[[B_VAL0:.*]] = load i32, ptr %[[B]], align 4 |
| // OGCG: %[[ADD0:.*]] = add nsw i32 %[[B_VAL0]], 1 |
| // OGCG: br label %[[SW1]] |
| // OGCG: [[SW1]]: |
| // OGCG: %[[B_VAL1:.*]] = load i32, ptr %[[B]], align 4 |
| // OGCG: br label %[[RETURN:.*]] |
| // OGCG: [[SW2]]: |
| // OGCG: %[[B_VAL2:.*]] = load i32, ptr %[[B]], align 4 |
| // OGCG: %[[ADD2:.*]] = add nsw i32 %[[B_VAL2]], 1 |
| // OGCG: %[[A_VAL2:.*]] = load i32, ptr %[[A_ADDR]], align 4 |
| // OGCG: %[[CMP1000:.*]] = icmp sgt i32 %[[A_VAL2]], 1000 |
| // OGCG: br i1 %[[CMP1000]], label %[[IFTHEN:.*]], label %[[IFEND:.*]] |
| // OGCG: [[IFTHEN]]: |
| // OGCG: br label %[[SW4]] |
| // OGCG: [[SW4]]: |
| // OGCG: %[[A_VAL4:.*]] = load i32, ptr %[[A_ADDR]], align 4 |
| // OGCG: %[[B_VAL4:.*]] = load i32, ptr %[[B]], align 4 |
| // OGCG: %[[ADD4:.*]] = add nsw i32 %[[A_VAL4]], %[[B_VAL4]] |
| // OGCG: br label %[[IFEND]] |
| // OGCG: [[IFEND]]: |
| // OGCG: %[[A_VAL5:.*]] = load i32, ptr %[[A_ADDR]], align 4 |
| // OGCG: %[[CMP500:.*]] = icmp sgt i32 %[[A_VAL5]], 500 |
| // OGCG: br i1 %[[CMP500]], label %[[IFTHEN7:.*]], label %[[IFEND10:.*]] |
| // OGCG: [[IFTHEN7]]: |
| // OGCG: br label %[[SW8]] |
| // OGCG: [[SW8]]: |
| // OGCG: %[[A_VAL8:.*]] = load i32, ptr %[[A_ADDR]], align 4 |
| // OGCG: %[[B_VAL8:.*]] = load i32, ptr %[[B]], align 4 |
| // OGCG: %[[ADD8:.*]] = add nsw i32 %[[A_VAL8]], %[[B_VAL8]] |
| // OGCG: br label %[[RETURN]] |
| // OGCG: [[IFEND10]]: |
| // OGCG: br label %[[EPILOG]] |
| // OGCG: [[EPILOG]]: |