xref: /freebsd/contrib/llvm-project/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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(E->getType());
26     Value *I = EmitScalarExpr(E->getArg(0));
27     Function *Callee =
28         CGM.getIntrinsic(Intrinsic::wasm_memory_size, ResultType);
29     return Builder.CreateCall(Callee, I);
30   }
31   case WebAssembly::BI__builtin_wasm_memory_grow: {
32     llvm::Type *ResultType = ConvertType(E->getType());
33     Value *Args[] = {EmitScalarExpr(E->getArg(0)),
34                      EmitScalarExpr(E->getArg(1))};
35     Function *Callee =
36         CGM.getIntrinsic(Intrinsic::wasm_memory_grow, ResultType);
37     return Builder.CreateCall(Callee, Args);
38   }
39   case WebAssembly::BI__builtin_wasm_tls_size: {
40     llvm::Type *ResultType = ConvertType(E->getType());
41     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_size, ResultType);
42     return Builder.CreateCall(Callee);
43   }
44   case WebAssembly::BI__builtin_wasm_tls_align: {
45     llvm::Type *ResultType = ConvertType(E->getType());
46     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_align, ResultType);
47     return Builder.CreateCall(Callee);
48   }
49   case WebAssembly::BI__builtin_wasm_tls_base: {
50     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_base);
51     return Builder.CreateCall(Callee);
52   }
53   case WebAssembly::BI__builtin_wasm_throw: {
54     Value *Tag = EmitScalarExpr(E->getArg(0));
55     Value *Obj = EmitScalarExpr(E->getArg(1));
56     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_throw);
57     return EmitRuntimeCallOrInvoke(Callee, {Tag, Obj});
58   }
59   case WebAssembly::BI__builtin_wasm_rethrow: {
60     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_rethrow);
61     return EmitRuntimeCallOrInvoke(Callee);
62   }
63   case WebAssembly::BI__builtin_wasm_memory_atomic_wait32: {
64     Value *Addr = EmitScalarExpr(E->getArg(0));
65     Value *Expected = EmitScalarExpr(E->getArg(1));
66     Value *Timeout = EmitScalarExpr(E->getArg(2));
67     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memory_atomic_wait32);
68     return Builder.CreateCall(Callee, {Addr, Expected, Timeout});
69   }
70   case WebAssembly::BI__builtin_wasm_memory_atomic_wait64: {
71     Value *Addr = EmitScalarExpr(E->getArg(0));
72     Value *Expected = EmitScalarExpr(E->getArg(1));
73     Value *Timeout = EmitScalarExpr(E->getArg(2));
74     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memory_atomic_wait64);
75     return Builder.CreateCall(Callee, {Addr, Expected, Timeout});
76   }
77   case WebAssembly::BI__builtin_wasm_memory_atomic_notify: {
78     Value *Addr = EmitScalarExpr(E->getArg(0));
79     Value *Count = EmitScalarExpr(E->getArg(1));
80     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memory_atomic_notify);
81     return Builder.CreateCall(Callee, {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->getArg(0));
88     llvm::Type *ResT = ConvertType(E->getType());
89     Function *Callee =
90         CGM.getIntrinsic(Intrinsic::wasm_trunc_signed, {ResT, Src->getType()});
91     return Builder.CreateCall(Callee, {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->getArg(0));
98     llvm::Type *ResT = ConvertType(E->getType());
99     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_trunc_unsigned,
100                                         {ResT, Src->getType()});
101     return Builder.CreateCall(Callee, {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->getArg(0));
110     llvm::Type *ResT = ConvertType(E->getType());
111     Function *Callee =
112         CGM.getIntrinsic(Intrinsic::fptosi_sat, {ResT, Src->getType()});
113     return Builder.CreateCall(Callee, {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->getArg(0));
122     llvm::Type *ResT = ConvertType(E->getType());
123     Function *Callee =
124         CGM.getIntrinsic(Intrinsic::fptoui_sat, {ResT, Src->getType()});
125     return Builder.CreateCall(Callee, {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->getArg(0));
133     Value *RHS = EmitScalarExpr(E->getArg(1));
134     Function *Callee =
135         CGM.getIntrinsic(Intrinsic::minimum, ConvertType(E->getType()));
136     return Builder.CreateCall(Callee, {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->getArg(0));
144     Value *RHS = EmitScalarExpr(E->getArg(1));
145     Function *Callee =
146         CGM.getIntrinsic(Intrinsic::maximum, ConvertType(E->getType()));
147     return Builder.CreateCall(Callee, {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->getArg(0));
153     Value *RHS = EmitScalarExpr(E->getArg(1));
154     Function *Callee =
155         CGM.getIntrinsic(Intrinsic::wasm_pmin, ConvertType(E->getType()));
156     return Builder.CreateCall(Callee, {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->getArg(0));
162     Value *RHS = EmitScalarExpr(E->getArg(1));
163     Function *Callee =
164         CGM.getIntrinsic(Intrinsic::wasm_pmax, ConvertType(E->getType()));
165     return Builder.CreateCall(Callee, {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->getArg(0));
205     Function *Callee = CGM.getIntrinsic(IntNo, ConvertType(E->getType()));
206     return Builder.CreateCall(Callee, Value);
207   }
208   case WebAssembly::BI__builtin_wasm_ref_null_extern: {
209     Function *Callee = CGM.getIntrinsic(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->getArg(0));
214     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_is_null_extern);
215     return Builder.CreateCall(Callee, {Src});
216   }
217   case WebAssembly::BI__builtin_wasm_ref_null_func: {
218     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_null_func);
219     return Builder.CreateCall(Callee);
220   }
221   case WebAssembly::BI__builtin_wasm_swizzle_i8x16: {
222     Value *Src = EmitScalarExpr(E->getArg(0));
223     Value *Indices = EmitScalarExpr(E->getArg(1));
224     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_swizzle);
225     return Builder.CreateCall(Callee, {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->getArg(0));
232     Value *Neg = Builder.CreateNeg(Vec, "neg");
233     Constant *Zero = llvm::Constant::getNullValue(Vec->getType());
234     Value *ICmp = Builder.CreateICmpSLT(Vec, Zero, "abscond");
235     return Builder.CreateSelect(ICmp, Neg, Vec, "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->getArg(0));
240     Value *RHS = EmitScalarExpr(E->getArg(1));
241     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_avgr_unsigned,
242                                         ConvertType(E->getType()));
243     return Builder.CreateCall(Callee, {LHS, RHS});
244   }
245   case WebAssembly::BI__builtin_wasm_q15mulr_sat_s_i16x8: {
246     Value *LHS = EmitScalarExpr(E->getArg(0));
247     Value *RHS = EmitScalarExpr(E->getArg(1));
248     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_q15mulr_sat_signed);
249     return Builder.CreateCall(Callee, {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->getArg(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(IntNo, ConvertType(E->getType()));
271     return Builder.CreateCall(Callee, Vec);
272   }
273   case WebAssembly::BI__builtin_wasm_bitselect: {
274     Value *V1 = EmitScalarExpr(E->getArg(0));
275     Value *V2 = EmitScalarExpr(E->getArg(1));
276     Value *C = EmitScalarExpr(E->getArg(2));
277     Function *Callee =
278         CGM.getIntrinsic(Intrinsic::wasm_bitselect, ConvertType(E->getType()));
279     return Builder.CreateCall(Callee, {V1, V2, C});
280   }
281   case WebAssembly::BI__builtin_wasm_dot_s_i32x4_i16x8: {
282     Value *LHS = EmitScalarExpr(E->getArg(0));
283     Value *RHS = EmitScalarExpr(E->getArg(1));
284     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_dot);
285     return Builder.CreateCall(Callee, {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->getArg(0));
307     Function *Callee = CGM.getIntrinsic(IntNo, Vec->getType());
308     return Builder.CreateCall(Callee, {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->getArg(0));
315     Function *Callee =
316         CGM.getIntrinsic(Intrinsic::wasm_bitmask, Vec->getType());
317     return Builder.CreateCall(Callee, {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->getArg(0));
323     Function *Callee = CGM.getIntrinsic(Intrinsic::fabs, Vec->getType());
324     return Builder.CreateCall(Callee, {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->getArg(0));
330     Function *Callee = CGM.getIntrinsic(Intrinsic::sqrt, Vec->getType());
331     return Builder.CreateCall(Callee, {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->getArg(0));
338     Value *High = EmitScalarExpr(E->getArg(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(IntNo, {ConvertType(E->getType()), Low->getType()});
354     return Builder.CreateCall(Callee, {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->getArg(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(Builder.getInt32Ty());
372     Function *Callee = CGM.getIntrinsic(IntNo, {TruncT, SrcT});
373     Value *Trunc = Builder.CreateCall(Callee, Vec);
374     Value *Splat = Constant::getNullValue(TruncT);
375     return Builder.CreateShuffleVector(Trunc, Splat, {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->getArg(0));
381     Ops[OpIdx++] = EmitScalarExpr(E->getArg(1));
382     while (OpIdx < 18) {
383       std::optional<llvm::APSInt> LaneConst =
384           E->getArg(OpIdx)->getIntegerConstantExpr(getContext());
385       assert(LaneConst && "Constant arg isn't actually constant?");
386       Ops[OpIdx++] = llvm::ConstantInt::get(getLLVMContext(), *LaneConst);
387     }
388     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_shuffle);
389     return Builder.CreateCall(Callee, 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->getArg(0));
398     Value *B = EmitScalarExpr(E->getArg(1));
399     Value *C = EmitScalarExpr(E->getArg(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(IntNo, A->getType());
416     return Builder.CreateCall(Callee, {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->getArg(0));
423     Value *B = EmitScalarExpr(E->getArg(1));
424     Value *C = EmitScalarExpr(E->getArg(2));
425     Function *Callee =
426         CGM.getIntrinsic(Intrinsic::wasm_relaxed_laneselect, A->getType());
427     return Builder.CreateCall(Callee, {A, B, C});
428   }
429   case WebAssembly::BI__builtin_wasm_relaxed_swizzle_i8x16: {
430     Value *Src = EmitScalarExpr(E->getArg(0));
431     Value *Indices = EmitScalarExpr(E->getArg(1));
432     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_relaxed_swizzle);
433     return Builder.CreateCall(Callee, {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->getArg(0));
440     Value *RHS = EmitScalarExpr(E->getArg(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(IntNo, LHS->getType());
455     return Builder.CreateCall(Callee, {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->getArg(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(IntNo);
480     return Builder.CreateCall(Callee, {Vec});
481   }
482   case WebAssembly::BI__builtin_wasm_relaxed_q15mulr_s_i16x8: {
483     Value *LHS = EmitScalarExpr(E->getArg(0));
484     Value *RHS = EmitScalarExpr(E->getArg(1));
485     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_relaxed_q15mulr_signed);
486     return Builder.CreateCall(Callee, {LHS, RHS});
487   }
488   case WebAssembly::BI__builtin_wasm_relaxed_dot_i8x16_i7x16_s_i16x8: {
489     Value *LHS = EmitScalarExpr(E->getArg(0));
490     Value *RHS = EmitScalarExpr(E->getArg(1));
491     Function *Callee =
492         CGM.getIntrinsic(Intrinsic::wasm_relaxed_dot_i8x16_i7x16_signed);
493     return Builder.CreateCall(Callee, {LHS, RHS});
494   }
495   case WebAssembly::BI__builtin_wasm_relaxed_dot_i8x16_i7x16_add_s_i32x4: {
496     Value *LHS = EmitScalarExpr(E->getArg(0));
497     Value *RHS = EmitScalarExpr(E->getArg(1));
498     Value *Acc = EmitScalarExpr(E->getArg(2));
499     Function *Callee =
500         CGM.getIntrinsic(Intrinsic::wasm_relaxed_dot_i8x16_i7x16_add_signed);
501     return Builder.CreateCall(Callee, {LHS, RHS, Acc});
502   }
503   case WebAssembly::BI__builtin_wasm_relaxed_dot_bf16x8_add_f32_f32x4: {
504     Value *LHS = EmitScalarExpr(E->getArg(0));
505     Value *RHS = EmitScalarExpr(E->getArg(1));
506     Value *Acc = EmitScalarExpr(E->getArg(2));
507     Function *Callee =
508         CGM.getIntrinsic(Intrinsic::wasm_relaxed_dot_bf16x8_add_f32);
509     return Builder.CreateCall(Callee, {LHS, RHS, Acc});
510   }
511   case WebAssembly::BI__builtin_wasm_loadf16_f32: {
512     Value *Addr = EmitScalarExpr(E->getArg(0));
513     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_loadf16_f32);
514     return Builder.CreateCall(Callee, {Addr});
515   }
516   case WebAssembly::BI__builtin_wasm_storef16_f32: {
517     Value *Val = EmitScalarExpr(E->getArg(0));
518     Value *Addr = EmitScalarExpr(E->getArg(1));
519     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_storef16_f32);
520     return Builder.CreateCall(Callee, {Val, Addr});
521   }
522   case WebAssembly::BI__builtin_wasm_splat_f16x8: {
523     Value *Val = EmitScalarExpr(E->getArg(0));
524     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_splat_f16x8);
525     return Builder.CreateCall(Callee, {Val});
526   }
527   case WebAssembly::BI__builtin_wasm_extract_lane_f16x8: {
528     Value *Vector = EmitScalarExpr(E->getArg(0));
529     Value *Index = EmitScalarExpr(E->getArg(1));
530     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_extract_lane_f16x8);
531     return Builder.CreateCall(Callee, {Vector, Index});
532   }
533   case WebAssembly::BI__builtin_wasm_replace_lane_f16x8: {
534     Value *Vector = EmitScalarExpr(E->getArg(0));
535     Value *Index = EmitScalarExpr(E->getArg(1));
536     Value *Val = EmitScalarExpr(E->getArg(2));
537     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_replace_lane_f16x8);
538     return Builder.CreateCall(Callee, {Vector, Index, Val});
539   }
540   case WebAssembly::BI__builtin_wasm_table_get: {
541     assert(E->getArg(0)->getType()->isArrayType());
542     Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
543     Value *Index = EmitScalarExpr(E->getArg(1));
544     Function *Callee;
545     if (E->getType().isWebAssemblyExternrefType())
546       Callee = CGM.getIntrinsic(Intrinsic::wasm_table_get_externref);
547     else if (E->getType().isWebAssemblyFuncrefType())
548       Callee = CGM.getIntrinsic(Intrinsic::wasm_table_get_funcref);
549     else
550       llvm_unreachable(
551           "Unexpected reference type for __builtin_wasm_table_get");
552     return Builder.CreateCall(Callee, {Table, Index});
553   }
554   case WebAssembly::BI__builtin_wasm_table_set: {
555     assert(E->getArg(0)->getType()->isArrayType());
556     Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
557     Value *Index = EmitScalarExpr(E->getArg(1));
558     Value *Val = EmitScalarExpr(E->getArg(2));
559     Function *Callee;
560     if (E->getArg(2)->getType().isWebAssemblyExternrefType())
561       Callee = CGM.getIntrinsic(Intrinsic::wasm_table_set_externref);
562     else if (E->getArg(2)->getType().isWebAssemblyFuncrefType())
563       Callee = CGM.getIntrinsic(Intrinsic::wasm_table_set_funcref);
564     else
565       llvm_unreachable(
566           "Unexpected reference type for __builtin_wasm_table_set");
567     return Builder.CreateCall(Callee, {Table, Index, Val});
568   }
569   case WebAssembly::BI__builtin_wasm_table_size: {
570     assert(E->getArg(0)->getType()->isArrayType());
571     Value *Value = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
572     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_table_size);
573     return Builder.CreateCall(Callee, Value);
574   }
575   case WebAssembly::BI__builtin_wasm_table_grow: {
576     assert(E->getArg(0)->getType()->isArrayType());
577     Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
578     Value *Val = EmitScalarExpr(E->getArg(1));
579     Value *NElems = EmitScalarExpr(E->getArg(2));
580 
581     Function *Callee;
582     if (E->getArg(1)->getType().isWebAssemblyExternrefType())
583       Callee = CGM.getIntrinsic(Intrinsic::wasm_table_grow_externref);
584     else if (E->getArg(2)->getType().isWebAssemblyFuncrefType())
585       Callee = CGM.getIntrinsic(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, {Table, Val, NElems});
591   }
592   case WebAssembly::BI__builtin_wasm_table_fill: {
593     assert(E->getArg(0)->getType()->isArrayType());
594     Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
595     Value *Index = EmitScalarExpr(E->getArg(1));
596     Value *Val = EmitScalarExpr(E->getArg(2));
597     Value *NElems = EmitScalarExpr(E->getArg(3));
598 
599     Function *Callee;
600     if (E->getArg(2)->getType().isWebAssemblyExternrefType())
601       Callee = CGM.getIntrinsic(Intrinsic::wasm_table_fill_externref);
602     else if (E->getArg(2)->getType().isWebAssemblyFuncrefType())
603       Callee = CGM.getIntrinsic(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, {Table, Index, Val, NElems});
609   }
610   case WebAssembly::BI__builtin_wasm_table_copy: {
611     assert(E->getArg(0)->getType()->isArrayType());
612     Value *TableX = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
613     Value *TableY = EmitArrayToPointerDecay(E->getArg(1)).emitRawPointer(*this);
614     Value *DstIdx = EmitScalarExpr(E->getArg(2));
615     Value *SrcIdx = EmitScalarExpr(E->getArg(3));
616     Value *NElems = EmitScalarExpr(E->getArg(4));
617 
618     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_table_copy);
619 
620     return Builder.CreateCall(Callee, {TableX, TableY, SrcIdx, DstIdx, NElems});
621   }
622   default:
623     return nullptr;
624   }
625 }
626