621 lines
27 KiB
C++
621 lines
27 KiB
C++
//===-- 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_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;
|
|
}
|
|
}
|