If a loop required a cleanup scope in the condition or step region of the loop, we crashed during CFG flattening because the flattening of the cleanup scope created multiple blocks in the region, but we were assuming there would only be one block. This change updates the CFG flattening code to look for the cir.condition or cir.yield operation in the last block of the region.
244 lines
7.6 KiB
C++
244 lines
7.6 KiB
C++
// 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
|