blob: 221c86a08e4dbbb125300453738d951310936b8e [file] [edit]
// RUN: %clang_cc1 -no-enable-noundef-analysis %s -triple=x86_64-linux-gnu -fclangir -emit-cir -std=c++17 -fcxx-exceptions -fexceptions -o %t.cir
// RUN: FileCheck -check-prefixes=CIR --input-file=%t.cir %s
// RUN: %clang_cc1 -no-enable-noundef-analysis %s -triple=x86_64-linux-gnu -fclangir -emit-llvm -std=c++17 -fcxx-exceptions -fexceptions -o %t-cir.ll
// RUN: FileCheck -check-prefixes=LLVM --input-file=%t-cir.ll %s
// RUN: %clang_cc1 -no-enable-noundef-analysis %s -triple=x86_64-linux-gnu -emit-llvm -std=c++17 -fcxx-exceptions -fexceptions -o %t.ll
// RUN: FileCheck -check-prefixes=OGCG --input-file=%t.ll %s
struct S {
S();
~S();
explicit operator bool();
};
void while_cond_var(int n) {
while (S s{})
--n;
}
// CIR-LABEL: cir.func {{.*}} @_Z14while_cond_vari
// CIR: %[[FLAG:.*]] = cir.alloca {{.*}}"cond.cleanup.isactive"{{.*}} : !cir.ptr<!cir.bool>
// CIR: cir.scope {
// CIR: %[[S:.*]] = cir.alloca {{.*}}"s"{{.*}} : !cir.ptr<!rec_S>
// CIR: cir.while {
// The cleanup active flag is cleared before the initializer and set once the
// condition variable is constructed, so we don't call the destructor if the
// variable wasn't successfully constructed.
// CIR: %[[FALSE:.*]] = cir.const #false
// CIR: cir.store %[[FALSE]], %[[FLAG]]
// CIR: cir.call @_ZN1SC1Ev(%[[S]])
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[FLAG]]
// CIR: %[[COND:.*]] = cir.call @_ZN1ScvbEv(%[[S]])
// CIR: cir.condition(%[[COND]])
// CIR: } do {
// CIR: } cleanup all {
// CIR: %[[ACTIVE:.*]] = cir.load {{.*}}%[[FLAG]]
// CIR: cir.if %[[ACTIVE]] {
// CIR: cir.call @_ZN1SD1Ev(%[[S]]) nothrow
// CIR: }
// CIR: cir.yield
// CIR: }
// LLVM-LABEL: define dso_local void @_Z14while_cond_vari(i32 %0) {{.*}} personality ptr @__gxx_personality_v0 {
// LLVM: %[[S:.*]] = alloca %struct.S
// LLVM: %[[FLAG:.*]] = alloca i8
// The loop header branches into the condition region or to the loop exit.
// LLVM: br label %{{.*}}
// LLVM: br label %[[COND:.*]]
// LLVM: [[COND]]:
// LLVM: br i1 true, label %{{.*}}, label %[[EXIT:.*]]
// LLVM: store i8 0, ptr %[[FLAG]]
// Unlike OGCG, the LLVM path emits an invoke here because our cleanup scope is
// the entire condition region. The active flag is used to skip the cleanup if
// we throw from here.
// LLVM: invoke void @_ZN1SC1Ev(ptr {{.*}} %[[S]])
// LLVM-NEXT: to label %[[CTOR_CONT:.*]] unwind label %[[LPAD:.*]]
// LLVM: [[CTOR_CONT]]:
// LLVM: store i8 1, ptr %[[FLAG]]
// LLVM: %[[CALL:.*]] = invoke i1 @_ZN1ScvbEv(ptr {{.*}} %[[S]])
// LLVM-NEXT: to label %[[CVB_CONT:.*]] unwind label %[[LPAD]]
// LLVM: [[CVB_CONT]]:
// LLVM: br i1 %[[CALL]], label %[[BODY:.*]], label %[[COND_FALSE:.*]]
// The body sets the cleanup destination selector to the "continue" value and
// the false (loop-exit) edge sets it to the "break" value; both then fall
// through to the shared cleanup.
// LLVM: [[BODY]]:
// LLVM: store i32 0, ptr %[[DEST:.*]],
// LLVM: br label %[[CLEANUP:.*]]
// LLVM: [[COND_FALSE]]:
// LLVM: store i32 1, ptr %[[DEST]]
// LLVM: br label %[[CLEANUP]]
// The cleanup tests the active flag, destroys the condition variable when set,
// then dispatches on the destination selector to the loop back-edge (continue)
// or the loop exit (break).
// LLVM: [[CLEANUP]]:
// LLVM: %[[ACT:.*]] = load i8, ptr %[[FLAG]]
// LLVM: %[[ACTB:.*]] = trunc i8 %[[ACT]] to i1
// LLVM: br i1 %[[ACTB]], label %[[DTOR:.*]], label %{{.*}}
// LLVM: [[DTOR]]:
// LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// LLVM: %[[SEL:.*]] = load i32, ptr %[[DEST]]
// LLVM: switch i32 %[[SEL]], label %{{.*}}
// LLVM: i32 0, label %[[CONTINUE:.*]]
// LLVM: i32 1, label %[[BREAK:.*]]
// LLVM: [[CONTINUE]]:
// LLVM: br label %[[BACKEDGE:.*]]
// LLVM: [[BREAK]]:
// LLVM: br label %[[EXIT]]
// LLVM: [[LPAD]]:
// LLVM: landingpad { ptr, i32 }
// LLVM-NEXT: cleanup
// LLVM: %[[EACT:.*]] = load i8, ptr %[[FLAG]]
// LLVM: %[[EACTB:.*]] = trunc i8 %[[EACT]] to i1
// LLVM: br i1 %[[EACTB]], label %[[EHDTOR:.*]], label %{{.*}}
// LLVM: [[EHDTOR]]:
// LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// LLVM: resume { ptr, i32 }
// LLVM: [[BACKEDGE]]:
// LLVM: br label %[[COND]]
// OGCG-LABEL: define dso_local void @_Z14while_cond_vari(i32 %n) {{.*}} personality ptr @__gxx_personality_v0 {
// OGCG: %[[S:.*]] = alloca %struct.S
// OGCG: br label %[[COND:.*]]
// OGCG: [[COND]]:
// OGCG: call void @_ZN1SC1Ev(ptr {{.*}} %[[S]])
// OGCG: %[[CALL:.*]] = invoke {{.*}} i1 @_ZN1ScvbEv(ptr {{.*}} %[[S]])
// OGCG-NEXT: to label %[[CONT:.*]] unwind label %[[LPAD:.*]]
// OGCG: [[CONT]]:
// OGCG: br i1 %[[CALL]], label %[[BODY:.*]], label %[[EXIT:.*]]
// OGCG: [[EXIT]]:
// OGCG: store i32 3, ptr %[[DEST:.*]],
// OGCG: br label %[[CLEANUP:.*]]
// OGCG: [[LPAD]]:
// OGCG: landingpad { ptr, i32 }
// OGCG-NEXT: cleanup
// OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// OGCG: br label %[[EHRESUME:.*]]
// OGCG: [[BODY]]:
// OGCG: store i32 0, ptr %[[DEST]]
// OGCG: br label %[[CLEANUP]]
// OGCG: [[CLEANUP]]:
// OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// OGCG: %[[SEL:.*]] = load i32, ptr %[[DEST]]
// OGCG: switch i32 %[[SEL]], label %{{.*}}
// OGCG: i32 0, label %[[CONTINUE:.*]]
// OGCG: i32 3, label %[[END:.*]]
// OGCG: [[CONTINUE]]:
// OGCG: br label %[[COND]]
// OGCG: [[END]]:
// OGCG: ret void
// OGCG: [[EHRESUME]]:
// OGCG: resume { ptr, i32 }
void while_cond_var_break() {
while (S s{}) {
break;
}
}
// CIR-LABEL: cir.func {{.*}} @_Z20while_cond_var_breakv
// CIR: %[[FLAG:.*]] = cir.alloca {{.*}}"cond.cleanup.isactive"{{.*}} : !cir.ptr<!cir.bool>
// CIR: cir.scope {
// CIR: %[[S:.*]] = cir.alloca {{.*}}"s"{{.*}} : !cir.ptr<!rec_S>
// CIR: cir.while {
// CIR: %[[FALSE:.*]] = cir.const #false
// CIR: cir.store %[[FALSE]], %[[FLAG]]
// CIR: cir.call @_ZN1SC1Ev(%[[S]])
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[FLAG]]
// CIR: %[[COND:.*]] = cir.call @_ZN1ScvbEv(%[[S]])
// CIR-NOT: cir.cleanup.scope
// CIR: cir.condition(%[[COND]])
// CIR: } do {
// CIR: cir.break
// CIR: } cleanup all {
// CIR: %[[ACTIVE:.*]] = cir.load {{.*}}%[[FLAG]]
// CIR: cir.if %[[ACTIVE]] {
// CIR: cir.call @_ZN1SD1Ev(%[[S]]) nothrow
// CIR: }
// CIR: cir.yield
// CIR: }
// LLVM-LABEL: define dso_local void @_Z20while_cond_var_breakv() {{.*}} personality ptr @__gxx_personality_v0 {
// LLVM: %[[S:.*]] = alloca %struct.S
// LLVM: %[[FLAG:.*]] = alloca i8
// LLVM: br label %{{.*}}
// LLVM: br label %[[COND:.*]]
// LLVM: [[COND]]:
// LLVM: br i1 true, label %{{.*}}, label %[[EXIT:.*]]
// LLVM: store i8 0, ptr %[[FLAG]]
// LLVM: invoke void @_ZN1SC1Ev(ptr {{.*}} %[[S]])
// LLVM-NEXT: to label %[[CTOR_CONT:.*]] unwind label %[[LPAD:.*]]
// LLVM: [[CTOR_CONT]]:
// LLVM: store i8 1, ptr %[[FLAG]]
// LLVM: %[[CALL:.*]] = invoke i1 @_ZN1ScvbEv(ptr {{.*}} %[[S]])
// LLVM-NEXT: to label %[[CVB_CONT:.*]] unwind label %[[LPAD]]
// LLVM: [[CVB_CONT]]:
// LLVM: br i1 %[[CALL]], label %[[BODY:.*]], label %[[COND_FALSE:.*]]
// LLVM: [[BODY]]:
// LLVM: store i32 1, ptr %[[DEST:.*]], align 4
// LLVM: br label %[[CLEANUP:.*]]
// LLVM: [[COND_FALSE]]:
// LLVM: store i32 2, ptr %[[DEST]], align 4
// LLVM: br label %[[CLEANUP]]
// LLVM: [[CLEANUP]]:
// LLVM: %[[ACT:.*]] = load i8, ptr %[[FLAG]]
// LLVM: %[[ACTB:.*]] = trunc i8 %[[ACT]] to i1
// LLVM: br i1 %[[ACTB]], label %[[DTOR:.*]], label %{{.*}}
// LLVM: [[DTOR]]:
// LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// LLVM: %[[SEL:.*]] = load i32, ptr %[[DEST]], align 4
// LLVM: switch i32 %[[SEL]], label %{{.*}}
// LLVM: i32 0, label %[[CONTINUE:.*]]
// LLVM: i32 1, label %[[BREAK:.*]]
// LLVM: [[BREAK]]:
// LLVM: br label %[[EXIT]]
// LLVM: [[LPAD]]:
// LLVM: landingpad { ptr, i32 }
// LLVM-NEXT: cleanup
// LLVM: %[[EACT:.*]] = load i8, ptr %[[FLAG]]
// LLVM: %[[EACTB:.*]] = trunc i8 %[[EACT]] to i1
// LLVM: br i1 %[[EACTB]], label %[[EHDTOR:.*]], label %{{.*}}
// LLVM: [[EHDTOR]]:
// LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// LLVM: resume { ptr, i32 }
// OGCG-LABEL: define dso_local void @_Z20while_cond_var_breakv() {{.*}} personality ptr @__gxx_personality_v0 {
// OGCG: %[[S:.*]] = alloca %struct.S
// OGCG: br label %[[COND:.*]]
// OGCG: [[COND]]:
// OGCG: call void @_ZN1SC1Ev(ptr {{.*}} %[[S]])
// OGCG: %[[CALL:.*]] = invoke {{.*}} i1 @_ZN1ScvbEv(ptr {{.*}} %[[S]])
// OGCG-NEXT: to label %[[CONT:.*]] unwind label %[[LPAD:.*]]
// OGCG: [[CONT]]:
// OGCG: br i1 %[[CALL]], label %[[BODY:.*]], label %[[COND_FALSE:.*]]
// OGCG: [[COND_FALSE]]:
// OGCG: store i32 3, ptr %[[DEST:.*]], align 4
// OGCG: br label %[[CLEANUP:.*]]
// OGCG: [[LPAD]]:
// OGCG: landingpad { ptr, i32 }
// OGCG-NEXT: cleanup
// OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// OGCG: br label %[[EHRESUME:.*]]
// OGCG: [[BODY]]:
// OGCG: store i32 3, ptr %[[DEST]], align 4
// OGCG: br label %[[CLEANUP]]
// OGCG: [[CLEANUP]]:
// OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// OGCG: br label %[[END:.*]]
// OGCG: [[END]]:
// OGCG: ret void
// OGCG: [[EHRESUME]]:
// OGCG: resume { ptr, i32 }
void while_cond_var_continue() {
while (S s{}) {
continue;
}
}
// CIR-LABEL: cir.func {{.*}} @_Z23while_cond_var_continuev
// CIR: %[[FLAG:.*]] = cir.alloca {{.*}}"cond.cleanup.isactive"{{.*}} : !cir.ptr<!cir.bool>
// CIR: cir.scope {
// CIR: %[[S:.*]] = cir.alloca {{.*}}"s"{{.*}} : !cir.ptr<!rec_S>
// CIR: cir.while {
// CIR: %[[FALSE:.*]] = cir.const #false
// CIR: cir.store %[[FALSE]], %[[FLAG]]
// CIR: cir.call @_ZN1SC1Ev(%[[S]])
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[FLAG]]
// CIR: %[[COND:.*]] = cir.call @_ZN1ScvbEv(%[[S]])
// CIR-NOT: cir.cleanup.scope
// CIR: cir.condition(%[[COND]])
// CIR: } do {
// CIR: cir.continue
// CIR: } cleanup all {
// CIR: %[[ACTIVE:.*]] = cir.load {{.*}}%[[FLAG]]
// CIR: cir.if %[[ACTIVE]] {
// CIR: cir.call @_ZN1SD1Ev(%[[S]]) nothrow
// CIR: }
// CIR: cir.yield
// CIR: }
// LLVM-LABEL: define dso_local void @_Z23while_cond_var_continuev() {{.*}} personality ptr @__gxx_personality_v0 {
// LLVM: %[[S:.*]] = alloca %struct.S
// LLVM: %[[FLAG:.*]] = alloca i8
// LLVM: br label %{{.*}}
// LLVM: br label %[[COND:.*]]
// LLVM: [[COND]]:
// LLVM: br i1 true, label %{{.*}}, label %[[EXIT:.*]]
// LLVM: store i8 0, ptr %[[FLAG]]
// LLVM: invoke void @_ZN1SC1Ev(ptr {{.*}} %[[S]])
// LLVM-NEXT: to label %[[CTOR_CONT:.*]] unwind label %[[LPAD:.*]]
// LLVM: [[CTOR_CONT]]:
// LLVM: store i8 1, ptr %[[FLAG]]
// LLVM: %[[CALL:.*]] = invoke i1 @_ZN1ScvbEv(ptr {{.*}} %[[S]])
// LLVM-NEXT: to label %[[CVB_CONT:.*]] unwind label %[[LPAD]]
// LLVM: [[CVB_CONT]]:
// LLVM: br i1 %[[CALL]], label %[[BODY:.*]], label %[[COND_FALSE:.*]]
// LLVM: [[BODY]]:
// LLVM: store i32 1, ptr %[[DEST:.*]], align 4
// LLVM: br label %[[CLEANUP:.*]]
// LLVM: [[COND_FALSE]]:
// LLVM: store i32 2, ptr %[[DEST]], align 4
// LLVM: br label %[[CLEANUP]]
// LLVM: [[CLEANUP]]:
// LLVM: %[[ACT:.*]] = load i8, ptr %[[FLAG]]
// LLVM: %[[ACTB:.*]] = trunc i8 %[[ACT]] to i1
// LLVM: br i1 %[[ACTB]], label %[[DTOR:.*]], label %{{.*}}
// LLVM: [[DTOR]]:
// LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// LLVM: %[[SEL:.*]] = load i32, ptr %[[DEST]], align 4
// LLVM: switch i32 %[[SEL]], label %{{.*}}
// LLVM: i32 1, label %[[CONTINUE:.*]]
// LLVM: i32 2, label %[[BREAK:.*]]
// LLVM: [[CONTINUE]]:
// LLVM: br label %[[COND]]
// LLVM: [[BREAK]]:
// LLVM: br label %[[EXIT]]
// LLVM: [[LPAD]]:
// LLVM: landingpad { ptr, i32 }
// LLVM-NEXT: cleanup
// LLVM: %[[EACT:.*]] = load i8, ptr %[[FLAG]]
// LLVM: %[[EACTB:.*]] = trunc i8 %[[EACT]] to i1
// LLVM: br i1 %[[EACTB]], label %[[EHDTOR:.*]], label %{{.*}}
// LLVM: [[EHDTOR]]:
// LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// LLVM: resume { ptr, i32 }
// OGCG-LABEL: define dso_local void @_Z23while_cond_var_continuev() {{.*}} personality ptr @__gxx_personality_v0 {
// OGCG: %[[S:.*]] = alloca %struct.S
// OGCG: br label %[[COND:.*]]
// OGCG: [[COND]]:
// OGCG: call void @_ZN1SC1Ev(ptr {{.*}} %[[S]])
// OGCG: %[[CALL:.*]] = invoke {{.*}} i1 @_ZN1ScvbEv(ptr {{.*}} %[[S]])
// OGCG-NEXT: to label %[[CONT:.*]] unwind label %[[LPAD:.*]]
// OGCG: [[CONT]]:
// OGCG: br i1 %[[CALL]], label %[[BODY:.*]], label %[[COND_FALSE:.*]]
// OGCG: [[COND_FALSE]]:
// OGCG: store i32 3, ptr %[[DEST:.*]], align 4
// OGCG: br label %[[CLEANUP:.*]]
// OGCG: [[LPAD]]:
// OGCG: landingpad { ptr, i32 }
// OGCG-NEXT: cleanup
// OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// OGCG: br label %[[EHRESUME:.*]]
// OGCG: [[BODY]]:
// OGCG: store i32 2, ptr %[[DEST]], align 4
// OGCG: br label %[[CLEANUP]]
// OGCG: [[CLEANUP]]:
// OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// OGCG: %[[SEL:.*]] = load i32, ptr %[[DEST]], align 4
// OGCG: switch i32 %[[SEL]], label %{{.*}}
// OGCG: i32 3, label %[[END:.*]]
// OGCG: i32 2, label %[[COND]]
// OGCG: [[END]]:
// OGCG: ret void
// OGCG: [[EHRESUME]]:
// OGCG: resume { ptr, i32 }
void for_cond_var_break() {
for (; S s{};) {
break;
}
}
// CIR-LABEL: cir.func {{.*}} @_Z18for_cond_var_breakv
// CIR: %[[FLAG:.*]] = cir.alloca {{.*}}"cond.cleanup.isactive"{{.*}} : !cir.ptr<!cir.bool>
// CIR: cir.scope {
// CIR: %[[S:.*]] = cir.alloca {{.*}}"s"{{.*}} : !cir.ptr<!rec_S>
// CIR: cir.for : cond {
// CIR: %[[FALSE:.*]] = cir.const #false
// CIR: cir.store %[[FALSE]], %[[FLAG]]
// CIR: cir.call @_ZN1SC1Ev(%[[S]])
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[FLAG]]
// CIR: %[[COND:.*]] = cir.call @_ZN1ScvbEv(%[[S]])
// CIR-NOT: cir.cleanup.scope
// CIR: cir.condition(%[[COND]])
// CIR: } body {
// CIR: cir.break
// CIR: } step {
// CIR: } cleanup all {
// CIR: %[[ACTIVE:.*]] = cir.load {{.*}}%[[FLAG]]
// CIR: cir.if %[[ACTIVE]] {
// CIR: cir.call @_ZN1SD1Ev(%[[S]]) nothrow
// CIR: }
// CIR: cir.yield
// CIR: }
// LLVM-LABEL: define dso_local void @_Z18for_cond_var_breakv() {{.*}} personality ptr @__gxx_personality_v0 {
// LLVM: %[[S:.*]] = alloca %struct.S
// LLVM: %[[FLAG:.*]] = alloca i8
// LLVM: br label %{{.*}}
// LLVM: br label %[[COND:.*]]
// LLVM: [[COND]]:
// LLVM: br i1 true, label %{{.*}}, label %[[EXIT:.*]]
// LLVM: store i8 0, ptr %[[FLAG]]
// LLVM: invoke void @_ZN1SC1Ev(ptr {{.*}} %[[S]])
// LLVM-NEXT: to label %[[CTOR_CONT:.*]] unwind label %[[LPAD:.*]]
// LLVM: [[CTOR_CONT]]:
// LLVM: store i8 1, ptr %[[FLAG]]
// LLVM: %[[CALL:.*]] = invoke i1 @_ZN1ScvbEv(ptr {{.*}} %[[S]])
// LLVM-NEXT: to label %[[CVB_CONT:.*]] unwind label %[[LPAD]]
// LLVM: [[CVB_CONT]]:
// LLVM: br i1 %[[CALL]], label %[[BODY:.*]], label %[[COND_FALSE:.*]]
// LLVM: [[BODY]]:
// LLVM: store i32 1, ptr %[[DEST:.*]], align 4
// LLVM: br label %[[CLEANUP:.*]]
// LLVM: [[COND_FALSE]]:
// LLVM: store i32 2, ptr %[[DEST]], align 4
// LLVM: br label %[[CLEANUP]]
// LLVM: [[CLEANUP]]:
// LLVM: %[[ACT:.*]] = load i8, ptr %[[FLAG]]
// LLVM: %[[ACTB:.*]] = trunc i8 %[[ACT]] to i1
// LLVM: br i1 %[[ACTB]], label %[[DTOR:.*]], label %{{.*}}
// LLVM: [[DTOR]]:
// LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// LLVM: %[[SEL:.*]] = load i32, ptr %[[DEST]], align 4
// LLVM: switch i32 %[[SEL]], label %{{.*}}
// LLVM: i32 0, label %[[CONTINUE:.*]]
// LLVM: i32 1, label %[[BREAK:.*]]
// LLVM: [[BREAK]]:
// LLVM: br label %[[EXIT]]
// LLVM: [[LPAD]]:
// LLVM: landingpad { ptr, i32 }
// LLVM-NEXT: cleanup
// LLVM: %[[EACT:.*]] = load i8, ptr %[[FLAG]]
// LLVM: %[[EACTB:.*]] = trunc i8 %[[EACT]] to i1
// LLVM: br i1 %[[EACTB]], label %[[EHDTOR:.*]], label %{{.*}}
// LLVM: [[EHDTOR]]:
// LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// LLVM: resume { ptr, i32 }
// OGCG-LABEL: define dso_local void @_Z18for_cond_var_breakv() {{.*}} personality ptr @__gxx_personality_v0 {
// OGCG: %[[S:.*]] = alloca %struct.S
// OGCG: br label %[[COND:.*]]
// OGCG: [[COND]]:
// OGCG: call void @_ZN1SC1Ev(ptr {{.*}} %[[S]])
// OGCG: %[[CALL:.*]] = invoke {{.*}} i1 @_ZN1ScvbEv(ptr {{.*}} %[[S]])
// OGCG-NEXT: to label %[[CONT:.*]] unwind label %[[LPAD:.*]]
// OGCG: [[CONT]]:
// OGCG: br i1 %[[CALL]], label %[[BODY:.*]], label %[[COND_FALSE:.*]]
// OGCG: [[COND_FALSE]]:
// OGCG: store i32 2, ptr %[[DEST:.*]], align 4
// OGCG: br label %[[CLEANUP:.*]]
// OGCG: [[LPAD]]:
// OGCG: landingpad { ptr, i32 }
// OGCG-NEXT: cleanup
// OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// OGCG: br label %[[EHRESUME:.*]]
// OGCG: [[BODY]]:
// OGCG: store i32 2, ptr %[[DEST]], align 4
// OGCG: br label %[[CLEANUP]]
// OGCG: [[CLEANUP]]:
// OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// OGCG: br label %[[END:.*]]
// OGCG: [[END]]:
// OGCG: ret void
// OGCG: [[EHRESUME]]:
// OGCG: resume { ptr, i32 }
void for_cond_var_continue() {
for (; S s{};) {
continue;
}
}
// CIR-LABEL: cir.func {{.*}} @_Z21for_cond_var_continuev
// CIR: %[[FLAG:.*]] = cir.alloca {{.*}}"cond.cleanup.isactive"{{.*}} : !cir.ptr<!cir.bool>
// CIR: cir.scope {
// CIR: %[[S:.*]] = cir.alloca {{.*}}"s"{{.*}} : !cir.ptr<!rec_S>
// CIR: cir.for : cond {
// CIR: %[[FALSE:.*]] = cir.const #false
// CIR: cir.store %[[FALSE]], %[[FLAG]]
// CIR: cir.call @_ZN1SC1Ev(%[[S]])
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[FLAG]]
// CIR: %[[COND:.*]] = cir.call @_ZN1ScvbEv(%[[S]])
// CIR-NOT: cir.cleanup.scope
// CIR: cir.condition(%[[COND]])
// CIR: } body {
// CIR: cir.continue
// CIR: } step {
// CIR: } cleanup all {
// CIR: %[[ACTIVE:.*]] = cir.load {{.*}}%[[FLAG]]
// CIR: cir.if %[[ACTIVE]] {
// CIR: cir.call @_ZN1SD1Ev(%[[S]]) nothrow
// CIR: }
// CIR: cir.yield
// CIR: }
// LLVM-LABEL: define dso_local void @_Z21for_cond_var_continuev() {{.*}} personality ptr @__gxx_personality_v0 {
// LLVM: %[[S:.*]] = alloca %struct.S
// LLVM: %[[FLAG:.*]] = alloca i8
// LLVM: br label %{{.*}}
// LLVM: br label %[[COND:.*]]
// LLVM: [[COND]]:
// LLVM: br i1 true, label %{{.*}}, label %[[EXIT:.*]]
// LLVM: store i8 0, ptr %[[FLAG]]
// LLVM: invoke void @_ZN1SC1Ev(ptr {{.*}} %[[S]])
// LLVM-NEXT: to label %[[CTOR_CONT:.*]] unwind label %[[LPAD:.*]]
// LLVM: [[CTOR_CONT]]:
// LLVM: store i8 1, ptr %[[FLAG]]
// LLVM: %[[CALL:.*]] = invoke i1 @_ZN1ScvbEv(ptr {{.*}} %[[S]])
// LLVM-NEXT: to label %[[CVB_CONT:.*]] unwind label %[[LPAD]]
// LLVM: [[CVB_CONT]]:
// LLVM: br i1 %[[CALL]], label %[[BODY:.*]], label %[[COND_FALSE:.*]]
// LLVM: [[BODY]]:
// LLVM: br label %[[STEP:.*]]
// LLVM: [[STEP]]:
// LLVM: store i32 0, ptr %[[DEST:.*]], align 4
// LLVM: br label %[[CLEANUP:.*]]
// LLVM: [[COND_FALSE]]:
// LLVM: store i32 1, ptr %[[DEST]], align 4
// LLVM: br label %[[CLEANUP]]
// LLVM: [[CLEANUP]]:
// LLVM: %[[ACT:.*]] = load i8, ptr %[[FLAG]]
// LLVM: %[[ACTB:.*]] = trunc i8 %[[ACT]] to i1
// LLVM: br i1 %[[ACTB]], label %[[DTOR:.*]], label %{{.*}}
// LLVM: [[DTOR]]:
// LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// LLVM: %[[SEL:.*]] = load i32, ptr %[[DEST]], align 4
// LLVM: switch i32 %[[SEL]], label %{{.*}}
// LLVM: i32 0, label %[[CONTINUE:.*]]
// LLVM: i32 1, label %[[BREAK:.*]]
// LLVM: [[CONTINUE]]:
// LLVM: br label %[[BACKEDGE0:.*]]
// LLVM: [[BREAK]]:
// LLVM: br label %[[EXIT]]
// LLVM: [[LPAD]]:
// LLVM: landingpad { ptr, i32 }
// LLVM-NEXT: cleanup
// LLVM: %[[EACT:.*]] = load i8, ptr %[[FLAG]]
// LLVM: %[[EACTB:.*]] = trunc i8 %[[EACT]] to i1
// LLVM: br i1 %[[EACTB]], label %[[EHDTOR:.*]], label %{{.*}}
// LLVM: [[EHDTOR]]:
// LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// LLVM: resume { ptr, i32 }
// LLVM: [[BACKEDGE0]]:
// LLVM: br label %[[BACKEDGE1:.*]]
// LLVM: [[BACKEDGE1]]:
// LLVM: br label %[[COND]]
// OGCG-LABEL: define dso_local void @_Z21for_cond_var_continuev() {{.*}} personality ptr @__gxx_personality_v0 {
// OGCG: %[[S:.*]] = alloca %struct.S
// OGCG: br label %[[COND:.*]]
// OGCG: [[COND]]:
// OGCG: call void @_ZN1SC1Ev(ptr {{.*}} %[[S]])
// OGCG: %[[CALL:.*]] = invoke {{.*}} i1 @_ZN1ScvbEv(ptr {{.*}} %[[S]])
// OGCG-NEXT: to label %[[CONT:.*]] unwind label %[[LPAD:.*]]
// OGCG: [[CONT]]:
// OGCG: br i1 %[[CALL]], label %[[BODY:.*]], label %[[COND_FALSE:.*]]
// OGCG: [[COND_FALSE]]:
// OGCG: store i32 2, ptr %[[DEST:.*]], align 4
// OGCG: br label %[[CLEANUP:.*]]
// OGCG: [[LPAD]]:
// OGCG: landingpad { ptr, i32 }
// OGCG-NEXT: cleanup
// OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// OGCG: br label %[[EHRESUME:.*]]
// OGCG: [[BODY]]:
// OGCG: store i32 3, ptr %[[DEST]], align 4
// OGCG: br label %[[CLEANUP]]
// OGCG: [[CLEANUP]]:
// OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// OGCG: %[[SEL:.*]] = load i32, ptr %[[DEST]], align 4
// OGCG: switch i32 %[[SEL]], label %{{.*}}
// OGCG: i32 2, label %[[END:.*]]
// OGCG: i32 3, label %[[COND]]
// OGCG: [[END]]:
// OGCG: ret void
// OGCG: [[EHRESUME]]:
// OGCG: resume { ptr, i32 }
void for_cond_var(int n) {
for (int i = 0; S s{}; ++i)
--n;
}
// CIR-LABEL: cir.func {{.*}} @_Z12for_cond_vari
// CIR: %[[FLAG:.*]] = cir.alloca {{.*}}"cond.cleanup.isactive"{{.*}} : !cir.ptr<!cir.bool>
// CIR: cir.scope {
// CIR: %[[S:.*]] = cir.alloca {{.*}}"s"{{.*}} : !cir.ptr<!rec_S>
// CIR: cir.for : cond {
// The active flag is cleared before the initializer and set once the condition
// variable is constructed.
// CIR: %[[FALSE:.*]] = cir.const #false
// CIR: cir.store %[[FALSE]], %[[FLAG]]
// CIR: cir.call @_ZN1SC1Ev(%[[S]])
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[FLAG]]
// CIR: %[[COND:.*]] = cir.call @_ZN1ScvbEv(%[[S]])
// CIR-NOT: cir.cleanup.scope
// CIR: cir.condition(%[[COND]])
// CIR: } body {
// CIR: } step {
// The per-iteration destructor is guarded by the active flag.
// CIR: } cleanup all {
// CIR: %[[ACTIVE:.*]] = cir.load {{.*}}%[[FLAG]]
// CIR: cir.if %[[ACTIVE]] {
// CIR: cir.call @_ZN1SD1Ev(%[[S]]) nothrow
// CIR: }
// CIR: cir.yield
// CIR: }
// LLVM-LABEL: define dso_local void @_Z12for_cond_vari(i32 %0) {{.*}} personality ptr @__gxx_personality_v0 {
// LLVM: %[[S:.*]] = alloca %struct.S
// LLVM: %[[FLAG:.*]] = alloca i8
// LLVM: br label %{{.*}}
// LLVM: br label %[[COND:.*]]
// LLVM: [[COND]]:
// LLVM: br i1 true, label %{{.*}}, label %[[EXIT:.*]]
// LLVM: store i8 0, ptr %[[FLAG]]
// LLVM: invoke void @_ZN1SC1Ev(ptr {{.*}} %[[S]])
// LLVM-NEXT: to label %[[CTOR_CONT:.*]] unwind label %[[LPAD:.*]]
// LLVM: [[CTOR_CONT]]:
// LLVM: store i8 1, ptr %[[FLAG]]
// LLVM: %[[CALL:.*]] = invoke i1 @_ZN1ScvbEv(ptr {{.*}} %[[S]])
// LLVM-NEXT: to label %[[CVB_CONT:.*]] unwind label %[[LPAD]]
// LLVM: [[CVB_CONT]]:
// LLVM: br i1 %[[CALL]], label %[[BODY:.*]], label %[[COND_FALSE:.*]]
// LLVM: [[BODY]]:
// LLVM: br label %[[STEP:.*]]
// LLVM: [[STEP]]:
// LLVM: store i32 0, ptr %[[DEST:.*]], align 4
// LLVM: br label %[[CLEANUP:.*]]
// LLVM: [[COND_FALSE]]:
// LLVM: store i32 1, ptr %[[DEST]], align 4
// LLVM: br label %[[CLEANUP]]
// LLVM: [[CLEANUP]]:
// LLVM: %[[ACT:.*]] = load i8, ptr %[[FLAG]]
// LLVM: %[[ACTB:.*]] = trunc i8 %[[ACT]] to i1
// LLVM: br i1 %[[ACTB]], label %[[DTOR:.*]], label %{{.*}}
// LLVM: [[DTOR]]:
// LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// LLVM: %[[SEL:.*]] = load i32, ptr %[[DEST]], align 4
// LLVM: switch i32 %[[SEL]], label %{{.*}}
// LLVM: i32 0, label %[[CONTINUE:.*]]
// LLVM: i32 1, label %[[BREAK:.*]]
// LLVM: [[CONTINUE]]:
// LLVM: br label %[[BACKEDGE0:.*]]
// LLVM: [[BREAK]]:
// LLVM: br label %[[EXIT]]
// LLVM: [[LPAD]]:
// LLVM: landingpad { ptr, i32 }
// LLVM-NEXT: cleanup
// LLVM: %[[EACT:.*]] = load i8, ptr %[[FLAG]]
// LLVM: %[[EACTB:.*]] = trunc i8 %[[EACT]] to i1
// LLVM: br i1 %[[EACTB]], label %[[EHDTOR:.*]], label %{{.*}}
// LLVM: [[EHDTOR]]:
// LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// LLVM: resume { ptr, i32 }
// LLVM: [[BACKEDGE0]]:
// LLVM: br label %[[BACKEDGE1:.*]]
// LLVM: [[BACKEDGE1]]:
// LLVM: br label %[[COND]]
// OGCG-LABEL: define dso_local void @_Z12for_cond_vari(i32 %n) {{.*}} personality ptr @__gxx_personality_v0 {
// OGCG: %[[S:.*]] = alloca %struct.S
// OGCG: br label %[[COND:.*]]
// OGCG: [[COND]]:
// OGCG: call void @_ZN1SC1Ev(ptr {{.*}} %[[S]])
// OGCG: %[[CALL:.*]] = invoke {{.*}} i1 @_ZN1ScvbEv(ptr {{.*}} %[[S]])
// OGCG-NEXT: to label %[[CONT:.*]] unwind label %[[LPAD:.*]]
// OGCG: [[CONT]]:
// OGCG: br i1 %[[CALL]], label %[[BODY:.*]], label %[[COND_CLEANUP:.*]]
// The loop-exit edge sets the cleanup destination selector to the "break"
// value.
// OGCG: [[COND_CLEANUP]]:
// OGCG: store i32 2, ptr %[[DEST:.*]],
// OGCG: br label %[[CLEANUP:.*]]
// OGCG: [[LPAD]]:
// OGCG: landingpad { ptr, i32 }
// OGCG-NEXT: cleanup
// OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// OGCG: br label %[[EHRESUME:.*]]
// OGCG: [[BODY]]:
// OGCG: br label %[[STEP:.*]]
// OGCG: [[STEP]]:
// OGCG: store i32 0, ptr %[[DEST]]
// OGCG: br label %[[CLEANUP]]
// OGCG: [[CLEANUP]]:
// OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// OGCG: %[[SEL:.*]] = load i32, ptr %[[DEST]]
// OGCG: switch i32 %[[SEL]], label %{{.*}}
// OGCG: i32 0, label %[[CONTINUE:.*]]
// OGCG: i32 2, label %[[END:.*]]
// OGCG: [[CONTINUE]]:
// OGCG: br label %[[COND]]
// OGCG: [[END]]:
// OGCG: ret void
// OGCG: [[EHRESUME]]:
// OGCG: resume { ptr, i32 }
S chainS(const S &);
S makeS();
void while_cond_var_temp(int n) {
while (S s = chainS(makeS()))
--n;
}
// CIR-LABEL: cir.func {{.*}} @_Z19while_cond_var_tempi
// CIR: %[[FLAG:.*]] = cir.alloca {{.*}}"cond.cleanup.isactive"{{.*}} : !cir.ptr<!cir.bool>
// CIR: %[[S:.*]] = cir.alloca {{.*}}"s"{{.*}} : !cir.ptr<!rec_S>
// CIR: %[[TMP:.*]] = cir.alloca {{.*}}"ref.tmp0"{{.*}} : !cir.ptr<!rec_S>
// CIR: cir.while {
// CIR: %[[FALSE:.*]] = cir.const #false
// CIR: cir.store %[[FALSE]], %[[FLAG]]
// CIR: cir.call @_Z5makeSv() : () -> !rec_S
// CIR: cir.cleanup.scope {
// CIR: cir.call @_Z6chainSRK1S(%[[TMP]])
// CIR: } cleanup all {
// CIR: cir.call @_ZN1SD1Ev(%[[TMP]]) nothrow
// CIR: cir.yield
// CIR: }
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[FLAG]]
// CIR-NOT: cir.cleanup.scope
// CIR: %[[COND:.*]] = cir.call @_ZN1ScvbEv(%[[S]])
// CIR: cir.condition(%[[COND]])
// CIR: } do {
// CIR: } cleanup all {
// CIR: %[[ACTIVE:.*]] = cir.load {{.*}}%[[FLAG]]
// CIR: cir.if %[[ACTIVE]] {
// CIR: cir.call @_ZN1SD1Ev(%[[S]]) nothrow
// CIR: }
// CIR: cir.yield
// CIR: }
// LLVM-LABEL: define dso_local void @_Z19while_cond_var_tempi(i32 %0) {{.*}} personality ptr @__gxx_personality_v0 {
// LLVM: %[[S:.*]] = alloca %struct.S
// LLVM: %[[TMP:.*]] = alloca %struct.S
// LLVM: %[[FLAG:.*]] = alloca i8
// LLVM: br label %{{.*}}
// LLVM: br label %[[COND:.*]]
// LLVM: [[COND]]:
// LLVM: br i1 true, label %{{.*}}, label %[[EXIT:.*]]
// LLVM: store i8 0, ptr %[[FLAG]], align 1
// LLVM: %[[MK:.*]] = invoke %struct.S @_Z5makeSv()
// LLVM-NEXT: to label %[[MK_CONT:.*]] unwind label %[[LPAD_OUTER:.*]]
// LLVM: [[MK_CONT]]:
// LLVM: store %struct.S %[[MK]], ptr %[[TMP]], align 1
// LLVM: %[[CH:.*]] = invoke %struct.S @_Z6chainSRK1S(ptr {{.*}} %[[TMP]])
// LLVM-NEXT: to label %[[CH_CONT:.*]] unwind label %[[LPAD_TMP:.*]]
// LLVM: [[CH_CONT]]:
// LLVM: store %struct.S %[[CH]], ptr %[[S]], align 1
// LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[TMP]])
// LLVM: [[LPAD_TMP]]:
// LLVM: landingpad { ptr, i32 }
// LLVM-NEXT: cleanup
// LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[TMP]])
// LLVM: br label %[[EHCOMMON:.*]]
// LLVM: store i8 1, ptr %[[FLAG]], align 1
// LLVM: %[[CALL:.*]] = invoke i1 @_ZN1ScvbEv(ptr {{.*}} %[[S]])
// LLVM-NEXT: to label %[[CVB_CONT:.*]] unwind label %[[LPAD_OUTER]]
// LLVM: [[CVB_CONT]]:
// LLVM: br i1 %[[CALL]], label %[[BODY:.*]], label %[[COND_FALSE:.*]]
// LLVM: [[BODY]]:
// LLVM: store i32 0, ptr %[[DEST:.*]], align 4
// LLVM: br label %[[CLEANUP:.*]]
// LLVM: [[COND_FALSE]]:
// LLVM: store i32 1, ptr %[[DEST]], align 4
// LLVM: br label %[[CLEANUP]]
// LLVM: [[CLEANUP]]:
// LLVM: %[[ACT:.*]] = load i8, ptr %[[FLAG]]
// LLVM: %[[ACTB:.*]] = trunc i8 %[[ACT]] to i1
// LLVM: br i1 %[[ACTB]], label %[[DTOR:.*]], label %{{.*}}
// LLVM: [[DTOR]]:
// LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// LLVM: %[[SEL:.*]] = load i32, ptr %[[DEST]], align 4
// LLVM: switch i32 %[[SEL]], label %{{.*}}
// LLVM: i32 0, label %[[CONTINUE:.*]]
// LLVM: i32 1, label %[[BREAK:.*]]
// LLVM: [[CONTINUE]]:
// LLVM: br label %[[BACKEDGE:.*]]
// LLVM: [[BREAK]]:
// LLVM: br label %[[EXIT]]
// LLVM: [[LPAD_OUTER]]:
// LLVM: landingpad { ptr, i32 }
// LLVM-NEXT: cleanup
// LLVM: br label %[[EHCOMMON]]
// LLVM: [[EHCOMMON]]:
// LLVM: %[[EACT:.*]] = load i8, ptr %[[FLAG]]
// LLVM: %[[EACTB:.*]] = trunc i8 %[[EACT]] to i1
// LLVM: br i1 %[[EACTB]], label %[[EHDTOR:.*]], label %{{.*}}
// LLVM: [[EHDTOR]]:
// LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// LLVM: resume { ptr, i32 }
// LLVM: [[BACKEDGE]]:
// LLVM: br label %[[COND]]
// OGCG-LABEL: define dso_local void @_Z19while_cond_var_tempi(i32 %n) {{.*}} personality ptr @__gxx_personality_v0 {
// OGCG: %[[S:.*]] = alloca %struct.S
// OGCG: %[[TMP:.*]] = alloca %struct.S
// OGCG: br label %[[COND:.*]]
// OGCG: [[COND]]:
// OGCG: call void @_Z5makeSv(ptr {{.*}} sret(%struct.S) {{.*}} %[[TMP]])
// OGCG: invoke void @_Z6chainSRK1S(ptr {{.*}} sret(%struct.S) {{.*}} %[[S]], ptr {{.*}} %[[TMP]])
// OGCG-NEXT: to label %[[CONT:.*]] unwind label %[[LPAD_TMP:.*]]
// OGCG: [[CONT]]:
// OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[TMP]])
// OGCG: %[[CALL:.*]] = invoke {{.*}} i1 @_ZN1ScvbEv(ptr {{.*}} %[[S]])
// OGCG-NEXT: to label %[[CONT2:.*]] unwind label %[[LPAD_S:.*]]
// OGCG: [[CONT2]]:
// OGCG: br i1 %[[CALL]], label %[[BODY:.*]], label %[[EXIT:.*]]
// OGCG: [[EXIT]]:
// OGCG: store i32 3, ptr %[[DEST:.*]], align 4
// OGCG: br label %[[CLEANUP:.*]]
// OGCG: [[LPAD_TMP]]:
// OGCG: landingpad { ptr, i32 }
// OGCG-NEXT: cleanup
// OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[TMP]])
// OGCG: br label %[[EHRESUME:.*]]
// OGCG: [[LPAD_S]]:
// OGCG: landingpad { ptr, i32 }
// OGCG-NEXT: cleanup
// OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// OGCG: br label %[[EHRESUME]]
// OGCG: [[BODY]]:
// OGCG: store i32 0, ptr %[[DEST]], align 4
// OGCG: br label %[[CLEANUP]]
// OGCG: [[CLEANUP]]:
// OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// OGCG: %[[SEL:.*]] = load i32, ptr %[[DEST]], align 4
// OGCG: switch i32 %[[SEL]], label %{{.*}}
// OGCG: i32 0, label %[[CONTINUE:.*]]
// OGCG: i32 3, label %[[END:.*]]
// OGCG: [[CONTINUE]]:
// OGCG: br label %[[COND]]
// OGCG: [[END]]:
// OGCG: ret void
// OGCG: [[EHRESUME]]:
// OGCG: resume { ptr, i32 }
void while_cond_var_nested(int n) {
while (S s = ({
while (S t{}) {
S bodyVar;
(void)bodyVar;
}
S{};
}))
--n;
}
// CIR-LABEL: cir.func {{.*}} @_Z21while_cond_var_nestedi
// Each loop's condition variable gets its own active flag.
// CIR: %[[FLAG_OUTER:.*]] = cir.alloca {{.*}}"cond.cleanup.isactive"{{.*}} : !cir.ptr<!cir.bool>
// CIR: %[[FLAG_INNER:.*]] = cir.alloca {{.*}}"cond.cleanup.isactive"{{.*}} : !cir.ptr<!cir.bool>
// CIR: %[[S:.*]] = cir.alloca {{.*}}"s"{{.*}} : !cir.ptr<!rec_S>
// CIR: cir.while {
// CIR: cir.store %{{.*}}, %[[FLAG_OUTER]]
// CIR: %[[T:.*]] = cir.alloca {{.*}}"t"{{.*}} : !cir.ptr<!rec_S>
// CIR: cir.while {
// CIR: cir.store %{{.*}}, %[[FLAG_INNER]]
// CIR: cir.call @_ZN1SC1Ev(%[[T]])
// CIR: cir.store %{{.*}}, %[[FLAG_INNER]]
// CIR: %[[TCOND:.*]] = cir.call @_ZN1ScvbEv(%[[T]])
// CIR: cir.condition(%[[TCOND]])
// CIR: } do {
// CIR: %[[BV:.*]] = cir.alloca {{.*}}"bodyVar"{{.*}} : !cir.ptr<!rec_S>
// CIR: cir.call @_ZN1SC1Ev(%[[BV]])
// CIR: cir.cleanup.scope {
// CIR: } cleanup all {
// CIR: cir.call @_ZN1SD1Ev(%[[BV]]) nothrow
// CIR: cir.yield
// CIR: }
// CIR: } cleanup all {
// CIR: %[[IACT:.*]] = cir.load {{.*}}%[[FLAG_INNER]]
// CIR: cir.if %[[IACT]] {
// CIR: cir.call @_ZN1SD1Ev(%[[T]]) nothrow
// CIR: }
// CIR: cir.yield
// CIR: }
// CIR: cir.call @_ZN1SC1Ev(%[[S]])
// CIR: cir.store %{{.*}}, %[[FLAG_OUTER]]
// CIR: %[[SCOND:.*]] = cir.call @_ZN1ScvbEv(%[[S]])
// CIR: cir.condition(%[[SCOND]])
// CIR: } do {
// CIR: } cleanup all {
// CIR: %[[OACT:.*]] = cir.load {{.*}}%[[FLAG_OUTER]]
// CIR: cir.if %[[OACT]] {
// CIR: cir.call @_ZN1SD1Ev(%[[S]]) nothrow
// CIR: }
// CIR: cir.yield
// CIR: }
// LLVM-LABEL: define dso_local void @_Z21while_cond_var_nestedi(i32 %0) {{.*}} personality ptr @__gxx_personality_v0 {
// LLVM: %[[S:.*]] = alloca %struct.S
// LLVM: %[[FLAG_OUTER:.*]] = alloca i8
// LLVM: %[[FLAG_INNER:.*]] = alloca i8
// LLVM: br label %{{.*}}
// LLVM: br label %[[OUTER_COND:.*]]
// LLVM: [[OUTER_COND]]:
// LLVM: br i1 true, label %{{.*}}, label %[[OUTER_EXIT:.*]]
// LLVM: store i8 0, ptr %[[FLAG_OUTER]], align 1
// LLVM: br label %{{.*}}
// LLVM: br label %{{.*}}
// LLVM: br label %[[INNER_COND:.*]]
// LLVM: [[INNER_COND]]:
// LLVM: br i1 true, label %{{.*}}, label %[[INNER_EXIT:.*]]
// LLVM: store i8 0, ptr %[[FLAG_INNER]], align 1
// LLVM: invoke void @_ZN1SC1Ev(ptr {{.*}} %[[T:.*]])
// LLVM-NEXT: to label %[[ICTOR_CONT:.*]] unwind label %[[INNER_LPAD:.*]]
// LLVM: [[ICTOR_CONT]]:
// LLVM: store i8 1, ptr %[[FLAG_INNER]], align 1
// LLVM: %[[TCALL:.*]] = invoke i1 @_ZN1ScvbEv(ptr {{.*}} %[[T]])
// LLVM-NEXT: to label %[[TCVB_CONT:.*]] unwind label %[[INNER_LPAD]]
// LLVM: [[TCVB_CONT]]:
// LLVM: br i1 %[[TCALL]], label %[[IBODY:.*]], label %[[ICOND_FALSE:.*]]
// LLVM: [[IBODY]]:
// LLVM: invoke void @_ZN1SC1Ev(ptr {{.*}} %[[BV:.*]])
// LLVM-NEXT: to label %[[BV_CONT:.*]] unwind label %[[INNER_LPAD]]
// LLVM: [[BV_CONT]]:
// LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[BV]])
// LLVM: store i32 0, ptr %[[DEST:.*]], align 4
// LLVM: br label %[[ICLEANUP:.*]]
// LLVM: [[ICOND_FALSE]]:
// LLVM: store i32 1, ptr %[[DEST]], align 4
// LLVM: br label %[[ICLEANUP]]
// LLVM: [[ICLEANUP]]:
// LLVM: %[[IACT:.*]] = load i8, ptr %[[FLAG_INNER]]
// LLVM: %[[IACTB:.*]] = trunc i8 %[[IACT]] to i1
// LLVM: br i1 %[[IACTB]], label %[[IDTOR:.*]], label %{{.*}}
// LLVM: [[IDTOR]]:
// LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[T]])
// LLVM: %[[ISEL:.*]] = load i32, ptr %[[DEST]], align 4
// LLVM: switch i32 %[[ISEL]], label %{{.*}}
// LLVM: i32 0, label %[[ICONTINUE:.*]]
// LLVM: i32 1, label %[[IBREAK:.*]]
// LLVM: [[ICONTINUE]]:
// LLVM: br label %[[IBACKEDGE:.*]]
// LLVM: [[IBREAK]]:
// LLVM: br label %[[INNER_EXIT]]
// LLVM: [[INNER_LPAD]]:
// LLVM: landingpad { ptr, i32 }
// LLVM-NEXT: cleanup
// LLVM: %[[EIACT:.*]] = load i8, ptr %[[FLAG_INNER]]
// LLVM: %[[EIACTB:.*]] = trunc i8 %[[EIACT]] to i1
// LLVM: br i1 %[[EIACTB]], label %[[EIDTOR:.*]], label %{{.*}}
// LLVM: [[EIDTOR]]:
// LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[T]])
// LLVM: br label %{{.*}}
// LLVM: br label %[[OUTER_EH:.*]]
// LLVM: [[IBACKEDGE]]:
// LLVM: br label %[[INNER_COND]]
// LLVM: [[INNER_EXIT]]:
// LLVM: invoke void @_ZN1SC1Ev(ptr {{.*}} %[[S]])
// LLVM-NEXT: to label %[[OCTOR_CONT:.*]] unwind label %[[OUTER_LPAD:.*]]
// LLVM: [[OCTOR_CONT]]:
// LLVM: store i8 1, ptr %[[FLAG_OUTER]], align 1
// LLVM: %[[SCALL:.*]] = invoke i1 @_ZN1ScvbEv(ptr {{.*}} %[[S]])
// LLVM-NEXT: to label %[[SCVB_CONT:.*]] unwind label %[[OUTER_LPAD]]
// LLVM: [[SCVB_CONT]]:
// LLVM: br i1 %[[SCALL]], label %[[OBODY:.*]], label %[[OCOND_FALSE:.*]]
// LLVM: [[OBODY]]:
// LLVM: store i32 0, ptr %[[DEST]], align 4
// LLVM: br label %[[OCLEANUP:.*]]
// LLVM: [[OCOND_FALSE]]:
// LLVM: store i32 1, ptr %[[DEST]], align 4
// LLVM: br label %[[OCLEANUP]]
// LLVM: [[OCLEANUP]]:
// LLVM: %[[OACT:.*]] = load i8, ptr %[[FLAG_OUTER]]
// LLVM: %[[OACTB:.*]] = trunc i8 %[[OACT]] to i1
// LLVM: br i1 %[[OACTB]], label %[[ODTOR:.*]], label %{{.*}}
// LLVM: [[ODTOR]]:
// LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// LLVM: %[[OSEL:.*]] = load i32, ptr %[[DEST]], align 4
// LLVM: switch i32 %[[OSEL]], label %{{.*}}
// LLVM: i32 0, label %[[OCONTINUE:.*]]
// LLVM: i32 1, label %[[OBREAK:.*]]
// LLVM: [[OCONTINUE]]:
// LLVM: br label %[[OBACKEDGE:.*]]
// LLVM: [[OBREAK]]:
// LLVM: br label %[[OUTER_EXIT]]
// LLVM: [[OUTER_LPAD]]:
// LLVM: landingpad { ptr, i32 }
// LLVM-NEXT: cleanup
// LLVM: br label %[[OUTER_EH]]
// LLVM: [[OUTER_EH]]:
// LLVM: %[[EOACT:.*]] = load i8, ptr %[[FLAG_OUTER]]
// LLVM: %[[EOACTB:.*]] = trunc i8 %[[EOACT]] to i1
// LLVM: br i1 %[[EOACTB]], label %[[EODTOR:.*]], label %{{.*}}
// LLVM: [[EODTOR]]:
// LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// LLVM: resume { ptr, i32 }
// LLVM: [[OBACKEDGE]]:
// LLVM: br label %[[OUTER_COND]]
// OGCG-LABEL: define dso_local void @_Z21while_cond_var_nestedi(i32 %n) {{.*}} personality ptr @__gxx_personality_v0 {
// OGCG: %[[S:.*]] = alloca %struct.S
// OGCG: %[[T:.*]] = alloca %struct.S
// OGCG: %[[BV:.*]] = alloca %struct.S
// OGCG: br label %[[OUTER_COND:.*]]
// OGCG: [[OUTER_COND]]:
// OGCG: br label %[[INNER_COND:.*]]
// OGCG: [[INNER_COND]]:
// OGCG: call void @_ZN1SC1Ev(ptr {{.*}} %[[T]])
// OGCG: %[[TCALL:.*]] = invoke {{.*}} i1 @_ZN1ScvbEv(ptr {{.*}} %[[T]])
// OGCG-NEXT: to label %[[ICONT:.*]] unwind label %[[INNER_LPAD:.*]]
// OGCG: [[ICONT]]:
// OGCG: br i1 %[[TCALL]], label %[[IBODY:.*]], label %[[INNER_EXIT:.*]]
// OGCG: [[INNER_EXIT]]:
// OGCG: store i32 5, ptr %[[DEST:.*]], align 4
// OGCG: br label %[[ICLEANUP:.*]]
// OGCG: [[INNER_LPAD]]:
// OGCG: landingpad { ptr, i32 }
// OGCG-NEXT: cleanup
// OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[T]])
// OGCG: br label %[[EHRESUME:.*]]
// OGCG: [[IBODY]]:
// OGCG: invoke void @_ZN1SC1Ev(ptr {{.*}} %[[BV]])
// OGCG-NEXT: to label %[[IBODY_CONT:.*]] unwind label %[[INNER_LPAD]]
// OGCG: [[IBODY_CONT]]:
// OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[BV]])
// OGCG: store i32 0, ptr %[[DEST]], align 4
// OGCG: br label %[[ICLEANUP]]
// OGCG: [[ICLEANUP]]:
// OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[T]])
// OGCG: %[[ISEL:.*]] = load i32, ptr %[[DEST]], align 4
// OGCG: switch i32 %[[ISEL]], label %{{.*}}
// OGCG: i32 0, label %[[ICONTINUE:.*]]
// OGCG: i32 5, label %[[INNER_END:.*]]
// OGCG: [[ICONTINUE]]:
// OGCG: br label %[[INNER_COND]]
// OGCG: [[INNER_END]]:
// OGCG: call void @_ZN1SC1Ev(ptr {{.*}} %[[S]])
// OGCG: %[[SCALL:.*]] = invoke {{.*}} i1 @_ZN1ScvbEv(ptr {{.*}} %[[S]])
// OGCG-NEXT: to label %[[OCONT:.*]] unwind label %[[OUTER_LPAD:.*]]
// OGCG: [[OCONT]]:
// OGCG: br i1 %[[SCALL]], label %[[OBODY:.*]], label %[[OUTER_EXIT:.*]]
// OGCG: [[OUTER_EXIT]]:
// OGCG: store i32 3, ptr %[[DEST]], align 4
// OGCG: br label %[[OCLEANUP:.*]]
// OGCG: [[OUTER_LPAD]]:
// OGCG: landingpad { ptr, i32 }
// OGCG-NEXT: cleanup
// OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// OGCG: br label %[[EHRESUME]]
// OGCG: [[OBODY]]:
// OGCG: store i32 0, ptr %[[DEST]], align 4
// OGCG: br label %[[OCLEANUP]]
// OGCG: [[OCLEANUP]]:
// OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[S]])
// OGCG: %[[OSEL:.*]] = load i32, ptr %[[DEST]], align 4
// OGCG: switch i32 %[[OSEL]], label %{{.*}}
// OGCG: i32 0, label %[[OCONTINUE:.*]]
// OGCG: i32 3, label %[[OUTER_END:.*]]
// OGCG: [[OCONTINUE]]:
// OGCG: br label %[[OUTER_COND]]
// OGCG: [[OUTER_END]]:
// OGCG: ret void
// OGCG: [[EHRESUME]]:
// OGCG: resume { ptr, i32 }