Use the DataLayout-aware TargetFolder instead of ConstantFolder in Clang's CGBuilder. The primary impact of this change is that GEP constant expressions are now emitted in canonical `getelementptr i8` form. This is in preparation for the migration to ptradd, which requires this form. Part of the test updates were performed by Claude Code and reviewed by me.
222 lines
7.5 KiB
C++
222 lines
7.5 KiB
C++
// 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 nuw (i8, ptr @_ZL1a, i64 40), 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 nuw (i8, ptr @_ZL1a, i64 40), 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>();
|