// 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(); operator bool(); }; S makeS(); void while_cond_cleanup(int n) { while (makeS()) --n; } // CIR-LABEL: cir.func {{.*}} @_Z18while_cond_cleanupi // CIR: cir.while { // CIR: cir.call @_Z5makeSv() // CIR: cir.cleanup.scope { // CIR: cir.call @_ZN1ScvbEv( // CIR: } cleanup all { // CIR: cir.call @_ZN1SD1Ev({{.*}}) nothrow // CIR: } // CIR: cir.condition( // CIR: } do { // LLVM-LABEL: define dso_local void @_Z18while_cond_cleanupi(i32 %0) {{.*}} personality ptr @__gxx_personality_v0 { // LLVM: %[[TMP:.*]] = alloca %struct.S // LLVM: call %struct.S @_Z5makeSv() // LLVM: invoke i1 @_ZN1ScvbEv(ptr {{.*}} %[[TMP]]) // LLVM: to label %[[CONT:.*]] unwind label %[[UNWIND:.*]] // LLVM: [[CONT]]: // LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[TMP]]) // LLVM: [[UNWIND]]: // LLVM: landingpad { ptr, i32 } // LLVM: cleanup // LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[TMP]]) // LLVM: resume { ptr, i32 } // LLVM: br i1 // LLVM: ret void // OGCG-LABEL: define dso_local void @_Z18while_cond_cleanupi(i32 %n) {{.*}} personality ptr @__gxx_personality_v0 { // OGCG: while.cond: // OGCG: %[[CALL:.*]] = invoke {{.*}} i1 @_ZN1ScvbEv( // OGCG: to label %[[CONT:.*]] unwind label %[[LPAD:.*]] // OGCG: [[CONT]]: // OGCG: call void @_ZN1SD1Ev( // OGCG: br i1 %[[CALL]], label %[[BODY:.*]], label %[[END:.*]] // OGCG: [[BODY]]: // OGCG: br label %while.cond // OGCG: [[LPAD]]: // OGCG: landingpad { ptr, i32 } // OGCG: cleanup // OGCG: call void @_ZN1SD1Ev( // OGCG: [[END]]: // OGCG: ret void void do_while_cond_cleanup(int n) { do { --n; } while (makeS()); } // CIR-LABEL: cir.func {{.*}} @_Z21do_while_cond_cleanupi // CIR: cir.do { // CIR: cir.yield // CIR: } while { // CIR: cir.call @_Z5makeSv() // CIR: cir.cleanup.scope { // CIR: cir.call @_ZN1ScvbEv( // CIR: } cleanup all { // CIR: cir.call @_ZN1SD1Ev({{.*}}) nothrow // CIR: } // CIR: cir.condition( // LLVM-LABEL: define dso_local void @_Z21do_while_cond_cleanupi(i32 %0) {{.*}} personality ptr @__gxx_personality_v0 { // LLVM: %[[TMP:.*]] = alloca %struct.S // LLVM: call %struct.S @_Z5makeSv() // LLVM: invoke i1 @_ZN1ScvbEv(ptr {{.*}} %[[TMP]]) // LLVM: to label %[[CONT:.*]] unwind label %[[UNWIND:.*]] // LLVM: [[CONT]]: // LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[TMP]]) // LLVM: [[UNWIND]]: // LLVM: landingpad { ptr, i32 } // LLVM: cleanup // LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[TMP]]) // LLVM: resume { ptr, i32 } // LLVM: br i1 // LLVM: ret void // OGCG-LABEL: define dso_local void @_Z21do_while_cond_cleanupi(i32 %n) {{.*}} personality ptr @__gxx_personality_v0 { // OGCG: do.cond: // OGCG: %[[CALL:.*]] = invoke {{.*}} i1 @_ZN1ScvbEv( // OGCG: to label %[[CONT:.*]] unwind label %[[LPAD:.*]] // OGCG: [[CONT]]: // OGCG: call void @_ZN1SD1Ev( // OGCG: br i1 %[[CALL]] // OGCG: ret void // OGCG: [[LPAD]]: // OGCG: landingpad { ptr, i32 } // OGCG: cleanup // OGCG: call void @_ZN1SD1Ev( void for_cond_cleanup(int n) { for (int i = 0; makeS(); ++i) --n; } // CIR-LABEL: cir.func {{.*}} @_Z16for_cond_cleanupi // CIR: cir.for : cond { // CIR: cir.call @_Z5makeSv() // CIR: cir.cleanup.scope { // CIR: cir.call @_ZN1ScvbEv( // CIR: } cleanup all { // CIR: cir.call @_ZN1SD1Ev({{.*}}) nothrow // CIR: } // CIR: cir.condition( // CIR: } body { // LLVM-LABEL: define dso_local void @_Z16for_cond_cleanupi(i32 %0) {{.*}} personality ptr @__gxx_personality_v0 { // LLVM: %[[TMP:.*]] = alloca %struct.S // LLVM: call %struct.S @_Z5makeSv() // LLVM: invoke i1 @_ZN1ScvbEv(ptr {{.*}} %[[TMP]]) // LLVM: to label %[[CONT:.*]] unwind label %[[UNWIND:.*]] // LLVM: [[CONT]]: // LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[TMP]]) // LLVM: [[UNWIND]]: // LLVM: landingpad { ptr, i32 } // LLVM: cleanup // LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[TMP]]) // LLVM: resume { ptr, i32 } // LLVM: br i1 // LLVM: ret void // OGCG-LABEL: define dso_local void @_Z16for_cond_cleanupi(i32 %n) {{.*}} personality ptr @__gxx_personality_v0 { // OGCG: for.cond: // OGCG: %[[CALL:.*]] = invoke {{.*}} i1 @_ZN1ScvbEv( // OGCG: to label %[[CONT:.*]] unwind label %[[LPAD:.*]] // OGCG: [[CONT]]: // OGCG: call void @_ZN1SD1Ev( // OGCG: br i1 %[[CALL]], label %[[BODY:.*]], label %[[END:.*]] // OGCG: [[LPAD]]: // OGCG: landingpad { ptr, i32 } // OGCG: cleanup // OGCG: call void @_ZN1SD1Ev( // OGCG: [[END]]: // OGCG: ret void void for_step_cleanup(int n) { for (int i = 0; i < n; (void)makeS()) --n; } // CIR-LABEL: cir.func {{.*}} @_Z16for_step_cleanupi // CIR: cir.for : cond { // CIR: } body { // CIR: } step { // CIR: cir.call @_Z5makeSv() // CIR: cir.cleanup.scope { // CIR: } cleanup all { // CIR: cir.call @_ZN1SD1Ev({{.*}}) nothrow // CIR: } // CIR: } // LLVM-LABEL: define dso_local void @_Z16for_step_cleanupi(i32 %0) {{.*}} { // LLVM: %[[TMP:.*]] = alloca %struct.S // LLVM: call %struct.S @_Z5makeSv() // LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[TMP]]) // LLVM: br label // LLVM: ret void // OGCG-LABEL: define dso_local void @_Z16for_step_cleanupi(i32 %n) {{.*}} { // OGCG: for.inc: // OGCG: call void @_Z5makeSv( // OGCG: call void @_ZN1SD1Ev( // OGCG: br label %for.cond struct EndSentinel {}; struct Iter { int operator*(); Iter &operator++(); }; S operator!=(Iter, EndSentinel); struct Range { Iter begin(); EndSentinel end(); }; Range getRange(); void range_for_cond_cleanup() { for (int x : getRange()) { (void)x; } } // CIR-LABEL: cir.func {{.*}} @_Z22range_for_cond_cleanupv // CIR: cir.for : cond { // CIR: cir.call @_Zne4Iter11EndSentinel( // CIR: cir.cleanup.scope { // CIR: cir.call @_ZN1ScvbEv( // CIR: } cleanup all { // CIR: cir.call @_ZN1SD1Ev({{.*}}) nothrow // CIR: } // CIR: cir.condition( // CIR: } body { // LLVM-LABEL: define dso_local void @_Z22range_for_cond_cleanupv() {{.*}} personality ptr @__gxx_personality_v0 { // LLVM: %[[TMP:.*]] = alloca %struct.S // LLVM: call %struct.S @_Zne4Iter11EndSentinel( // LLVM: invoke i1 @_ZN1ScvbEv(ptr {{.*}} %[[TMP]]) // LLVM: to label %[[CONT:.*]] unwind label %[[UNWIND:.*]] // LLVM: [[CONT]]: // LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[TMP]]) // LLVM: [[UNWIND]]: // LLVM: landingpad { ptr, i32 } // LLVM: cleanup // LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[TMP]]) // LLVM: resume { ptr, i32 } // LLVM: br i1 // LLVM: ret void // OGCG-LABEL: define dso_local void @_Z22range_for_cond_cleanupv() {{.*}} personality ptr @__gxx_personality_v0 { // OGCG: for.cond: // OGCG: %[[CALL:.*]] = invoke {{.*}} i1 @_ZN1ScvbEv( // OGCG: to label %[[CONT:.*]] unwind label %[[LPAD:.*]] // OGCG: [[CONT]]: // OGCG: call void @_ZN1SD1Ev( // OGCG: br i1 %[[CALL]], label %[[BODY:.*]], label %[[END:.*]] // OGCG: [[LPAD]]: // OGCG: landingpad { ptr, i32 } // OGCG: cleanup // OGCG: call void @_ZN1SD1Ev( // OGCG: [[END]]: // OGCG: ret void void while_body_temp_ref() { while (0) const S &op = 1 ? S() : S(); } // CIR-LABEL: cir.func {{.*}} @_Z19while_body_temp_refv // CIR: cir.scope { // CIR: cir.while { // CIR: } do { // CIR: cir.if // CIR: cir.cleanup.scope { // CIR: } cleanup eh { // CIR: cir.call @_ZN1SD1Ev({{.*}}) nothrow // CIR: } // CIR: cir.cleanup.scope { // CIR: } cleanup all { // CIR: cir.call @_ZN1SD1Ev({{.*}}) nothrow // CIR: } // CIR: } // CIR: } // CIR: cir.return // LLVM-LABEL: define dso_local void @_Z19while_body_temp_refv() // LLVM: %[[REF_TMP:.*]] = alloca %struct.S // LLVM: %[[OP:.*]] = alloca ptr // LLVM: %[[SPILL:.*]] = alloca ptr // LLVM: br label %{{.*}} // LLVM: br label %[[LOOP_COND:.*]] // LLVM: [[LOOP_COND]]: // LLVM: br i1 false, label %[[BODY:.*]], label %[[AFTER:.*]] // LLVM: [[BODY]]: // LLVM: br i1 true, label %[[TRUE:.*]], label %[[FALSE:.*]] // LLVM: [[TRUE]]: // LLVM: call void @_ZN1SC1Ev(ptr {{.*}} %[[REF_TMP]]) // LLVM: [[FALSE]]: // LLVM: call void @_ZN1SC1Ev(ptr {{.*}} %[[REF_TMP]]) // LLVM: store ptr %[[REF_TMP]], ptr %[[SPILL]] // LLVM: %[[RELOAD:.*]] = load ptr, ptr %[[SPILL]] // LLVM: store ptr %[[RELOAD]], ptr %[[OP]] // LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[REF_TMP]]) // LLVM: br label %[[LOOP_COND]] // LLVM: [[AFTER]]: // LLVM: ret void // OGCG-LABEL: define dso_local void @_Z19while_body_temp_refv() // OGCG: %[[OP:.*]] = alloca ptr // OGCG: %[[REF_TMP:.*]] = alloca %struct.S // OGCG: br label %[[WHILE_COND:.*]] // OGCG: [[WHILE_COND]]: // OGCG: br i1 false, label %[[WHILE_BODY:.*]], label %[[WHILE_END:.*]] // OGCG: [[WHILE_BODY]]: // OGCG: br i1 true, label %[[COND_TRUE:.*]], label %[[COND_FALSE:.*]] // OGCG: [[COND_TRUE]]: // OGCG: call void @_ZN1SC1Ev(ptr {{.*}} %[[REF_TMP]]) // OGCG: [[COND_FALSE]]: // OGCG: call void @_ZN1SC1Ev(ptr {{.*}} %[[REF_TMP]]) // OGCG: store ptr %[[REF_TMP]], ptr %[[OP]] // OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[REF_TMP]]) // OGCG: br label %[[WHILE_COND]] // OGCG: [[WHILE_END]]: // OGCG: ret void void for_body_temp_ref() { for (int i = 0; i < 0; ++i) const S &op = 1 ? S() : S(); } // CIR-LABEL: cir.func {{.*}} @_Z17for_body_temp_refv // CIR: cir.scope { // CIR: cir.for : cond { // CIR: } body { // CIR: cir.if // CIR: cir.cleanup.scope { // CIR: } cleanup eh { // CIR: cir.call @_ZN1SD1Ev({{.*}}) nothrow // CIR: } // CIR: cir.cleanup.scope { // CIR: } cleanup all { // CIR: cir.call @_ZN1SD1Ev({{.*}}) nothrow // CIR: } // CIR: } step { // CIR: } // CIR: } // CIR: cir.return // LLVM-LABEL: define dso_local void @_Z17for_body_temp_refv() // LLVM: %[[I:.*]] = alloca i32 // LLVM: %[[REF_TMP:.*]] = alloca %struct.S // LLVM: %[[OP:.*]] = alloca ptr // LLVM: %[[SPILL:.*]] = alloca ptr // LLVM: br label %{{.*}} // LLVM: store i32 0, ptr %[[I]] // LLVM: br label %[[LOOP_COND:.*]] // LLVM: [[LOOP_COND]]: // LLVM: %[[IVAL:.*]] = load i32, ptr %[[I]] // LLVM: %[[CMP:.*]] = icmp slt i32 %[[IVAL]], 0 // LLVM: br i1 %[[CMP]], label %[[BODY:.*]], label %[[AFTER:.*]] // LLVM: [[BODY]]: // LLVM: br i1 true, label %[[TRUE:.*]], label %[[FALSE:.*]] // LLVM: [[TRUE]]: // LLVM: call void @_ZN1SC1Ev(ptr {{.*}} %[[REF_TMP]]) // LLVM: [[FALSE]]: // LLVM: call void @_ZN1SC1Ev(ptr {{.*}} %[[REF_TMP]]) // LLVM: store ptr %[[REF_TMP]], ptr %[[SPILL]] // LLVM: %[[RELOAD:.*]] = load ptr, ptr %[[SPILL]] // LLVM: store ptr %[[RELOAD]], ptr %[[OP]] // LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[REF_TMP]]) // LLVM: %[[OLDI:.*]] = load i32, ptr %[[I]] // LLVM: %[[NEWI:.*]] = add nsw i32 %[[OLDI]], 1 // LLVM: store i32 %[[NEWI]], ptr %[[I]] // LLVM: br label %[[LOOP_COND]] // LLVM: [[AFTER]]: // LLVM: ret void // OGCG-LABEL: define dso_local void @_Z17for_body_temp_refv() // OGCG: %[[I:.*]] = alloca i32 // OGCG: %[[OP:.*]] = alloca ptr // OGCG: %[[REF_TMP:.*]] = alloca %struct.S // OGCG: store i32 0, ptr %[[I]] // OGCG: br label %[[FOR_COND:.*]] // OGCG: [[FOR_COND]]: // OGCG: %[[IVAL:.*]] = load i32, ptr %[[I]] // OGCG: %[[CMP:.*]] = icmp slt i32 %[[IVAL]], 0 // OGCG: br i1 %[[CMP]], label %[[FOR_BODY:.*]], label %[[FOR_END:.*]] // OGCG: [[FOR_BODY]]: // OGCG: br i1 true, label %[[COND_TRUE:.*]], label %[[COND_FALSE:.*]] // OGCG: [[COND_TRUE]]: // OGCG: call void @_ZN1SC1Ev(ptr {{.*}} %[[REF_TMP]]) // OGCG: [[COND_FALSE]]: // OGCG: call void @_ZN1SC1Ev(ptr {{.*}} %[[REF_TMP]]) // OGCG: store ptr %[[REF_TMP]], ptr %[[OP]] // OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[REF_TMP]]) // OGCG: br label %[[FOR_INC:.*]] // OGCG: [[FOR_INC]]: // OGCG: %[[OLDI:.*]] = load i32, ptr %[[I]] // OGCG: %[[NEWI:.*]] = add nsw i32 %[[OLDI]], 1 // OGCG: store i32 %[[NEWI]], ptr %[[I]] // OGCG: br label %[[FOR_COND]] // OGCG: [[FOR_END]]: // OGCG: ret void void do_body_temp_ref() { do const S &op = 1 ? S() : S(); while (0); } // CIR-LABEL: cir.func {{.*}} @_Z16do_body_temp_refv // CIR: cir.scope { // CIR: cir.do { // CIR: cir.if // CIR: cir.cleanup.scope { // CIR: } cleanup eh { // CIR: cir.call @_ZN1SD1Ev({{.*}}) nothrow // CIR: } // CIR: cir.cleanup.scope { // CIR: } cleanup all { // CIR: cir.call @_ZN1SD1Ev({{.*}}) nothrow // CIR: } // CIR: } while { // CIR: } // CIR: } // CIR: cir.return // LLVM-LABEL: define dso_local void @_Z16do_body_temp_refv() // LLVM: %[[REF_TMP:.*]] = alloca %struct.S // LLVM: %[[OP:.*]] = alloca ptr // LLVM: %[[SPILL:.*]] = alloca ptr // LLVM: br label %{{.*}} // LLVM: br label %[[BODY:.*]] // LLVM: [[LOOP_COND:.*]]: // LLVM: br i1 false, label %[[BODY]], label %[[AFTER:.*]] // LLVM: [[BODY]]: // LLVM: br i1 true, label %[[TRUE:.*]], label %[[FALSE:.*]] // LLVM: [[TRUE]]: // LLVM: call void @_ZN1SC1Ev(ptr {{.*}} %[[REF_TMP]]) // LLVM: [[FALSE]]: // LLVM: call void @_ZN1SC1Ev(ptr {{.*}} %[[REF_TMP]]) // LLVM: store ptr %[[REF_TMP]], ptr %[[SPILL]] // LLVM: %[[RELOAD:.*]] = load ptr, ptr %[[SPILL]] // LLVM: store ptr %[[RELOAD]], ptr %[[OP]] // LLVM: call void @_ZN1SD1Ev(ptr {{.*}} %[[REF_TMP]]) // LLVM: br label %[[LOOP_COND]] // LLVM: [[AFTER]]: // LLVM: ret void // OGCG-LABEL: define dso_local void @_Z16do_body_temp_refv() // OGCG: %[[OP:.*]] = alloca ptr // OGCG: %[[REF_TMP:.*]] = alloca %struct.S // OGCG: br label %[[DO_BODY:.*]] // OGCG: [[DO_BODY]]: // OGCG: br i1 true, label %[[COND_TRUE:.*]], label %[[COND_FALSE:.*]] // OGCG: [[COND_TRUE]]: // OGCG: call void @_ZN1SC1Ev(ptr {{.*}} %[[REF_TMP]]) // OGCG: [[COND_FALSE]]: // OGCG: call void @_ZN1SC1Ev(ptr {{.*}} %[[REF_TMP]]) // OGCG: store ptr %[[REF_TMP]], ptr %[[OP]] // OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[REF_TMP]]) // OGCG: br label %[[DO_END:.*]] // OGCG: [[DO_END]]: // OGCG: ret void