678 lines · cpp
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-exception6//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/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 24Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,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 type228 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 function236 // pointer so we need to insert this type information somehow. The237 // @llvm.wasm.ref.test.func takes varargs arguments whose values are unused238 // to indicate the type of the function to test for. See the test here:239 // llvm/test/CodeGen/WebAssembly/ref-test-func.ll240 //241 // The format is: first we include the return types (since this is a C242 // function pointer, there will be 0 or one of these) then a token type to243 // indicate the boundary between return types and param types, then the244 // 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 FuncRef254 Args.push_back(FuncRef);255 256 // Add the type information257 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 param262 // 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;597 if (E->getType().isWebAssemblyExternrefType())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 else602 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 else617 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 else639 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 else657 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}678