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