Andy Kaylor 1e45ea12db
[CIR] Add support for function linkage and visibility (#145600)
This change adds support for function linkage and visibility and related
attributes. Most of the test changes are generalizations to allow
'dso_local' to be accepted where we aren't specifically testing for it.
Some tests based on CIR inputs have been updated to add 'private' to
function declarations where required by newly supported interfaces.

The dso-local.c test has been updated to add specific tests for
dso_local being set correctly, and a new test, func-linkage.cpp tests
other linkage settings.

This change sets `comdat` correctly in CIR, but it is not yet applied to
functions when lowering to LLVM IR. That will be handled in a later
change.
2025-06-25 10:59:30 -07:00

634 lines
22 KiB
C++

// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
void l0() {
for (;;) {
}
}
// CIR: cir.func{{.*}} @_Z2l0v
// CIR: cir.scope {
// CIR: cir.for : cond {
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.condition(%[[TRUE]])
// CIR: } body {
// CIR: cir.yield
// CIR: } step {
// CIR: cir.yield
// CIR: }
// CIR: }
// CIR: cir.return
// CIR: }
// LLVM: define{{.*}} void @_Z2l0v()
// LLVM: br label %[[LABEL1:.*]]
// LLVM: [[LABEL1]]:
// LLVM: br label %[[LABEL2:.*]]
// LLVM: [[LABEL2]]:
// LLVM: br i1 true, label %[[LABEL3:.*]], label %[[LABEL5:.*]]
// LLVM: [[LABEL3]]:
// LLVM: br label %[[LABEL4:.*]]
// LLVM: [[LABEL4]]:
// LLVM: br label %[[LABEL2]]
// LLVM: [[LABEL5]]:
// LLVM: br label %[[LABEL6:.*]]
// LLVM: [[LABEL6]]:
// LLVM: ret void
// OGCG: define{{.*}} void @_Z2l0v()
// OGCG: entry:
// OGCG: br label %[[FOR_COND:.*]]
// OGCG: [[FOR_COND]]:
// OGCG: br label %[[FOR_COND]]
void l1() {
for (int i = 0; ; ) {
}
}
// CIR: cir.func{{.*}} @_Z2l1v
// CIR-NEXT: cir.scope {
// CIR-NEXT: %[[I:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["i", init] {alignment = 4 : i64}
// CIR-NEXT: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
// CIR-NEXT: cir.store{{.*}} %[[ZERO]], %[[I]] : !s32i, !cir.ptr<!s32i>
// CIR-NEXT: cir.for : cond {
// CIR-NEXT: %[[TRUE:.*]] = cir.const #true
// CIR-NEXT: cir.condition(%[[TRUE]])
// CIR-NEXT: } body {
// CIR-NEXT: cir.yield
// CIR-NEXT: } step {
// CIR-NEXT: cir.yield
// CIR-NEXT: }
// CIR-NEXT: }
// CIR-NEXT: cir.return
// CIR-NEXT: }
// LLVM: define{{.*}} void @_Z2l1v()
// LLVM: %[[I:.*]] = alloca i32, i64 1, align 4
// LLVM: br label %[[LABEL1:.*]]
// LLVM: [[LABEL1]]:
// LLVM: store i32 0, ptr %[[I]], align 4
// LLVM: br label %[[LABEL2:.*]]
// LLVM: [[LABEL2]]:
// LLVM: br i1 true, label %[[LABEL3:.*]], label %[[LABEL5:.*]]
// LLVM: [[LABEL3]]:
// LLVM: br label %[[LABEL4:.*]]
// LLVM: [[LABEL4]]:
// LLVM: br label %[[LABEL2]]
// LLVM: [[LABEL5]]:
// LLVM: br label %[[LABEL6:.*]]
// LLVM: [[LABEL6]]:
// LLVM: ret void
// OGCG: define{{.*}} void @_Z2l1v()
// OGCG: entry:
// OGCG: %[[I:.*]] = alloca i32, align 4
// OGCG: store i32 0, ptr %[[I]], align 4
// OGCG: br label %[[FOR_COND:.*]]
// OGCG: [[FOR_COND]]:
// OGCG: br label %[[FOR_COND]]
void l2() {
for (;;) {
int i = 0;
}
}
// CIR: cir.func{{.*}} @_Z2l2v
// CIR-NEXT: cir.scope {
// CIR-NEXT: cir.for : cond {
// CIR-NEXT: %[[TRUE:.*]] = cir.const #true
// CIR-NEXT: cir.condition(%[[TRUE]])
// CIR-NEXT: } body {
// CIR-NEXT: cir.scope {
// CIR-NEXT: %[[I:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["i", init] {alignment = 4 : i64}
// CIR-NEXT: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
// CIR-NEXT: cir.store{{.*}} %[[ZERO]], %[[I]] : !s32i, !cir.ptr<!s32i>
// CIR-NEXT: }
// CIR-NEXT: cir.yield
// CIR-NEXT: } step {
// CIR-NEXT: cir.yield
// CIR-NEXT: }
// CIR-NEXT: }
// CIR-NEXT: cir.return
// CIR-NEXT: }
// LLVM: define{{.*}} void @_Z2l2v()
// LLVM: %[[I:.*]] = alloca i32, i64 1, align 4
// LLVM: br label %[[LABEL1:.*]]
// LLVM: [[LABEL1]]:
// LLVM: br label %[[LABEL2:.*]]
// LLVM: [[LABEL2]]:
// LLVM: br i1 true, label %[[LABEL3:.*]], label %[[LABEL5:.*]]
// LLVM: [[LABEL3]]:
// LLVM: store i32 0, ptr %[[I]], align 4
// LLVM: br label %[[LABEL4:.*]]
// LLVM: [[LABEL4]]:
// LLVM: br label %[[LABEL2]]
// LLVM: [[LABEL5]]:
// LLVM: br label %[[LABEL6:.*]]
// LLVM: [[LABEL6]]:
// LLVM: ret void
// OGCG: define{{.*}} void @_Z2l2v()
// OGCG: entry:
// OGCG: %[[I:.*]] = alloca i32, align 4
// OGCG: br label %[[FOR_COND:.*]]
// OGCG: [[FOR_COND]]:
// OGCG: store i32 0, ptr %[[I]], align 4
// OGCG: br label %[[FOR_COND]]
// This is the same as l2 but without a compound statement for the body.
void l3() {
for (;;)
int i = 0;
}
// CIR: cir.func{{.*}} @_Z2l3v
// CIR-NEXT: cir.scope {
// CIR-NEXT: %[[I:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["i", init] {alignment = 4 : i64}
// CIR-NEXT: cir.for : cond {
// CIR-NEXT: %[[TRUE:.*]] = cir.const #true
// CIR-NEXT: cir.condition(%[[TRUE]])
// CIR-NEXT: } body {
// CIR-NEXT: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
// CIR-NEXT: cir.store{{.*}} %[[ZERO]], %[[I]] : !s32i, !cir.ptr<!s32i>
// CIR-NEXT: cir.yield
// CIR-NEXT: } step {
// CIR-NEXT: cir.yield
// CIR-NEXT: }
// CIR-NEXT: }
// CIR-NEXT: cir.return
// CIR-NEXT: }
// LLVM: define{{.*}} void @_Z2l3v()
// LLVM: %[[I:.*]] = alloca i32, i64 1, align 4
// LLVM: br label %[[LABEL1:.*]]
// LLVM: [[LABEL1]]:
// LLVM: br label %[[LABEL2:.*]]
// LLVM: [[LABEL2]]:
// LLVM: br i1 true, label %[[LABEL3:.*]], label %[[LABEL5:.*]]
// LLVM: [[LABEL3]]:
// LLVM: store i32 0, ptr %[[I]], align 4
// LLVM: br label %[[LABEL4:.*]]
// LLVM: [[LABEL4]]:
// LLVM: br label %[[LABEL2]]
// LLVM: [[LABEL5]]:
// LLVM: br label %[[LABEL6:.*]]
// LLVM: [[LABEL6]]:
// LLVM: ret void
// OGCG: define{{.*}} void @_Z2l3v()
// OGCG: entry:
// OGCG: %[[I:.*]] = alloca i32, align 4
// OGCG: br label %[[FOR_COND:.*]]
// OGCG: [[FOR_COND]]:
// OGCG: store i32 0, ptr %[[I]], align 4
// OGCG: br label %[[FOR_COND]]
void l4() {
int a[10];
for (int n : a)
;
}
// CIR: cir.func{{.*}} @_Z2l4v
// CIR: %[[A_ADDR:.*]] = cir.alloca {{.*}} ["a"]
// CIR: cir.scope {
// CIR: %[[RANGE_ADDR:.*]] = cir.alloca {{.*}} ["__range1", init, const]
// CIR: %[[BEGIN_ADDR:.*]] = cir.alloca {{.*}} ["__begin1", init]
// CIR: %[[END_ADDR:.*]] = cir.alloca {{.*}} ["__end1", init]
// CIR: %[[N_ADDR:.*]] = cir.alloca {{.*}} ["n", init]
// CIR: cir.store{{.*}} %[[A_ADDR]], %[[RANGE_ADDR]]
// CIR: %[[RANGE_LOAD:.*]] = cir.load{{.*}} %[[RANGE_ADDR]]
// CIR: %[[RANGE_CAST:.*]] = cir.cast(array_to_ptrdecay, %[[RANGE_LOAD]] : {{.*}})
// CIR: cir.store{{.*}} %[[RANGE_CAST]], %[[BEGIN_ADDR]]
// CIR: %[[BEGIN:.*]] = cir.load{{.*}} %[[RANGE_ADDR]]
// CIR: %[[BEGIN_CAST:.*]] = cir.cast(array_to_ptrdecay, %[[BEGIN]] : {{.*}})
// CIR: %[[TEN:.*]] = cir.const #cir.int<10>
// CIR: %[[END_PTR:.*]] = cir.ptr_stride(%[[BEGIN_CAST]] : {{.*}}, %[[TEN]] : {{.*}})
// CIR: cir.store{{.*}} %[[END_PTR]], %[[END_ADDR]]
// CIR: cir.for : cond {
// CIR: %[[CUR:.*]] = cir.load{{.*}} %[[BEGIN_ADDR]]
// CIR: %[[END:.*]] = cir.load{{.*}} %[[END_ADDR]]
// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[CUR]], %[[END]])
// CIR: cir.condition(%[[CMP]])
// CIR: } body {
// CIR: %[[CUR:.*]] = cir.load deref{{.*}} %[[BEGIN_ADDR]]
// CIR: %[[N:.*]] = cir.load{{.*}} %[[CUR]]
// CIR: cir.store{{.*}} %[[N]], %[[N_ADDR]]
// CIR: cir.yield
// CIR: } step {
// CIR: %[[CUR:.*]] = cir.load{{.*}} %[[BEGIN_ADDR]]
// CIR: %[[ONE:.*]] = cir.const #cir.int<1>
// CIR: %[[NEXT:.*]] = cir.ptr_stride(%[[CUR]] : {{.*}}, %[[ONE]] : {{.*}})
// CIR: cir.store{{.*}} %[[NEXT]], %[[BEGIN_ADDR]]
// CIR: cir.yield
// CIR: }
// CIR: }
// LLVM: define{{.*}} void @_Z2l4v() {
// LLVM: %[[RANGE_ADDR:.*]] = alloca ptr
// LLVM: %[[BEGIN_ADDR:.*]] = alloca ptr
// LLVM: %[[END_ADDR:.*]] = alloca ptr
// LLVM: %[[N_ADDR:.*]] = alloca i32
// LLVM: %[[A_ADDR:.*]] = alloca [10 x i32]
// LLVM: br label %[[SETUP:.*]]
// LLVM: [[SETUP]]:
// LLVM: store ptr %[[A_ADDR]], ptr %[[RANGE_ADDR]]
// LLVM: %[[BEGIN:.*]] = load ptr, ptr %[[RANGE_ADDR]]
// LLVM: %[[BEGIN_CAST:.*]] = getelementptr i32, ptr %[[BEGIN]], i32 0
// LLVM: store ptr %[[BEGIN_CAST]], ptr %[[BEGIN_ADDR]]
// LLVM: %[[RANGE:.*]] = load ptr, ptr %[[RANGE_ADDR]]
// LLVM: %[[RANGE_CAST:.*]] = getelementptr i32, ptr %[[RANGE]], i32 0
// LLVM: %[[END_PTR:.*]] = getelementptr i32, ptr %[[RANGE_CAST]], i64 10
// LLVM: store ptr %[[END_PTR]], ptr %[[END_ADDR]]
// LLVM: br label %[[COND:.*]]
// LLVM: [[COND]]:
// LLVM: %[[BEGIN:.*]] = load ptr, ptr %[[BEGIN_ADDR]]
// LLVM: %[[END:.*]] = load ptr, ptr %[[END_ADDR]]
// LLVM: %[[CMP:.*]] = icmp ne ptr %[[BEGIN]], %[[END]]
// LLVM: br i1 %[[CMP]], label %[[BODY:.*]], label %[[END:.*]]
// LLVM: [[BODY]]:
// LLVM: %[[CUR:.*]] = load ptr, ptr %[[BEGIN_ADDR]]
// LLVM: %[[A_CUR:.*]] = load i32, ptr %[[CUR]]
// LLVM: store i32 %[[A_CUR]], ptr %[[N_ADDR]]
// LLVM: br label %[[STEP:.*]]
// LLVM: [[STEP]]:
// LLVM: %[[BEGIN:.*]] = load ptr, ptr %[[BEGIN_ADDR]]
// LLVM: %[[NEXT:.*]] = getelementptr i32, ptr %[[BEGIN]], i64 1
// LLVM: store ptr %[[NEXT]], ptr %[[BEGIN_ADDR]]
// LLVM: br label %[[COND]]
// LLVM: [[END]]:
// LLVM: br label %[[EXIT:.*]]
// LLVM: [[EXIT]]:
// LLVM: ret void
// OGCG: define{{.*}} void @_Z2l4v()
// OGCG: %[[A_ADDR:.*]] = alloca [10 x i32]
// OGCG: %[[RANGE_ADDR:.*]] = alloca ptr
// OGCG: %[[BEGIN_ADDR:.*]] = alloca ptr
// OGCG: %[[END_ADDR:.*]] = alloca ptr
// OGCG: %[[N_ADDR:.*]] = alloca i32
// OGCG: store ptr %[[A_ADDR]], ptr %[[RANGE_ADDR]]
// OGCG: %[[BEGIN:.*]] = load ptr, ptr %[[RANGE_ADDR]]
// OGCG: %[[BEGIN_CAST:.*]] = getelementptr inbounds [10 x i32], ptr %[[BEGIN]], i64 0, i64 0
// OGCG: store ptr %[[BEGIN_CAST]], ptr %[[BEGIN_ADDR]]
// OGCG: %[[RANGE:.*]] = load ptr, ptr %[[RANGE_ADDR]]
// OGCG: %[[RANGE_CAST:.*]] = getelementptr inbounds [10 x i32], ptr %[[RANGE]], i64 0, i64 0
// OGCG: %[[END_PTR:.*]] = getelementptr inbounds i32, ptr %[[RANGE_CAST]], i64 10
// OGCG: store ptr %[[END_PTR]], ptr %[[END_ADDR]]
// OGCG: br label %[[COND:.*]]
// OGCG: [[COND]]:
// OGCG: %[[BEGIN:.*]] = load ptr, ptr %[[BEGIN_ADDR]]
// OGCG: %[[END:.*]] = load ptr, ptr %[[END_ADDR]]
// OGCG: %[[CMP:.*]] = icmp ne ptr %[[BEGIN]], %[[END]]
// OGCG: br i1 %[[CMP]], label %[[BODY:.*]], label %[[END:.*]]
// OGCG: [[BODY]]:
// OGCG: %[[CUR:.*]] = load ptr, ptr %[[BEGIN_ADDR]]
// OGCG: %[[A_CUR:.*]] = load i32, ptr %[[CUR]]
// OGCG: store i32 %[[A_CUR]], ptr %[[N_ADDR]]
// OGCG: br label %[[STEP:.*]]
// OGCG: [[STEP]]:
// OGCG: %[[BEGIN:.*]] = load ptr, ptr %[[BEGIN_ADDR]]
// OGCG: %[[NEXT:.*]] = getelementptr inbounds nuw i32, ptr %[[BEGIN]], i32 1
// OGCG: store ptr %[[NEXT]], ptr %[[BEGIN_ADDR]]
// OGCG: br label %[[COND]]
// OGCG: [[END]]:
// OGCG: ret void
void l5() {
for (int arr[]{1,2,3,4}; auto x : arr) {}
}
// CIR: cir.func{{.*}} @_Z2l5v
// CIR: cir.scope {
// CIR: %[[ARR_ADDR:.*]] = cir.alloca {{.*}} ["arr", init]
// CIR: %[[RANGE_ADDR:.*]] = cir.alloca {{.*}} ["__range1", init, const]
// CIR: %[[BEGIN_ADDR:.*]] = cir.alloca {{.*}} ["__begin1", init]
// CIR: %[[END_ADDR:.*]] = cir.alloca {{.*}} ["__end1", init]
// CIR: %[[X_ADDR:.*]] = cir.alloca {{.*}} ["x", init]
// CIR: %[[ARR_CAST:.*]] = cir.cast(array_to_ptrdecay, %[[ARR_ADDR]] : {{.*}})
// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s32i
// CIR: cir.store{{.*}} %[[ONE]], %[[ARR_CAST]]
// CIR: %[[OFFSET1:.*]] = cir.const #cir.int<1> : !s64i
// CIR: %[[STRIDE:.*]] = cir.ptr_stride(%[[ARR_CAST]] : {{.*}}, %[[OFFSET1]] : {{.*}})
// CIR: %[[TWO:.*]] = cir.const #cir.int<2> : !s32i
// CIR: cir.store{{.*}} %[[TWO]], %[[STRIDE]]
// CIR: %[[OFFSET2:.*]] = cir.const #cir.int<2> : !s64i
// CIR: %[[STRIDE2:.*]] = cir.ptr_stride(%[[ARR_CAST]] : {{.*}}, %[[OFFSET2]] : {{.*}})
// CIR: %[[THREE:.*]] = cir.const #cir.int<3> : !s32i
// CIR: cir.store{{.*}} %[[THREE]], %[[STRIDE2]]
// CIR: %[[OFFSET3:.*]] = cir.const #cir.int<3> : !s64i
// CIR: %[[STRIDE3:.*]] = cir.ptr_stride(%[[ARR_CAST]] : {{.*}}, %[[OFFSET3]] : {{.*}})
// CIR: %[[FOUR:.*]] = cir.const #cir.int<4> : !s32i
// CIR: cir.store{{.*}} %[[FOUR]], %[[STRIDE3]]
// CIR: cir.store{{.*}} %[[ARR_ADDR]], %[[RANGE_ADDR]]
// CIR: %[[RANGE_LOAD:.*]] = cir.load{{.*}} %[[RANGE_ADDR]]
// CIR: %[[RANGE_CAST:.*]] = cir.cast(array_to_ptrdecay, %[[RANGE_LOAD]] : {{.*}})
// CIR: cir.store{{.*}} %[[RANGE_CAST]], %[[BEGIN_ADDR]]
// CIR: %[[BEGIN:.*]] = cir.load{{.*}} %[[RANGE_ADDR]]
// CIR: %[[BEGIN_CAST:.*]] = cir.cast(array_to_ptrdecay, %[[BEGIN]] : {{.*}})
// CIR: %[[FOUR:.*]] = cir.const #cir.int<4> : !s64i
// CIR: %[[END_PTR:.*]] = cir.ptr_stride(%[[BEGIN_CAST]] : {{.*}}, %[[FOUR]] : {{.*}})
// CIR: cir.store{{.*}} %[[END_PTR]], %[[END_ADDR]]
// CIR: cir.for : cond {
// CIR: %[[CUR:.*]] = cir.load{{.*}} %[[BEGIN_ADDR]]
// CIR: %[[END:.*]] = cir.load{{.*}} %[[END_ADDR]]
// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[CUR]], %[[END]])
// CIR: cir.condition(%[[CMP]])
// CIR: } body {
// CIR: %[[CUR:.*]] = cir.load deref{{.*}} %[[BEGIN_ADDR]]
// CIR: %[[X:.*]] = cir.load{{.*}} %[[CUR]]
// CIR: cir.store{{.*}} %[[X]], %[[X_ADDR]]
// CIR: cir.yield
// CIR: } step {
// CIR: %[[CUR:.*]] = cir.load{{.*}} %[[BEGIN_ADDR]]
// CIR: %[[ONE:.*]] = cir.const #cir.int<1>
// CIR: %[[NEXT:.*]] = cir.ptr_stride(%[[CUR]] : {{.*}}, %[[ONE]] : {{.*}})
// CIR: cir.store{{.*}} %[[NEXT]], %[[BEGIN_ADDR]]
// CIR: cir.yield
// CIR: }
// CIR: }
// LLVM: define{{.*}} void @_Z2l5v() {
// LLVM: %[[ARR_ADDR:.*]] = alloca [4 x i32]
// LLVM: %[[RANGE_ADDR:.*]] = alloca ptr
// LLVM: %[[BEGIN_ADDR:.*]] = alloca ptr
// LLVM: %[[END_ADDR:.*]] = alloca ptr
// LLVM: %[[X_ADDR:.*]] = alloca i32
// LLVM: br label %[[SETUP:.*]]
// LLVM: [[SETUP]]:
// LLVM: %[[ARR_0:.*]] = getelementptr i32, ptr %[[ARR_ADDR]], i32 0
// LLVM: store i32 1, ptr %[[ARR_0]]
// LLVM: %[[ARR_1:.*]] = getelementptr i32, ptr %[[ARR_0]], i64 1
// LLVM: store i32 2, ptr %[[ARR_1]]
// LLVM: %[[ARR_2:.*]] = getelementptr i32, ptr %[[ARR_0]], i64 2
// LLVM: store i32 3, ptr %[[ARR_2]]
// LLVM: %[[ARR_3:.*]] = getelementptr i32, ptr %[[ARR_0]], i64 3
// LLVM: store i32 4, ptr %[[ARR_3]]
// LLVM: store ptr %[[ARR_ADDR]], ptr %[[RANGE_ADDR]]
// LLVM: %[[BEGIN:.*]] = load ptr, ptr %[[RANGE_ADDR]]
// LLVM: %[[BEGIN_CAST:.*]] = getelementptr i32, ptr %[[BEGIN]], i32 0
// LLVM: store ptr %[[BEGIN_CAST]], ptr %[[BEGIN_ADDR]]
// LLVM: %[[RANGE:.*]] = load ptr, ptr %[[RANGE_ADDR]]
// LLVM: %[[RANGE_CAST:.*]] = getelementptr i32, ptr %[[RANGE]], i32 0
// LLVM: %[[END_PTR:.*]] = getelementptr i32, ptr %[[RANGE_CAST]], i64 4
// LLVM: store ptr %[[END_PTR]], ptr %[[END_ADDR]]
// LLVM: br label %[[COND:.*]]
// LLVM: [[COND]]:
// LLVM: %[[BEGIN:.*]] = load ptr, ptr %[[BEGIN_ADDR]]
// LLVM: %[[END:.*]] = load ptr, ptr %[[END_ADDR]]
// LLVM: %[[CMP:.*]] = icmp ne ptr %[[BEGIN]], %[[END]]
// LLVM: br i1 %[[CMP]], label %[[BODY:.*]], label %[[END:.*]]
// LLVM: [[BODY]]:
// LLVM: %[[CUR:.*]] = load ptr, ptr %[[BEGIN_ADDR]]
// LLVM: %[[ARR_CUR:.*]] = load i32, ptr %[[CUR]]
// LLVM: store i32 %[[ARR_CUR]], ptr %[[X_ADDR]]
// LLVM: br label %[[STEP:.*]]
// LLVM: [[STEP]]:
// LLVM: %[[BEGIN:.*]] = load ptr, ptr %[[BEGIN_ADDR]]
// LLVM: %[[NEXT:.*]] = getelementptr i32, ptr %[[BEGIN]], i64 1
// LLVM: store ptr %[[NEXT]], ptr %[[BEGIN_ADDR]]
// LLVM: br label %[[COND]]
// LLVM: [[END]]:
// LLVM: br label %[[EXIT:.*]]
// LLVM: [[EXIT]]:
// LLVM: ret void
// OGCG: define{{.*}} void @_Z2l5v()
// OGCG: %[[ARR_ADDR:.*]] = alloca [4 x i32]
// OGCG: %[[RANGE_ADDR:.*]] = alloca ptr
// OGCG: %[[BEGIN_ADDR:.*]] = alloca ptr
// OGCG: %[[END_ADDR:.*]] = alloca ptr
// OGCG: %[[X_ADDR:.*]] = alloca i32
// OGCG: call void @llvm.memcpy.p0.p0.i64
// OGCG: store ptr %[[ARR_ADDR]], ptr %[[RANGE_ADDR]]
// OGCG: %[[BEGIN:.*]] = load ptr, ptr %[[RANGE_ADDR]]
// OGCG: %[[BEGIN_CAST:.*]] = getelementptr inbounds [4 x i32], ptr %[[BEGIN]], i64 0, i64 0
// OGCG: store ptr %[[BEGIN_CAST]], ptr %[[BEGIN_ADDR]]
// OGCG: %[[RANGE:.*]] = load ptr, ptr %[[RANGE_ADDR]]
// OGCG: %[[RANGE_CAST:.*]] = getelementptr inbounds [4 x i32], ptr %[[RANGE]], i64 0, i64 0
// OGCG: %[[END_PTR:.*]] = getelementptr inbounds i32, ptr %[[RANGE_CAST]], i64 4
// OGCG: store ptr %[[END_PTR]], ptr %[[END_ADDR]]
// OGCG: br label %[[COND:.*]]
// OGCG: [[COND]]:
// OGCG: %[[BEGIN:.*]] = load ptr, ptr %[[BEGIN_ADDR]]
// OGCG: %[[END:.*]] = load ptr, ptr %[[END_ADDR]]
// OGCG: %[[CMP:.*]] = icmp ne ptr %[[BEGIN]], %[[END]]
// OGCG: br i1 %[[CMP]], label %[[BODY:.*]], label %[[END:.*]]
// OGCG: [[BODY]]:
// OGCG: %[[CUR:.*]] = load ptr, ptr %[[BEGIN_ADDR]]
// OGCG: %[[ARR_CUR:.*]] = load i32, ptr %[[CUR]]
// OGCG: store i32 %[[ARR_CUR]], ptr %[[X_ADDR]]
// OGCG: br label %[[STEP:.*]]
// OGCG: [[STEP]]:
// OGCG: %[[BEGIN:.*]] = load ptr, ptr %[[BEGIN_ADDR]]
// OGCG: %[[NEXT:.*]] = getelementptr inbounds nuw i32, ptr %[[BEGIN]], i32 1
// OGCG: store ptr %[[NEXT]], ptr %[[BEGIN_ADDR]]
// OGCG: br label %[[COND]]
// OGCG: [[END]]:
// OGCG: ret void
void test_do_while_false() {
do {
} while (0);
}
// CIR: cir.func{{.*}} @_Z19test_do_while_falsev()
// CIR-NEXT: cir.scope {
// CIR-NEXT: cir.do {
// CIR-NEXT: cir.yield
// CIR-NEXT: } while {
// CIR-NEXT: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
// CIR-NEXT: %[[FALSE:.*]] = cir.cast(int_to_bool, %[[ZERO]] : !s32i), !cir.bool
// CIR-NEXT: cir.condition(%[[FALSE]])
// LLVM: define{{.*}} void @_Z19test_do_while_falsev()
// LLVM: br label %[[LABEL1:.*]]
// LLVM: [[LABEL1]]:
// LLVM: br label %[[LABEL3:.*]]
// LLVM: [[LABEL2:.*]]:
// LLVM: br i1 false, label %[[LABEL3]], label %[[LABEL4:.*]]
// LLVM: [[LABEL3]]:
// LLVM: br label %[[LABEL2]]
// LLVM: [[LABEL4]]:
// LLVM: br label %[[LABEL5:.*]]
// LLVM: [[LABEL5]]:
// LLVM: ret void
// OGCG: define{{.*}} void @_Z19test_do_while_falsev()
// OGCG: entry:
// OGCG: br label %[[DO_BODY:.*]]
// OGCG: [[DO_BODY]]:
// OGCG: br label %[[DO_END:.*]]
// OGCG: [[DO_END]]:
// OGCG: ret void
void test_empty_while_true() {
while (true) {
return;
}
}
// CIR: cir.func{{.*}} @_Z21test_empty_while_truev()
// CIR-NEXT: cir.scope {
// CIR-NEXT: cir.while {
// CIR-NEXT: %[[TRUE:.*]] = cir.const #true
// CIR-NEXT: cir.condition(%[[TRUE]])
// CIR-NEXT: } do {
// CIR-NEXT: cir.scope {
// CIR-NEXT: cir.return
// CIR-NEXT: }
// CIR-NEXT: cir.yield
// LLVM: define{{.*}} void @_Z21test_empty_while_truev()
// LLVM: br label %[[LABEL1:.*]]
// LLVM: [[LABEL1]]:
// LLVM: br label %[[LABEL2:.*]]
// LLVM: [[LABEL2]]:
// LLVM: br i1 true, label %[[LABEL3:.*]], label %[[LABEL6:.*]]
// LLVM: [[LABEL3]]:
// LLVM: br label %[[LABEL4]]
// LLVM: [[LABEL4]]:
// LLVM: ret void
// LLVM: [[LABEL5:.*]]:
// LLVM-SAME: ; No predecessors!
// LLVM: br label %[[LABEL2:.*]]
// LLVM: [[LABEL6]]:
// LLVM: br label %[[LABEL7:.*]]
// LLVM: [[LABEL7]]:
// LLVM: ret void
// OGCG: define{{.*}} void @_Z21test_empty_while_truev()
// OGCG: entry:
// OGCG: br label %[[WHILE_BODY:.*]]
// OGCG: [[WHILE_BODY]]:
// OGCG: ret void
void unreachable_after_continue() {
for (;;) {
continue;
int x = 1;
}
}
// CIR: cir.func{{.*}} @_Z26unreachable_after_continuev()
// CIR: cir.scope {
// CIR: cir.for : cond {
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.condition(%[[TRUE]])
// CIR: } body {
// CIR: cir.scope {
// CIR: %[[X:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init] {alignment = 4 : i64}
// CIR: cir.continue
// CIR: ^bb1: // no predecessors
// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s32i
// CIR: cir.store{{.*}} %[[ONE]], %[[X]] : !s32i, !cir.ptr<!s32i>
// CIR: cir.yield
// CIR: }
// CIR: cir.yield
// CIR: } step {
// CIR: cir.yield
// CIR: }
// CIR: }
// CIR: cir.return
// CIR: }
// LLVM: define{{.*}} void @_Z26unreachable_after_continuev()
// LLVM: %[[X:.*]] = alloca i32, i64 1, align 4
// LLVM: br label %[[LABEL1:.*]]
// LLVM: [[LABEL1]]:
// LLVM: br label %[[LABEL2:.*]]
// LLVM: [[LABEL2]]:
// LLVM: br i1 true, label %[[LABEL3:.*]], label %[[LABEL8:.*]]
// LLVM: [[LABEL3]]:
// LLVM: br label %[[LABEL4:.*]]
// LLVM: [[LABEL4]]:
// LLVM: br label %[[LABEL7:.*]]
// LLVM: [[LABEL5:.*]]:
// LLVM-SAME: ; No predecessors!
// LLVM: store i32 1, ptr %[[X]], align 4
// LLVM: br label %[[LABEL6:.*]]
// LLVM: [[LABEL6]]:
// LLVM: br label %[[LABEL7:.*]]
// LLVM: [[LABEL7]]:
// LLVM: br label %[[LABEL2]]
// LLVM: [[LABEL8]]:
// LLVM: br label %[[LABEL9:]]
// LLVM: [[LABEL9]]:
// LLVM: ret void
// OGCG: define{{.*}} void @_Z26unreachable_after_continuev()
// OGCG: entry:
// OGCG: %[[X:.*]] = alloca i32, align 4
// OGCG: br label %[[FOR_COND:.*]]
// OGCG: [[FOR_COND]]:
// OGCG: br label %[[FOR_COND]]
void unreachable_after_break() {
for (;;) {
break;
int x = 1;
}
}
// CIR: cir.func{{.*}} @_Z23unreachable_after_breakv()
// CIR: cir.scope {
// CIR: cir.for : cond {
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.condition(%[[TRUE]])
// CIR: } body {
// CIR: cir.scope {
// CIR: %[[X:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init] {alignment = 4 : i64}
// CIR: cir.break
// CIR: ^bb1: // no predecessors
// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s32i
// CIR: cir.store{{.*}} %[[ONE]], %[[X]] : !s32i, !cir.ptr<!s32i>
// CIR: cir.yield
// CIR: }
// CIR: cir.yield
// CIR: } step {
// CIR: cir.yield
// CIR: }
// CIR: }
// CIR: cir.return
// CIR: }
// LLVM: define{{.*}} void @_Z23unreachable_after_breakv()
// LLVM: %[[X:.*]] = alloca i32, i64 1, align 4
// LLVM: br label %[[LABEL1:.*]]
// LLVM: [[LABEL1]]:
// LLVM: br label %[[LABEL2:.*]]
// LLVM: [[LABEL2]]:
// LLVM: br i1 true, label %[[LABEL3:.*]], label %[[LABEL8:.*]]
// LLVM: [[LABEL3]]:
// LLVM: br label %[[LABEL4:.*]]
// LLVM: [[LABEL4]]:
// LLVM: br label %[[LABEL8]]
// LLVM: [[LABEL5:.*]]:
// LLVM-SAME: ; No predecessors!
// LLVM: store i32 1, ptr %[[X]], align 4
// LLVM: br label %[[LABEL6:.*]]
// LLVM: [[LABEL6]]:
// LLVM: br label %[[LABEL7:.*]]
// LLVM: [[LABEL7]]:
// LLVM: br label %[[LABEL2]]
// LLVM: [[LABEL8]]:
// LLVM: br label %[[LABEL9:]]
// LLVM: [[LABEL9]]:
// LLVM: ret void
// OGCG: define{{.*}} void @_Z23unreachable_after_breakv()
// OGCG: entry:
// OGCG: %[[X:.*]] = alloca i32, align 4
// OGCG: br label %[[FOR_COND:.*]]
// OGCG: [[FOR_COND]]:
// OGCG: br label %[[FOR_END:.*]]
// OGCG: [[FOR_END]]:
// OGCG: ret void