| // RUN: %clang_cc1 -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 -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 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll |
| // RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG |
| |
| struct StructWithDestructor { |
| ~StructWithDestructor(); |
| }; |
| |
| void use(StructWithDestructor &a); |
| |
| void test_goto_within_cleanup(bool cond) { |
| StructWithDestructor a; |
| if (cond) |
| goto end; |
| use(a); |
| end: |
| use(a); |
| } |
| |
| // CIR-LABEL: cir.func {{.*}} @_Z24test_goto_within_cleanupb |
| // CIR: %[[A_ADDR:.*]] = cir.alloca "a" {{.*}} : !cir.ptr<!rec_StructWithDestructor> |
| // CIR: cir.cleanup.scope { |
| // CIR: cir.scope { |
| // CIR: cir.if {{.*}} { |
| // CIR: cir.goto "end" |
| // CIR: } |
| // CIR: } |
| // CIR: cir.call @_Z3useR20StructWithDestructor(%[[A_ADDR]]) |
| // CIR: cir.br ^[[BB_LABEL:bb[0-9]+]] |
| // CIR: ^[[BB_LABEL]]: |
| // CIR: cir.label "end" |
| // CIR: cir.call @_Z3useR20StructWithDestructor(%[[A_ADDR]]) |
| // CIR: cir.yield |
| // CIR: } cleanup normal { |
| // CIR: cir.call @_ZN20StructWithDestructorD1Ev(%[[A_ADDR]]) |
| // CIR: cir.yield |
| // CIR: } |
| // CIR: cir.return |
| |
| // LLVM-LABEL: define dso_local void @_Z24test_goto_within_cleanupb(i1 noundef %{{.*}}) |
| // LLVM: %[[COND_ADDR:.*]] = alloca i8 |
| // LLVM: %[[A_ADDR:.*]] = alloca %struct.StructWithDestructor |
| // LLVM: %[[COND_BYTE:.*]] = load i8, ptr %[[COND_ADDR]] |
| // LLVM: %[[COND_BIT:.*]] = trunc i8 %[[COND_BYTE]] to i1 |
| // LLVM: br i1 %[[COND_BIT]], label %[[GOTO_BB:.*]], label %[[FALLTHROUGH:.*]] |
| // LLVM: [[GOTO_BB]]: |
| // LLVM: br label %[[LABEL_BB:[0-9]+]] |
| // LLVM: [[FALLTHROUGH]]: |
| // LLVM: br label %[[USE_BB:.*]] |
| // LLVM: [[USE_BB]]: |
| // LLVM: call void @_Z3useR20StructWithDestructor(ptr {{.*}} %[[A_ADDR]]) |
| // LLVM: br label %[[LABEL_BB]] |
| // LLVM: [[LABEL_BB]]: |
| // LLVM: call void @_Z3useR20StructWithDestructor(ptr {{.*}} %[[A_ADDR]]) |
| // LLVM: br label %[[CLEANUP:.*]] |
| // LLVM: [[CLEANUP]]: |
| // LLVM: call void @_ZN20StructWithDestructorD1Ev(ptr {{.*}} %[[A_ADDR]]) |
| // LLVM-NOT: call void @_ZN20StructWithDestructorD1Ev |
| // LLVM: ret void |
| |
| // OGCG-LABEL: define dso_local void @_Z24test_goto_within_cleanupb(i1 noundef zeroext %cond) |
| // OGCG: %[[A_ADDR:.*]] = alloca %struct.StructWithDestructor |
| // OGCG: br i1 %{{.*}}, label %if.then, label %if.end |
| // OGCG: if.then: |
| // OGCG: br label %end |
| // OGCG: if.end: |
| // OGCG: call void @_Z3useR20StructWithDestructor(ptr {{.*}} %[[A_ADDR]]) |
| // OGCG: br label %end |
| // OGCG: end: |
| // OGCG: call void @_Z3useR20StructWithDestructor(ptr {{.*}} %[[A_ADDR]]) |
| // OGCG: call void @_ZN20StructWithDestructorD1Ev(ptr {{.*}} %[[A_ADDR]]) |
| // OGCG-NOT: call void @_ZN20StructWithDestructorD1Ev |
| // OGCG: ret void |
| |
| void test_goto_jump_into_nested_op(bool cond1, bool cond2) { |
| StructWithDestructor a; |
| if (cond1) |
| goto skip; |
| use(a); |
| if (cond2) { |
| skip: |
| use(a); |
| } |
| } |
| |
| // CIR-LABEL: cir.func {{.*}} @_Z29test_goto_jump_into_nested_opbb |
| // CIR: %[[A_ADDR:.*]] = cir.alloca "a" {{.*}} : !cir.ptr<!rec_StructWithDestructor> |
| // CIR: cir.cleanup.scope { |
| // CIR: cir.scope { |
| // CIR: cir.if {{.*}} { |
| // CIR: cir.goto "skip" |
| // CIR: } |
| // CIR: } |
| // CIR: cir.call @_Z3useR20StructWithDestructor(%[[A_ADDR]]) |
| // CIR: cir.scope { |
| // CIR: cir.if {{.*}} { |
| // CIR: cir.br ^[[BB_LABEL:bb[0-9]+]] |
| // CIR: ^[[BB_LABEL]]: |
| // CIR: cir.label "skip" |
| // CIR: cir.call @_Z3useR20StructWithDestructor(%[[A_ADDR]]) |
| // CIR: cir.yield |
| // CIR: } |
| // CIR: } |
| // CIR: cir.yield |
| // CIR: } cleanup normal { |
| // CIR: cir.call @_ZN20StructWithDestructorD1Ev(%[[A_ADDR]]) |
| // CIR: cir.yield |
| // CIR: } |
| // CIR: cir.return |
| |
| // LLVM-LABEL: define dso_local void @_Z29test_goto_jump_into_nested_opbb(i1 noundef %{{.*}}, i1 noundef %{{.*}}) |
| // LLVM: %[[COND1_ADDR:.*]] = alloca i8 |
| // LLVM: %[[COND2_ADDR:.*]] = alloca i8 |
| // LLVM: %[[A_ADDR:.*]] = alloca %struct.StructWithDestructor |
| // LLVM: %[[COND1_BYTE:.*]] = load i8, ptr %[[COND1_ADDR]] |
| // LLVM: %[[COND1_BIT:.*]] = trunc i8 %[[COND1_BYTE]] to i1 |
| // LLVM: br i1 %[[COND1_BIT]], label %[[GOTO_BB:.*]], label %[[FALLTHROUGH:.*]] |
| // LLVM: [[GOTO_BB]]: |
| // LLVM: br label %[[SKIP_BB:[0-9]+]] |
| // LLVM: [[FALLTHROUGH]]: |
| // LLVM: br label %[[USE_BB:.*]] |
| // LLVM: [[USE_BB]]: |
| // LLVM: call void @_Z3useR20StructWithDestructor(ptr {{.*}} %[[A_ADDR]]) |
| // LLVM: br label %[[COND2_BB:.*]] |
| // LLVM: [[COND2_BB]]: |
| // LLVM: %[[COND2_BYTE:.*]] = load i8, ptr %[[COND2_ADDR]] |
| // LLVM: %[[COND2_BIT:.*]] = trunc i8 %[[COND2_BYTE]] to i1 |
| // LLVM: br i1 %[[COND2_BIT]], label %[[GOTO_BB2:.*]], label %[[MERGE:.*]] |
| // LLVM: [[GOTO_BB2]]: |
| // LLVM: br label %[[SKIP_BB]] |
| // LLVM: [[SKIP_BB]]: |
| // LLVM: call void @_Z3useR20StructWithDestructor(ptr {{.*}} %[[A_ADDR]]) |
| // LLVM: br label %[[MERGE]] |
| // LLVM: [[MERGE]]: |
| // LLVM: br label %[[CLEANUP:.*]] |
| // LLVM: [[CLEANUP]]: |
| // LLVM: call void @_ZN20StructWithDestructorD1Ev(ptr {{.*}} %[[A_ADDR]]) |
| // LLVM-NOT: call void @_ZN20StructWithDestructorD1Ev |
| // LLVM: ret void |
| |
| // OGCG-LABEL: define dso_local void @_Z29test_goto_jump_into_nested_opbb(i1 noundef zeroext %cond1, i1 noundef zeroext %cond2) |
| // OGCG: %[[COND1_ADDR:.*]] = alloca i8 |
| // OGCG: %[[COND2_ADDR:.*]] = alloca i8 |
| // OGCG: %[[A_ADDR:.*]] = alloca %struct.StructWithDestructor |
| // OGCG: %[[COND1_BYTE:.*]] = load i8, ptr %[[COND1_ADDR]] |
| // OGCG: %[[COND1_BIT:.*]] = icmp ne i8 %[[COND1_BYTE]], 0 |
| // OGCG: br i1 %[[COND1_BIT]], label %if.then, label %if.end |
| // OGCG: if.then: |
| // OGCG: br label %skip |
| // OGCG: if.end: |
| // OGCG: call void @_Z3useR20StructWithDestructor(ptr {{.*}} %[[A_ADDR]]) |
| // OGCG: %[[COND2_BYTE:.*]] = load i8, ptr %[[COND2_ADDR]] |
| // OGCG: %[[COND2_BIT:.*]] = icmp ne i8 %[[COND2_BYTE]], 0 |
| // OGCG: br i1 %[[COND2_BIT]], label %if.then{{[0-9]+}}, label %[[ENDIF:if\.end[0-9]+]] |
| // OGCG: if.then{{[0-9]+}}: |
| // OGCG: br label %skip |
| // OGCG: skip: |
| // OGCG: call void @_Z3useR20StructWithDestructor(ptr {{.*}} %[[A_ADDR]]) |
| // OGCG: br label %[[ENDIF]] |
| // OGCG: [[ENDIF]]: |
| // OGCG: call void @_ZN20StructWithDestructorD1Ev(ptr {{.*}} %[[A_ADDR]]) |
| // OGCG-NOT: call void @_ZN20StructWithDestructorD1Ev |
| // OGCG: ret void |