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
17using namespace clang;
18using namespace CodeGen;
19using namespace llvm;
20
21Value *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