| // RUN: %clang_cc1 -std=c++23 -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++23 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll |
| // RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM |
| // RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll |
| // RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG |
| |
| void pre_case_label() { |
| switch (1) { |
| LABEL1:; |
| case 1:; |
| } |
| } |
| |
| // CIR-LABEL: cir.func{{.*}} @_Z14pre_case_labelv |
| // CIR: cir.switch({{.*}} : !s32i) { |
| // CIR: cir.br ^bb1 |
| // CIR: ^bb1: |
| // CIR: cir.label "LABEL1" |
| // CIR: cir.case(equal, [#cir.int<1> : !s32i]) { |
| // CIR: cir.yield loc(#loc7) |
| // CIR: } |
| // CIR: cir.yield |
| // CIR: } |
| |
| // LLVM-LABEL: define{{.*}} void @_Z14pre_case_labelv |
| // LLVM: switch i32 1, label %[[END:.*]] [ |
| // LLVM: i32 1, label %[[CASE1:.*]] |
| // LLVM: ] |
| // LLVM: [[LABEL:.*]]:{{.*}}; No predecessors! |
| // LLVM: br label %[[JUMPS_TO_CASE1:.*]] |
| // LLVM: [[JUMPS_TO_CASE1]]: |
| // LLVM: br label %[[CASE1]] |
| // CIR inserts a bunch of 'empty' blocks all over the place that just jump to |
| // the next, so unifying these check blocks/checking more is pretty |
| // awful/doesn't result in good checks. |
| // LLVM: [[END]]: |
| // LLVM: br label |
| |
| // OGCG-LABEL: define{{.*}} void @_Z14pre_case_labelv |
| // OGCG: switch i32 1, label %[[END:.*]] [ |
| // OGCG: i32 1, label %[[CASE1:.*]] |
| // OGCG: ] |
| // OGCG: [[LABEL:.*]]:{{.*}}; No predecessors! |
| // OGCG: br label %[[CASE1]] |
| // OGCG: [[CASE1]]: |
| // OGCG: br label %[[END]] |
| // OGCG: [[END]]: |
| // OGCG: ret void |
| |
| void multiple_pre_case_labels() { |
| switch (1) { |
| LABEL1:; |
| LABEL2:; |
| case 1:; |
| } |
| } |
| |
| // CIR-LABEL: cir.func{{.*}} @_Z24multiple_pre_case_labelsv |
| // CIR: cir.switch({{.*}} : !s32i) { |
| // CIR: cir.br ^bb1 |
| // CIR: ^bb1: |
| // CIR: cir.label "LABEL1" |
| // CIR: cir.br ^bb2 |
| // CIR: ^bb2: |
| // CIR: cir.label "LABEL2" |
| // CIR: cir.case(equal, [#cir.int<1> : !s32i]) { |
| // CIR: cir.yield |
| // CIR: } |
| // CIR: cir.yield |
| // CIR: } |
| |
| // LLVM-LABEL: define{{.*}} @_Z24multiple_pre_case_labelsv |
| // LLVM: switch i32 1, label %[[END:.*]] [ |
| // LLVM: i32 1, label %[[CASE1:.*]] |
| // LLVM: ] |
| // LLVM: [[LABEL1:.*]]: |
| // LLVM: br label %[[LABEL2:.*]] |
| // LLVM: [[LABEL2]]: |
| // LLVM: br label %[[JUMPS_TO_CASE1:.*]] |
| // LLVM: [[JUMPS_TO_CASE1]]: |
| // LLVM: br label %[[CASE1]] |
| // LLVM: [[CASE1]]: |
| // LLVM: br label %[[JUMPS_TO_END:.*]] |
| // LLVM: [[JUMPS_TO_END]]: |
| // LLVM: br label %[[END]] |
| // LLVM: [[END]]: |
| // LLVM: br label |
| |
| // OGCG-LABEL: define{{.*}} @_Z24multiple_pre_case_labelsv |
| // OGCG: switch i32 1, label %[[END:.*]] [ |
| // OGCG: i32 1, label %[[CASE1:.*]] |
| // OGCG: ] |
| // OGCG: [[LABEL1:.*]]:{{.*}}; No predecessors! |
| // OGCG: br label %[[LABEL2:.*]] |
| // OGCG: [[LABEL2]]: |
| // OGCG: br label %[[CASE1]] |
| // OGCG: [[CASE1]]: |
| // OGCG: br label %[[END]] |
| // OGCG: [[END]]: |
| // OGCG: ret void |
| // OGCG: } |
| |
| void pre_case_goto() { |
| switch (1) { |
| goto end; |
| case 1:; |
| end:; |
| } |
| } |
| |
| // CIR-LABEL: cir.func{{.*}} @_Z13pre_case_gotov |
| // CIR: cir.switch({{.*}} : !s32i) { |
| // CIR: cir.goto "end" |
| // CIR: ^bb1: |
| // CIR: cir.case(equal, [#cir.int<1> : !s32i]) { |
| // CIR: cir.br ^bb1 |
| // CIR: ^bb1: |
| // CIR: cir.label "end" |
| // CIR: cir.yield |
| // CIR: } |
| // CIR: cir.yield |
| // CIR: } |
| |
| // Classic-codegen manages to remove the switch, but we don't have that sort of |
| // analysis working right. So this variant has a switch still in place. |
| // LLVM-LABEL: define{{.*}} @_Z13pre_case_gotov |
| // LLVM: switch i32 1, label %[[END:.*]] [ |
| // LLVM: i32 1, label %[[CASE1:.*]] |
| // LLVM: ] |
| // |
| // OGCG-LABEL: define{{.*}} @_Z13pre_case_gotov |
| // OGCG: br label %[[END:.*]] |
| // OGCG: [[END]]: |
| // OGCG: ret void |
| |
| void pre_case_if(int cond) { |
| switch (1) { |
| if (cond) {} |
| case 1:; |
| } |
| } |
| |
| // CIR-LABEL: cir.func{{.*}} @_Z11pre_case_ifi |
| // CIR: cir.switch({{.*}} : !s32i) { |
| // CIR: cir.scope { |
| // CIR: cir.load |
| // CIR: cir.cast int_to_bool |
| // CIR: cir.if {{.*}} { |
| // CIR: } |
| // CIR: } |
| // CIR: cir.case(equal, [#cir.int<1> : !s32i]) { |
| // CIR: cir.yield |
| // CIR: } |
| // CIR: cir.yield |
| // CIR: } |
| |
| // Once again, classic-codegen manages to make this a 'noop' and remove it. |
| // LLVM-LABEL: define{{.*}} @_Z11pre_case_ifi |
| // LLVM: switch i32 1, label %[[END:.*]] [ |
| // LLVM: i32 1, label %[[CASE1:.*]] |
| // LLVM: ] |
| // LLVM: [[ENTRY:.*]]:{{.*}}; No predecessors! |
| // LLVM: br label %[[IF_BLOCK:.*]] |
| // LLVM: [[IF_BLOCK]]: |
| // LLVM: load i32 |
| // LLVM: icmp ne i32 |
| // LLVM: br i1 %{{.*}}, label %[[TRUE:.*]], label %[[FALSE:.*]] |
| // LLVM: [[TRUE]]: |
| // LLVM: br label %[[FALSE]] |
| // LLVM: [[FALSE]]: |
| // LLVM: br label %[[JUMPS_TO_CASE1:.*]] |
| // LLVM: [[JUMPS_TO_CASE1:.*]]: |
| // LLVM: br label %[[CASE1]] |
| // LLVM: [[CASE1]]: |
| // LLVM: [[END]]: |
| |
| // OGCG-LABEL: define{{.*}} @_Z11pre_case_ifi |
| // OGCG: alloca i32 |
| // OGCG: store i32 %{{.*}}, ptr % |
| // OGCG: ret void |
| |
| void pre_case_return() { |
| switch (1) { |
| return; |
| case 1:; |
| } |
| } |
| |
| // CIR-LABEL: cir.func{{.*}} @_Z15pre_case_returnv |
| // CIR: cir.switch({{.*}} : !s32i) { |
| // CIR: cir.return |
| // CIR: ^bb1: |
| // CIR: cir.case(equal, [#cir.int<1> : !s32i]) { |
| // CIR: cir.yield |
| // CIR: } |
| // CIR: cir.yield |
| // CIR: } |
| |
| // Once again, classic codegen skips this entirely, but CIR doesn't. |
| // LLVM-LABEL: define{{.*}} @_Z15pre_case_returnv |
| // LLVM: switch i32 1, label %[[END:.*]] [ |
| // LLVM: i32 1, label %[[CASE1:.*]] |
| // LLVM: ] |
| // LLVM: [[ENTRY:.*]]:{{.*}}; No predecessors! |
| // LLVM: ret void |
| // LLVM: [[CASE1]]: |
| // LLVM: [[END]]: |
| |
| // OGCG-LABEL: define{{.*}} @_Z15pre_case_returnv |
| // OGCG: ret void |
| |
| void pre_case_break() { |
| switch (1) { |
| break; |
| case 1:; |
| } |
| } |
| |
| // CIR-LABEL: cir.func{{.*}} @_Z14pre_case_breakv |
| // CIR: cir.switch({{.*}} : !s32i) { |
| // CIR: cir.break |
| // CIR: ^bb1: |
| // CIR: cir.case(equal, [#cir.int<1> : !s32i]) { |
| // CIR: cir.yield |
| // CIR: } |
| // CIR: cir.yield |
| // CIR: } |
| |
| // LLVM-LABEL: define{{.*}} @_Z14pre_case_breakv |
| // LLVM: switch i32 1, label %[[END:.*]] [ |
| // LLVM: i32 1, label %[[CASE1:.*]] |
| // LLVM: ] |
| // LLVM: [[ENTRY:.*]]:{{.*}}; No predecessors! |
| // LLVM: br label %[[END]] |
| // LLVM: [[CASE1]]: |
| // LLVM: [[END]]: |
| // |
| // OGCG-LABEL: define{{.*}} @_Z14pre_case_breakv |
| // OGCG: ret void |
| |
| void label_only_switch() { |
| switch (1) { |
| LABEL:; |
| } |
| } |
| |
| // CIR-LABEL: cir.func{{.*}} @_Z17label_only_switchv |
| // CIR: cir.switch({{.*}} : !s32i) { |
| // CIR: cir.br ^bb1 |
| // CIR: ^bb1: |
| // CIR: cir.label "LABEL" |
| // CIR: cir.yield |
| // CIR: } |
| // CIR:} |
| |
| // LLVM-LABEL: define{{.*}} @_Z17label_only_switchv |
| // LLVM: switch i32 1, label %[[END:.*]] [ |
| // LLVM: ] |
| // LLVM: [[LABEL:.*]]:{{.*}}; No predecessors! |
| // LLVM: br label %[[JUMPS_TO_END:.*]] |
| // LLVM: [[JUMPS_TO_END]]: |
| // LLVM: br label %[[END]] |
| |
| // OGCG-LABEL: define{{.*}} @_Z17label_only_switchv |
| // OGCG: switch i32 1, label %[[END:.*]] [ |
| // OGCG: ] |
| // OGCG: [[LABEL:.*]]:{{.*}}; No predecessors! |
| // OGCG: br label %[[END]] |
| // OGCG: [[END]]: |
| // OGCG: ret void |
| |
| void external_goto_into_pre_case(int cond) { |
| if (cond) goto LABEL; |
| switch (1) { |
| LABEL:; |
| case 1:; |
| } |
| } |
| // CIR-LABEL: cir.func{{.*}} @_Z27external_goto_into_pre_casei |
| // CIR: cir.if {{.*}} { |
| // CIR: cir.goto "LABEL" |
| // CIR: cir.switch({{.*}} : !s32i) { |
| // CIR: cir.br ^bb1 |
| // CIR: ^bb1: |
| // CIR: cir.label "LABEL" |
| // CIR: cir.case(equal, [#cir.int<1> : !s32i]) { |
| // CIR: cir.yield |
| // CIR: } |
| // CIR: cir.yield |
| // CIR: } |
| |
| // LLVM-LABEL: define{{.*}} @_Z27external_goto_into_pre_casei |
| // LLVM: br i1 %{{.*}}, label %[[TRUE:.*]], label %[[FALSE:.*]] |
| // LLVM: [[TRUE]]: |
| // LLVM: br label %[[LABEL:.*]] |
| // LLVM: [[FALSE]]: |
| // Some empty blocks that just do jumps removed here. |
| // LLVM: switch i32 1, label %[[END:.*]] [ |
| // LLVM: i32 1, label %[[CASE1:.*]] |
| // LLVM: ] |
| // LLVM: [[ENTRY:.*]]:{{.*}}; No predecessors! |
| // LLVM: br label %[[LABEL]] |
| // LLVM: [[LABEL]]: |
| // LLVM: br label %[[CASE1]] |
| // LLVM: [[CASE1]]: |
| // LLVM: [[END]]: |
| |
| // OGCG-LABEL: define{{.*}} @_Z27external_goto_into_pre_casei |
| // OGCG: br i1 %{{.*}}, label %[[TRUE:.*]], label %[[FALSE:.*]] |
| // OGCG: [[TRUE]]: |
| // OGCG: br label %[[LABEL:.*]] |
| // OGCG: [[FALSE]]: |
| // OGCG: switch i32 1, label %[[END:.*]] [ |
| // OGCG: i32 1, label %[[CASE1:.*]] |
| // OGCG: ] |
| // OGCG: [[LABEL]]: |
| // OGCG: br label %[[CASE1]] |
| // OGCG: [[CASE1]]: |
| // OGCG: br label %[[END]] |
| // OGCG: [[END]]: |
| // OGCG: ret void |
| |
| void external_goto_into_pre_case_empty(int cond) { |
| if (cond) goto LABEL; |
| switch (1) { |
| LABEL:; |
| } |
| } |
| // CIR-LABEL: cir.func{{.*}} @_Z33external_goto_into_pre_case_emptyi |
| // CIR: cir.if {{.*}} { |
| // CIR: cir.goto "LABEL" |
| // CIR: cir.switch({{.*}} : !s32i) { |
| // CIR: cir.br ^bb1 |
| // CIR: ^bb1: |
| // CIR: cir.label "LABEL" |
| // CIR: cir.yield |
| // CIR: } |
| |
| // LLVM-LABEL: define{{.*}} @_Z33external_goto_into_pre_case_emptyi |
| // LLVM: br i1 %{{.*}}, label %[[TRUE:.*]], label %[[FALSE:.*]] |
| // LLVM: [[TRUE]]: |
| // LLVM: br label %[[LABEL:.*]] |
| // LLVM: [[FALSE]]: |
| // Some empty blocks that just do jumps removed here. |
| // LLVM: switch i32 1, label %[[END:.*]] [ |
| // LLVM: ] |
| // LLVM: [[ENTRY:.*]]:{{.*}}; No predecessors! |
| // LLVM: br label %[[LABEL]] |
| // LLVM: [[LABEL]]: |
| // LLVM: br label %[[END]] |
| // LLVM: [[END]]: |
| |
| // OGCG-LABEL: define{{.*}} @_Z33external_goto_into_pre_case_emptyi |
| // OGCG: br i1 %{{.*}}, label %[[TRUE:.*]], label %[[FALSE:.*]] |
| // OGCG: [[TRUE]]: |
| // OGCG: br label %[[LABEL:.*]] |
| // OGCG: [[FALSE]]: |
| // OGCG: switch i32 1, label %[[END:.*]] [ |
| // OGCG: ] |
| // OGCG: [[LABEL]]: |
| // OGCG: br label %[[END]] |
| // OGCG: [[END]]: |
| // OGCG: ret void |