|
| 1 | +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir |
| 2 | +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s |
| 3 | +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll |
| 4 | +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s |
| 5 | +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll |
| 6 | +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s |
| 7 | + |
| 8 | +// We declare anonymous record types to represent lambdas. Rather than trying to |
| 9 | +// to match the declarations, we establish variables for these when they are used. |
| 10 | + |
| 11 | +int g3() { |
| 12 | + auto* fn = +[](int const& i) -> int { return i; }; |
| 13 | + auto task = fn(3); |
| 14 | + return task; |
| 15 | +} |
| 16 | + |
| 17 | +// The order of these functions is different in OGCG. |
| 18 | + |
| 19 | +// OGCG: define dso_local noundef i32 @_Z2g3v() |
| 20 | +// OGCG: %[[FN_PTR:.*]] = alloca ptr |
| 21 | +// OGCG: %[[REF_TMP:.*]] = alloca %[[REC_LAM_G3:.*]] |
| 22 | +// OGCG: %[[TASK:.*]] = alloca i32 |
| 23 | +// OGCG: %[[REF_TMP1:.*]] = alloca i32 |
| 24 | +// OGCG: %[[CALL:.*]] = call {{.*}} ptr @"_ZZ2g3vENK3$_0cvPFiRKiEEv"(ptr {{.*}} %[[REF_TMP]]) |
| 25 | +// OGCG: store ptr %[[CALL]], ptr %[[FN_PTR]] |
| 26 | +// OGCG: %[[FN:.*]] = load ptr, ptr %[[FN_PTR]] |
| 27 | +// OGCG: store i32 3, ptr %[[REF_TMP1]] |
| 28 | +// OGCG: %[[CALL2:.*]] = call {{.*}} i32 %[[FN]](ptr {{.*}} %[[REF_TMP1]]) |
| 29 | +// OGCG: store i32 %[[CALL2]], ptr %[[TASK]] |
| 30 | +// OGCG: %[[RESULT:.*]] = load i32, ptr %[[TASK]] |
| 31 | +// OGCG: ret i32 %[[RESULT]] |
| 32 | + |
| 33 | +// OGCG: define internal noundef ptr @"_ZZ2g3vENK3$_0cvPFiRKiEEv"(ptr {{.*}} %[[THIS_ARG:.*]]) |
| 34 | +// OGCG: %[[THIS_ADDR:.*]] = alloca ptr |
| 35 | +// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]] |
| 36 | +// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]] |
| 37 | +// OGCG: ret ptr @"_ZZ2g3vEN3$_08__invokeERKi" |
| 38 | + |
| 39 | +// lambda operator() |
| 40 | +// CIR: cir.func lambda internal private dso_local @_ZZ2g3vENK3$_0clERKi(%[[THIS_ARG:.*]]: !cir.ptr<![[REC_LAM_G3:.*]]> {{.*}}, %[[REF_I_ARG:.*]]: !cir.ptr<!s32i> {{.*}}) |
| 41 | +// CIR: %[[THIS_ALLOCA:.*]] = cir.alloca !cir.ptr<![[REC_LAM_G3]]>, !cir.ptr<!cir.ptr<![[REC_LAM_G3]]>>, ["this", init] |
| 42 | +// CIR: %[[REF_I_ALLOCA:.*]] = cir.alloca {{.*}} ["i", init, const] |
| 43 | +// CIR: %[[RETVAL:.*]] = cir.alloca {{.*}} ["__retval"] |
| 44 | +// CIR: cir.store %[[THIS_ARG]], %[[THIS_ALLOCA]] |
| 45 | +// CIR: cir.store %[[REF_I_ARG]], %[[REF_I_ALLOCA]] |
| 46 | +// CIR: %[[THIS:.*]] = cir.load %[[THIS_ALLOCA]] |
| 47 | +// CIR: %[[REF_I:.*]] = cir.load %[[REF_I_ALLOCA]] |
| 48 | +// CIR: %[[I:.*]] = cir.load{{.*}} %[[REF_I]] |
| 49 | +// CIR: cir.store %[[I]], %[[RETVAL]] |
| 50 | +// CIR: %[[RET:.*]] = cir.load %[[RETVAL]] |
| 51 | +// CIR: cir.return %[[RET]] |
| 52 | + |
| 53 | +// LLVM: define internal i32 @"_ZZ2g3vENK3$_0clERKi"(ptr %[[THIS_ARG:.*]], ptr %[[REF_I_ARG:.*]]) { |
| 54 | +// LLVM: %[[THIS_ALLOCA:.*]] = alloca ptr |
| 55 | +// LLVM: %[[REF_I_ALLOCA:.*]] = alloca ptr |
| 56 | +// LLVM: %[[RETVAL:.*]] = alloca i32 |
| 57 | +// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ALLOCA]] |
| 58 | +// LLVM: store ptr %[[REF_I_ARG]], ptr %[[REF_I_ALLOCA]] |
| 59 | +// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ALLOCA]] |
| 60 | +// LLVM: %[[REF_I:.*]] = load ptr, ptr %[[REF_I_ALLOCA]] |
| 61 | +// LLVM: %[[I:.*]] = load i32, ptr %[[REF_I]] |
| 62 | +// LLVM: store i32 %[[I]], ptr %[[RETVAL]] |
| 63 | +// LLVM: %[[RET:.*]] = load i32, ptr %[[RETVAL]] |
| 64 | +// LLVM: ret i32 %[[RET]] |
| 65 | + |
| 66 | +// In OGCG, the _ZZ2g3vENK3$_0clERKi function is emitted after _ZZ2g3vEN3$_08__invokeERKi, see below. |
| 67 | + |
| 68 | +// lambda invoker |
| 69 | +// CIR: cir.func internal private dso_local @_ZZ2g3vEN3$_08__invokeERKi(%[[REF_I_ARG:.*]]: !cir.ptr<!s32i> {{.*}}) -> !s32i { |
| 70 | +// CIR: %[[REF_I_ALLOCA:.*]] = cir.alloca {{.*}} ["i", init, const] |
| 71 | +// CIR: %[[RETVAL:.*]] = cir.alloca {{.*}} ["__retval"] |
| 72 | +// CIR: %[[LAM_ALLOCA:.*]] = cir.alloca ![[REC_LAM_G3]], !cir.ptr<![[REC_LAM_G3]]>, ["unused.capture"] |
| 73 | +// CIR: cir.store %[[REF_I_ARG]], %[[REF_I_ALLOCA]] |
| 74 | +// CIR: %[[REF_I:.*]] = cir.load{{.*}} %[[REF_I_ALLOCA]] |
| 75 | +// CIR: %[[LAM_RESULT:.*]] = cir.call @_ZZ2g3vENK3$_0clERKi(%2, %3) : (!cir.ptr<![[REC_LAM_G3]]>, !cir.ptr<!s32i>) -> !s32i |
| 76 | +// CIR: cir.store{{.*}} %[[LAM_RESULT]], %[[RETVAL]] |
| 77 | +// CIR: %[[RET:.*]] = cir.load %[[RETVAL]] |
| 78 | +// CIR: cir.return %[[RET]] |
| 79 | + |
| 80 | +// LLVM: define internal i32 @"_ZZ2g3vEN3$_08__invokeERKi"(ptr %[[REF_I_ARG:.*]]) { |
| 81 | +// LLVM: %[[REF_I_ALLOCA:.*]] = alloca ptr |
| 82 | +// LLVM: %[[RETVAL:.*]] = alloca i32 |
| 83 | +// LLVM: %[[LAM_ALLOCA:.*]] = alloca %[[REC_LAM_G3:.*]], |
| 84 | +// LLVM: store ptr %[[REF_I_ARG]], ptr %[[REF_I_ALLOCA]] |
| 85 | +// LLVM: %[[REF_I:.*]] = load ptr, ptr %[[REF_I_ALLOCA]] |
| 86 | +// LLVM: %[[LAM_RESULT:.*]] = call i32 @"_ZZ2g3vENK3$_0clERKi"(ptr %[[LAM_ALLOCA]], ptr %[[REF_I]]) |
| 87 | +// LLVM: store i32 %[[LAM_RESULT]], ptr %[[RETVAL]] |
| 88 | +// LLVM: %[[RET:.*]] = load i32, ptr %[[RETVAL]] |
| 89 | +// LLVM: ret i32 %[[RET]] |
| 90 | + |
| 91 | +// In OGCG, the _ZZ2g3vEN3$_08__invokeERKi function is emitted after _ZN1A3barEv, see below. |
| 92 | + |
| 93 | +// lambda operator int (*)(int const&)() |
| 94 | +// CIR: cir.func internal private dso_local @_ZZ2g3vENK3$_0cvPFiRKiEEv(%[[THIS_ARG:.*]]: !cir.ptr<![[REC_LAM_G3]]> {{.*}}) -> !cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> !s32i>> { |
| 95 | +// CIR: %[[THIS_ALLOCA:.*]] = cir.alloca !cir.ptr<![[REC_LAM_G3]]>, !cir.ptr<!cir.ptr<![[REC_LAM_G3]]>>, ["this", init] |
| 96 | +// CIR: %[[RETVAL:.*]] = cir.alloca !cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> !s32i>>, !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> !s32i>>>, ["__retval"] |
| 97 | +// CIR: cir.store %[[THIS_ARG]], %[[THIS_ALLOCA]] |
| 98 | +// CIR: %[[THIS:.*]] = cir.load %[[THIS_ALLOCA]] |
| 99 | +// CIR: %[[INVOKER:.*]] = cir.get_global @_ZZ2g3vEN3$_08__invokeERKi : !cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> !s32i>> |
| 100 | +// CIR: cir.store %[[INVOKER]], %[[RETVAL]] |
| 101 | +// CIR: %[[RET:.*]] = cir.load %[[RETVAL]] |
| 102 | +// CIR: cir.return %[[RET]] |
| 103 | + |
| 104 | +// LLVM: define internal ptr @"_ZZ2g3vENK3$_0cvPFiRKiEEv"(ptr %[[THIS_ARG:.*]]) { |
| 105 | +// LLVM: %[[THIS_ALLOCA:.*]] = alloca ptr |
| 106 | +// LLVM: %[[RETVAL:.*]] = alloca ptr |
| 107 | +// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ALLOCA]] |
| 108 | +// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ALLOCA]] |
| 109 | +// LLVM: store ptr @"_ZZ2g3vEN3$_08__invokeERKi", ptr %[[RETVAL]] |
| 110 | +// LLVM: %[[RET:.*]] = load ptr, ptr %[[RETVAL]] |
| 111 | +// LLVM: ret ptr %[[RET]] |
| 112 | + |
| 113 | +// In OGCG, the _ZZ2g3vENK3$_0cvPFiRKiEEv function is emitted just after the _Z2g3v function, see above. |
| 114 | + |
| 115 | +// CIR: cir.func{{.*}} @_Z2g3v() -> !s32i { |
| 116 | +// CIR: %[[RETVAL:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] |
| 117 | +// CIR: %[[FN_ADDR:.*]] = cir.alloca !cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> !s32i>>, !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> !s32i>>>, ["fn", init] |
| 118 | +// CIR: %[[TASK:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["task", init] |
| 119 | + |
| 120 | +// 1. Use `operator int (*)(int const&)()` to retrieve the fnptr to `__invoke()`. |
| 121 | +// CIR: %[[SCOPE_RET:.*]] = cir.scope { |
| 122 | +// CIR: %[[LAM_ALLOCA:.*]] = cir.alloca ![[REC_LAM_G3]], !cir.ptr<![[REC_LAM_G3]]>, ["ref.tmp0"] |
| 123 | +// CIR: %[[OPERATOR_RESULT:.*]] = cir.call @_ZZ2g3vENK3$_0cvPFiRKiEEv(%[[LAM_ALLOCA]]){{.*}} |
| 124 | +// CIR: %[[PLUS:.*]] = cir.unary(plus, %[[OPERATOR_RESULT]]) |
| 125 | +// CIR: cir.yield %[[PLUS]] |
| 126 | +// CIR: } |
| 127 | + |
| 128 | +// 2. Load ptr to `__invoke()`. |
| 129 | +// CIR: cir.store{{.*}} %[[SCOPE_RET]], %[[FN_ADDR]] |
| 130 | +// CIR: %[[SCOPE_RET2:.*]] = cir.scope { |
| 131 | +// CIR: %[[REF_TMP1:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["ref.tmp1", init] |
| 132 | +// CIR: %[[FN:.*]] = cir.load{{.*}} %[[FN_ADDR]] |
| 133 | +// CIR: %[[THREE:.*]] = cir.const #cir.int<3> : !s32i |
| 134 | +// CIR: cir.store{{.*}} %[[THREE]], %[[REF_TMP1]] |
| 135 | + |
| 136 | +// 3. Call `__invoke()`, which effectively executes `operator()`. |
| 137 | +// CIR: %[[RESULT:.*]] = cir.call %[[FN]](%[[REF_TMP1]]) |
| 138 | +// CIR: cir.yield %[[RESULT]] |
| 139 | +// CIR: } |
| 140 | + |
| 141 | +// CIR: cir.store{{.*}} %[[SCOPE_RET2]], %[[TASK]] |
| 142 | +// CIR: %[[TASK_RET:.*]] = cir.load{{.*}} %[[TASK]] |
| 143 | +// CIR: cir.store{{.*}} %[[TASK_RET]], %[[RETVAL]] |
| 144 | +// CIR: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL]] |
| 145 | +// CIR: cir.return %[[RET]] |
| 146 | +// CIR: } |
| 147 | + |
| 148 | +// LLVM: define dso_local i32 @_Z2g3v() { |
| 149 | +// LLVM: %[[LAM_ALLOCA:.*]] = alloca %[[REC_LAM_G3]] |
| 150 | +// LLVM: %[[REF_TMP1:.*]] = alloca i32 |
| 151 | +// LLVM: %[[RETVAL:.*]] = alloca i32 |
| 152 | +// LLVM: %[[FN_PTR:.*]] = alloca ptr |
| 153 | +// LLVM: %[[TASK:.*]] = alloca i32 |
| 154 | +// LLVM: br label %[[SCOPE_BB0:.*]] |
| 155 | + |
| 156 | +// LLVM: [[SCOPE_BB0]]: |
| 157 | +// LLVM: %[[OPERATOR_RESULT:.*]] = call ptr @"_ZZ2g3vENK3$_0cvPFiRKiEEv"(ptr %[[LAM_ALLOCA]]) |
| 158 | +// LLVM: br label %[[SCOPE_BB1:.*]] |
| 159 | + |
| 160 | +// LLVM: [[SCOPE_BB1]]: |
| 161 | +// LLVM: %[[TMP0:.*]] = phi ptr [ %[[OPERATOR_RESULT]], %[[SCOPE_BB0]] ] |
| 162 | +// LLVM: store ptr %[[TMP0]], ptr %[[FN_PTR]] |
| 163 | +// LLVM: br label %[[SCOPE_BB2:.*]] |
| 164 | + |
| 165 | +// LLVM: [[SCOPE_BB2]]: |
| 166 | +// LLVM: %[[FN:.*]] = load ptr, ptr %[[FN_PTR]] |
| 167 | +// LLVM: store i32 3, ptr %[[REF_TMP1]] |
| 168 | +// LLVM: %[[RESULT:.*]] = call i32 %[[FN]](ptr %[[REF_TMP1]]) |
| 169 | +// LLVM: br label %[[RET_BB:.*]] |
| 170 | + |
| 171 | +// LLVM: [[RET_BB]]: |
| 172 | +// LLVM: %[[TMP1:.*]] = phi i32 [ %[[RESULT]], %[[SCOPE_BB2]] ] |
| 173 | +// LLVM: store i32 %[[TMP1]], ptr %[[TASK]] |
| 174 | +// LLVM: %[[TMP2:.*]] = load i32, ptr %[[TASK]] |
| 175 | +// LLVM: store i32 %[[TMP2]], ptr %[[RETVAL]] |
| 176 | +// LLVM: %[[RET:.*]] = load i32, ptr %[[RETVAL]] |
| 177 | +// LLVM: ret i32 %[[RET]] |
| 178 | + |
| 179 | +// The definition for _Z2g3v in OGCG is first among the functions for the g3 test, see above. |
| 180 | + |
| 181 | +// The functions below are emitted later in OGCG, see above for the corresponding LLVM checks. |
| 182 | + |
| 183 | +// OGCG: define internal noundef i32 @"_ZZ2g3vEN3$_08__invokeERKi"(ptr {{.*}} %[[I_ARG:.*]]) |
| 184 | +// OGCG: %[[I_ADDR:.*]] = alloca ptr |
| 185 | +// OGCG: %[[UNUSED_CAPTURE:.*]] = alloca %[[REC_LAM_G3:.*]] |
| 186 | +// OGCG: store ptr %[[I_ARG]], ptr %[[I_ADDR]] |
| 187 | +// OGCG: %[[I_PTR:.*]] = load ptr, ptr %[[I_ADDR]] |
| 188 | +// OGCG: %[[CALL:.*]] = call {{.*}} i32 @"_ZZ2g3vENK3$_0clERKi"(ptr {{.*}} %[[UNUSED_CAPTURE]], ptr {{.*}} %[[I_PTR]]) |
| 189 | +// OGCG: ret i32 %[[CALL]] |
| 190 | + |
| 191 | +// OGCG: define internal noundef i32 @"_ZZ2g3vENK3$_0clERKi"(ptr {{.*}} %[[THIS_ARG:.*]], ptr {{.*}} %[[I_ARG:.*]]) |
| 192 | +// OGCG: %[[THIS_ADDR:.*]] = alloca ptr |
| 193 | +// OGCG: %[[I_ADDR:.*]] = alloca ptr |
| 194 | +// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]] |
| 195 | +// OGCG: store ptr %[[I_ARG]], ptr %[[I_ADDR]] |
| 196 | +// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]] |
| 197 | +// OGCG: %[[I_PTR:.*]] = load ptr, ptr %[[I_ADDR]] |
| 198 | +// OGCG: %[[I:.*]] = load i32, ptr %[[I_PTR]] |
| 199 | +// OGCG: ret i32 %[[I]] |
0 commit comments