1 | //===-- WebAssembly.cpp - Emit LLVM Code for builtins ---------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This contains code to emit Builtin calls as LLVM code. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "CGBuiltin.h" |
14 | #include "clang/Basic/TargetBuiltins.h" |
15 | #include "llvm/IR/IntrinsicsWebAssembly.h" |
16 | |
17 | using namespace clang; |
18 | using namespace CodeGen; |
19 | using namespace llvm; |
20 | |
21 | Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, |
22 | const CallExpr *E) { |
23 | switch (BuiltinID) { |
24 | case WebAssembly::BI__builtin_wasm_memory_size: { |
25 | llvm::Type *ResultType = ConvertType(T: E->getType()); |
26 | Value *I = EmitScalarExpr(E: E->getArg(Arg: 0)); |
27 | Function *Callee = |
28 | CGM.getIntrinsic(IID: Intrinsic::wasm_memory_size, Tys: ResultType); |
29 | return Builder.CreateCall(Callee, Args: I); |
30 | } |
31 | case WebAssembly::BI__builtin_wasm_memory_grow: { |
32 | llvm::Type *ResultType = ConvertType(T: E->getType()); |
33 | Value *Args[] = {EmitScalarExpr(E: E->getArg(Arg: 0)), |
34 | EmitScalarExpr(E: E->getArg(Arg: 1))}; |
35 | Function *Callee = |
36 | CGM.getIntrinsic(IID: Intrinsic::wasm_memory_grow, Tys: ResultType); |
37 | return Builder.CreateCall(Callee, Args); |
38 | } |
39 | case WebAssembly::BI__builtin_wasm_tls_size: { |
40 | llvm::Type *ResultType = ConvertType(T: E->getType()); |
41 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_tls_size, Tys: ResultType); |
42 | return Builder.CreateCall(Callee); |
43 | } |
44 | case WebAssembly::BI__builtin_wasm_tls_align: { |
45 | llvm::Type *ResultType = ConvertType(T: E->getType()); |
46 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_tls_align, Tys: ResultType); |
47 | return Builder.CreateCall(Callee); |
48 | } |
49 | case WebAssembly::BI__builtin_wasm_tls_base: { |
50 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_tls_base); |
51 | return Builder.CreateCall(Callee); |
52 | } |
53 | case WebAssembly::BI__builtin_wasm_throw: { |
54 | Value *Tag = EmitScalarExpr(E: E->getArg(Arg: 0)); |
55 | Value *Obj = EmitScalarExpr(E: E->getArg(Arg: 1)); |
56 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_throw); |
57 | return EmitRuntimeCallOrInvoke(callee: Callee, args: {Tag, Obj}); |
58 | } |
59 | case WebAssembly::BI__builtin_wasm_rethrow: { |
60 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_rethrow); |
61 | return EmitRuntimeCallOrInvoke(callee: Callee); |
62 | } |
63 | case WebAssembly::BI__builtin_wasm_memory_atomic_wait32: { |
64 | Value *Addr = EmitScalarExpr(E: E->getArg(Arg: 0)); |
65 | Value *Expected = EmitScalarExpr(E: E->getArg(Arg: 1)); |
66 | Value *Timeout = EmitScalarExpr(E: E->getArg(Arg: 2)); |
67 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_memory_atomic_wait32); |
68 | return Builder.CreateCall(Callee, Args: {Addr, Expected, Timeout}); |
69 | } |
70 | case WebAssembly::BI__builtin_wasm_memory_atomic_wait64: { |
71 | Value *Addr = EmitScalarExpr(E: E->getArg(Arg: 0)); |
72 | Value *Expected = EmitScalarExpr(E: E->getArg(Arg: 1)); |
73 | Value *Timeout = EmitScalarExpr(E: E->getArg(Arg: 2)); |
74 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_memory_atomic_wait64); |
75 | return Builder.CreateCall(Callee, Args: {Addr, Expected, Timeout}); |
76 | } |
77 | case WebAssembly::BI__builtin_wasm_memory_atomic_notify: { |
78 | Value *Addr = EmitScalarExpr(E: E->getArg(Arg: 0)); |
79 | Value *Count = EmitScalarExpr(E: E->getArg(Arg: 1)); |
80 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_memory_atomic_notify); |
81 | return Builder.CreateCall(Callee, Args: {Addr, Count}); |
82 | } |
83 | case WebAssembly::BI__builtin_wasm_trunc_s_i32_f32: |
84 | case WebAssembly::BI__builtin_wasm_trunc_s_i32_f64: |
85 | case WebAssembly::BI__builtin_wasm_trunc_s_i64_f32: |
86 | case WebAssembly::BI__builtin_wasm_trunc_s_i64_f64: { |
87 | Value *Src = EmitScalarExpr(E: E->getArg(Arg: 0)); |
88 | llvm::Type *ResT = ConvertType(T: E->getType()); |
89 | Function *Callee = |
90 | CGM.getIntrinsic(IID: Intrinsic::wasm_trunc_signed, Tys: {ResT, Src->getType()}); |
91 | return Builder.CreateCall(Callee, Args: {Src}); |
92 | } |
93 | case WebAssembly::BI__builtin_wasm_trunc_u_i32_f32: |
94 | case WebAssembly::BI__builtin_wasm_trunc_u_i32_f64: |
95 | case WebAssembly::BI__builtin_wasm_trunc_u_i64_f32: |
96 | case WebAssembly::BI__builtin_wasm_trunc_u_i64_f64: { |
97 | Value *Src = EmitScalarExpr(E: E->getArg(Arg: 0)); |
98 | llvm::Type *ResT = ConvertType(T: E->getType()); |
99 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_trunc_unsigned, |
100 | Tys: {ResT, Src->getType()}); |
101 | return Builder.CreateCall(Callee, Args: {Src}); |
102 | } |
103 | case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32_f32: |
104 | case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32_f64: |
105 | case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i64_f32: |
106 | case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i64_f64: |
107 | case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i16x8_f16x8: |
108 | case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32x4_f32x4: { |
109 | Value *Src = EmitScalarExpr(E: E->getArg(Arg: 0)); |
110 | llvm::Type *ResT = ConvertType(T: E->getType()); |
111 | Function *Callee = |
112 | CGM.getIntrinsic(IID: Intrinsic::fptosi_sat, Tys: {ResT, Src->getType()}); |
113 | return Builder.CreateCall(Callee, Args: {Src}); |
114 | } |
115 | case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i32_f32: |
116 | case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i32_f64: |
117 | case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i64_f32: |
118 | case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i64_f64: |
119 | case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i16x8_f16x8: |
120 | case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i32x4_f32x4: { |
121 | Value *Src = EmitScalarExpr(E: E->getArg(Arg: 0)); |
122 | llvm::Type *ResT = ConvertType(T: E->getType()); |
123 | Function *Callee = |
124 | CGM.getIntrinsic(IID: Intrinsic::fptoui_sat, Tys: {ResT, Src->getType()}); |
125 | return Builder.CreateCall(Callee, Args: {Src}); |
126 | } |
127 | case WebAssembly::BI__builtin_wasm_min_f32: |
128 | case WebAssembly::BI__builtin_wasm_min_f64: |
129 | case WebAssembly::BI__builtin_wasm_min_f16x8: |
130 | case WebAssembly::BI__builtin_wasm_min_f32x4: |
131 | case WebAssembly::BI__builtin_wasm_min_f64x2: { |
132 | Value *LHS = EmitScalarExpr(E: E->getArg(Arg: 0)); |
133 | Value *RHS = EmitScalarExpr(E: E->getArg(Arg: 1)); |
134 | Function *Callee = |
135 | CGM.getIntrinsic(IID: Intrinsic::minimum, Tys: ConvertType(T: E->getType())); |
136 | return Builder.CreateCall(Callee, Args: {LHS, RHS}); |
137 | } |
138 | case WebAssembly::BI__builtin_wasm_max_f32: |
139 | case WebAssembly::BI__builtin_wasm_max_f64: |
140 | case WebAssembly::BI__builtin_wasm_max_f16x8: |
141 | case WebAssembly::BI__builtin_wasm_max_f32x4: |
142 | case WebAssembly::BI__builtin_wasm_max_f64x2: { |
143 | Value *LHS = EmitScalarExpr(E: E->getArg(Arg: 0)); |
144 | Value *RHS = EmitScalarExpr(E: E->getArg(Arg: 1)); |
145 | Function *Callee = |
146 | CGM.getIntrinsic(IID: Intrinsic::maximum, Tys: ConvertType(T: E->getType())); |
147 | return Builder.CreateCall(Callee, Args: {LHS, RHS}); |
148 | } |
149 | case WebAssembly::BI__builtin_wasm_pmin_f16x8: |
150 | case WebAssembly::BI__builtin_wasm_pmin_f32x4: |
151 | case WebAssembly::BI__builtin_wasm_pmin_f64x2: { |
152 | Value *LHS = EmitScalarExpr(E: E->getArg(Arg: 0)); |
153 | Value *RHS = EmitScalarExpr(E: E->getArg(Arg: 1)); |
154 | Function *Callee = |
155 | CGM.getIntrinsic(IID: Intrinsic::wasm_pmin, Tys: ConvertType(T: E->getType())); |
156 | return Builder.CreateCall(Callee, Args: {LHS, RHS}); |
157 | } |
158 | case WebAssembly::BI__builtin_wasm_pmax_f16x8: |
159 | case WebAssembly::BI__builtin_wasm_pmax_f32x4: |
160 | case WebAssembly::BI__builtin_wasm_pmax_f64x2: { |
161 | Value *LHS = EmitScalarExpr(E: E->getArg(Arg: 0)); |
162 | Value *RHS = EmitScalarExpr(E: E->getArg(Arg: 1)); |
163 | Function *Callee = |
164 | CGM.getIntrinsic(IID: Intrinsic::wasm_pmax, Tys: ConvertType(T: E->getType())); |
165 | return Builder.CreateCall(Callee, Args: {LHS, RHS}); |
166 | } |
167 | case WebAssembly::BI__builtin_wasm_ceil_f16x8: |
168 | case WebAssembly::BI__builtin_wasm_floor_f16x8: |
169 | case WebAssembly::BI__builtin_wasm_trunc_f16x8: |
170 | case WebAssembly::BI__builtin_wasm_nearest_f16x8: |
171 | case WebAssembly::BI__builtin_wasm_ceil_f32x4: |
172 | case WebAssembly::BI__builtin_wasm_floor_f32x4: |
173 | case WebAssembly::BI__builtin_wasm_trunc_f32x4: |
174 | case WebAssembly::BI__builtin_wasm_nearest_f32x4: |
175 | case WebAssembly::BI__builtin_wasm_ceil_f64x2: |
176 | case WebAssembly::BI__builtin_wasm_floor_f64x2: |
177 | case WebAssembly::BI__builtin_wasm_trunc_f64x2: |
178 | case WebAssembly::BI__builtin_wasm_nearest_f64x2: { |
179 | unsigned IntNo; |
180 | switch (BuiltinID) { |
181 | case WebAssembly::BI__builtin_wasm_ceil_f16x8: |
182 | case WebAssembly::BI__builtin_wasm_ceil_f32x4: |
183 | case WebAssembly::BI__builtin_wasm_ceil_f64x2: |
184 | IntNo = Intrinsic::ceil; |
185 | break; |
186 | case WebAssembly::BI__builtin_wasm_floor_f16x8: |
187 | case WebAssembly::BI__builtin_wasm_floor_f32x4: |
188 | case WebAssembly::BI__builtin_wasm_floor_f64x2: |
189 | IntNo = Intrinsic::floor; |
190 | break; |
191 | case WebAssembly::BI__builtin_wasm_trunc_f16x8: |
192 | case WebAssembly::BI__builtin_wasm_trunc_f32x4: |
193 | case WebAssembly::BI__builtin_wasm_trunc_f64x2: |
194 | IntNo = Intrinsic::trunc; |
195 | break; |
196 | case WebAssembly::BI__builtin_wasm_nearest_f16x8: |
197 | case WebAssembly::BI__builtin_wasm_nearest_f32x4: |
198 | case WebAssembly::BI__builtin_wasm_nearest_f64x2: |
199 | IntNo = Intrinsic::nearbyint; |
200 | break; |
201 | default: |
202 | llvm_unreachable("unexpected builtin ID" ); |
203 | } |
204 | Value *Value = EmitScalarExpr(E: E->getArg(Arg: 0)); |
205 | Function *Callee = CGM.getIntrinsic(IID: IntNo, Tys: ConvertType(T: E->getType())); |
206 | return Builder.CreateCall(Callee, Args: Value); |
207 | } |
208 | case WebAssembly::BI__builtin_wasm_ref_null_extern: { |
209 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_ref_null_extern); |
210 | return Builder.CreateCall(Callee); |
211 | } |
212 | case WebAssembly::BI__builtin_wasm_ref_is_null_extern: { |
213 | Value *Src = EmitScalarExpr(E: E->getArg(Arg: 0)); |
214 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_ref_is_null_extern); |
215 | return Builder.CreateCall(Callee, Args: {Src}); |
216 | } |
217 | case WebAssembly::BI__builtin_wasm_ref_null_func: { |
218 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_ref_null_func); |
219 | return Builder.CreateCall(Callee); |
220 | } |
221 | case WebAssembly::BI__builtin_wasm_swizzle_i8x16: { |
222 | Value *Src = EmitScalarExpr(E: E->getArg(Arg: 0)); |
223 | Value *Indices = EmitScalarExpr(E: E->getArg(Arg: 1)); |
224 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_swizzle); |
225 | return Builder.CreateCall(Callee, Args: {Src, Indices}); |
226 | } |
227 | case WebAssembly::BI__builtin_wasm_abs_i8x16: |
228 | case WebAssembly::BI__builtin_wasm_abs_i16x8: |
229 | case WebAssembly::BI__builtin_wasm_abs_i32x4: |
230 | case WebAssembly::BI__builtin_wasm_abs_i64x2: { |
231 | Value *Vec = EmitScalarExpr(E: E->getArg(Arg: 0)); |
232 | Value *Neg = Builder.CreateNeg(V: Vec, Name: "neg" ); |
233 | Constant *Zero = llvm::Constant::getNullValue(Ty: Vec->getType()); |
234 | Value *ICmp = Builder.CreateICmpSLT(LHS: Vec, RHS: Zero, Name: "abscond" ); |
235 | return Builder.CreateSelect(C: ICmp, True: Neg, False: Vec, Name: "abs" ); |
236 | } |
237 | case WebAssembly::BI__builtin_wasm_avgr_u_i8x16: |
238 | case WebAssembly::BI__builtin_wasm_avgr_u_i16x8: { |
239 | Value *LHS = EmitScalarExpr(E: E->getArg(Arg: 0)); |
240 | Value *RHS = EmitScalarExpr(E: E->getArg(Arg: 1)); |
241 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_avgr_unsigned, |
242 | Tys: ConvertType(T: E->getType())); |
243 | return Builder.CreateCall(Callee, Args: {LHS, RHS}); |
244 | } |
245 | case WebAssembly::BI__builtin_wasm_q15mulr_sat_s_i16x8: { |
246 | Value *LHS = EmitScalarExpr(E: E->getArg(Arg: 0)); |
247 | Value *RHS = EmitScalarExpr(E: E->getArg(Arg: 1)); |
248 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_q15mulr_sat_signed); |
249 | return Builder.CreateCall(Callee, Args: {LHS, RHS}); |
250 | } |
251 | case WebAssembly::BI__builtin_wasm_extadd_pairwise_i8x16_s_i16x8: |
252 | case WebAssembly::BI__builtin_wasm_extadd_pairwise_i8x16_u_i16x8: |
253 | case WebAssembly::BI__builtin_wasm_extadd_pairwise_i16x8_s_i32x4: |
254 | case WebAssembly::BI__builtin_wasm_extadd_pairwise_i16x8_u_i32x4: { |
255 | Value *Vec = EmitScalarExpr(E: E->getArg(Arg: 0)); |
256 | unsigned IntNo; |
257 | switch (BuiltinID) { |
258 | case WebAssembly::BI__builtin_wasm_extadd_pairwise_i8x16_s_i16x8: |
259 | case WebAssembly::BI__builtin_wasm_extadd_pairwise_i16x8_s_i32x4: |
260 | IntNo = Intrinsic::wasm_extadd_pairwise_signed; |
261 | break; |
262 | case WebAssembly::BI__builtin_wasm_extadd_pairwise_i8x16_u_i16x8: |
263 | case WebAssembly::BI__builtin_wasm_extadd_pairwise_i16x8_u_i32x4: |
264 | IntNo = Intrinsic::wasm_extadd_pairwise_unsigned; |
265 | break; |
266 | default: |
267 | llvm_unreachable("unexpected builtin ID" ); |
268 | } |
269 | |
270 | Function *Callee = CGM.getIntrinsic(IID: IntNo, Tys: ConvertType(T: E->getType())); |
271 | return Builder.CreateCall(Callee, Args: Vec); |
272 | } |
273 | case WebAssembly::BI__builtin_wasm_bitselect: { |
274 | Value *V1 = EmitScalarExpr(E: E->getArg(Arg: 0)); |
275 | Value *V2 = EmitScalarExpr(E: E->getArg(Arg: 1)); |
276 | Value *C = EmitScalarExpr(E: E->getArg(Arg: 2)); |
277 | Function *Callee = |
278 | CGM.getIntrinsic(IID: Intrinsic::wasm_bitselect, Tys: ConvertType(T: E->getType())); |
279 | return Builder.CreateCall(Callee, Args: {V1, V2, C}); |
280 | } |
281 | case WebAssembly::BI__builtin_wasm_dot_s_i32x4_i16x8: { |
282 | Value *LHS = EmitScalarExpr(E: E->getArg(Arg: 0)); |
283 | Value *RHS = EmitScalarExpr(E: E->getArg(Arg: 1)); |
284 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_dot); |
285 | return Builder.CreateCall(Callee, Args: {LHS, RHS}); |
286 | } |
287 | case WebAssembly::BI__builtin_wasm_any_true_v128: |
288 | case WebAssembly::BI__builtin_wasm_all_true_i8x16: |
289 | case WebAssembly::BI__builtin_wasm_all_true_i16x8: |
290 | case WebAssembly::BI__builtin_wasm_all_true_i32x4: |
291 | case WebAssembly::BI__builtin_wasm_all_true_i64x2: { |
292 | unsigned IntNo; |
293 | switch (BuiltinID) { |
294 | case WebAssembly::BI__builtin_wasm_any_true_v128: |
295 | IntNo = Intrinsic::wasm_anytrue; |
296 | break; |
297 | case WebAssembly::BI__builtin_wasm_all_true_i8x16: |
298 | case WebAssembly::BI__builtin_wasm_all_true_i16x8: |
299 | case WebAssembly::BI__builtin_wasm_all_true_i32x4: |
300 | case WebAssembly::BI__builtin_wasm_all_true_i64x2: |
301 | IntNo = Intrinsic::wasm_alltrue; |
302 | break; |
303 | default: |
304 | llvm_unreachable("unexpected builtin ID" ); |
305 | } |
306 | Value *Vec = EmitScalarExpr(E: E->getArg(Arg: 0)); |
307 | Function *Callee = CGM.getIntrinsic(IID: IntNo, Tys: Vec->getType()); |
308 | return Builder.CreateCall(Callee, Args: {Vec}); |
309 | } |
310 | case WebAssembly::BI__builtin_wasm_bitmask_i8x16: |
311 | case WebAssembly::BI__builtin_wasm_bitmask_i16x8: |
312 | case WebAssembly::BI__builtin_wasm_bitmask_i32x4: |
313 | case WebAssembly::BI__builtin_wasm_bitmask_i64x2: { |
314 | Value *Vec = EmitScalarExpr(E: E->getArg(Arg: 0)); |
315 | Function *Callee = |
316 | CGM.getIntrinsic(IID: Intrinsic::wasm_bitmask, Tys: Vec->getType()); |
317 | return Builder.CreateCall(Callee, Args: {Vec}); |
318 | } |
319 | case WebAssembly::BI__builtin_wasm_abs_f16x8: |
320 | case WebAssembly::BI__builtin_wasm_abs_f32x4: |
321 | case WebAssembly::BI__builtin_wasm_abs_f64x2: { |
322 | Value *Vec = EmitScalarExpr(E: E->getArg(Arg: 0)); |
323 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::fabs, Tys: Vec->getType()); |
324 | return Builder.CreateCall(Callee, Args: {Vec}); |
325 | } |
326 | case WebAssembly::BI__builtin_wasm_sqrt_f16x8: |
327 | case WebAssembly::BI__builtin_wasm_sqrt_f32x4: |
328 | case WebAssembly::BI__builtin_wasm_sqrt_f64x2: { |
329 | Value *Vec = EmitScalarExpr(E: E->getArg(Arg: 0)); |
330 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::sqrt, Tys: Vec->getType()); |
331 | return Builder.CreateCall(Callee, Args: {Vec}); |
332 | } |
333 | case WebAssembly::BI__builtin_wasm_narrow_s_i8x16_i16x8: |
334 | case WebAssembly::BI__builtin_wasm_narrow_u_i8x16_i16x8: |
335 | case WebAssembly::BI__builtin_wasm_narrow_s_i16x8_i32x4: |
336 | case WebAssembly::BI__builtin_wasm_narrow_u_i16x8_i32x4: { |
337 | Value *Low = EmitScalarExpr(E: E->getArg(Arg: 0)); |
338 | Value *High = EmitScalarExpr(E: E->getArg(Arg: 1)); |
339 | unsigned IntNo; |
340 | switch (BuiltinID) { |
341 | case WebAssembly::BI__builtin_wasm_narrow_s_i8x16_i16x8: |
342 | case WebAssembly::BI__builtin_wasm_narrow_s_i16x8_i32x4: |
343 | IntNo = Intrinsic::wasm_narrow_signed; |
344 | break; |
345 | case WebAssembly::BI__builtin_wasm_narrow_u_i8x16_i16x8: |
346 | case WebAssembly::BI__builtin_wasm_narrow_u_i16x8_i32x4: |
347 | IntNo = Intrinsic::wasm_narrow_unsigned; |
348 | break; |
349 | default: |
350 | llvm_unreachable("unexpected builtin ID" ); |
351 | } |
352 | Function *Callee = |
353 | CGM.getIntrinsic(IID: IntNo, Tys: {ConvertType(T: E->getType()), Low->getType()}); |
354 | return Builder.CreateCall(Callee, Args: {Low, High}); |
355 | } |
356 | case WebAssembly::BI__builtin_wasm_trunc_sat_s_zero_f64x2_i32x4: |
357 | case WebAssembly::BI__builtin_wasm_trunc_sat_u_zero_f64x2_i32x4: { |
358 | Value *Vec = EmitScalarExpr(E: E->getArg(Arg: 0)); |
359 | unsigned IntNo; |
360 | switch (BuiltinID) { |
361 | case WebAssembly::BI__builtin_wasm_trunc_sat_s_zero_f64x2_i32x4: |
362 | IntNo = Intrinsic::fptosi_sat; |
363 | break; |
364 | case WebAssembly::BI__builtin_wasm_trunc_sat_u_zero_f64x2_i32x4: |
365 | IntNo = Intrinsic::fptoui_sat; |
366 | break; |
367 | default: |
368 | llvm_unreachable("unexpected builtin ID" ); |
369 | } |
370 | llvm::Type *SrcT = Vec->getType(); |
371 | llvm::Type *TruncT = SrcT->getWithNewType(EltTy: Builder.getInt32Ty()); |
372 | Function *Callee = CGM.getIntrinsic(IID: IntNo, Tys: {TruncT, SrcT}); |
373 | Value *Trunc = Builder.CreateCall(Callee, Args: Vec); |
374 | Value *Splat = Constant::getNullValue(Ty: TruncT); |
375 | return Builder.CreateShuffleVector(V1: Trunc, V2: Splat, Mask: {0, 1, 2, 3}); |
376 | } |
377 | case WebAssembly::BI__builtin_wasm_shuffle_i8x16: { |
378 | Value *Ops[18]; |
379 | size_t OpIdx = 0; |
380 | Ops[OpIdx++] = EmitScalarExpr(E: E->getArg(Arg: 0)); |
381 | Ops[OpIdx++] = EmitScalarExpr(E: E->getArg(Arg: 1)); |
382 | while (OpIdx < 18) { |
383 | std::optional<llvm::APSInt> LaneConst = |
384 | E->getArg(Arg: OpIdx)->getIntegerConstantExpr(Ctx: getContext()); |
385 | assert(LaneConst && "Constant arg isn't actually constant?" ); |
386 | Ops[OpIdx++] = llvm::ConstantInt::get(Context&: getLLVMContext(), V: *LaneConst); |
387 | } |
388 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_shuffle); |
389 | return Builder.CreateCall(Callee, Args: Ops); |
390 | } |
391 | case WebAssembly::BI__builtin_wasm_relaxed_madd_f16x8: |
392 | case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f16x8: |
393 | case WebAssembly::BI__builtin_wasm_relaxed_madd_f32x4: |
394 | case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f32x4: |
395 | case WebAssembly::BI__builtin_wasm_relaxed_madd_f64x2: |
396 | case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f64x2: { |
397 | Value *A = EmitScalarExpr(E: E->getArg(Arg: 0)); |
398 | Value *B = EmitScalarExpr(E: E->getArg(Arg: 1)); |
399 | Value *C = EmitScalarExpr(E: E->getArg(Arg: 2)); |
400 | unsigned IntNo; |
401 | switch (BuiltinID) { |
402 | case WebAssembly::BI__builtin_wasm_relaxed_madd_f16x8: |
403 | case WebAssembly::BI__builtin_wasm_relaxed_madd_f32x4: |
404 | case WebAssembly::BI__builtin_wasm_relaxed_madd_f64x2: |
405 | IntNo = Intrinsic::wasm_relaxed_madd; |
406 | break; |
407 | case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f16x8: |
408 | case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f32x4: |
409 | case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f64x2: |
410 | IntNo = Intrinsic::wasm_relaxed_nmadd; |
411 | break; |
412 | default: |
413 | llvm_unreachable("unexpected builtin ID" ); |
414 | } |
415 | Function *Callee = CGM.getIntrinsic(IID: IntNo, Tys: A->getType()); |
416 | return Builder.CreateCall(Callee, Args: {A, B, C}); |
417 | } |
418 | case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i8x16: |
419 | case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i16x8: |
420 | case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i32x4: |
421 | case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i64x2: { |
422 | Value *A = EmitScalarExpr(E: E->getArg(Arg: 0)); |
423 | Value *B = EmitScalarExpr(E: E->getArg(Arg: 1)); |
424 | Value *C = EmitScalarExpr(E: E->getArg(Arg: 2)); |
425 | Function *Callee = |
426 | CGM.getIntrinsic(IID: Intrinsic::wasm_relaxed_laneselect, Tys: A->getType()); |
427 | return Builder.CreateCall(Callee, Args: {A, B, C}); |
428 | } |
429 | case WebAssembly::BI__builtin_wasm_relaxed_swizzle_i8x16: { |
430 | Value *Src = EmitScalarExpr(E: E->getArg(Arg: 0)); |
431 | Value *Indices = EmitScalarExpr(E: E->getArg(Arg: 1)); |
432 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_relaxed_swizzle); |
433 | return Builder.CreateCall(Callee, Args: {Src, Indices}); |
434 | } |
435 | case WebAssembly::BI__builtin_wasm_relaxed_min_f32x4: |
436 | case WebAssembly::BI__builtin_wasm_relaxed_max_f32x4: |
437 | case WebAssembly::BI__builtin_wasm_relaxed_min_f64x2: |
438 | case WebAssembly::BI__builtin_wasm_relaxed_max_f64x2: { |
439 | Value *LHS = EmitScalarExpr(E: E->getArg(Arg: 0)); |
440 | Value *RHS = EmitScalarExpr(E: E->getArg(Arg: 1)); |
441 | unsigned IntNo; |
442 | switch (BuiltinID) { |
443 | case WebAssembly::BI__builtin_wasm_relaxed_min_f32x4: |
444 | case WebAssembly::BI__builtin_wasm_relaxed_min_f64x2: |
445 | IntNo = Intrinsic::wasm_relaxed_min; |
446 | break; |
447 | case WebAssembly::BI__builtin_wasm_relaxed_max_f32x4: |
448 | case WebAssembly::BI__builtin_wasm_relaxed_max_f64x2: |
449 | IntNo = Intrinsic::wasm_relaxed_max; |
450 | break; |
451 | default: |
452 | llvm_unreachable("unexpected builtin ID" ); |
453 | } |
454 | Function *Callee = CGM.getIntrinsic(IID: IntNo, Tys: LHS->getType()); |
455 | return Builder.CreateCall(Callee, Args: {LHS, RHS}); |
456 | } |
457 | case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_i32x4_f32x4: |
458 | case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_i32x4_f32x4: |
459 | case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_zero_i32x4_f64x2: |
460 | case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_zero_i32x4_f64x2: { |
461 | Value *Vec = EmitScalarExpr(E: E->getArg(Arg: 0)); |
462 | unsigned IntNo; |
463 | switch (BuiltinID) { |
464 | case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_i32x4_f32x4: |
465 | IntNo = Intrinsic::wasm_relaxed_trunc_signed; |
466 | break; |
467 | case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_i32x4_f32x4: |
468 | IntNo = Intrinsic::wasm_relaxed_trunc_unsigned; |
469 | break; |
470 | case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_zero_i32x4_f64x2: |
471 | IntNo = Intrinsic::wasm_relaxed_trunc_signed_zero; |
472 | break; |
473 | case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_zero_i32x4_f64x2: |
474 | IntNo = Intrinsic::wasm_relaxed_trunc_unsigned_zero; |
475 | break; |
476 | default: |
477 | llvm_unreachable("unexpected builtin ID" ); |
478 | } |
479 | Function *Callee = CGM.getIntrinsic(IID: IntNo); |
480 | return Builder.CreateCall(Callee, Args: {Vec}); |
481 | } |
482 | case WebAssembly::BI__builtin_wasm_relaxed_q15mulr_s_i16x8: { |
483 | Value *LHS = EmitScalarExpr(E: E->getArg(Arg: 0)); |
484 | Value *RHS = EmitScalarExpr(E: E->getArg(Arg: 1)); |
485 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_relaxed_q15mulr_signed); |
486 | return Builder.CreateCall(Callee, Args: {LHS, RHS}); |
487 | } |
488 | case WebAssembly::BI__builtin_wasm_relaxed_dot_i8x16_i7x16_s_i16x8: { |
489 | Value *LHS = EmitScalarExpr(E: E->getArg(Arg: 0)); |
490 | Value *RHS = EmitScalarExpr(E: E->getArg(Arg: 1)); |
491 | Function *Callee = |
492 | CGM.getIntrinsic(IID: Intrinsic::wasm_relaxed_dot_i8x16_i7x16_signed); |
493 | return Builder.CreateCall(Callee, Args: {LHS, RHS}); |
494 | } |
495 | case WebAssembly::BI__builtin_wasm_relaxed_dot_i8x16_i7x16_add_s_i32x4: { |
496 | Value *LHS = EmitScalarExpr(E: E->getArg(Arg: 0)); |
497 | Value *RHS = EmitScalarExpr(E: E->getArg(Arg: 1)); |
498 | Value *Acc = EmitScalarExpr(E: E->getArg(Arg: 2)); |
499 | Function *Callee = |
500 | CGM.getIntrinsic(IID: Intrinsic::wasm_relaxed_dot_i8x16_i7x16_add_signed); |
501 | return Builder.CreateCall(Callee, Args: {LHS, RHS, Acc}); |
502 | } |
503 | case WebAssembly::BI__builtin_wasm_relaxed_dot_bf16x8_add_f32_f32x4: { |
504 | Value *LHS = EmitScalarExpr(E: E->getArg(Arg: 0)); |
505 | Value *RHS = EmitScalarExpr(E: E->getArg(Arg: 1)); |
506 | Value *Acc = EmitScalarExpr(E: E->getArg(Arg: 2)); |
507 | Function *Callee = |
508 | CGM.getIntrinsic(IID: Intrinsic::wasm_relaxed_dot_bf16x8_add_f32); |
509 | return Builder.CreateCall(Callee, Args: {LHS, RHS, Acc}); |
510 | } |
511 | case WebAssembly::BI__builtin_wasm_loadf16_f32: { |
512 | Value *Addr = EmitScalarExpr(E: E->getArg(Arg: 0)); |
513 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_loadf16_f32); |
514 | return Builder.CreateCall(Callee, Args: {Addr}); |
515 | } |
516 | case WebAssembly::BI__builtin_wasm_storef16_f32: { |
517 | Value *Val = EmitScalarExpr(E: E->getArg(Arg: 0)); |
518 | Value *Addr = EmitScalarExpr(E: E->getArg(Arg: 1)); |
519 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_storef16_f32); |
520 | return Builder.CreateCall(Callee, Args: {Val, Addr}); |
521 | } |
522 | case WebAssembly::BI__builtin_wasm_splat_f16x8: { |
523 | Value *Val = EmitScalarExpr(E: E->getArg(Arg: 0)); |
524 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_splat_f16x8); |
525 | return Builder.CreateCall(Callee, Args: {Val}); |
526 | } |
527 | case WebAssembly::BI__builtin_wasm_extract_lane_f16x8: { |
528 | Value *Vector = EmitScalarExpr(E: E->getArg(Arg: 0)); |
529 | Value *Index = EmitScalarExpr(E: E->getArg(Arg: 1)); |
530 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_extract_lane_f16x8); |
531 | return Builder.CreateCall(Callee, Args: {Vector, Index}); |
532 | } |
533 | case WebAssembly::BI__builtin_wasm_replace_lane_f16x8: { |
534 | Value *Vector = EmitScalarExpr(E: E->getArg(Arg: 0)); |
535 | Value *Index = EmitScalarExpr(E: E->getArg(Arg: 1)); |
536 | Value *Val = EmitScalarExpr(E: E->getArg(Arg: 2)); |
537 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_replace_lane_f16x8); |
538 | return Builder.CreateCall(Callee, Args: {Vector, Index, Val}); |
539 | } |
540 | case WebAssembly::BI__builtin_wasm_table_get: { |
541 | assert(E->getArg(0)->getType()->isArrayType()); |
542 | Value *Table = EmitArrayToPointerDecay(Array: E->getArg(Arg: 0)).emitRawPointer(CGF&: *this); |
543 | Value *Index = EmitScalarExpr(E: E->getArg(Arg: 1)); |
544 | Function *Callee; |
545 | if (E->getType().isWebAssemblyExternrefType()) |
546 | Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_table_get_externref); |
547 | else if (E->getType().isWebAssemblyFuncrefType()) |
548 | Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_table_get_funcref); |
549 | else |
550 | llvm_unreachable( |
551 | "Unexpected reference type for __builtin_wasm_table_get" ); |
552 | return Builder.CreateCall(Callee, Args: {Table, Index}); |
553 | } |
554 | case WebAssembly::BI__builtin_wasm_table_set: { |
555 | assert(E->getArg(0)->getType()->isArrayType()); |
556 | Value *Table = EmitArrayToPointerDecay(Array: E->getArg(Arg: 0)).emitRawPointer(CGF&: *this); |
557 | Value *Index = EmitScalarExpr(E: E->getArg(Arg: 1)); |
558 | Value *Val = EmitScalarExpr(E: E->getArg(Arg: 2)); |
559 | Function *Callee; |
560 | if (E->getArg(Arg: 2)->getType().isWebAssemblyExternrefType()) |
561 | Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_table_set_externref); |
562 | else if (E->getArg(Arg: 2)->getType().isWebAssemblyFuncrefType()) |
563 | Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_table_set_funcref); |
564 | else |
565 | llvm_unreachable( |
566 | "Unexpected reference type for __builtin_wasm_table_set" ); |
567 | return Builder.CreateCall(Callee, Args: {Table, Index, Val}); |
568 | } |
569 | case WebAssembly::BI__builtin_wasm_table_size: { |
570 | assert(E->getArg(0)->getType()->isArrayType()); |
571 | Value *Value = EmitArrayToPointerDecay(Array: E->getArg(Arg: 0)).emitRawPointer(CGF&: *this); |
572 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_table_size); |
573 | return Builder.CreateCall(Callee, Args: Value); |
574 | } |
575 | case WebAssembly::BI__builtin_wasm_table_grow: { |
576 | assert(E->getArg(0)->getType()->isArrayType()); |
577 | Value *Table = EmitArrayToPointerDecay(Array: E->getArg(Arg: 0)).emitRawPointer(CGF&: *this); |
578 | Value *Val = EmitScalarExpr(E: E->getArg(Arg: 1)); |
579 | Value *NElems = EmitScalarExpr(E: E->getArg(Arg: 2)); |
580 | |
581 | Function *Callee; |
582 | if (E->getArg(Arg: 1)->getType().isWebAssemblyExternrefType()) |
583 | Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_table_grow_externref); |
584 | else if (E->getArg(Arg: 2)->getType().isWebAssemblyFuncrefType()) |
585 | Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_table_fill_funcref); |
586 | else |
587 | llvm_unreachable( |
588 | "Unexpected reference type for __builtin_wasm_table_grow" ); |
589 | |
590 | return Builder.CreateCall(Callee, Args: {Table, Val, NElems}); |
591 | } |
592 | case WebAssembly::BI__builtin_wasm_table_fill: { |
593 | assert(E->getArg(0)->getType()->isArrayType()); |
594 | Value *Table = EmitArrayToPointerDecay(Array: E->getArg(Arg: 0)).emitRawPointer(CGF&: *this); |
595 | Value *Index = EmitScalarExpr(E: E->getArg(Arg: 1)); |
596 | Value *Val = EmitScalarExpr(E: E->getArg(Arg: 2)); |
597 | Value *NElems = EmitScalarExpr(E: E->getArg(Arg: 3)); |
598 | |
599 | Function *Callee; |
600 | if (E->getArg(Arg: 2)->getType().isWebAssemblyExternrefType()) |
601 | Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_table_fill_externref); |
602 | else if (E->getArg(Arg: 2)->getType().isWebAssemblyFuncrefType()) |
603 | Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_table_fill_funcref); |
604 | else |
605 | llvm_unreachable( |
606 | "Unexpected reference type for __builtin_wasm_table_fill" ); |
607 | |
608 | return Builder.CreateCall(Callee, Args: {Table, Index, Val, NElems}); |
609 | } |
610 | case WebAssembly::BI__builtin_wasm_table_copy: { |
611 | assert(E->getArg(0)->getType()->isArrayType()); |
612 | Value *TableX = EmitArrayToPointerDecay(Array: E->getArg(Arg: 0)).emitRawPointer(CGF&: *this); |
613 | Value *TableY = EmitArrayToPointerDecay(Array: E->getArg(Arg: 1)).emitRawPointer(CGF&: *this); |
614 | Value *DstIdx = EmitScalarExpr(E: E->getArg(Arg: 2)); |
615 | Value *SrcIdx = EmitScalarExpr(E: E->getArg(Arg: 3)); |
616 | Value *NElems = EmitScalarExpr(E: E->getArg(Arg: 4)); |
617 | |
618 | Function *Callee = CGM.getIntrinsic(IID: Intrinsic::wasm_table_copy); |
619 | |
620 | return Builder.CreateCall(Callee, Args: {TableX, TableY, SrcIdx, DstIdx, NElems}); |
621 | } |
622 | default: |
623 | return nullptr; |
624 | } |
625 | } |
626 | |