clang 24.0.0git
WebAssembly.cpp
Go to the documentation of this file.
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"
15#include "llvm/ADT/APInt.h"
16#include "llvm/IR/Constants.h"
17#include "llvm/IR/IntrinsicsWebAssembly.h"
18#include "llvm/Support/ErrorHandling.h"
19
20using namespace clang;
21using namespace CodeGen;
22using namespace llvm;
23
25 const CallExpr *E) {
26 switch (BuiltinID) {
27 case WebAssembly::BI__builtin_wasm_memory_size: {
28 llvm::Type *ResultType = ConvertType(E->getType());
29 Value *I = EmitScalarExpr(E->getArg(0));
30 Function *Callee =
31 CGM.getIntrinsic(Intrinsic::wasm_memory_size, ResultType);
32 return Builder.CreateCall(Callee, I);
33 }
34 case WebAssembly::BI__builtin_wasm_memory_grow: {
35 llvm::Type *ResultType = ConvertType(E->getType());
36 Value *Args[] = {EmitScalarExpr(E->getArg(0)),
37 EmitScalarExpr(E->getArg(1))};
38 Function *Callee =
39 CGM.getIntrinsic(Intrinsic::wasm_memory_grow, ResultType);
40 return Builder.CreateCall(Callee, Args);
41 }
42 case WebAssembly::BI__builtin_wasm_memory_copy: {
43 Value *DstMem = EmitScalarExpr(E->getArg(0));
44 Value *SrcMem = EmitScalarExpr(E->getArg(1));
45 Value *Dst = EmitScalarExpr(E->getArg(2));
46 Value *Src = EmitScalarExpr(E->getArg(3));
47 Value *Size = EmitScalarExpr(E->getArg(4));
48 Function *Callee =
49 CGM.getIntrinsic(Intrinsic::wasm_memory_copy, Size->getType());
50 return Builder.CreateCall(Callee, {DstMem, SrcMem, Dst, Src, Size});
51 }
52 case WebAssembly::BI__builtin_wasm_memory_fill: {
53 Value *Mem = EmitScalarExpr(E->getArg(0));
54 Value *Dst = EmitScalarExpr(E->getArg(1));
55 Value *Val = EmitScalarExpr(E->getArg(2));
56 Value *Size = EmitScalarExpr(E->getArg(3));
57 Function *Callee =
58 CGM.getIntrinsic(Intrinsic::wasm_memory_fill, Size->getType());
59 return Builder.CreateCall(Callee, {Mem, Dst, Val, Size});
60 }
61 case WebAssembly::BI__builtin_wasm_tls_size: {
62 llvm::Type *ResultType = ConvertType(E->getType());
63 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_size, ResultType);
64 return Builder.CreateCall(Callee);
65 }
66 case WebAssembly::BI__builtin_wasm_tls_align: {
67 llvm::Type *ResultType = ConvertType(E->getType());
68 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_align, ResultType);
69 return Builder.CreateCall(Callee);
70 }
71 case WebAssembly::BI__builtin_wasm_tls_base: {
72 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_base);
73 return Builder.CreateCall(Callee);
74 }
75 case WebAssembly::BI__builtin_wasm_throw: {
76 Value *Tag = EmitScalarExpr(E->getArg(0));
77 Value *Obj = EmitScalarExpr(E->getArg(1));
78 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_throw);
79 return EmitRuntimeCallOrInvoke(Callee, {Tag, Obj});
80 }
81 case WebAssembly::BI__builtin_wasm_rethrow: {
82 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_rethrow);
83 return EmitRuntimeCallOrInvoke(Callee);
84 }
85 case WebAssembly::BI__builtin_wasm_memory_atomic_wait32: {
88 Value *Timeout = EmitScalarExpr(E->getArg(2));
89 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memory_atomic_wait32);
90 return Builder.CreateCall(Callee, {Addr, Expected, Timeout});
91 }
92 case WebAssembly::BI__builtin_wasm_memory_atomic_wait64: {
95 Value *Timeout = EmitScalarExpr(E->getArg(2));
96 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memory_atomic_wait64);
97 return Builder.CreateCall(Callee, {Addr, Expected, Timeout});
98 }
99 case WebAssembly::BI__builtin_wasm_memory_atomic_notify: {
101 Value *Count = EmitScalarExpr(E->getArg(1));
102 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memory_atomic_notify);
103 return Builder.CreateCall(Callee, {Addr, Count});
104 }
105 case WebAssembly::BI__builtin_wasm_trunc_s_i32_f32:
106 case WebAssembly::BI__builtin_wasm_trunc_s_i32_f64:
107 case WebAssembly::BI__builtin_wasm_trunc_s_i64_f32:
108 case WebAssembly::BI__builtin_wasm_trunc_s_i64_f64: {
109 Value *Src = EmitScalarExpr(E->getArg(0));
110 llvm::Type *ResT = ConvertType(E->getType());
111 Function *Callee =
112 CGM.getIntrinsic(Intrinsic::wasm_trunc_signed, {ResT, Src->getType()});
113 return Builder.CreateCall(Callee, {Src});
114 }
115 case WebAssembly::BI__builtin_wasm_trunc_u_i32_f32:
116 case WebAssembly::BI__builtin_wasm_trunc_u_i32_f64:
117 case WebAssembly::BI__builtin_wasm_trunc_u_i64_f32:
118 case WebAssembly::BI__builtin_wasm_trunc_u_i64_f64: {
119 Value *Src = EmitScalarExpr(E->getArg(0));
120 llvm::Type *ResT = ConvertType(E->getType());
121 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_trunc_unsigned,
122 {ResT, Src->getType()});
123 return Builder.CreateCall(Callee, {Src});
124 }
125 case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32_f32:
126 case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32_f64:
127 case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i64_f32:
128 case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i64_f64:
129 case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i16x8_f16x8:
130 case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32x4_f32x4: {
131 Value *Src = EmitScalarExpr(E->getArg(0));
132 llvm::Type *ResT = ConvertType(E->getType());
133 Function *Callee =
134 CGM.getIntrinsic(Intrinsic::fptosi_sat, {ResT, Src->getType()});
135 return Builder.CreateCall(Callee, {Src});
136 }
137 case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i32_f32:
138 case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i32_f64:
139 case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i64_f32:
140 case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i64_f64:
141 case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i16x8_f16x8:
142 case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i32x4_f32x4: {
143 Value *Src = EmitScalarExpr(E->getArg(0));
144 llvm::Type *ResT = ConvertType(E->getType());
145 Function *Callee =
146 CGM.getIntrinsic(Intrinsic::fptoui_sat, {ResT, Src->getType()});
147 return Builder.CreateCall(Callee, {Src});
148 }
149 case WebAssembly::BI__builtin_wasm_min_f32:
150 case WebAssembly::BI__builtin_wasm_min_f64:
151 case WebAssembly::BI__builtin_wasm_min_f16x8:
152 case WebAssembly::BI__builtin_wasm_min_f32x4:
153 case WebAssembly::BI__builtin_wasm_min_f64x2: {
154 Value *LHS = EmitScalarExpr(E->getArg(0));
155 Value *RHS = EmitScalarExpr(E->getArg(1));
156 Function *Callee =
157 CGM.getIntrinsic(Intrinsic::minimum, ConvertType(E->getType()));
158 return Builder.CreateCall(Callee, {LHS, RHS});
159 }
160 case WebAssembly::BI__builtin_wasm_max_f32:
161 case WebAssembly::BI__builtin_wasm_max_f64:
162 case WebAssembly::BI__builtin_wasm_max_f16x8:
163 case WebAssembly::BI__builtin_wasm_max_f32x4:
164 case WebAssembly::BI__builtin_wasm_max_f64x2: {
165 Value *LHS = EmitScalarExpr(E->getArg(0));
166 Value *RHS = EmitScalarExpr(E->getArg(1));
167 Function *Callee =
168 CGM.getIntrinsic(Intrinsic::maximum, ConvertType(E->getType()));
169 return Builder.CreateCall(Callee, {LHS, RHS});
170 }
171 case WebAssembly::BI__builtin_wasm_pmin_f16x8:
172 case WebAssembly::BI__builtin_wasm_pmin_f32x4:
173 case WebAssembly::BI__builtin_wasm_pmin_f64x2: {
174 Value *LHS = EmitScalarExpr(E->getArg(0));
175 Value *RHS = EmitScalarExpr(E->getArg(1));
176 Function *Callee =
177 CGM.getIntrinsic(Intrinsic::wasm_pmin, ConvertType(E->getType()));
178 return Builder.CreateCall(Callee, {LHS, RHS});
179 }
180 case WebAssembly::BI__builtin_wasm_pmax_f16x8:
181 case WebAssembly::BI__builtin_wasm_pmax_f32x4:
182 case WebAssembly::BI__builtin_wasm_pmax_f64x2: {
183 Value *LHS = EmitScalarExpr(E->getArg(0));
184 Value *RHS = EmitScalarExpr(E->getArg(1));
185 Function *Callee =
186 CGM.getIntrinsic(Intrinsic::wasm_pmax, ConvertType(E->getType()));
187 return Builder.CreateCall(Callee, {LHS, RHS});
188 }
189 case WebAssembly::BI__builtin_wasm_ceil_f16x8:
190 case WebAssembly::BI__builtin_wasm_floor_f16x8:
191 case WebAssembly::BI__builtin_wasm_trunc_f16x8:
192 case WebAssembly::BI__builtin_wasm_nearest_f16x8:
193 case WebAssembly::BI__builtin_wasm_ceil_f32x4:
194 case WebAssembly::BI__builtin_wasm_floor_f32x4:
195 case WebAssembly::BI__builtin_wasm_trunc_f32x4:
196 case WebAssembly::BI__builtin_wasm_nearest_f32x4:
197 case WebAssembly::BI__builtin_wasm_ceil_f64x2:
198 case WebAssembly::BI__builtin_wasm_floor_f64x2:
199 case WebAssembly::BI__builtin_wasm_trunc_f64x2:
200 case WebAssembly::BI__builtin_wasm_nearest_f64x2: {
201 unsigned IntNo;
202 switch (BuiltinID) {
203 case WebAssembly::BI__builtin_wasm_ceil_f16x8:
204 case WebAssembly::BI__builtin_wasm_ceil_f32x4:
205 case WebAssembly::BI__builtin_wasm_ceil_f64x2:
206 IntNo = Intrinsic::ceil;
207 break;
208 case WebAssembly::BI__builtin_wasm_floor_f16x8:
209 case WebAssembly::BI__builtin_wasm_floor_f32x4:
210 case WebAssembly::BI__builtin_wasm_floor_f64x2:
211 IntNo = Intrinsic::floor;
212 break;
213 case WebAssembly::BI__builtin_wasm_trunc_f16x8:
214 case WebAssembly::BI__builtin_wasm_trunc_f32x4:
215 case WebAssembly::BI__builtin_wasm_trunc_f64x2:
216 IntNo = Intrinsic::trunc;
217 break;
218 case WebAssembly::BI__builtin_wasm_nearest_f16x8:
219 case WebAssembly::BI__builtin_wasm_nearest_f32x4:
220 case WebAssembly::BI__builtin_wasm_nearest_f64x2:
221 IntNo = Intrinsic::nearbyint;
222 break;
223 default:
224 llvm_unreachable("unexpected builtin ID");
225 }
227 Function *Callee = CGM.getIntrinsic(IntNo, ConvertType(E->getType()));
228 return Builder.CreateCall(Callee, Value);
229 }
230 case WebAssembly::BI__builtin_wasm_ref_null_extern: {
231 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_null_extern);
232 return Builder.CreateCall(Callee);
233 }
234 case WebAssembly::BI__builtin_wasm_ref_is_null_extern: {
235 Value *Src = EmitScalarExpr(E->getArg(0));
236 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_is_null_extern);
237 return Builder.CreateCall(Callee, {Src});
238 }
239 case WebAssembly::BI__builtin_wasm_ref_null_func: {
240 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_null_func);
241 return Builder.CreateCall(Callee);
242 }
243 case WebAssembly::BI__builtin_wasm_test_function_pointer_signature: {
244 Value *FuncRef = EmitScalarExpr(E->getArg(0));
245
246 // Get the function type from the argument's static type
247 QualType ArgType = E->getArg(0)->getType();
248 const PointerType *PtrTy = ArgType->getAs<PointerType>();
249 assert(PtrTy && "Sema should have ensured this is a function pointer");
250
251 const FunctionType *FuncTy = PtrTy->getPointeeType()->getAs<FunctionType>();
252 assert(FuncTy && "Sema should have ensured this is a function pointer");
253
254 // In the llvm IR, we won't have access any more to the type of the function
255 // pointer so we need to insert this type information somehow. The
256 // @llvm.wasm.ref.test.func takes varargs arguments whose values are unused
257 // to indicate the type of the function to test for. See the test here:
258 // llvm/test/CodeGen/WebAssembly/ref-test-func.ll
259 //
260 // The format is: first we include the return types (since this is a C
261 // function pointer, there will be 0 or one of these) then a token type to
262 // indicate the boundary between return types and param types, then the
263 // param types.
264
265 llvm::FunctionType *LLVMFuncTy =
267
268 bool VarArg = LLVMFuncTy->isVarArg();
269 unsigned NParams = LLVMFuncTy->getNumParams();
270 std::vector<Value *> Args;
271 Args.reserve(NParams + 3 + VarArg);
272 // The only real argument is the FuncRef
273 Args.push_back(FuncRef);
274
275 // Add the type information
276 llvm::Type *RetType = LLVMFuncTy->getReturnType();
277 if (!RetType->isVoidTy()) {
278 Args.push_back(PoisonValue::get(RetType));
279 }
280 // The token type indicates the boundary between return types and param
281 // types.
282 Args.push_back(PoisonValue::get(llvm::Type::getTokenTy(getLLVMContext())));
283 for (unsigned i = 0; i < NParams; i++) {
284 Args.push_back(PoisonValue::get(LLVMFuncTy->getParamType(i)));
285 }
286 if (VarArg) {
287 Args.push_back(PoisonValue::get(Builder.getPtrTy()));
288 }
289 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_test_func);
290 return Builder.CreateCall(Callee, Args);
291 }
292 case WebAssembly::BI__builtin_wasm_swizzle_i8x16: {
293 Value *Src = EmitScalarExpr(E->getArg(0));
294 Value *Indices = EmitScalarExpr(E->getArg(1));
295 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_swizzle);
296 return Builder.CreateCall(Callee, {Src, Indices});
297 }
298 case WebAssembly::BI__builtin_wasm_abs_i8x16:
299 case WebAssembly::BI__builtin_wasm_abs_i16x8:
300 case WebAssembly::BI__builtin_wasm_abs_i32x4:
301 case WebAssembly::BI__builtin_wasm_abs_i64x2: {
302 Value *Vec = EmitScalarExpr(E->getArg(0));
303 Value *Neg = Builder.CreateNeg(Vec, "neg");
304 Constant *Zero = llvm::Constant::getNullValue(Vec->getType());
305 Value *ICmp = Builder.CreateICmpSLT(Vec, Zero, "abscond");
306 return Builder.CreateSelect(ICmp, Neg, Vec, "abs");
307 }
308 case WebAssembly::BI__builtin_wasm_avgr_u_i8x16:
309 case WebAssembly::BI__builtin_wasm_avgr_u_i16x8: {
310 Value *LHS = EmitScalarExpr(E->getArg(0));
311 Value *RHS = EmitScalarExpr(E->getArg(1));
312 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_avgr_unsigned,
313 ConvertType(E->getType()));
314 return Builder.CreateCall(Callee, {LHS, RHS});
315 }
316 case WebAssembly::BI__builtin_wasm_q15mulr_sat_s_i16x8: {
317 Value *LHS = EmitScalarExpr(E->getArg(0));
318 Value *RHS = EmitScalarExpr(E->getArg(1));
319 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_q15mulr_sat_signed);
320 return Builder.CreateCall(Callee, {LHS, RHS});
321 }
322 case WebAssembly::BI__builtin_wasm_extadd_pairwise_i8x16_s_i16x8:
323 case WebAssembly::BI__builtin_wasm_extadd_pairwise_i8x16_u_i16x8:
324 case WebAssembly::BI__builtin_wasm_extadd_pairwise_i16x8_s_i32x4:
325 case WebAssembly::BI__builtin_wasm_extadd_pairwise_i16x8_u_i32x4: {
326 Value *Vec = EmitScalarExpr(E->getArg(0));
327 unsigned IntNo;
328 switch (BuiltinID) {
329 case WebAssembly::BI__builtin_wasm_extadd_pairwise_i8x16_s_i16x8:
330 case WebAssembly::BI__builtin_wasm_extadd_pairwise_i16x8_s_i32x4:
331 IntNo = Intrinsic::wasm_extadd_pairwise_signed;
332 break;
333 case WebAssembly::BI__builtin_wasm_extadd_pairwise_i8x16_u_i16x8:
334 case WebAssembly::BI__builtin_wasm_extadd_pairwise_i16x8_u_i32x4:
335 IntNo = Intrinsic::wasm_extadd_pairwise_unsigned;
336 break;
337 default:
338 llvm_unreachable("unexpected builtin ID");
339 }
340
341 Function *Callee = CGM.getIntrinsic(IntNo, ConvertType(E->getType()));
342 return Builder.CreateCall(Callee, Vec);
343 }
344 case WebAssembly::BI__builtin_wasm_bitselect: {
345 Value *V1 = EmitScalarExpr(E->getArg(0));
346 Value *V2 = EmitScalarExpr(E->getArg(1));
347 Value *C = EmitScalarExpr(E->getArg(2));
348 Function *Callee =
349 CGM.getIntrinsic(Intrinsic::wasm_bitselect, ConvertType(E->getType()));
350 return Builder.CreateCall(Callee, {V1, V2, C});
351 }
352 case WebAssembly::BI__builtin_wasm_dot_s_i32x4_i16x8: {
353 Value *LHS = EmitScalarExpr(E->getArg(0));
354 Value *RHS = EmitScalarExpr(E->getArg(1));
355 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_dot);
356 return Builder.CreateCall(Callee, {LHS, RHS});
357 }
358 case WebAssembly::BI__builtin_wasm_any_true_v128:
359 case WebAssembly::BI__builtin_wasm_all_true_i8x16:
360 case WebAssembly::BI__builtin_wasm_all_true_i16x8:
361 case WebAssembly::BI__builtin_wasm_all_true_i32x4:
362 case WebAssembly::BI__builtin_wasm_all_true_i64x2: {
363 unsigned IntNo;
364 switch (BuiltinID) {
365 case WebAssembly::BI__builtin_wasm_any_true_v128:
366 IntNo = Intrinsic::wasm_anytrue;
367 break;
368 case WebAssembly::BI__builtin_wasm_all_true_i8x16:
369 case WebAssembly::BI__builtin_wasm_all_true_i16x8:
370 case WebAssembly::BI__builtin_wasm_all_true_i32x4:
371 case WebAssembly::BI__builtin_wasm_all_true_i64x2:
372 IntNo = Intrinsic::wasm_alltrue;
373 break;
374 default:
375 llvm_unreachable("unexpected builtin ID");
376 }
377 Value *Vec = EmitScalarExpr(E->getArg(0));
378 Function *Callee = CGM.getIntrinsic(IntNo, Vec->getType());
379 return Builder.CreateCall(Callee, {Vec});
380 }
381 case WebAssembly::BI__builtin_wasm_bitmask_i8x16:
382 case WebAssembly::BI__builtin_wasm_bitmask_i16x8:
383 case WebAssembly::BI__builtin_wasm_bitmask_i32x4:
384 case WebAssembly::BI__builtin_wasm_bitmask_i64x2: {
385 Value *Vec = EmitScalarExpr(E->getArg(0));
386 Function *Callee =
387 CGM.getIntrinsic(Intrinsic::wasm_bitmask, Vec->getType());
388 return Builder.CreateCall(Callee, {Vec});
389 }
390 case WebAssembly::BI__builtin_wasm_abs_f16x8:
391 case WebAssembly::BI__builtin_wasm_abs_f32x4:
392 case WebAssembly::BI__builtin_wasm_abs_f64x2: {
393 Value *Vec = EmitScalarExpr(E->getArg(0));
394 return Builder.CreateFAbs(Vec);
395 }
396 case WebAssembly::BI__builtin_wasm_sqrt_f16x8:
397 case WebAssembly::BI__builtin_wasm_sqrt_f32x4:
398 case WebAssembly::BI__builtin_wasm_sqrt_f64x2: {
399 Value *Vec = EmitScalarExpr(E->getArg(0));
400 Function *Callee = CGM.getIntrinsic(Intrinsic::sqrt, Vec->getType());
401 return Builder.CreateCall(Callee, {Vec});
402 }
403 case WebAssembly::BI__builtin_wasm_narrow_s_i8x16_i16x8:
404 case WebAssembly::BI__builtin_wasm_narrow_u_i8x16_i16x8:
405 case WebAssembly::BI__builtin_wasm_narrow_s_i16x8_i32x4:
406 case WebAssembly::BI__builtin_wasm_narrow_u_i16x8_i32x4: {
407 Value *Low = EmitScalarExpr(E->getArg(0));
408 Value *High = EmitScalarExpr(E->getArg(1));
409 unsigned IntNo;
410 switch (BuiltinID) {
411 case WebAssembly::BI__builtin_wasm_narrow_s_i8x16_i16x8:
412 case WebAssembly::BI__builtin_wasm_narrow_s_i16x8_i32x4:
413 IntNo = Intrinsic::wasm_narrow_signed;
414 break;
415 case WebAssembly::BI__builtin_wasm_narrow_u_i8x16_i16x8:
416 case WebAssembly::BI__builtin_wasm_narrow_u_i16x8_i32x4:
417 IntNo = Intrinsic::wasm_narrow_unsigned;
418 break;
419 default:
420 llvm_unreachable("unexpected builtin ID");
421 }
422 Function *Callee =
423 CGM.getIntrinsic(IntNo, {ConvertType(E->getType()), Low->getType()});
424 return Builder.CreateCall(Callee, {Low, High});
425 }
426 case WebAssembly::BI__builtin_wasm_trunc_sat_s_zero_f64x2_i32x4:
427 case WebAssembly::BI__builtin_wasm_trunc_sat_u_zero_f64x2_i32x4: {
428 Value *Vec = EmitScalarExpr(E->getArg(0));
429 unsigned IntNo;
430 switch (BuiltinID) {
431 case WebAssembly::BI__builtin_wasm_trunc_sat_s_zero_f64x2_i32x4:
432 IntNo = Intrinsic::fptosi_sat;
433 break;
434 case WebAssembly::BI__builtin_wasm_trunc_sat_u_zero_f64x2_i32x4:
435 IntNo = Intrinsic::fptoui_sat;
436 break;
437 default:
438 llvm_unreachable("unexpected builtin ID");
439 }
440 llvm::Type *SrcT = Vec->getType();
441 llvm::Type *TruncT = SrcT->getWithNewType(Builder.getInt32Ty());
442 Function *Callee = CGM.getIntrinsic(IntNo, {TruncT, SrcT});
443 Value *Trunc = Builder.CreateCall(Callee, Vec);
444 Value *Splat = Constant::getNullValue(TruncT);
445 return Builder.CreateShuffleVector(Trunc, Splat, {0, 1, 2, 3});
446 }
447 case WebAssembly::BI__builtin_wasm_shuffle_i8x16: {
448 Value *Ops[18];
449 size_t OpIdx = 0;
450 Ops[OpIdx++] = EmitScalarExpr(E->getArg(0));
451 Ops[OpIdx++] = EmitScalarExpr(E->getArg(1));
452 while (OpIdx < 18) {
453 std::optional<llvm::APSInt> LaneConst =
455 assert(LaneConst && "Constant arg isn't actually constant?");
456 Ops[OpIdx++] = llvm::ConstantInt::get(getLLVMContext(), *LaneConst);
457 }
458 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_shuffle);
459 return Builder.CreateCall(Callee, Ops);
460 }
461 case WebAssembly::BI__builtin_wasm_relaxed_madd_f16x8:
462 case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f16x8:
463 case WebAssembly::BI__builtin_wasm_relaxed_madd_f32x4:
464 case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f32x4:
465 case WebAssembly::BI__builtin_wasm_relaxed_madd_f64x2:
466 case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f64x2: {
467 Value *A = EmitScalarExpr(E->getArg(0));
468 Value *B = EmitScalarExpr(E->getArg(1));
469 Value *C = EmitScalarExpr(E->getArg(2));
470 unsigned IntNo;
471 switch (BuiltinID) {
472 case WebAssembly::BI__builtin_wasm_relaxed_madd_f16x8:
473 case WebAssembly::BI__builtin_wasm_relaxed_madd_f32x4:
474 case WebAssembly::BI__builtin_wasm_relaxed_madd_f64x2:
475 IntNo = Intrinsic::wasm_relaxed_madd;
476 break;
477 case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f16x8:
478 case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f32x4:
479 case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f64x2:
480 IntNo = Intrinsic::wasm_relaxed_nmadd;
481 break;
482 default:
483 llvm_unreachable("unexpected builtin ID");
484 }
485 Function *Callee = CGM.getIntrinsic(IntNo, A->getType());
486 return Builder.CreateCall(Callee, {A, B, C});
487 }
488 case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i8x16:
489 case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i16x8:
490 case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i32x4:
491 case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i64x2: {
492 Value *A = EmitScalarExpr(E->getArg(0));
493 Value *B = EmitScalarExpr(E->getArg(1));
494 Value *C = EmitScalarExpr(E->getArg(2));
495 Function *Callee =
496 CGM.getIntrinsic(Intrinsic::wasm_relaxed_laneselect, A->getType());
497 return Builder.CreateCall(Callee, {A, B, C});
498 }
499 case WebAssembly::BI__builtin_wasm_relaxed_swizzle_i8x16: {
500 Value *Src = EmitScalarExpr(E->getArg(0));
501 Value *Indices = EmitScalarExpr(E->getArg(1));
502 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_relaxed_swizzle);
503 return Builder.CreateCall(Callee, {Src, Indices});
504 }
505 case WebAssembly::BI__builtin_wasm_relaxed_min_f32x4:
506 case WebAssembly::BI__builtin_wasm_relaxed_max_f32x4:
507 case WebAssembly::BI__builtin_wasm_relaxed_min_f64x2:
508 case WebAssembly::BI__builtin_wasm_relaxed_max_f64x2: {
509 Value *LHS = EmitScalarExpr(E->getArg(0));
510 Value *RHS = EmitScalarExpr(E->getArg(1));
511 unsigned IntNo;
512 switch (BuiltinID) {
513 case WebAssembly::BI__builtin_wasm_relaxed_min_f32x4:
514 case WebAssembly::BI__builtin_wasm_relaxed_min_f64x2:
515 IntNo = Intrinsic::wasm_relaxed_min;
516 break;
517 case WebAssembly::BI__builtin_wasm_relaxed_max_f32x4:
518 case WebAssembly::BI__builtin_wasm_relaxed_max_f64x2:
519 IntNo = Intrinsic::wasm_relaxed_max;
520 break;
521 default:
522 llvm_unreachable("unexpected builtin ID");
523 }
524 Function *Callee = CGM.getIntrinsic(IntNo, LHS->getType());
525 return Builder.CreateCall(Callee, {LHS, RHS});
526 }
527 case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_i32x4_f32x4:
528 case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_i32x4_f32x4:
529 case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_zero_i32x4_f64x2:
530 case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_zero_i32x4_f64x2: {
531 Value *Vec = EmitScalarExpr(E->getArg(0));
532 unsigned IntNo;
533 switch (BuiltinID) {
534 case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_i32x4_f32x4:
535 IntNo = Intrinsic::wasm_relaxed_trunc_signed;
536 break;
537 case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_i32x4_f32x4:
538 IntNo = Intrinsic::wasm_relaxed_trunc_unsigned;
539 break;
540 case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_zero_i32x4_f64x2:
541 IntNo = Intrinsic::wasm_relaxed_trunc_signed_zero;
542 break;
543 case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_zero_i32x4_f64x2:
544 IntNo = Intrinsic::wasm_relaxed_trunc_unsigned_zero;
545 break;
546 default:
547 llvm_unreachable("unexpected builtin ID");
548 }
549 Function *Callee = CGM.getIntrinsic(IntNo);
550 return Builder.CreateCall(Callee, {Vec});
551 }
552 case WebAssembly::BI__builtin_wasm_relaxed_q15mulr_s_i16x8: {
553 Value *LHS = EmitScalarExpr(E->getArg(0));
554 Value *RHS = EmitScalarExpr(E->getArg(1));
555 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_relaxed_q15mulr_signed);
556 return Builder.CreateCall(Callee, {LHS, RHS});
557 }
558 case WebAssembly::BI__builtin_wasm_relaxed_dot_i8x16_i7x16_s_i16x8: {
559 Value *LHS = EmitScalarExpr(E->getArg(0));
560 Value *RHS = EmitScalarExpr(E->getArg(1));
561 Function *Callee =
562 CGM.getIntrinsic(Intrinsic::wasm_relaxed_dot_i8x16_i7x16_signed);
563 return Builder.CreateCall(Callee, {LHS, RHS});
564 }
565 case WebAssembly::BI__builtin_wasm_relaxed_dot_i8x16_i7x16_add_s_i32x4: {
566 Value *LHS = EmitScalarExpr(E->getArg(0));
567 Value *RHS = EmitScalarExpr(E->getArg(1));
568 Value *Acc = EmitScalarExpr(E->getArg(2));
569 Function *Callee =
570 CGM.getIntrinsic(Intrinsic::wasm_relaxed_dot_i8x16_i7x16_add_signed);
571 return Builder.CreateCall(Callee, {LHS, RHS, Acc});
572 }
573 case WebAssembly::BI__builtin_wasm_relaxed_dot_bf16x8_add_f32_f32x4: {
574 Value *LHS = EmitScalarExpr(E->getArg(0));
575 Value *RHS = EmitScalarExpr(E->getArg(1));
576 Value *Acc = EmitScalarExpr(E->getArg(2));
577 Function *Callee =
578 CGM.getIntrinsic(Intrinsic::wasm_relaxed_dot_bf16x8_add_f32);
579 return Builder.CreateCall(Callee, {LHS, RHS, Acc});
580 }
581 case WebAssembly::BI__builtin_wasm_loadf16_f32: {
583 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_loadf16_f32);
584 return Builder.CreateCall(Callee, {Addr});
585 }
586 case WebAssembly::BI__builtin_wasm_storef16_f32: {
587 Value *Val = EmitScalarExpr(E->getArg(0));
589 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_storef16_f32);
590 return Builder.CreateCall(Callee, {Val, Addr});
591 }
592 case WebAssembly::BI__builtin_wasm_splat_f16x8: {
593 Value *Val = EmitScalarExpr(E->getArg(0));
594 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_splat_f16x8);
595 return Builder.CreateCall(Callee, {Val});
596 }
597 case WebAssembly::BI__builtin_wasm_extract_lane_f16x8: {
599 Value *Index = EmitScalarExpr(E->getArg(1));
600 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_extract_lane_f16x8);
601 return Builder.CreateCall(Callee, {Vector, Index});
602 }
603 case WebAssembly::BI__builtin_wasm_replace_lane_f16x8: {
605 Value *Index = EmitScalarExpr(E->getArg(1));
606 Value *Val = EmitScalarExpr(E->getArg(2));
607 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_replace_lane_f16x8);
608 return Builder.CreateCall(Callee, {Vector, Index, Val});
609 }
610 case WebAssembly::BI__builtin_wasm_table_get: {
611 assert(E->getArg(0)->getType()->isArrayType());
612 Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
613 Value *Index = EmitScalarExpr(E->getArg(1));
614 Function *Callee;
616 Callee = CGM.getIntrinsic(Intrinsic::wasm_table_get_externref);
617 else if (E->getType().isWebAssemblyFuncrefType())
618 Callee = CGM.getIntrinsic(Intrinsic::wasm_table_get_funcref);
619 else
620 llvm_unreachable(
621 "Unexpected reference type for __builtin_wasm_table_get");
622 return Builder.CreateCall(Callee, {Table, Index});
623 }
624 case WebAssembly::BI__builtin_wasm_table_set: {
625 assert(E->getArg(0)->getType()->isArrayType());
626 Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
627 Value *Index = EmitScalarExpr(E->getArg(1));
628 Value *Val = EmitScalarExpr(E->getArg(2));
629 Function *Callee;
631 Callee = CGM.getIntrinsic(Intrinsic::wasm_table_set_externref);
632 else if (E->getArg(2)->getType().isWebAssemblyFuncrefType())
633 Callee = CGM.getIntrinsic(Intrinsic::wasm_table_set_funcref);
634 else
635 llvm_unreachable(
636 "Unexpected reference type for __builtin_wasm_table_set");
637 return Builder.CreateCall(Callee, {Table, Index, Val});
638 }
639 case WebAssembly::BI__builtin_wasm_table_size: {
640 assert(E->getArg(0)->getType()->isArrayType());
642 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_table_size);
643 return Builder.CreateCall(Callee, Value);
644 }
645 case WebAssembly::BI__builtin_wasm_table_grow: {
646 assert(E->getArg(0)->getType()->isArrayType());
647 Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
648 Value *Val = EmitScalarExpr(E->getArg(1));
649 Value *NElems = EmitScalarExpr(E->getArg(2));
650
651 Function *Callee;
653 Callee = CGM.getIntrinsic(Intrinsic::wasm_table_grow_externref);
654 else if (E->getArg(1)->getType().isWebAssemblyFuncrefType())
655 Callee = CGM.getIntrinsic(Intrinsic::wasm_table_grow_funcref);
656 else
657 llvm_unreachable(
658 "Unexpected reference type for __builtin_wasm_table_grow");
659
660 return Builder.CreateCall(Callee, {Table, Val, NElems});
661 }
662 case WebAssembly::BI__builtin_wasm_table_fill: {
663 assert(E->getArg(0)->getType()->isArrayType());
664 Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
665 Value *Index = EmitScalarExpr(E->getArg(1));
666 Value *Val = EmitScalarExpr(E->getArg(2));
667 Value *NElems = EmitScalarExpr(E->getArg(3));
668
669 Function *Callee;
671 Callee = CGM.getIntrinsic(Intrinsic::wasm_table_fill_externref);
672 else if (E->getArg(2)->getType().isWebAssemblyFuncrefType())
673 Callee = CGM.getIntrinsic(Intrinsic::wasm_table_fill_funcref);
674 else
675 llvm_unreachable(
676 "Unexpected reference type for __builtin_wasm_table_fill");
677
678 return Builder.CreateCall(Callee, {Table, Index, Val, NElems});
679 }
680 case WebAssembly::BI__builtin_wasm_table_copy: {
681 assert(E->getArg(0)->getType()->isArrayType());
682 Value *TableX = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
683 Value *TableY = EmitArrayToPointerDecay(E->getArg(1)).emitRawPointer(*this);
684 Value *DstIdx = EmitScalarExpr(E->getArg(2));
685 Value *SrcIdx = EmitScalarExpr(E->getArg(3));
686 Value *NElems = EmitScalarExpr(E->getArg(4));
687
688 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_table_copy);
689
690 return Builder.CreateCall(Callee, {TableX, TableY, SrcIdx, DstIdx, NElems});
691 }
692 default:
693 return nullptr;
694 }
695}
Enumerates target-specific builtins in their own namespaces within namespace clang.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2987
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3191
llvm::Value * emitRawPointer(CodeGenFunction &CGF) const
Return the pointer contained in this class after authenticating it and adding offset to it if necessa...
Definition Address.h:253
llvm::Type * ConvertType(QualType T)
llvm::CallBase * EmitRuntimeCallOrInvoke(llvm::FunctionCallee callee, ArrayRef< llvm::Value * > args, const Twine &name="")
Emits a call or invoke instruction to the given runtime function.
Definition CGCall.cpp:5512
llvm::Value * EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, const CallExpr *E)
Address EmitArrayToPointerDecay(const Expr *Array, LValueBaseInfo *BaseInfo=nullptr, TBAAAccessInfo *TBAAInfo=nullptr)
Definition CGExpr.cpp:4662
llvm::Value * EmitScalarExpr(const Expr *E, bool IgnoreResultAssign=false)
EmitScalarExpr - Emit the computation of the specified expression of LLVM scalar type,...
llvm::LLVMContext & getLLVMContext()
std::optional< llvm::APSInt > getIntegerConstantExpr(const ASTContext &Ctx, bool AllowRelaxedEval=false) const
isIntegerConstantExpr - Return the value if this expression is a valid integer constant expression.
QualType getType() const
Definition Expr.h:145
FunctionType - C99 6.7.5.3 - Function Declarators.
Definition TypeBase.h:4581
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition TypeBase.h:3396
A (possibly-)qualified type.
Definition TypeBase.h:938
bool isWebAssemblyFuncrefType() const
Returns true if it is a WebAssembly Funcref Type.
Definition Type.cpp:3082
bool isWebAssemblyExternrefType() const
Returns true if it is a WebAssembly Externref Type.
Definition Type.cpp:3078
bool isArrayType() const
Definition TypeBase.h:8754
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:789
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9254
QualType getType() const
Definition Value.cpp:238
Top level wrappers for InstallAPI frontend operations.
@ Vector
'vector' clause, allowed on 'loop', Combined, and 'routine' directives.
U cast(CodeGen::Address addr)
Definition Address.h:327
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30