|  | //===-- WebAssembly.cpp - Emit LLVM Code for builtins ---------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This contains code to emit Builtin calls as LLVM code. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "CGBuiltin.h" | 
|  | #include "clang/Basic/TargetBuiltins.h" | 
|  | #include "llvm/IR/IntrinsicsWebAssembly.h" | 
|  |  | 
|  | using namespace clang; | 
|  | using namespace CodeGen; | 
|  | using namespace llvm; | 
|  |  | 
|  | Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, | 
|  | const CallExpr *E) { | 
|  | switch (BuiltinID) { | 
|  | case WebAssembly::BI__builtin_wasm_memory_size: { | 
|  | llvm::Type *ResultType = ConvertType(E->getType()); | 
|  | Value *I = EmitScalarExpr(E->getArg(0)); | 
|  | Function *Callee = | 
|  | CGM.getIntrinsic(Intrinsic::wasm_memory_size, ResultType); | 
|  | return Builder.CreateCall(Callee, I); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_memory_grow: { | 
|  | llvm::Type *ResultType = ConvertType(E->getType()); | 
|  | Value *Args[] = {EmitScalarExpr(E->getArg(0)), | 
|  | EmitScalarExpr(E->getArg(1))}; | 
|  | Function *Callee = | 
|  | CGM.getIntrinsic(Intrinsic::wasm_memory_grow, ResultType); | 
|  | return Builder.CreateCall(Callee, Args); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_tls_size: { | 
|  | llvm::Type *ResultType = ConvertType(E->getType()); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_size, ResultType); | 
|  | return Builder.CreateCall(Callee); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_tls_align: { | 
|  | llvm::Type *ResultType = ConvertType(E->getType()); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_align, ResultType); | 
|  | return Builder.CreateCall(Callee); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_tls_base: { | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_base); | 
|  | return Builder.CreateCall(Callee); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_throw: { | 
|  | Value *Tag = EmitScalarExpr(E->getArg(0)); | 
|  | Value *Obj = EmitScalarExpr(E->getArg(1)); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_throw); | 
|  | return EmitRuntimeCallOrInvoke(Callee, {Tag, Obj}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_rethrow: { | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_rethrow); | 
|  | return EmitRuntimeCallOrInvoke(Callee); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_memory_atomic_wait32: { | 
|  | Value *Addr = EmitScalarExpr(E->getArg(0)); | 
|  | Value *Expected = EmitScalarExpr(E->getArg(1)); | 
|  | Value *Timeout = EmitScalarExpr(E->getArg(2)); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memory_atomic_wait32); | 
|  | return Builder.CreateCall(Callee, {Addr, Expected, Timeout}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_memory_atomic_wait64: { | 
|  | Value *Addr = EmitScalarExpr(E->getArg(0)); | 
|  | Value *Expected = EmitScalarExpr(E->getArg(1)); | 
|  | Value *Timeout = EmitScalarExpr(E->getArg(2)); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memory_atomic_wait64); | 
|  | return Builder.CreateCall(Callee, {Addr, Expected, Timeout}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_memory_atomic_notify: { | 
|  | Value *Addr = EmitScalarExpr(E->getArg(0)); | 
|  | Value *Count = EmitScalarExpr(E->getArg(1)); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memory_atomic_notify); | 
|  | return Builder.CreateCall(Callee, {Addr, Count}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_trunc_s_i32_f32: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_s_i32_f64: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_s_i64_f32: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_s_i64_f64: { | 
|  | Value *Src = EmitScalarExpr(E->getArg(0)); | 
|  | llvm::Type *ResT = ConvertType(E->getType()); | 
|  | Function *Callee = | 
|  | CGM.getIntrinsic(Intrinsic::wasm_trunc_signed, {ResT, Src->getType()}); | 
|  | return Builder.CreateCall(Callee, {Src}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_trunc_u_i32_f32: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_u_i32_f64: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_u_i64_f32: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_u_i64_f64: { | 
|  | Value *Src = EmitScalarExpr(E->getArg(0)); | 
|  | llvm::Type *ResT = ConvertType(E->getType()); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_trunc_unsigned, | 
|  | {ResT, Src->getType()}); | 
|  | return Builder.CreateCall(Callee, {Src}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32_f32: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32_f64: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i64_f32: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i64_f64: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i16x8_f16x8: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32x4_f32x4: { | 
|  | Value *Src = EmitScalarExpr(E->getArg(0)); | 
|  | llvm::Type *ResT = ConvertType(E->getType()); | 
|  | Function *Callee = | 
|  | CGM.getIntrinsic(Intrinsic::fptosi_sat, {ResT, Src->getType()}); | 
|  | return Builder.CreateCall(Callee, {Src}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i32_f32: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i32_f64: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i64_f32: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i64_f64: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i16x8_f16x8: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i32x4_f32x4: { | 
|  | Value *Src = EmitScalarExpr(E->getArg(0)); | 
|  | llvm::Type *ResT = ConvertType(E->getType()); | 
|  | Function *Callee = | 
|  | CGM.getIntrinsic(Intrinsic::fptoui_sat, {ResT, Src->getType()}); | 
|  | return Builder.CreateCall(Callee, {Src}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_min_f32: | 
|  | case WebAssembly::BI__builtin_wasm_min_f64: | 
|  | case WebAssembly::BI__builtin_wasm_min_f16x8: | 
|  | case WebAssembly::BI__builtin_wasm_min_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_min_f64x2: { | 
|  | Value *LHS = EmitScalarExpr(E->getArg(0)); | 
|  | Value *RHS = EmitScalarExpr(E->getArg(1)); | 
|  | Function *Callee = | 
|  | CGM.getIntrinsic(Intrinsic::minimum, ConvertType(E->getType())); | 
|  | return Builder.CreateCall(Callee, {LHS, RHS}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_max_f32: | 
|  | case WebAssembly::BI__builtin_wasm_max_f64: | 
|  | case WebAssembly::BI__builtin_wasm_max_f16x8: | 
|  | case WebAssembly::BI__builtin_wasm_max_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_max_f64x2: { | 
|  | Value *LHS = EmitScalarExpr(E->getArg(0)); | 
|  | Value *RHS = EmitScalarExpr(E->getArg(1)); | 
|  | Function *Callee = | 
|  | CGM.getIntrinsic(Intrinsic::maximum, ConvertType(E->getType())); | 
|  | return Builder.CreateCall(Callee, {LHS, RHS}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_pmin_f16x8: | 
|  | case WebAssembly::BI__builtin_wasm_pmin_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_pmin_f64x2: { | 
|  | Value *LHS = EmitScalarExpr(E->getArg(0)); | 
|  | Value *RHS = EmitScalarExpr(E->getArg(1)); | 
|  | Function *Callee = | 
|  | CGM.getIntrinsic(Intrinsic::wasm_pmin, ConvertType(E->getType())); | 
|  | return Builder.CreateCall(Callee, {LHS, RHS}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_pmax_f16x8: | 
|  | case WebAssembly::BI__builtin_wasm_pmax_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_pmax_f64x2: { | 
|  | Value *LHS = EmitScalarExpr(E->getArg(0)); | 
|  | Value *RHS = EmitScalarExpr(E->getArg(1)); | 
|  | Function *Callee = | 
|  | CGM.getIntrinsic(Intrinsic::wasm_pmax, ConvertType(E->getType())); | 
|  | return Builder.CreateCall(Callee, {LHS, RHS}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_ceil_f16x8: | 
|  | case WebAssembly::BI__builtin_wasm_floor_f16x8: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_f16x8: | 
|  | case WebAssembly::BI__builtin_wasm_nearest_f16x8: | 
|  | case WebAssembly::BI__builtin_wasm_ceil_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_floor_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_nearest_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_ceil_f64x2: | 
|  | case WebAssembly::BI__builtin_wasm_floor_f64x2: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_f64x2: | 
|  | case WebAssembly::BI__builtin_wasm_nearest_f64x2: { | 
|  | unsigned IntNo; | 
|  | switch (BuiltinID) { | 
|  | case WebAssembly::BI__builtin_wasm_ceil_f16x8: | 
|  | case WebAssembly::BI__builtin_wasm_ceil_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_ceil_f64x2: | 
|  | IntNo = Intrinsic::ceil; | 
|  | break; | 
|  | case WebAssembly::BI__builtin_wasm_floor_f16x8: | 
|  | case WebAssembly::BI__builtin_wasm_floor_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_floor_f64x2: | 
|  | IntNo = Intrinsic::floor; | 
|  | break; | 
|  | case WebAssembly::BI__builtin_wasm_trunc_f16x8: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_f64x2: | 
|  | IntNo = Intrinsic::trunc; | 
|  | break; | 
|  | case WebAssembly::BI__builtin_wasm_nearest_f16x8: | 
|  | case WebAssembly::BI__builtin_wasm_nearest_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_nearest_f64x2: | 
|  | IntNo = Intrinsic::nearbyint; | 
|  | break; | 
|  | default: | 
|  | llvm_unreachable("unexpected builtin ID"); | 
|  | } | 
|  | Value *Value = EmitScalarExpr(E->getArg(0)); | 
|  | Function *Callee = CGM.getIntrinsic(IntNo, ConvertType(E->getType())); | 
|  | return Builder.CreateCall(Callee, Value); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_ref_null_extern: { | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_null_extern); | 
|  | return Builder.CreateCall(Callee); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_ref_is_null_extern: { | 
|  | Value *Src = EmitScalarExpr(E->getArg(0)); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_is_null_extern); | 
|  | return Builder.CreateCall(Callee, {Src}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_ref_null_func: { | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_null_func); | 
|  | return Builder.CreateCall(Callee); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_swizzle_i8x16: { | 
|  | Value *Src = EmitScalarExpr(E->getArg(0)); | 
|  | Value *Indices = EmitScalarExpr(E->getArg(1)); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_swizzle); | 
|  | return Builder.CreateCall(Callee, {Src, Indices}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_abs_i8x16: | 
|  | case WebAssembly::BI__builtin_wasm_abs_i16x8: | 
|  | case WebAssembly::BI__builtin_wasm_abs_i32x4: | 
|  | case WebAssembly::BI__builtin_wasm_abs_i64x2: { | 
|  | Value *Vec = EmitScalarExpr(E->getArg(0)); | 
|  | Value *Neg = Builder.CreateNeg(Vec, "neg"); | 
|  | Constant *Zero = llvm::Constant::getNullValue(Vec->getType()); | 
|  | Value *ICmp = Builder.CreateICmpSLT(Vec, Zero, "abscond"); | 
|  | return Builder.CreateSelect(ICmp, Neg, Vec, "abs"); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_avgr_u_i8x16: | 
|  | case WebAssembly::BI__builtin_wasm_avgr_u_i16x8: { | 
|  | Value *LHS = EmitScalarExpr(E->getArg(0)); | 
|  | Value *RHS = EmitScalarExpr(E->getArg(1)); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_avgr_unsigned, | 
|  | ConvertType(E->getType())); | 
|  | return Builder.CreateCall(Callee, {LHS, RHS}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_q15mulr_sat_s_i16x8: { | 
|  | Value *LHS = EmitScalarExpr(E->getArg(0)); | 
|  | Value *RHS = EmitScalarExpr(E->getArg(1)); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_q15mulr_sat_signed); | 
|  | return Builder.CreateCall(Callee, {LHS, RHS}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_extadd_pairwise_i8x16_s_i16x8: | 
|  | case WebAssembly::BI__builtin_wasm_extadd_pairwise_i8x16_u_i16x8: | 
|  | case WebAssembly::BI__builtin_wasm_extadd_pairwise_i16x8_s_i32x4: | 
|  | case WebAssembly::BI__builtin_wasm_extadd_pairwise_i16x8_u_i32x4: { | 
|  | Value *Vec = EmitScalarExpr(E->getArg(0)); | 
|  | unsigned IntNo; | 
|  | switch (BuiltinID) { | 
|  | case WebAssembly::BI__builtin_wasm_extadd_pairwise_i8x16_s_i16x8: | 
|  | case WebAssembly::BI__builtin_wasm_extadd_pairwise_i16x8_s_i32x4: | 
|  | IntNo = Intrinsic::wasm_extadd_pairwise_signed; | 
|  | break; | 
|  | case WebAssembly::BI__builtin_wasm_extadd_pairwise_i8x16_u_i16x8: | 
|  | case WebAssembly::BI__builtin_wasm_extadd_pairwise_i16x8_u_i32x4: | 
|  | IntNo = Intrinsic::wasm_extadd_pairwise_unsigned; | 
|  | break; | 
|  | default: | 
|  | llvm_unreachable("unexpected builtin ID"); | 
|  | } | 
|  |  | 
|  | Function *Callee = CGM.getIntrinsic(IntNo, ConvertType(E->getType())); | 
|  | return Builder.CreateCall(Callee, Vec); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_bitselect: { | 
|  | Value *V1 = EmitScalarExpr(E->getArg(0)); | 
|  | Value *V2 = EmitScalarExpr(E->getArg(1)); | 
|  | Value *C = EmitScalarExpr(E->getArg(2)); | 
|  | Function *Callee = | 
|  | CGM.getIntrinsic(Intrinsic::wasm_bitselect, ConvertType(E->getType())); | 
|  | return Builder.CreateCall(Callee, {V1, V2, C}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_dot_s_i32x4_i16x8: { | 
|  | Value *LHS = EmitScalarExpr(E->getArg(0)); | 
|  | Value *RHS = EmitScalarExpr(E->getArg(1)); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_dot); | 
|  | return Builder.CreateCall(Callee, {LHS, RHS}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_any_true_v128: | 
|  | case WebAssembly::BI__builtin_wasm_all_true_i8x16: | 
|  | case WebAssembly::BI__builtin_wasm_all_true_i16x8: | 
|  | case WebAssembly::BI__builtin_wasm_all_true_i32x4: | 
|  | case WebAssembly::BI__builtin_wasm_all_true_i64x2: { | 
|  | unsigned IntNo; | 
|  | switch (BuiltinID) { | 
|  | case WebAssembly::BI__builtin_wasm_any_true_v128: | 
|  | IntNo = Intrinsic::wasm_anytrue; | 
|  | break; | 
|  | case WebAssembly::BI__builtin_wasm_all_true_i8x16: | 
|  | case WebAssembly::BI__builtin_wasm_all_true_i16x8: | 
|  | case WebAssembly::BI__builtin_wasm_all_true_i32x4: | 
|  | case WebAssembly::BI__builtin_wasm_all_true_i64x2: | 
|  | IntNo = Intrinsic::wasm_alltrue; | 
|  | break; | 
|  | default: | 
|  | llvm_unreachable("unexpected builtin ID"); | 
|  | } | 
|  | Value *Vec = EmitScalarExpr(E->getArg(0)); | 
|  | Function *Callee = CGM.getIntrinsic(IntNo, Vec->getType()); | 
|  | return Builder.CreateCall(Callee, {Vec}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_bitmask_i8x16: | 
|  | case WebAssembly::BI__builtin_wasm_bitmask_i16x8: | 
|  | case WebAssembly::BI__builtin_wasm_bitmask_i32x4: | 
|  | case WebAssembly::BI__builtin_wasm_bitmask_i64x2: { | 
|  | Value *Vec = EmitScalarExpr(E->getArg(0)); | 
|  | Function *Callee = | 
|  | CGM.getIntrinsic(Intrinsic::wasm_bitmask, Vec->getType()); | 
|  | return Builder.CreateCall(Callee, {Vec}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_abs_f16x8: | 
|  | case WebAssembly::BI__builtin_wasm_abs_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_abs_f64x2: { | 
|  | Value *Vec = EmitScalarExpr(E->getArg(0)); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::fabs, Vec->getType()); | 
|  | return Builder.CreateCall(Callee, {Vec}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_sqrt_f16x8: | 
|  | case WebAssembly::BI__builtin_wasm_sqrt_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_sqrt_f64x2: { | 
|  | Value *Vec = EmitScalarExpr(E->getArg(0)); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::sqrt, Vec->getType()); | 
|  | return Builder.CreateCall(Callee, {Vec}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_narrow_s_i8x16_i16x8: | 
|  | case WebAssembly::BI__builtin_wasm_narrow_u_i8x16_i16x8: | 
|  | case WebAssembly::BI__builtin_wasm_narrow_s_i16x8_i32x4: | 
|  | case WebAssembly::BI__builtin_wasm_narrow_u_i16x8_i32x4: { | 
|  | Value *Low = EmitScalarExpr(E->getArg(0)); | 
|  | Value *High = EmitScalarExpr(E->getArg(1)); | 
|  | unsigned IntNo; | 
|  | switch (BuiltinID) { | 
|  | case WebAssembly::BI__builtin_wasm_narrow_s_i8x16_i16x8: | 
|  | case WebAssembly::BI__builtin_wasm_narrow_s_i16x8_i32x4: | 
|  | IntNo = Intrinsic::wasm_narrow_signed; | 
|  | break; | 
|  | case WebAssembly::BI__builtin_wasm_narrow_u_i8x16_i16x8: | 
|  | case WebAssembly::BI__builtin_wasm_narrow_u_i16x8_i32x4: | 
|  | IntNo = Intrinsic::wasm_narrow_unsigned; | 
|  | break; | 
|  | default: | 
|  | llvm_unreachable("unexpected builtin ID"); | 
|  | } | 
|  | Function *Callee = | 
|  | CGM.getIntrinsic(IntNo, {ConvertType(E->getType()), Low->getType()}); | 
|  | return Builder.CreateCall(Callee, {Low, High}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_trunc_sat_s_zero_f64x2_i32x4: | 
|  | case WebAssembly::BI__builtin_wasm_trunc_sat_u_zero_f64x2_i32x4: { | 
|  | Value *Vec = EmitScalarExpr(E->getArg(0)); | 
|  | unsigned IntNo; | 
|  | switch (BuiltinID) { | 
|  | case WebAssembly::BI__builtin_wasm_trunc_sat_s_zero_f64x2_i32x4: | 
|  | IntNo = Intrinsic::fptosi_sat; | 
|  | break; | 
|  | case WebAssembly::BI__builtin_wasm_trunc_sat_u_zero_f64x2_i32x4: | 
|  | IntNo = Intrinsic::fptoui_sat; | 
|  | break; | 
|  | default: | 
|  | llvm_unreachable("unexpected builtin ID"); | 
|  | } | 
|  | llvm::Type *SrcT = Vec->getType(); | 
|  | llvm::Type *TruncT = SrcT->getWithNewType(Builder.getInt32Ty()); | 
|  | Function *Callee = CGM.getIntrinsic(IntNo, {TruncT, SrcT}); | 
|  | Value *Trunc = Builder.CreateCall(Callee, Vec); | 
|  | Value *Splat = Constant::getNullValue(TruncT); | 
|  | return Builder.CreateShuffleVector(Trunc, Splat, {0, 1, 2, 3}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_shuffle_i8x16: { | 
|  | Value *Ops[18]; | 
|  | size_t OpIdx = 0; | 
|  | Ops[OpIdx++] = EmitScalarExpr(E->getArg(0)); | 
|  | Ops[OpIdx++] = EmitScalarExpr(E->getArg(1)); | 
|  | while (OpIdx < 18) { | 
|  | std::optional<llvm::APSInt> LaneConst = | 
|  | E->getArg(OpIdx)->getIntegerConstantExpr(getContext()); | 
|  | assert(LaneConst && "Constant arg isn't actually constant?"); | 
|  | Ops[OpIdx++] = llvm::ConstantInt::get(getLLVMContext(), *LaneConst); | 
|  | } | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_shuffle); | 
|  | return Builder.CreateCall(Callee, Ops); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_madd_f16x8: | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f16x8: | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_madd_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_madd_f64x2: | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f64x2: { | 
|  | Value *A = EmitScalarExpr(E->getArg(0)); | 
|  | Value *B = EmitScalarExpr(E->getArg(1)); | 
|  | Value *C = EmitScalarExpr(E->getArg(2)); | 
|  | unsigned IntNo; | 
|  | switch (BuiltinID) { | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_madd_f16x8: | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_madd_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_madd_f64x2: | 
|  | IntNo = Intrinsic::wasm_relaxed_madd; | 
|  | break; | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f16x8: | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f64x2: | 
|  | IntNo = Intrinsic::wasm_relaxed_nmadd; | 
|  | break; | 
|  | default: | 
|  | llvm_unreachable("unexpected builtin ID"); | 
|  | } | 
|  | Function *Callee = CGM.getIntrinsic(IntNo, A->getType()); | 
|  | return Builder.CreateCall(Callee, {A, B, C}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i8x16: | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i16x8: | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i32x4: | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i64x2: { | 
|  | Value *A = EmitScalarExpr(E->getArg(0)); | 
|  | Value *B = EmitScalarExpr(E->getArg(1)); | 
|  | Value *C = EmitScalarExpr(E->getArg(2)); | 
|  | Function *Callee = | 
|  | CGM.getIntrinsic(Intrinsic::wasm_relaxed_laneselect, A->getType()); | 
|  | return Builder.CreateCall(Callee, {A, B, C}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_swizzle_i8x16: { | 
|  | Value *Src = EmitScalarExpr(E->getArg(0)); | 
|  | Value *Indices = EmitScalarExpr(E->getArg(1)); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_relaxed_swizzle); | 
|  | return Builder.CreateCall(Callee, {Src, Indices}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_min_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_max_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_min_f64x2: | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_max_f64x2: { | 
|  | Value *LHS = EmitScalarExpr(E->getArg(0)); | 
|  | Value *RHS = EmitScalarExpr(E->getArg(1)); | 
|  | unsigned IntNo; | 
|  | switch (BuiltinID) { | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_min_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_min_f64x2: | 
|  | IntNo = Intrinsic::wasm_relaxed_min; | 
|  | break; | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_max_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_max_f64x2: | 
|  | IntNo = Intrinsic::wasm_relaxed_max; | 
|  | break; | 
|  | default: | 
|  | llvm_unreachable("unexpected builtin ID"); | 
|  | } | 
|  | Function *Callee = CGM.getIntrinsic(IntNo, LHS->getType()); | 
|  | return Builder.CreateCall(Callee, {LHS, RHS}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_i32x4_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_i32x4_f32x4: | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_zero_i32x4_f64x2: | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_zero_i32x4_f64x2: { | 
|  | Value *Vec = EmitScalarExpr(E->getArg(0)); | 
|  | unsigned IntNo; | 
|  | switch (BuiltinID) { | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_i32x4_f32x4: | 
|  | IntNo = Intrinsic::wasm_relaxed_trunc_signed; | 
|  | break; | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_i32x4_f32x4: | 
|  | IntNo = Intrinsic::wasm_relaxed_trunc_unsigned; | 
|  | break; | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_zero_i32x4_f64x2: | 
|  | IntNo = Intrinsic::wasm_relaxed_trunc_signed_zero; | 
|  | break; | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_zero_i32x4_f64x2: | 
|  | IntNo = Intrinsic::wasm_relaxed_trunc_unsigned_zero; | 
|  | break; | 
|  | default: | 
|  | llvm_unreachable("unexpected builtin ID"); | 
|  | } | 
|  | Function *Callee = CGM.getIntrinsic(IntNo); | 
|  | return Builder.CreateCall(Callee, {Vec}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_q15mulr_s_i16x8: { | 
|  | Value *LHS = EmitScalarExpr(E->getArg(0)); | 
|  | Value *RHS = EmitScalarExpr(E->getArg(1)); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_relaxed_q15mulr_signed); | 
|  | return Builder.CreateCall(Callee, {LHS, RHS}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_dot_i8x16_i7x16_s_i16x8: { | 
|  | Value *LHS = EmitScalarExpr(E->getArg(0)); | 
|  | Value *RHS = EmitScalarExpr(E->getArg(1)); | 
|  | Function *Callee = | 
|  | CGM.getIntrinsic(Intrinsic::wasm_relaxed_dot_i8x16_i7x16_signed); | 
|  | return Builder.CreateCall(Callee, {LHS, RHS}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_dot_i8x16_i7x16_add_s_i32x4: { | 
|  | Value *LHS = EmitScalarExpr(E->getArg(0)); | 
|  | Value *RHS = EmitScalarExpr(E->getArg(1)); | 
|  | Value *Acc = EmitScalarExpr(E->getArg(2)); | 
|  | Function *Callee = | 
|  | CGM.getIntrinsic(Intrinsic::wasm_relaxed_dot_i8x16_i7x16_add_signed); | 
|  | return Builder.CreateCall(Callee, {LHS, RHS, Acc}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_relaxed_dot_bf16x8_add_f32_f32x4: { | 
|  | Value *LHS = EmitScalarExpr(E->getArg(0)); | 
|  | Value *RHS = EmitScalarExpr(E->getArg(1)); | 
|  | Value *Acc = EmitScalarExpr(E->getArg(2)); | 
|  | Function *Callee = | 
|  | CGM.getIntrinsic(Intrinsic::wasm_relaxed_dot_bf16x8_add_f32); | 
|  | return Builder.CreateCall(Callee, {LHS, RHS, Acc}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_loadf16_f32: { | 
|  | Value *Addr = EmitScalarExpr(E->getArg(0)); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_loadf16_f32); | 
|  | return Builder.CreateCall(Callee, {Addr}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_storef16_f32: { | 
|  | Value *Val = EmitScalarExpr(E->getArg(0)); | 
|  | Value *Addr = EmitScalarExpr(E->getArg(1)); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_storef16_f32); | 
|  | return Builder.CreateCall(Callee, {Val, Addr}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_splat_f16x8: { | 
|  | Value *Val = EmitScalarExpr(E->getArg(0)); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_splat_f16x8); | 
|  | return Builder.CreateCall(Callee, {Val}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_extract_lane_f16x8: { | 
|  | Value *Vector = EmitScalarExpr(E->getArg(0)); | 
|  | Value *Index = EmitScalarExpr(E->getArg(1)); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_extract_lane_f16x8); | 
|  | return Builder.CreateCall(Callee, {Vector, Index}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_replace_lane_f16x8: { | 
|  | Value *Vector = EmitScalarExpr(E->getArg(0)); | 
|  | Value *Index = EmitScalarExpr(E->getArg(1)); | 
|  | Value *Val = EmitScalarExpr(E->getArg(2)); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_replace_lane_f16x8); | 
|  | return Builder.CreateCall(Callee, {Vector, Index, Val}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_table_get: { | 
|  | assert(E->getArg(0)->getType()->isArrayType()); | 
|  | Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); | 
|  | Value *Index = EmitScalarExpr(E->getArg(1)); | 
|  | Function *Callee; | 
|  | if (E->getType().isWebAssemblyExternrefType()) | 
|  | Callee = CGM.getIntrinsic(Intrinsic::wasm_table_get_externref); | 
|  | else if (E->getType().isWebAssemblyFuncrefType()) | 
|  | Callee = CGM.getIntrinsic(Intrinsic::wasm_table_get_funcref); | 
|  | else | 
|  | llvm_unreachable( | 
|  | "Unexpected reference type for __builtin_wasm_table_get"); | 
|  | return Builder.CreateCall(Callee, {Table, Index}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_table_set: { | 
|  | assert(E->getArg(0)->getType()->isArrayType()); | 
|  | Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); | 
|  | Value *Index = EmitScalarExpr(E->getArg(1)); | 
|  | Value *Val = EmitScalarExpr(E->getArg(2)); | 
|  | Function *Callee; | 
|  | if (E->getArg(2)->getType().isWebAssemblyExternrefType()) | 
|  | Callee = CGM.getIntrinsic(Intrinsic::wasm_table_set_externref); | 
|  | else if (E->getArg(2)->getType().isWebAssemblyFuncrefType()) | 
|  | Callee = CGM.getIntrinsic(Intrinsic::wasm_table_set_funcref); | 
|  | else | 
|  | llvm_unreachable( | 
|  | "Unexpected reference type for __builtin_wasm_table_set"); | 
|  | return Builder.CreateCall(Callee, {Table, Index, Val}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_table_size: { | 
|  | assert(E->getArg(0)->getType()->isArrayType()); | 
|  | Value *Value = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_table_size); | 
|  | return Builder.CreateCall(Callee, Value); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_table_grow: { | 
|  | assert(E->getArg(0)->getType()->isArrayType()); | 
|  | Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); | 
|  | Value *Val = EmitScalarExpr(E->getArg(1)); | 
|  | Value *NElems = EmitScalarExpr(E->getArg(2)); | 
|  |  | 
|  | Function *Callee; | 
|  | if (E->getArg(1)->getType().isWebAssemblyExternrefType()) | 
|  | Callee = CGM.getIntrinsic(Intrinsic::wasm_table_grow_externref); | 
|  | else if (E->getArg(2)->getType().isWebAssemblyFuncrefType()) | 
|  | Callee = CGM.getIntrinsic(Intrinsic::wasm_table_fill_funcref); | 
|  | else | 
|  | llvm_unreachable( | 
|  | "Unexpected reference type for __builtin_wasm_table_grow"); | 
|  |  | 
|  | return Builder.CreateCall(Callee, {Table, Val, NElems}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_table_fill: { | 
|  | assert(E->getArg(0)->getType()->isArrayType()); | 
|  | Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); | 
|  | Value *Index = EmitScalarExpr(E->getArg(1)); | 
|  | Value *Val = EmitScalarExpr(E->getArg(2)); | 
|  | Value *NElems = EmitScalarExpr(E->getArg(3)); | 
|  |  | 
|  | Function *Callee; | 
|  | if (E->getArg(2)->getType().isWebAssemblyExternrefType()) | 
|  | Callee = CGM.getIntrinsic(Intrinsic::wasm_table_fill_externref); | 
|  | else if (E->getArg(2)->getType().isWebAssemblyFuncrefType()) | 
|  | Callee = CGM.getIntrinsic(Intrinsic::wasm_table_fill_funcref); | 
|  | else | 
|  | llvm_unreachable( | 
|  | "Unexpected reference type for __builtin_wasm_table_fill"); | 
|  |  | 
|  | return Builder.CreateCall(Callee, {Table, Index, Val, NElems}); | 
|  | } | 
|  | case WebAssembly::BI__builtin_wasm_table_copy: { | 
|  | assert(E->getArg(0)->getType()->isArrayType()); | 
|  | Value *TableX = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); | 
|  | Value *TableY = EmitArrayToPointerDecay(E->getArg(1)).emitRawPointer(*this); | 
|  | Value *DstIdx = EmitScalarExpr(E->getArg(2)); | 
|  | Value *SrcIdx = EmitScalarExpr(E->getArg(3)); | 
|  | Value *NElems = EmitScalarExpr(E->getArg(4)); | 
|  |  | 
|  | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_table_copy); | 
|  |  | 
|  | return Builder.CreateCall(Callee, {TableX, TableY, SrcIdx, DstIdx, NElems}); | 
|  | } | 
|  | default: | 
|  | return nullptr; | 
|  | } | 
|  | } |