Skip to content

Commit 70a2723

Browse files
authored
[CIR][NFC][Test] Add llvm ir test for lambdas (#1170)
Added a few FIXMEs. There are 2 types of FIXMEs; 1. Most of them are missing func call and parameter attributes. I didn't add for all missing sites for this type as it would have been just copy pastes. 2. FIXME in lambda __invoke(): OG simply returns but CIR generates call to llvm.trap. This is just temporary and we will fix in in near future. But I feel I should still list those IRs so once we fix problem with codegen of invoke, we'd get test failure on this one and fix it. Actually, this way, this test file would be a natural test case for implementation of invoke.
1 parent 676b861 commit 70a2723

File tree

1 file changed

+151
-0
lines changed

1 file changed

+151
-0
lines changed

clang/test/CIR/CodeGen/lambda.cpp

+151
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -Wno-return-stack-address -emit-cir %s -o %t.cir
22
// RUN: FileCheck --input-file=%t.cir %s
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm -o - %s \
4+
// RUN: | opt -S -passes=instcombine,mem2reg,simplifycfg -o %t.ll
5+
// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
36

47
void fn() {
58
auto a = [](){};
@@ -15,6 +18,21 @@ void fn() {
1518
// CHECK-NEXT: %0 = cir.alloca !ty_anon2E0_, !cir.ptr<!ty_anon2E0_>, ["a"]
1619
// CHECK: cir.call @_ZZ2fnvENK3$_0clEv
1720

21+
// LLVM: {{.*}}void @"_ZZ2fnvENK3$_0clEv"(ptr [[THIS:%.*]])
22+
// FIXME: argument attributes should be emmitted, and lambda's alignment
23+
// COM: LLVM: {{.*}} @"_ZZ2fnvENK3$_0clEv"(ptr noundef nonnull align 1 dereferenceable(1) [[THIS:%.*]]){{%.*}} align 2 {
24+
// LLVM: [[THIS_ADDR:%.*]] = alloca ptr, i64 1, align 8
25+
// LLVM: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8
26+
// LLVM: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
27+
// LLVM: ret void
28+
29+
// LLVM-LABEL: _Z2fnv
30+
// LLVM: [[a:%.*]] = alloca %class.anon.0, i64 1, align 1
31+
// FIXME: parameter attributes should be emitted
32+
// LLVM: call void @"_ZZ2fnvENK3$_0clEv"(ptr [[a]])
33+
// COM: LLVM: call void @"_ZZ2fnvENK3$_0clEv"(ptr noundef nonnull align 1 dereferenceable(1) [[a]])
34+
// LLVM: ret void
35+
1836
void l0() {
1937
int i;
2038
auto a = [&](){ i = i + 1; };
@@ -37,6 +55,34 @@ void l0() {
3755

3856
// CHECK: cir.func @_Z2l0v()
3957

58+
// LLVM: {{.* }}void @"_ZZ2l0vENK3$_0clEv"(ptr [[THIS:%.*]])
59+
// LLVM: [[THIS_ADDR:%.*]] = alloca ptr, i64 1, align 8
60+
// LLVM: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8
61+
// LLVM: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
62+
// LLVM: [[I:%.*]] = getelementptr %class.anon.2, ptr [[THIS1]], i32 0, i32 0
63+
// FIXME: getelementptr argument attributes should be emitted
64+
// COM: LLVM: [[I:%.*]] = getelementptr inbounds nuw %class.anon.0, ptr [[THIS1]], i32 0, i32 0
65+
// LLVM: [[TMP0:%.*]] = load ptr, ptr [[I]], align 8
66+
// LLVM: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4
67+
// LLVM: [[ADD:%.*]] = add nsw i32 [[TMP1]], 1
68+
// LLVM: [[I:%.*]] = getelementptr %class.anon.2, ptr [[THIS1]], i32 0, i32
69+
// COM: LLVM: [[I:%.*]] = getelementptr inbounds nuw %class.anon.0, ptr [[THIS1]], i32 0, i32 0
70+
// LLVM: [[TMP4:%.*]] = load ptr, ptr [[I]], align 8
71+
// LLVM: store i32 [[ADD]], ptr [[TMP4]], align 4
72+
// LLVM: ret void
73+
74+
// LLVM-LABEL: _Z2l0v
75+
// LLVM: [[i:%.*]] = alloca i32, i64 1, align 4
76+
// LLVM: [[a:%.*]] = alloca %class.anon.2, i64 1, align 8
77+
// FIXME: getelementptr argument attributes should be emitted
78+
// COM: LLVM: [[TMP0:%.*]] = getelementptr inbounds %class.anon.2, ptr [[a]], i32 0, i32 0
79+
// LLVM: [[TMP0:%.*]] = getelementptr %class.anon.2, ptr [[a]], i32 0, i32 0
80+
// LLVM: store ptr [[i]], ptr [[TMP0]], align 8
81+
// FIXME: parameter attributes should be emitted
82+
// COM: LLVM: call void @"_ZZ2l0vENK3$_0clEv"(ptr noundef nonnull align 1 dereferenceable(1) [[a]])
83+
// LLVM: call void @"_ZZ2l0vENK3$_0clEv"(ptr [[a]])
84+
// LLVM: ret void
85+
4086
auto g() {
4187
int i = 12;
4288
return [&] {
@@ -55,6 +101,15 @@ auto g() {
55101
// CHECK: %4 = cir.load %0 : !cir.ptr<!ty_anon2E3_>, !ty_anon2E3_
56102
// CHECK: cir.return %4 : !ty_anon2E3_
57103

104+
// LLVM-LABEL: @_Z1gv()
105+
// LLVM: [[retval:%.*]] = alloca %class.anon.3, i64 1, align 8
106+
// LLVM: [[i:%.*]] = alloca i32, i64 1, align 4
107+
// LLVM: store i32 12, ptr [[i]], align 4
108+
// LLVM: [[i_addr:%.*]] = getelementptr %class.anon.3, ptr [[retval]], i32 0, i32 0
109+
// LLVM: store ptr [[i]], ptr [[i_addr]], align 8
110+
// LLVM: [[tmp:%.*]] = load %class.anon.3, ptr [[retval]], align 8
111+
// LLVM: ret %class.anon.3 [[tmp]]
112+
58113
auto g2() {
59114
int i = 12;
60115
auto lam = [&] {
@@ -75,6 +130,15 @@ auto g2() {
75130
// CHECK-NEXT: %4 = cir.load %0 : !cir.ptr<!ty_anon2E4_>, !ty_anon2E4_
76131
// CHECK-NEXT: cir.return %4 : !ty_anon2E4_
77132

133+
// LLVM-LABEL: @_Z2g2v()
134+
// LLVM: [[retval:%.*]] = alloca %class.anon.4, i64 1, align 8
135+
// LLVM: [[i:%.*]] = alloca i32, i64 1, align 4
136+
// LLVM: store i32 12, ptr [[i]], align 4
137+
// LLVM: [[i_addr:%.*]] = getelementptr %class.anon.4, ptr [[retval]], i32 0, i32 0
138+
// LLVM: store ptr [[i]], ptr [[i_addr]], align 8
139+
// LLVM: [[tmp:%.*]] = load %class.anon.4, ptr [[retval]], align 8
140+
// LLVM: ret %class.anon.4 [[tmp]]
141+
78142
int f() {
79143
return g2()();
80144
}
@@ -92,6 +156,36 @@ int f() {
92156
// CHECK-NEXT: cir.return %1 : !s32i
93157
// CHECK-NEXT: }
94158

159+
// LLVM: {{.*}}i32 @"_ZZ2g2vENK3$_0clEv"(ptr [[THIS:%.*]])
160+
// LLVM: [[THIS_ADDR:%.*]] = alloca ptr, i64 1, align 8
161+
// LLVM: [[I_SAVE:%.*]] = alloca i32, i64 1, align 4
162+
// LLVM: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8
163+
// LLVM: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
164+
// LLVM: [[I:%.*]] = getelementptr %class.anon.4, ptr [[THIS1]], i32 0, i32 0
165+
// LLVM: [[TMP0:%.*]] = load ptr, ptr [[I]], align 8
166+
// LLVM: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4
167+
// LLVM: [[ADD:%.*]] = add nsw i32 [[TMP1]], 100
168+
// LLVM: [[I:%.*]] = getelementptr %class.anon.4, ptr [[THIS1]], i32 0, i32 0
169+
// LLVM: [[TMP4:%.*]] = load ptr, ptr [[I]], align 8
170+
// LLVM: [[TMP5:%.*]] = load i32, ptr [[TMP4]], align 4
171+
// LLVM: store i32 [[TMP5]], ptr [[I_SAVE]], align 4
172+
// LLVM: [[TMP6:%.*]] = load i32, ptr [[I_SAVE]], align 4
173+
// LLVM: ret i32 [[TMP6]]
174+
175+
// LLVM-LABEL: _Z1fv
176+
// LLVM: [[ref_tmp0:%.*]] = alloca %class.anon.4, i64 1, align 8
177+
// LLVM: [[ret_val:%.*]] = alloca i32, i64 1, align 4
178+
// LLVM: br label %[[scope_bb:[0-9]+]],
179+
// LLVM: [[scope_bb]]:
180+
// LLVM: [[tmp0:%.*]] = call %class.anon.4 @_Z2g2v()
181+
// LLVM: store %class.anon.4 [[tmp0]], ptr [[ref_tmp0]], align 8
182+
// LLVM: [[tmp1:%.*]] = call i32 @"_ZZ2g2vENK3$_0clEv"(ptr [[ref_tmp0]])
183+
// LLVM: store i32 [[tmp1]], ptr [[ret_val]], align 4
184+
// LLVM: br label %[[ret_bb:[0-9]+]],
185+
// LLVM: [[ret_bb]]:
186+
// LLVM: [[tmp2:%.*]] = load i32, ptr [[ret_val]], align 4
187+
// LLVM: ret i32 [[tmp2]]
188+
95189
int g3() {
96190
auto* fn = +[](int const& i) -> int { return i; };
97191
auto task = fn(3);
@@ -134,3 +228,60 @@ int g3() {
134228
// CHECK: }
135229

136230
// CHECK: }
231+
232+
// lambda operator()
233+
// FIXME: argument attributes should be emitted
234+
// COM: LLVM: define internal noundef i32 @"_ZZ2g3vENK3$_0clERKi"(ptr noundef nonnull align 1 dereferenceable(1) {{%.*}}, ptr noundef nonnull align 4 dereferenceable(4){{%.*}}) #0 align 2
235+
// LLVM: {{.*}}i32 @"_ZZ2g3vENK3$_0clERKi"(ptr {{%.*}}, ptr {{%.*}})
236+
237+
// lambda __invoke()
238+
// LLVM: {{.*}}i32 @"_ZZ2g3vEN3$_08__invokeERKi"(ptr [[i:%.*]])
239+
// LLVM: [[i_addr:%.*]] = alloca ptr, i64 1, align 8
240+
// LLVM: [[ret_val:%.*]] = alloca i32, i64 1, align 4
241+
// LLVM: [[unused_capture:%.*]] = alloca %class.anon.5, i64 1, align 1
242+
// LLVM: store ptr [[i]], ptr [[i_addr]], align 8
243+
// LLVM: [[TMP0:%.*]] = load ptr, ptr [[i_addr]], align 8
244+
// FIXME: call and argument attributes should be emitted
245+
// COM: LLVM: [[CALL:%.*]] = call noundef i32 @"_ZZ2g3vENK3$_0clERKi"(ptr noundef nonnull align 1 dereferenceable(1) [[unused_capture]], ptr noundef nonnull align 4 dereferenceable(4) [[TMP0]])
246+
// LLVM: [[CALL:%.*]] = call i32 @"_ZZ2g3vENK3$_0clERKi"(ptr [[unused_capture]], ptr [[TMP0]])
247+
// LLVM: store i32 [[CALL]], ptr [[ret_val]], align 4
248+
// FIXME: should just return result
249+
// COM: LLVM: ret i32 [[ret_val]]
250+
// LLVM: call void @llvm.trap()
251+
// LLVM: unreachable
252+
253+
// lambda operator int (*)(int const&)()
254+
// LLVM-LABEL: @"_ZZ2g3vENK3$_0cvPFiRKiEEv"
255+
// LLVM: store ptr @"_ZZ2g3vEN3$_08__invokeERKi", ptr [[ret_val:%.*]], align 8
256+
// LLVM: [[TMP0:%.*]] = load ptr, ptr [[ret_val]], align 8
257+
// LLVM: ret ptr [[TMP0]]
258+
259+
// LLVM-LABEL: _Z2g3v
260+
// LLVM-DAG: [[ref_tmp0:%.*]] = alloca %class.anon.5, i64 1, align 1
261+
// LLVM-DAG: [[ref_tmp1:%.*]] = alloca i32, i64 1, align 4
262+
// LLVM-DAG: [[ret_val:%.*]] = alloca i32, i64 1, align 4
263+
// LLVM-DAG: [[fn_ptr:%.*]] = alloca ptr, i64 1, align 8
264+
// LLVM-DAG: [[task:%.*]] = alloca i32, i64 1, align 4
265+
// LLVM: br label %[[scope0_bb:[0-9]+]],
266+
267+
// LLVM: [[scope0_bb]]: {{.*}}; preds = %0
268+
// LLVM: [[call:%.*]] = call ptr @"_ZZ2g3vENK3$_0cvPFiRKiEEv"(ptr [[ref_tmp0]])
269+
// LLVM: br label %[[scope1_before:[0-9]+]],
270+
271+
// LLVM: [[scope1_before]]: {{.*}}; preds = %[[scope0_bb]]
272+
// LLVM: [[tmp0:%.*]] = phi ptr [ [[call]], %[[scope0_bb]] ]
273+
// LLVM: br label %[[scope1_bb:[0-9]+]],
274+
275+
// LLVM: [[scope1_bb]]: {{.*}}; preds = %[[scope1_before]]
276+
// LLVM: [[fn:%.*]] = load ptr, ptr [[fn_ptr]], align 8
277+
// LLVM: store i32 3, ptr [[ref_tmp1]], align 4
278+
// LLVM: [[call1:%.*]] = call i32 [[fn]](ptr [[ref_tmp1]])
279+
// LLVM: br label %[[ret_bb:[0-9]+]],
280+
281+
// LLVM: [[ret_bb]]: {{.*}}; preds = %[[scope1_bb]]
282+
// LLVM: [[tmp1:%.*]] = phi i32 [ [[call1]], %[[scope1_bb]] ]
283+
// LLVM: store i32 [[tmp1]], ptr [[task]], align 4
284+
// LLVM: [[tmp2:%.*]] = load i32, ptr [[task]], align 4
285+
// LLVM: store i32 [[tmp2]], ptr [[ret_val]], align 4
286+
// LLVM: [[tmp3:%.*]] = load i32, ptr [[ret_val]], align 4
287+
// LLVM: ret i32 [[tmp3]]

0 commit comments

Comments
 (0)