blob: 4bdb5369aa8f130d641ceae81bcf47db9e715930 [file] [log] [blame] [edit]
// RUN: %clang_cc1 -fnamed-loops -triple x86_64-unknown-linux -std=c++20 -emit-llvm -o - %s | FileCheck %s
static int a[10]{};
struct NonTrivialDestructor {
~NonTrivialDestructor();
};
bool g(int);
bool h();
// CHECK-LABEL: define {{.*}} void @_Z2f1v()
// CHECK: entry:
// CHECK: %__range1 = alloca ptr, align 8
// CHECK: %__begin1 = alloca ptr, align 8
// CHECK: %__end1 = alloca ptr, align 8
// CHECK: %i = alloca i32, align 4
// CHECK: br label %x
// CHECK: x:
// CHECK: store ptr @_ZL1a, ptr %__range1, align 8
// CHECK: store ptr @_ZL1a, ptr %__begin1, align 8
// CHECK: store ptr getelementptr inbounds (i32, ptr @_ZL1a, i64 10), ptr %__end1, align 8
// CHECK: br label %for.cond
// CHECK: for.cond:
// CHECK: %0 = load ptr, ptr %__begin1, align 8
// CHECK: %1 = load ptr, ptr %__end1, align 8
// CHECK: %cmp = icmp ne ptr %0, %1
// CHECK: br i1 %cmp, label %for.body, label %for.end
// CHECK: for.body:
// CHECK: %2 = load ptr, ptr %__begin1, align 8
// CHECK: %3 = load i32, ptr %2, align 4
// CHECK: store i32 %3, ptr %i, align 4
// CHECK: %4 = load i32, ptr %i, align 4
// CHECK: %call = call {{.*}} i1 @_Z1gi(i32 {{.*}} %4)
// CHECK: br i1 %call, label %if.then, label %if.end
// CHECK: if.then:
// CHECK: br label %for.end
// CHECK: if.end:
// CHECK: %5 = load i32, ptr %i, align 4
// CHECK: %call1 = call {{.*}} i1 @_Z1gi(i32 {{.*}} %5)
// CHECK: br i1 %call1, label %if.then2, label %if.end3
// CHECK: if.then2:
// CHECK: br label %for.inc
// CHECK: if.end3:
// CHECK: br label %for.inc
// CHECK: for.inc:
// CHECK: %6 = load ptr, ptr %__begin1, align 8
// CHECK: %incdec.ptr = getelementptr inbounds nuw i32, ptr %6, i32 1
// CHECK: store ptr %incdec.ptr, ptr %__begin1, align 8
// CHECK: br label %for.cond
// CHECK: for.end:
// CHECK: ret void
void f1() {
x: for (int i : a) {
if (g(i)) break x;
if (g(i)) continue x;
}
}
// CHECK-LABEL: define {{.*}} void @_Z2f2v()
// CHECK: entry:
// CHECK: %n1 = alloca %struct.NonTrivialDestructor, align 1
// CHECK: %__range2 = alloca ptr, align 8
// CHECK: %__begin2 = alloca ptr, align 8
// CHECK: %__end2 = alloca ptr, align 8
// CHECK: %i = alloca i32, align 4
// CHECK: %n2 = alloca %struct.NonTrivialDestructor, align 1
// CHECK: %cleanup.dest.slot = alloca i32, align 4
// CHECK: %n3 = alloca %struct.NonTrivialDestructor, align 1
// CHECK: %n4 = alloca %struct.NonTrivialDestructor, align 1
// CHECK: br label %l1
// CHECK: l1:
// CHECK: br label %while.cond
// CHECK: while.cond:
// CHECK: %call = call {{.*}} i1 @_Z1gi(i32 {{.*}} 0)
// CHECK: br i1 %call, label %while.body, label %while.end
// CHECK: while.body:
// CHECK: br label %l2
// CHECK: l2:
// CHECK: store ptr @_ZL1a, ptr %__range2, align 8
// CHECK: store ptr @_ZL1a, ptr %__begin2, align 8
// CHECK: store ptr getelementptr inbounds (i32, ptr @_ZL1a, i64 10), ptr %__end2, align 8
// CHECK: br label %for.cond
// CHECK: for.cond:
// CHECK: %0 = load ptr, ptr %__begin2, align 8
// CHECK: %1 = load ptr, ptr %__end2, align 8
// CHECK: %cmp = icmp ne ptr %0, %1
// CHECK: br i1 %cmp, label %for.body, label %for.end
// CHECK: for.body:
// CHECK: %2 = load ptr, ptr %__begin2, align 8
// CHECK: %3 = load i32, ptr %2, align 4
// CHECK: store i32 %3, ptr %i, align 4
// CHECK: %4 = load i32, ptr %i, align 4
// CHECK: %call1 = call {{.*}} i1 @_Z1gi(i32 {{.*}} %4)
// CHECK: br i1 %call1, label %if.then, label %if.end
// CHECK: if.then:
// CHECK: store i32 4, ptr %cleanup.dest.slot, align 4
// CHECK: br label %cleanup
// CHECK: if.end:
// CHECK: %5 = load i32, ptr %i, align 4
// CHECK: %call2 = call {{.*}} i1 @_Z1gi(i32 {{.*}} %5)
// CHECK: br i1 %call2, label %if.then3, label %if.end4
// CHECK: if.then3:
// CHECK: store i32 3, ptr %cleanup.dest.slot, align 4
// CHECK: br label %cleanup
// CHECK: if.end4:
// CHECK: %6 = load i32, ptr %i, align 4
// CHECK: %call5 = call {{.*}} i1 @_Z1gi(i32 {{.*}} %6)
// CHECK: br i1 %call5, label %if.then6, label %if.end7
// CHECK: if.then6:
// CHECK: store i32 6, ptr %cleanup.dest.slot, align 4
// CHECK: br label %cleanup
// CHECK: if.end7:
// CHECK: %7 = load i32, ptr %i, align 4
// CHECK: %call8 = call {{.*}} i1 @_Z1gi(i32 {{.*}} %7)
// CHECK: br i1 %call8, label %if.then9, label %if.end10
// CHECK: if.then9:
// CHECK: store i32 7, ptr %cleanup.dest.slot, align 4
// CHECK: br label %cleanup
// CHECK: if.end10:
// CHECK: call void @_ZN20NonTrivialDestructorD1Ev(ptr {{.*}} %n3)
// CHECK: store i32 0, ptr %cleanup.dest.slot, align 4
// CHECK: br label %cleanup
// CHECK: cleanup:
// CHECK: call void @_ZN20NonTrivialDestructorD1Ev(ptr {{.*}} %n2)
// CHECK: %cleanup.dest = load i32, ptr %cleanup.dest.slot, align 4
// CHECK: switch i32 %cleanup.dest, label %cleanup11 [
// CHECK: i32 0, label %cleanup.cont
// CHECK: i32 6, label %for.end
// CHECK: i32 7, label %for.inc
// CHECK: ]
// CHECK: cleanup.cont:
// CHECK: br label %for.inc
// CHECK: for.inc:
// CHECK: %8 = load ptr, ptr %__begin2, align 8
// CHECK: %incdec.ptr = getelementptr inbounds nuw i32, ptr %8, i32 1
// CHECK: store ptr %incdec.ptr, ptr %__begin2, align 8
// CHECK: br label %for.cond
// CHECK: for.end:
// CHECK: call void @_ZN20NonTrivialDestructorD1Ev(ptr {{.*}} %n4)
// CHECK: store i32 0, ptr %cleanup.dest.slot, align 4
// CHECK: br label %cleanup11
// CHECK: cleanup11:
// CHECK: call void @_ZN20NonTrivialDestructorD1Ev(ptr {{.*}} %n1)
// CHECK: %cleanup.dest12 = load i32, ptr %cleanup.dest.slot, align 4
// CHECK: switch i32 %cleanup.dest12, label %unreachable [
// CHECK: i32 0, label %cleanup.cont13
// CHECK: i32 4, label %while.end
// CHECK: i32 3, label %while.cond
// CHECK: ]
// CHECK: cleanup.cont13:
// CHECK: br label %while.cond
// CHECK: while.end:
// CHECK: ret void
// CHECK: unreachable:
// CHECK: unreachable
void f2() {
l1: while (g(0)) {
NonTrivialDestructor n1;
l2: for (int i : a) {
NonTrivialDestructor n2;
if (g(i)) break l1;
if (g(i)) continue l1;
if (g(i)) break l2;
if (g(i)) continue l2;
NonTrivialDestructor n3;
}
NonTrivialDestructor n4;
}
}
template <bool Continue>
void f3() {
l1: while (g(1)) {
for (;g(2);) {
if constexpr (Continue) continue l1;
else break l1;
}
}
}
// CHECK-LABEL: define {{.*}} void @_Z2f3ILb1EEvv()
// CHECK: entry:
// CHECK: br label %l1
// CHECK: l1:
// CHECK: br label %while.cond
// CHECK: while.cond:
// CHECK: %call = call {{.*}} i1 @_Z1gi(i32 {{.*}} 1)
// CHECK: br i1 %call, label %while.body, label %while.end
// CHECK: while.body:
// CHECK: br label %for.cond
// CHECK: for.cond:
// CHECK: %call1 = call {{.*}} i1 @_Z1gi(i32 {{.*}} 2)
// CHECK: br i1 %call1, label %for.body, label %for.end
// CHECK: for.body:
// CHECK: br label %while.cond
// CHECK: for.end:
// CHECK: br label %while.cond
// CHECK: while.end:
// CHECK: ret void
template void f3<true>();
// CHECK-LABEL: define {{.*}} void @_Z2f3ILb0EEvv()
// CHECK: entry:
// CHECK: br label %l1
// CHECK: l1:
// CHECK: br label %while.cond
// CHECK: while.cond:
// CHECK: %call = call {{.*}} i1 @_Z1gi(i32 {{.*}} 1)
// CHECK: br i1 %call, label %while.body, label %while.end
// CHECK: while.body:
// CHECK: br label %for.cond
// CHECK: for.cond:
// CHECK: %call1 = call {{.*}} i1 @_Z1gi(i32 {{.*}} 2)
// CHECK: br i1 %call1, label %for.body, label %for.end
// CHECK: for.body:
// CHECK: br label %while.end
// CHECK: for.end:
// CHECK: br label %while.cond
// CHECK: while.end:
// CHECK: ret void
template void f3<false>();