Implement SIMD latest opcodes and update LLVM to 13.0 (#758)

Implement the latest SIMD opcodes and update LLVM 13.0,
update the llvm build scripts, update the sample workloads‘ build scripts,
and build customized wasi-sdk to build some workloads.
Also refine the CI rules.

Signed-off-by: Wenyong Huang <wenyong.huang@intel.com>
This commit is contained in:
Wenyong Huang
2021-09-17 19:12:57 +08:00
committed by GitHub
parent 7e60a5db8d
commit 7be0d385a6
82 changed files with 5266 additions and 4698 deletions

File diff suppressed because it is too large Load Diff

View File

@ -28,11 +28,7 @@ typedef enum IntArithmetic {
typedef enum V128Arithmetic {
V128_ADD = 0,
V128_ADD_SATURATE_S,
V128_ADD_SATURATE_U,
V128_SUB,
V128_SUB_SATURATE_S,
V128_SUB_SATURATE_U,
V128_MUL,
V128_DIV,
V128_NEG,
@ -52,7 +48,7 @@ typedef enum V128Bitwise {
V128_ANDNOT,
V128_OR,
V128_XOR,
V128_BITSELECT
V128_BITSELECT,
} V128Bitwise;
typedef enum IntShift {
@ -79,7 +75,7 @@ typedef enum FloatArithmetic {
FLOAT_MUL,
FLOAT_DIV,
FLOAT_MIN,
FLOAT_MAX
FLOAT_MAX,
} FloatArithmetic;
static inline bool
@ -246,27 +242,29 @@ check_type_compatible(uint8 src_type, uint8 dst_type)
#define F64_CONST(v) LLVMConstReal(F64_TYPE, v)
#define I8_CONST(v) LLVMConstInt(INT8_TYPE, v, true)
#define I8_ZERO (comp_ctx->llvm_consts.i8_zero)
#define I32_ZERO (comp_ctx->llvm_consts.i32_zero)
#define I64_ZERO (comp_ctx->llvm_consts.i64_zero)
#define F32_ZERO (comp_ctx->llvm_consts.f32_zero)
#define F64_ZERO (comp_ctx->llvm_consts.f64_zero)
#define I32_ONE (comp_ctx->llvm_consts.i32_one)
#define I32_TWO (comp_ctx->llvm_consts.i32_two)
#define I32_THREE (comp_ctx->llvm_consts.i32_three)
#define I32_FOUR (comp_ctx->llvm_consts.i32_four)
#define I32_FIVE (comp_ctx->llvm_consts.i32_five)
#define I32_SIX (comp_ctx->llvm_consts.i32_six)
#define I32_SEVEN (comp_ctx->llvm_consts.i32_seven)
#define I32_EIGHT (comp_ctx->llvm_consts.i32_eight)
#define I32_NEG_ONE (comp_ctx->llvm_consts.i32_neg_one)
#define I64_NEG_ONE (comp_ctx->llvm_consts.i64_neg_one)
#define I32_MIN (comp_ctx->llvm_consts.i32_min)
#define I64_MIN (comp_ctx->llvm_consts.i64_min)
#define I32_31 (comp_ctx->llvm_consts.i32_31)
#define I32_32 (comp_ctx->llvm_consts.i32_32)
#define I64_63 (comp_ctx->llvm_consts.i64_63)
#define I64_64 (comp_ctx->llvm_consts.i64_64)
#define LLVM_CONST(name) (comp_ctx->llvm_consts.name)
#define I8_ZERO LLVM_CONST(i8_zero)
#define I32_ZERO LLVM_CONST(i32_zero)
#define I64_ZERO LLVM_CONST(i64_zero)
#define F32_ZERO LLVM_CONST(f32_zero)
#define F64_ZERO LLVM_CONST(f64_zero)
#define I32_ONE LLVM_CONST(i32_one)
#define I32_TWO LLVM_CONST(i32_two)
#define I32_THREE LLVM_CONST(i32_three)
#define I32_FOUR LLVM_CONST(i32_four)
#define I32_FIVE LLVM_CONST(i32_five)
#define I32_SIX LLVM_CONST(i32_six)
#define I32_SEVEN LLVM_CONST(i32_seven)
#define I32_EIGHT LLVM_CONST(i32_eight)
#define I32_NEG_ONE LLVM_CONST(i32_neg_one)
#define I64_NEG_ONE LLVM_CONST(i64_neg_one)
#define I32_MIN LLVM_CONST(i32_min)
#define I64_MIN LLVM_CONST(i64_min)
#define I32_31 LLVM_CONST(i32_31)
#define I32_32 LLVM_CONST(i32_32)
#define I64_63 LLVM_CONST(i64_63)
#define I64_64 LLVM_CONST(i64_64)
#define REF_NULL I32_NEG_ONE
#define V128_TYPE comp_ctx->basic_types.v128_type
#define V128_PTR_TYPE comp_ctx->basic_types.v128_ptr_type
@ -277,15 +275,12 @@ check_type_compatible(uint8 src_type, uint8 dst_type)
#define V128_f32x4_TYPE comp_ctx->basic_types.f32x4_vec_type
#define V128_f64x2_TYPE comp_ctx->basic_types.f64x2_vec_type
#define V128_ZERO (comp_ctx->llvm_consts.v128_zero)
#define V128_i8x16_ZERO (comp_ctx->llvm_consts.i8x16_vec_zero)
#define V128_i16x8_ZERO (comp_ctx->llvm_consts.i16x8_vec_zero)
#define V128_i32x4_ZERO (comp_ctx->llvm_consts.i32x4_vec_zero)
#define V128_i64x2_ZERO (comp_ctx->llvm_consts.i64x2_vec_zero)
#define V128_f32x4_ZERO (comp_ctx->llvm_consts.f32x4_vec_zero)
#define V128_f64x2_ZERO (comp_ctx->llvm_consts.f64x2_vec_zero)
#define REF_NULL (comp_ctx->llvm_consts.i32_neg_one)
#define V128_i8x16_ZERO LLVM_CONST(i8x16_vec_zero)
#define V128_i16x8_ZERO LLVM_CONST(i16x8_vec_zero)
#define V128_i32x4_ZERO LLVM_CONST(i32x4_vec_zero)
#define V128_i64x2_ZERO LLVM_CONST(i64x2_vec_zero)
#define V128_f32x4_ZERO LLVM_CONST(f32x4_vec_zero)
#define V128_f64x2_ZERO LLVM_CONST(f64x2_vec_zero)
#define TO_V128_i8x16(v) LLVMBuildBitCast(comp_ctx->builder, v, \
V128_i8x16_TYPE, "i8x16_val")

View File

@ -435,6 +435,20 @@ aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
}
else if (label_type == LABEL_TYPE_IF) {
POP_COND(value);
if (LLVMIsUndef(value)
#if LLVM_VERSION_NUMBER >= 12
|| LLVMIsPoison(value)
#endif
) {
if (!(aot_emit_exception(comp_ctx, func_ctx, EXCE_INTEGER_OVERFLOW,
false, NULL, NULL))) {
goto fail;
}
return aot_handle_next_reachable_block(comp_ctx, func_ctx,
p_frame_ip);
}
if (!LLVMIsConstant(value)) {
/* Compare value is not constant, create condition br IR */
/* Create entry block */
@ -791,6 +805,19 @@ aot_compile_op_br_if(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
#endif
POP_COND(value_cmp);
if (LLVMIsUndef(value_cmp)
#if LLVM_VERSION_NUMBER >= 12
|| LLVMIsPoison(value_cmp)
#endif
) {
if (!(aot_emit_exception(comp_ctx, func_ctx, EXCE_INTEGER_OVERFLOW,
false, NULL, NULL))) {
goto fail;
}
return aot_handle_next_reachable_block(comp_ctx, func_ctx, p_frame_ip);
}
if (!LLVMIsConstant(value_cmp)) {
/* Compare value is not constant, create condition br IR */
if (!(block_dst = get_target_block(func_ctx, br_depth))) {
@ -917,6 +944,19 @@ aot_compile_op_br_table(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
#endif
POP_I32(value_cmp);
if (LLVMIsUndef(value_cmp)
#if LLVM_VERSION_NUMBER >= 12
|| LLVMIsPoison(value_cmp)
#endif
) {
if (!(aot_emit_exception(comp_ctx, func_ctx, EXCE_INTEGER_OVERFLOW,
false, NULL, NULL))) {
goto fail;
}
return aot_handle_next_reachable_block(comp_ctx, func_ctx, p_frame_ip);
}
if (!LLVMIsConstant(value_cmp)) {
/* Compare value is not constant, create switch IR */
for (i = 0; i <= br_count; i++) {

View File

@ -126,8 +126,16 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
POP_I32(addr);
/*
* Note: not throw the integer-overflow-exception here since it must
* have been thrown when converting float to integer before
*/
/* return addres directly if constant offset and inside memory space */
if (LLVMIsConstant(addr)) {
if (LLVMIsConstant(addr) && !LLVMIsUndef(addr)
#if LLVM_VERSION_NUMBER >= 12
&& !LLVMIsPoison(addr)
#endif
) {
uint64 mem_offset = (uint64)LLVMConstIntGetZExtValue(addr)
+ (uint64)offset;
uint32 num_bytes_per_page =
@ -764,8 +772,16 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
}
}
/*
* Note: not throw the integer-overflow-exception here since it must
* have been thrown when converting float to integer before
*/
/* return addres directly if constant offset and inside memory space */
if (LLVMIsConstant(offset) && LLVMIsConstant(bytes)) {
if (!LLVMIsUndef(offset) && !LLVMIsUndef(bytes)
#if LLVM_VERSION_NUMBER >= 12
&& !LLVMIsPoison(offset) && !LLVMIsPoison(bytes)
#endif
&& LLVMIsConstant(offset) && LLVMIsConstant(bytes)) {
uint64 mem_offset = (uint64)LLVMConstIntGetZExtValue(offset);
uint64 mem_len = (uint64)LLVMConstIntGetZExtValue(bytes);
uint32 num_bytes_per_page =

View File

@ -36,10 +36,17 @@
LLVMMoveBasicBlockAfter(block, LLVMGetInsertBlock(comp_ctx->builder)); \
} while (0)
#define IS_CONST_ZERO(val) \
(LLVMIsConstant(val) \
&& ((is_i32 && (int32)LLVMConstIntGetZExtValue(val) == 0) \
#if LLVM_VERSION_NUMBER >= 12
#define IS_CONST_ZERO(val) \
(!LLVMIsUndef(val) && !LLVMIsPoison(val) && LLVMIsConstant(val) \
&& ((is_i32 && (int32)LLVMConstIntGetZExtValue(val) == 0) \
|| (!is_i32 && (int64)LLVMConstIntGetSExtValue(val) == 0)))
#else
#define IS_CONST_ZERO(val) \
(!LLVMIsUndef(val) && LLVMIsConstant(val) \
&& ((is_i32 && (int32)LLVMConstIntGetZExtValue(val) == 0) \
|| (!is_i32 && (int64)LLVMConstIntGetSExtValue(val) == 0)))
#endif
#define CHECK_INT_OVERFLOW(type) do { \
LLVMValueRef cmp_min_int, cmp_neg_one; \
@ -399,6 +406,18 @@ compile_int_div(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
POP_INT(right);
POP_INT(left);
if (LLVMIsUndef(right) || LLVMIsUndef(left)
#if LLVM_VERSION_NUMBER >= 12
|| LLVMIsPoison(right) || LLVMIsPoison(left)
#endif
) {
if (!(aot_emit_exception(comp_ctx, func_ctx, EXCE_INTEGER_OVERFLOW,
false, NULL, NULL))) {
goto fail;
}
return aot_handle_next_reachable_block(comp_ctx, func_ctx, p_frame_ip);
}
if (LLVMIsConstant(right)) {
int64 right_val = (int64)LLVMConstIntGetSExtValue(right);
switch (right_val) {

View File

@ -811,7 +811,7 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx,
local_value = F64_ZERO;
break;
case VALUE_TYPE_V128:
local_value = V128_ZERO;
local_value = V128_i64x2_ZERO;
break;
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
@ -963,6 +963,8 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context)
basic_types->v128_type = basic_types->i64x2_vec_type;
basic_types->v128_ptr_type = LLVMPointerType(basic_types->v128_type, 0);
basic_types->i1x2_vec_type = LLVMVectorType(basic_types->int1_type, 2);
basic_types->funcref_type = LLVMInt32TypeInContext(context);
basic_types->externref_type = LLVMInt32TypeInContext(context);
@ -979,6 +981,7 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context)
&& basic_types->i64x2_vec_type
&& basic_types->f32x4_vec_type
&& basic_types->f64x2_vec_type
&& basic_types->i1x2_vec_type
&& basic_types->meta_data_type
&& basic_types->funcref_type
&& basic_types->externref_type) ? true : false;
@ -987,73 +990,89 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context)
static bool
aot_create_llvm_consts(AOTLLVMConsts *consts, AOTCompContext *comp_ctx)
{
LLVMValueRef i64_consts[2];
#define CREATE_I1_CONST(name, value) \
if (!(consts->i1_##name = \
LLVMConstInt(comp_ctx->basic_types.int1_type, value, true))) \
return false;
consts->i8_zero = I8_CONST(0);
consts->i32_zero = I32_CONST(0);
consts->i64_zero = I64_CONST(0);
consts->f32_zero = F32_CONST(0);
consts->f64_zero = F64_CONST(0);
CREATE_I1_CONST(zero, 0)
CREATE_I1_CONST(one, 1)
#undef CREATE_I1_CONST
if (consts->i64_zero) {
i64_consts[0] = i64_consts[1] = consts->i64_zero;
consts->v128_zero = consts->i64x2_vec_zero =
LLVMConstVector(i64_consts, 2);
if (consts->i64x2_vec_zero) {
consts->i8x16_vec_zero = TO_V128_i8x16(consts->i64x2_vec_zero);
consts->i16x8_vec_zero = TO_V128_i16x8(consts->i64x2_vec_zero);
consts->i32x4_vec_zero = TO_V128_i32x4(consts->i64x2_vec_zero);
consts->f32x4_vec_zero = TO_V128_f32x4(consts->i64x2_vec_zero);
consts->f64x2_vec_zero = TO_V128_f64x2(consts->i64x2_vec_zero);
}
if (!(consts->i8_zero = I8_CONST(0)))
return false;
if (!(consts->f32_zero = F32_CONST(0)))
return false;
if (!(consts->f64_zero = F64_CONST(0)))
return false;
#define CREATE_I32_CONST(name, value) \
if (!(consts->i32_##name = LLVMConstInt(I32_TYPE, value, true))) \
return false;
CREATE_I32_CONST(min, (uint32)INT32_MIN)
CREATE_I32_CONST(neg_one, (uint32)-1)
CREATE_I32_CONST(zero, 0)
CREATE_I32_CONST(one, 1)
CREATE_I32_CONST(two, 2)
CREATE_I32_CONST(three, 3)
CREATE_I32_CONST(four, 4)
CREATE_I32_CONST(five, 5)
CREATE_I32_CONST(six, 6)
CREATE_I32_CONST(seven, 7)
CREATE_I32_CONST(eight, 8)
CREATE_I32_CONST(nine, 9)
CREATE_I32_CONST(ten, 10)
CREATE_I32_CONST(eleven, 11)
CREATE_I32_CONST(twelve, 12)
CREATE_I32_CONST(thirteen, 13)
CREATE_I32_CONST(fourteen, 14)
CREATE_I32_CONST(fifteen, 15)
CREATE_I32_CONST(31, 31)
CREATE_I32_CONST(32, 32)
#undef CREATE_I32_CONST
#define CREATE_I64_CONST(name, value) \
if (!(consts->i64_##name = LLVMConstInt(I64_TYPE, value, true))) \
return false;
CREATE_I64_CONST(min, (uint64)INT64_MIN)
CREATE_I64_CONST(neg_one, (uint64)-1)
CREATE_I64_CONST(zero, 0)
CREATE_I64_CONST(63, 63)
CREATE_I64_CONST(64, 64)
#undef CREATE_I64_CONST
#define CREATE_V128_CONST(name, type) \
if (!(consts->name##_vec_zero = LLVMConstNull(type))) \
return false; \
if (!(consts->name##_undef = LLVMGetUndef(type))) \
return false;
CREATE_V128_CONST(i8x16, V128_i8x16_TYPE)
CREATE_V128_CONST(i16x8, V128_i16x8_TYPE)
CREATE_V128_CONST(i32x4, V128_i32x4_TYPE)
CREATE_V128_CONST(i64x2, V128_i64x2_TYPE)
CREATE_V128_CONST(f32x4, V128_f32x4_TYPE)
CREATE_V128_CONST(f64x2, V128_f64x2_TYPE)
#undef CREATE_V128_CONST
#define CREATE_VEC_ZERO_MASK(slot) \
{ \
LLVMTypeRef type = LLVMVectorType(I32_TYPE, slot); \
if (!type || !(consts->i32x##slot##_zero = LLVMConstNull(type))) \
return false; \
}
consts->i32_one = I32_CONST(1);
consts->i32_two = I32_CONST(2);
consts->i32_three = I32_CONST(3);
consts->i32_four = I32_CONST(4);
consts->i32_five = I32_CONST(5);
consts->i32_six = I32_CONST(6);
consts->i32_seven = I32_CONST(7);
consts->i32_eight = I32_CONST(8);
consts->i32_neg_one = I32_CONST((uint32)-1);
consts->i64_neg_one = I64_CONST((uint64)-1);
consts->i32_min = I32_CONST((uint32)INT32_MIN);
consts->i64_min = I64_CONST((uint64)INT64_MIN);
consts->i32_31 = I32_CONST(31);
consts->i32_32 = I32_CONST(32);
consts->i64_63 = I64_CONST(63);
consts->i64_64 = I64_CONST(64);
consts->ref_null = I32_CONST(NULL_REF);
CREATE_VEC_ZERO_MASK(16)
CREATE_VEC_ZERO_MASK(8)
CREATE_VEC_ZERO_MASK(4)
CREATE_VEC_ZERO_MASK(2)
#undef CREATE_VEC_ZERO_MASK
return (consts->i8_zero
&& consts->i32_zero
&& consts->i64_zero
&& consts->f32_zero
&& consts->f64_zero
&& consts->i8x16_vec_zero
&& consts->i16x8_vec_zero
&& consts->i32x4_vec_zero
&& consts->i64x2_vec_zero
&& consts->f32x4_vec_zero
&& consts->f64x2_vec_zero
&& consts->i32_one
&& consts->i32_two
&& consts->i32_three
&& consts->i32_four
&& consts->i32_five
&& consts->i32_six
&& consts->i32_seven
&& consts->i32_eight
&& consts->i32_neg_one
&& consts->i64_neg_one
&& consts->i32_min
&& consts->i64_min
&& consts->i32_31
&& consts->i32_32
&& consts->i64_63
&& consts->i64_64
&& consts->ref_null) ? true : false;
return true;
}
typedef struct ArchItem {
@ -2213,7 +2232,8 @@ aot_build_zero_function_ret(AOTCompContext *comp_ctx,
ret = LLVMBuildRet(comp_ctx->builder, F64_ZERO);
break;
case VALUE_TYPE_V128:
ret = LLVMBuildRet(comp_ctx->builder, V128_ZERO);
ret =
LLVMBuildRet(comp_ctx->builder, LLVM_CONST(i64x2_vec_zero));
break;
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
@ -2315,7 +2335,7 @@ __call_llvm_intrinsic(const AOTCompContext *comp_ctx,
LLVMValueRef
aot_call_llvm_intrinsic(const AOTCompContext *comp_ctx,
const AOTFuncContext *func_ctx,
const char *name,
const char *intrinsic,
LLVMTypeRef ret_type,
LLVMTypeRef *param_types,
int param_count,
@ -2340,8 +2360,8 @@ aot_call_llvm_intrinsic(const AOTCompContext *comp_ctx,
param_values[i++] = va_arg(argptr, LLVMValueRef);
va_end(argptr);
ret = __call_llvm_intrinsic(comp_ctx, func_ctx, name, ret_type, param_types,
param_count, param_values);
ret = __call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic, ret_type,
param_types, param_count, param_values);
wasm_runtime_free(param_values);
@ -2351,7 +2371,7 @@ aot_call_llvm_intrinsic(const AOTCompContext *comp_ctx,
LLVMValueRef
aot_call_llvm_intrinsic_v(const AOTCompContext *comp_ctx,
const AOTFuncContext *func_ctx,
const char *name,
const char *intrinsic,
LLVMTypeRef ret_type,
LLVMTypeRef *param_types,
int param_count,
@ -2373,8 +2393,8 @@ aot_call_llvm_intrinsic_v(const AOTCompContext *comp_ctx,
while (i < param_count)
param_values[i++] = va_arg(param_value_list, LLVMValueRef);
ret = __call_llvm_intrinsic(comp_ctx, func_ctx, name, ret_type, param_types,
param_count, param_values);
ret = __call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic, ret_type,
param_types, param_count, param_values);
wasm_runtime_free(param_values);

View File

@ -178,6 +178,8 @@ typedef struct AOTLLVMTypes {
LLVMTypeRef f32x4_vec_type;
LLVMTypeRef f64x2_vec_type;
LLVMTypeRef i1x2_vec_type;
LLVMTypeRef meta_data_type;
LLVMTypeRef funcref_type;
@ -185,18 +187,13 @@ typedef struct AOTLLVMTypes {
} AOTLLVMTypes;
typedef struct AOTLLVMConsts {
LLVMValueRef i1_zero;
LLVMValueRef i1_one;
LLVMValueRef i8_zero;
LLVMValueRef i32_zero;
LLVMValueRef i64_zero;
LLVMValueRef f32_zero;
LLVMValueRef f64_zero;
LLVMValueRef v128_zero;
LLVMValueRef i8x16_vec_zero;
LLVMValueRef i16x8_vec_zero;
LLVMValueRef i32x4_vec_zero;
LLVMValueRef i64x2_vec_zero;
LLVMValueRef f32x4_vec_zero;
LLVMValueRef f64x2_vec_zero;
LLVMValueRef i32_one;
LLVMValueRef i32_two;
LLVMValueRef i32_three;
@ -205,6 +202,13 @@ typedef struct AOTLLVMConsts {
LLVMValueRef i32_six;
LLVMValueRef i32_seven;
LLVMValueRef i32_eight;
LLVMValueRef i32_nine;
LLVMValueRef i32_ten;
LLVMValueRef i32_eleven;
LLVMValueRef i32_twelve;
LLVMValueRef i32_thirteen;
LLVMValueRef i32_fourteen;
LLVMValueRef i32_fifteen;
LLVMValueRef i32_neg_one;
LLVMValueRef i64_neg_one;
LLVMValueRef i32_min;
@ -213,7 +217,22 @@ typedef struct AOTLLVMConsts {
LLVMValueRef i32_32;
LLVMValueRef i64_63;
LLVMValueRef i64_64;
LLVMValueRef ref_null;
LLVMValueRef i8x16_vec_zero;
LLVMValueRef i16x8_vec_zero;
LLVMValueRef i32x4_vec_zero;
LLVMValueRef i64x2_vec_zero;
LLVMValueRef f32x4_vec_zero;
LLVMValueRef f64x2_vec_zero;
LLVMValueRef i8x16_undef;
LLVMValueRef i16x8_undef;
LLVMValueRef i32x4_undef;
LLVMValueRef i64x2_undef;
LLVMValueRef f32x4_undef;
LLVMValueRef f64x2_undef;
LLVMValueRef i32x16_zero;
LLVMValueRef i32x8_zero;
LLVMValueRef i32x4_zero;
LLVMValueRef i32x2_zero;
} AOTLLVMConsts;
/**
@ -393,7 +412,7 @@ aot_build_zero_function_ret(AOTCompContext *comp_ctx,
LLVMValueRef
aot_call_llvm_intrinsic(const AOTCompContext *comp_ctx,
const AOTFuncContext *func_ctx,
const char *name,
const char *intrinsic,
LLVMTypeRef ret_type,
LLVMTypeRef *param_types,
int param_count,
@ -402,7 +421,7 @@ aot_call_llvm_intrinsic(const AOTCompContext *comp_ctx,
LLVMValueRef
aot_call_llvm_intrinsic_v(const AOTCompContext *comp_ctx,
const AOTFuncContext *func_ctx,
const char *name,
const char *intrinsic,
LLVMTypeRef ret_type,
LLVMTypeRef *param_types,
int param_count,

View File

@ -8,39 +8,6 @@
#include "../aot_emit_exception.h"
#include "../../aot/aot_runtime.h"
static bool
is_target_x86(AOTCompContext *comp_ctx)
{
return !strncmp(comp_ctx->target_arch, "x86_64", 6) ||
!strncmp(comp_ctx->target_arch, "i386", 4);
}
static LLVMValueRef
build_intx16_vector(const AOTCompContext *comp_ctx,
const LLVMTypeRef element_type,
const int *element_value)
{
LLVMValueRef vector, elements[16];
unsigned i;
for (i = 0; i < 16; i++) {
if (!(elements[i] =
LLVMConstInt(element_type, element_value[i], true))) {
HANDLE_FAILURE("LLVMConstInst");
goto fail;
}
}
if (!(vector = LLVMConstVector(elements, 16))) {
HANDLE_FAILURE("LLVMConstVector");
goto fail;
}
return vector;
fail:
return NULL;
}
bool
aot_compile_simd_shuffle(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
@ -67,7 +34,8 @@ aot_compile_simd_shuffle(AOTCompContext *comp_ctx,
}
/* build a vector <16 x i32> */
if (!(mask = build_intx16_vector(comp_ctx, I32_TYPE, values))) {
if (!(mask =
simd_build_const_integer_vector(comp_ctx, I32_TYPE, values, 16))) {
goto fail;
}
@ -77,29 +45,20 @@ aot_compile_simd_shuffle(AOTCompContext *comp_ctx,
goto fail;
}
if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE,
"ret"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
PUSH_V128(result);
return true;
fail:
return false;
}
/*TODO: llvm.experimental.vector.*/
/* shufflevector is not an option, since it requires *mask as a const */
bool
aot_compile_simd_swizzle_x86(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
aot_compile_simd_swizzle_x86(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
LLVMValueRef vector, mask, max_lanes, condition, mask_lanes, result;
LLVMTypeRef param_types[2];
int max_lane_id[16] = { 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16 },
mask_lane_id[16] = { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 };
if (!(mask = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i8x16_TYPE,
"mask"))) {
@ -112,7 +71,15 @@ aot_compile_simd_swizzle_x86(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
}
/* icmp uge <16 x i8> mask, <16, 16, 16, 16, ...> */
if (!(max_lanes = build_intx16_vector(comp_ctx, INT8_TYPE, max_lane_id))) {
if (!(max_lanes = simd_build_splat_const_integer_vector(
comp_ctx, INT8_TYPE, 16, 16))) {
goto fail;
}
/* if the highest bit of every i8 of mask is 1, means doesn't pick up from vector */
/* select <16 x i1> %condition, <16 x i8> <0x80, 0x80, ...>, <16 x i8> %mask */
if (!(mask_lanes = simd_build_splat_const_integer_vector(
comp_ctx, INT8_TYPE, 0x80, 16))) {
goto fail;
}
@ -122,13 +89,6 @@ aot_compile_simd_swizzle_x86(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
goto fail;
}
/* if the highest bit of every i8 of mask is 1, means doesn't pick up from vector */
/* select <16 x i1> %condition, <16 x i8> <0x80, 0x80, ...>, <16 x i8> %mask */
if (!(mask_lanes =
build_intx16_vector(comp_ctx, INT8_TYPE, mask_lane_id))) {
goto fail;
}
if (!(mask = LLVMBuildSelect(comp_ctx->builder, condition, mask_lanes,
mask, "mask"))) {
HANDLE_FAILURE("LLVMBuildSelect");
@ -158,17 +118,13 @@ fail:
}
static bool
aot_compile_simd_swizzle_common(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
aot_compile_simd_swizzle_common(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
LLVMValueRef vector, mask, default_lane_value, condition, max_lane_id,
result, idx, id, replace_with_zero, elem, elem_or_zero, undef;
uint8 i;
int const_lane_ids[16] = { 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16 },
const_zeors[16] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
if (!(mask = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i8x16_TYPE,
"mask"))) {
goto fail;
@ -185,8 +141,8 @@ aot_compile_simd_swizzle_common(AOTCompContext *comp_ctx, AOTFuncContext *func_c
}
/* icmp uge <16 x i8> mask, <16, 16, 16, 16, ...> */
if (!(max_lane_id =
build_intx16_vector(comp_ctx, INT8_TYPE, const_lane_ids))) {
if (!(max_lane_id = simd_build_splat_const_integer_vector(
comp_ctx, INT8_TYPE, 16, 16))) {
goto fail;
}
@ -197,8 +153,8 @@ aot_compile_simd_swizzle_common(AOTCompContext *comp_ctx, AOTFuncContext *func_c
}
/* if the id is out of range (>=16), set the id as 0 */
if (!(default_lane_value =
build_intx16_vector(comp_ctx, INT8_TYPE, const_zeors))) {
if (!(default_lane_value = simd_build_splat_const_integer_vector(
comp_ctx, INT8_TYPE, 0, 16))) {
goto fail;
}
@ -277,9 +233,9 @@ aot_compile_simd_extract(AOTCompContext *comp_ctx,
LLVMTypeRef result_type,
unsigned aot_value_type)
{
LLVMValueRef vector, idx, result;
LLVMValueRef vector, lane, result;
if (!(idx = I8_CONST(lane_id))) {
if (!(lane = simd_lane_id_to_llvm_value(comp_ctx, lane_id))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
@ -291,7 +247,7 @@ aot_compile_simd_extract(AOTCompContext *comp_ctx,
}
/* extractelement <vector_type> %vector, i8 lane_id*/
if (!(result = LLVMBuildExtractElement(comp_ctx->builder, vector, idx,
if (!(result = LLVMBuildExtractElement(comp_ctx->builder, vector, lane,
"element"))) {
HANDLE_FAILURE("LLVMBuildExtractElement");
goto fail;
@ -390,23 +346,20 @@ aot_compile_simd_replace(AOTCompContext *comp_ctx,
bool need_reduce,
LLVMTypeRef element_type)
{
LLVMValueRef vector, new_value, idx, result;
LLVMValueRef vector, new_value, lane, result;
POP(new_value, new_value_type);
if (!(idx = I8_CONST(lane_id))) {
HANDLE_FAILURE("LLVMConstInt");
if (!(lane = simd_lane_id_to_llvm_value(comp_ctx, lane_id))) {
goto fail;
}
/* bitcast <2 x i64> %0 to <vector_type> */
if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"vec"))) {
goto fail;
}
/* bitcast <new_value_type> to <element_type> */
/* trunc <new_value_type> to <element_type> */
if (need_reduce) {
if (!(new_value = LLVMBuildTrunc(comp_ctx->builder, new_value,
element_type, "element"))) {
@ -415,23 +368,15 @@ aot_compile_simd_replace(AOTCompContext *comp_ctx,
}
}
/* insertelement <vector_type> %vector, <element_type> %element, i8 idx */
/* insertelement <vector_type> %vector, <element_type> %element, i32 lane */
if (!(result = LLVMBuildInsertElement(comp_ctx->builder, vector, new_value,
idx, "new_vector"))) {
lane, "new_vector"))) {
HANDLE_FAILURE("LLVMBuildInsertElement");
goto fail;
}
/* bitcast <vector_type> %result to <2 x i64> */
if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE,
"ret"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "reesult");
PUSH_V128(result);
return true;
fail:
return false;
}

View File

@ -82,6 +82,26 @@ aot_compile_simd_replace_f64x2(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint8 lane_id);
bool
aot_compile_simd_load8_lane(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint8 lane_id);
bool
aot_compile_simd_load16_lane(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint8 lane_id);
bool
aot_compile_simd_load32_lane(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint8 lane_id);
bool
aot_compile_simd_load64_lane(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint8 lane_id);
#ifdef __cplusplus
} /* end of extern "C" */
#endif

View File

@ -8,121 +8,112 @@
#include "../aot_emit_exception.h"
#include "../../aot/aot_runtime.h"
enum integer_shift {
e_shift_i8x16,
e_shift_i16x8,
e_shift_i32x4,
e_shift_i64x2,
};
static bool
simd_shift(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
IntShift shift_op,
LLVMTypeRef vector_type,
LLVMTypeRef element_type,
unsigned lane_width)
enum integer_shift itype)
{
LLVMValueRef vector, offset, width, undef, zeros, result;
LLVMTypeRef zeros_type;
LLVMValueRef vector, offset, result = NULL;
LLVMTypeRef vector_type[] = { V128_i8x16_TYPE, V128_i16x8_TYPE,
V128_i32x4_TYPE, V128_i64x2_TYPE };
LLVMTypeRef element_type[] = { INT8_TYPE, INT16_TYPE, I32_TYPE, I64_TYPE };
LLVMValueRef undef[] = { LLVM_CONST(i8x16_undef), LLVM_CONST(i16x8_undef),
LLVM_CONST(i32x4_undef),
LLVM_CONST(i64x2_undef) };
LLVMValueRef mask[] = { LLVM_CONST(i8x16_vec_zero),
LLVM_CONST(i16x8_vec_zero),
LLVM_CONST(i32x4_vec_zero),
LLVM_CONST(i64x2_vec_zero) };
LLVMValueRef lane_bits[] = {
LLVM_CONST(i32_eight),
LLVMConstInt(I32_TYPE, 16, true),
LLVMConstInt(I32_TYPE, 32, true),
LLVMConstInt(I32_TYPE, 64, true),
};
POP_I32(offset);
if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"vec"))) {
goto fail;
if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
vector_type[itype], "vec"))) {
return false;
}
if (!(width = LLVMConstInt(I32_TYPE, lane_width, true))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
/* offset mod LaneBits */
if (!lane_bits[itype]
|| !(offset = LLVMBuildSRem(comp_ctx->builder, offset,
lane_bits[itype], "offset_fix"))) {
HANDLE_FAILURE("LLVMBuildSRem");
return false;
}
/* change type */
if (itype < e_shift_i32x4) {
offset = LLVMBuildTrunc(comp_ctx->builder, offset, element_type[itype],
"offset_trunc");
}
else if (itype == e_shift_i64x2) {
offset = LLVMBuildZExt(comp_ctx->builder, offset, element_type[itype],
"offset_ext");
}
if (!offset) {
HANDLE_FAILURE("LLVMBuildZext/LLVMBuildTrunc");
return false;
}
/* splat to a vector */
if (!(offset =
LLVMBuildInsertElement(comp_ctx->builder, undef[itype], offset,
I32_ZERO, "offset_vector_base"))) {
HANDLE_FAILURE("LLVMBuildInsertElement");
return false;
}
if (!(offset =
LLVMBuildURem(comp_ctx->builder, offset, width, "remainder"))) {
HANDLE_FAILURE("LLVMBuildURem");
goto fail;
}
if (I64_TYPE == element_type) {
if (!(offset = LLVMBuildZExt(comp_ctx->builder, offset, element_type,
"offset_scalar"))) {
HANDLE_FAILURE("LLVMBuildZExt");
goto fail;
}
}
else {
if (!(offset = LLVMBuildTruncOrBitCast(
comp_ctx->builder, offset, element_type, "offset_scalar"))) {
HANDLE_FAILURE("LLVMBuildTrunc");
goto fail;
}
}
/* create a vector with offset */
if (!(undef = LLVMGetUndef(vector_type))) {
HANDLE_FAILURE("LLVMGetUndef");
goto fail;
}
if (!(zeros_type = LLVMVectorType(I32_TYPE, 128 / lane_width))) {
HANDLE_FAILURE("LVMVectorType");
goto fail;
}
if (!(zeros = LLVMConstNull(zeros_type))) {
HANDLE_FAILURE("LLVMConstNull");
goto fail;
}
if (!(offset = LLVMBuildInsertElement(comp_ctx->builder, undef, offset,
I32_ZERO, "base_vector"))) {
HANDLE_FAILURE("LLVMBuildInsertElement");
goto fail;
}
if (!(offset = LLVMBuildShuffleVector(comp_ctx->builder, offset, undef,
zeros, "offset_vector"))) {
LLVMBuildShuffleVector(comp_ctx->builder, offset, undef[itype],
mask[itype], "offset_vector"))) {
HANDLE_FAILURE("LLVMBuildShuffleVector");
goto fail;
return false;
}
switch (shift_op) {
case INT_SHL:
{
if (!(result =
LLVMBuildShl(comp_ctx->builder, vector, offset, "shl"))) {
HANDLE_FAILURE("LLVMBuildShl");
goto fail;
}
result = LLVMBuildShl(comp_ctx->builder, vector, offset, "shl");
break;
}
case INT_SHR_S:
{
if (!(result = LLVMBuildAShr(comp_ctx->builder, vector, offset,
"ashr"))) {
HANDLE_FAILURE("LLVMBuildAShr");
goto fail;
}
result = LLVMBuildAShr(comp_ctx->builder, vector, offset, "ashr");
break;
}
case INT_SHR_U:
{
if (!(result = LLVMBuildLShr(comp_ctx->builder, vector, offset,
"lshr"))) {
HANDLE_FAILURE("LLVMBuildLShr");
goto fail;
}
result = LLVMBuildLShr(comp_ctx->builder, vector, offset, "lshr");
break;
}
default:
{
bh_assert(0);
goto fail;
break;
}
}
if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE,
"result"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
if (!result) {
HANDLE_FAILURE("LLVMBuildShl/LLVMBuildLShr/LLVMBuildAShr");
goto fail;
}
PUSH_V128(result);
return true;
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
fail:
return false;
}
@ -132,8 +123,7 @@ aot_compile_simd_i8x16_shift(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
IntShift shift_op)
{
return simd_shift(comp_ctx, func_ctx, shift_op, V128_i8x16_TYPE, INT8_TYPE,
8);
return simd_shift(comp_ctx, func_ctx, shift_op, e_shift_i8x16);
}
bool
@ -141,8 +131,7 @@ aot_compile_simd_i16x8_shift(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
IntShift shift_op)
{
return simd_shift(comp_ctx, func_ctx, shift_op, V128_i16x8_TYPE,
INT16_TYPE, 16);
return simd_shift(comp_ctx, func_ctx, shift_op, e_shift_i16x8);
}
bool
@ -150,8 +139,7 @@ aot_compile_simd_i32x4_shift(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
IntShift shift_op)
{
return simd_shift(comp_ctx, func_ctx, shift_op, V128_i32x4_TYPE, I32_TYPE,
32);
return simd_shift(comp_ctx, func_ctx, shift_op, e_shift_i32x4);
}
bool
@ -159,6 +147,5 @@ aot_compile_simd_i64x2_shift(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
IntShift shift_op)
{
return simd_shift(comp_ctx, func_ctx, shift_op, V128_i64x2_TYPE, I64_TYPE,
64);
return simd_shift(comp_ctx, func_ctx, shift_op, e_shift_i64x2);
}

View File

@ -8,70 +8,92 @@
#include "../aot_emit_exception.h"
#include "../../aot/aot_runtime.h"
enum integer_bitmask_type {
e_bitmask_i8x16,
e_bitmask_i16x8,
e_bitmask_i32x4,
e_bitmask_i64x2,
};
/* TODO: should use a much clever intrinsic */
static bool
simd_build_bitmask(const AOTCompContext *comp_ctx,
const AOTFuncContext *func_ctx,
uint8 length,
LLVMTypeRef vector_type,
LLVMTypeRef element_type,
const char *intrinsic)
enum integer_bitmask_type itype)
{
LLVMValueRef vector, zeros, mask, mask_elements[16], cond, result;
LLVMTypeRef param_types[1], vector_ext_type;
const uint32 numbers[16] = { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20,
0x40, 0x80, 0x100, 0x200, 0x400, 0x800,
0x1000, 0x2000, 0x4000, 0x8000 };
LLVMValueRef vector, mask, result;
uint8 i;
LLVMTypeRef vector_ext_type;
if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"vec"))) {
uint32 lanes[] = { 16, 8, 4, 2 };
uint32 lane_bits[] = { 8, 16, 32, 64 };
LLVMTypeRef element_type[] = { INT8_TYPE, INT16_TYPE, I32_TYPE, I64_TYPE };
LLVMTypeRef vector_type[] = { V128_i8x16_TYPE, V128_i16x8_TYPE,
V128_i32x4_TYPE, V128_i64x2_TYPE };
int32 mask_element[16] = { 0 };
const char *intrinsic[] = {
"llvm.vector.reduce.or.v16i64",
"llvm.vector.reduce.or.v8i64",
"llvm.vector.reduce.or.v4i64",
"llvm.vector.reduce.or.v2i64",
};
LLVMValueRef ashr_distance;
if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
vector_type[itype], "vec"))) {
goto fail;
}
if (!(vector_ext_type = LLVMVectorType(I32_TYPE, length))) {
/* fill every bit in a lange with its sign bit */
if (!(ashr_distance = simd_build_splat_const_integer_vector(
comp_ctx, element_type[itype], lane_bits[itype] - 1,
lanes[itype]))) {
goto fail;
}
if (!(vector = LLVMBuildAShr(comp_ctx->builder, vector, ashr_distance,
"vec_ashr"))) {
HANDLE_FAILURE("LLVMBuildAShr");
goto fail;
}
if (!(vector_ext_type = LLVMVectorType(I64_TYPE, lanes[itype]))) {
HANDLE_FAILURE("LLVMVectorType");
goto fail;
}
if (!(vector = LLVMBuildSExt(comp_ctx->builder, vector, vector_ext_type,
"vec_ext"))) {
HANDLE_FAILURE("LLVMBuildSExt");
goto fail;
}
if (!(zeros = LLVMConstNull(vector_ext_type))) {
HANDLE_FAILURE("LLVMConstNull");
goto fail;
}
for (i = 0; i < 16; i++) {
if (!(mask_elements[i] = LLVMConstInt(I32_TYPE, numbers[i], false))) {
HANDLE_FAILURE("LLVMConstInt");
if (e_bitmask_i64x2 != itype) {
if (!(vector = LLVMBuildSExt(comp_ctx->builder, vector,
vector_ext_type, "zext_to_i64"))) {
goto fail;
}
}
if (!(mask = LLVMConstVector(mask_elements, length))) {
HANDLE_FAILURE("LLVMConstVector");
for (i = 0; i < 16; i++) {
mask_element[i] = 0x1 << i;
}
if (!(mask = simd_build_const_integer_vector(
comp_ctx, I64_TYPE, mask_element, lanes[itype]))) {
goto fail;
}
if (!(cond = LLVMBuildICmp(comp_ctx->builder, LLVMIntSLT, vector, zeros,
"lt_zero"))) {
HANDLE_FAILURE("LLVMBuildICmp");
if (!(vector =
LLVMBuildAnd(comp_ctx->builder, vector, mask, "mask_bits"))) {
HANDLE_FAILURE("LLVMBuildAnd");
goto fail;
}
if (!(result =
LLVMBuildSelect(comp_ctx->builder, cond, mask, zeros, "select"))) {
HANDLE_FAILURE("LLVMBuildSelect");
aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic[itype],
I64_TYPE, &vector_ext_type, 1, vector))) {
goto fail;
}
param_types[0] = vector_ext_type;
if (!(result = aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic, I32_TYPE,
param_types, 1, result))) {
HANDLE_FAILURE("LLVMBuildCall");
if (!(result =
LLVMBuildTrunc(comp_ctx->builder, result, I32_TYPE, "to_i32"))) {
HANDLE_FAILURE("LLVMBuildTrunc");
goto fail;
}
@ -86,24 +108,26 @@ bool
aot_compile_simd_i8x16_bitmask(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_build_bitmask(comp_ctx, func_ctx, 16, V128_i8x16_TYPE,
INT8_TYPE,
"llvm.experimental.vector.reduce.or.v16i32");
return simd_build_bitmask(comp_ctx, func_ctx, e_bitmask_i8x16);
}
bool
aot_compile_simd_i16x8_bitmask(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_build_bitmask(comp_ctx, func_ctx, 8, V128_i16x8_TYPE,
INT16_TYPE,
"llvm.experimental.vector.reduce.or.v8i32");
return simd_build_bitmask(comp_ctx, func_ctx, e_bitmask_i16x8);
}
bool
aot_compile_simd_i32x4_bitmask(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_build_bitmask(comp_ctx, func_ctx, 4, V128_i32x4_TYPE, I32_TYPE,
"llvm.experimental.vector.reduce.or.v4i32");
return simd_build_bitmask(comp_ctx, func_ctx, e_bitmask_i32x4);
}
bool
aot_compile_simd_i64x2_bitmask(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_build_bitmask(comp_ctx, func_ctx, e_bitmask_i64x2);
}

View File

@ -13,17 +13,23 @@ extern "C" {
#endif
bool
aot_compile_simd_i8x16_bitmask(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
aot_compile_simd_i8x16_bitmask(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_i16x8_bitmask(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
aot_compile_simd_i16x8_bitmask(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_i32x4_bitmask(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
aot_compile_simd_i32x4_bitmask(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_i64x2_bitmask(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
#ifdef __cplusplus
} /* end of extern "C" */
#endif
#endif /* end of _SIMD_BITMASK_EXTRACTS_H_ */

View File

@ -86,7 +86,7 @@ fail:
/* v128.or(v128.and(v1, c), v128.and(v2, v128.not(c))) */
static bool
v128_bitwise_bit_select(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
v128_bitwise_bitselect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
LLVMValueRef vector1, vector2, vector3, result;
@ -138,7 +138,7 @@ aot_compile_simd_v128_bitwise(AOTCompContext *comp_ctx,
case V128_NOT:
return v128_bitwise_not(comp_ctx, func_ctx);
case V128_BITSELECT:
return v128_bitwise_bit_select(comp_ctx, func_ctx);
return v128_bitwise_bitselect(comp_ctx, func_ctx);
default:
bh_assert(0);
return false;

View File

@ -8,145 +8,62 @@
#include "../aot_emit_exception.h"
#include "../../aot/aot_runtime.h"
static bool
simd_any_true(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
LLVMTypeRef vector_type,
LLVMTypeRef element_type,
const char *intrinsic)
{
LLVMValueRef vector, zeros, non_zero, result;
if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"vec"))) {
goto fail;
}
if (!(zeros = LLVMConstNull(vector_type))) {
HANDLE_FAILURE("LLVMConstNull");
goto fail;
}
/* icmp eq <N x iX> %vector, zeroinitialize */
if (!(non_zero = LLVMBuildICmp(comp_ctx->builder, LLVMIntNE, vector, zeros,
"non_zero"))) {
HANDLE_FAILURE("LLVMBuildICmp");
goto fail;
}
/* zext <N x i1> to <N x iX> */
if (!(non_zero = LLVMBuildZExt(comp_ctx->builder, non_zero, vector_type,
"non_zero_ex"))) {
HANDLE_FAILURE("LLVMBuildZExt");
goto fail;
}
if (!(result = aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic, element_type,
&vector_type, 1, non_zero))) {
HANDLE_FAILURE("LLVMBuildCall");
goto fail;
}
if (!(zeros = LLVMConstNull(element_type))) {
HANDLE_FAILURE("LLVMConstNull");
goto fail;
}
if (!(result = LLVMBuildICmp(comp_ctx->builder, LLVMIntNE, result, zeros,
"gt_zero"))) {
HANDLE_FAILURE("LLVMBuildICmp");
goto fail;
}
if (!(result =
LLVMBuildZExt(comp_ctx->builder, result, I32_TYPE, "ret"))) {
HANDLE_FAILURE("LLVMBuildZExt");
goto fail;
}
PUSH_I32(result);
return true;
fail:
return false;
}
bool
aot_compile_simd_i8x16_any_true(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_any_true(comp_ctx, func_ctx, V128_i8x16_TYPE, INT8_TYPE,
"llvm.experimental.vector.reduce.add.v16i8");
}
bool
aot_compile_simd_i16x8_any_true(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_any_true(comp_ctx, func_ctx, V128_i16x8_TYPE, INT16_TYPE,
"llvm.experimental.vector.reduce.add.v8i16");
}
bool
aot_compile_simd_i32x4_any_true(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_any_true(comp_ctx, func_ctx, V128_i32x4_TYPE, I32_TYPE,
"llvm.experimental.vector.reduce.add.v4i32");
}
enum integer_all_true {
e_int_all_true_v16i8,
e_int_all_true_v8i16,
e_int_all_true_v4i32,
e_int_all_true_v2i64,
};
static bool
simd_all_true(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
LLVMTypeRef vector_type,
LLVMTypeRef element_type,
const char *intrinsic)
enum integer_all_true itype)
{
LLVMValueRef vector, zeros, is_zero, result;
LLVMValueRef vector, result;
LLVMTypeRef vector_i1_type;
LLVMTypeRef vector_type[] = { V128_i8x16_TYPE, V128_i16x8_TYPE,
V128_i32x4_TYPE, V128_i64x2_TYPE };
uint32 lanes[] = { 16, 8, 4, 2 };
const char *intrinsic[] = {
"llvm.vector.reduce.and.v16i1",
"llvm.vector.reduce.and.v8i1",
"llvm.vector.reduce.and.v4i1",
"llvm.vector.reduce.and.v2i1",
};
LLVMValueRef zero[] = {
LLVM_CONST(i8x16_vec_zero),
LLVM_CONST(i16x8_vec_zero),
LLVM_CONST(i32x4_vec_zero),
LLVM_CONST(i64x2_vec_zero),
};
if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"vec"))) {
if (!(vector_i1_type = LLVMVectorType(INT1_TYPE, lanes[itype]))) {
HANDLE_FAILURE("LLVMVectorType");
goto fail;
}
if (!(zeros = LLVMConstNull(vector_type))) {
HANDLE_FAILURE("LLVMConstNull");
if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
vector_type[itype], "vector"))) {
goto fail;
}
/* icmp eq <N x iX> %vector, zeroinitialize */
if (!(is_zero = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ, vector, zeros,
"is_zero"))) {
/* compare with zero */
if (!(result = LLVMBuildICmp(comp_ctx->builder, LLVMIntNE, vector,
zero[itype], "ne_zero"))) {
HANDLE_FAILURE("LLVMBuildICmp");
goto fail;
}
/* zext <N x i1> to <N x iX> */
if (!(is_zero = LLVMBuildZExt(comp_ctx->builder, is_zero, vector_type,
"is_zero_ex"))) {
HANDLE_FAILURE("LLVMBuildZExt");
goto fail;
}
if (!(result = aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic, element_type,
&vector_type, 1, is_zero))) {
HANDLE_FAILURE("LLVMBuildCall");
goto fail;
}
if (!(zeros = LLVMConstNull(element_type))) {
HANDLE_FAILURE("LLVMConstNull");
goto fail;
}
if (!(result = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ, result, zeros,
"none"))) {
HANDLE_FAILURE("LLVMBuildICmp");
/* check zero */
if (!(result = aot_call_llvm_intrinsic(comp_ctx, func_ctx,
intrinsic[itype], INT1_TYPE,
&vector_i1_type, 1, result))) {
goto fail;
}
if (!(result =
LLVMBuildZExt(comp_ctx->builder, result, I32_TYPE, "ret"))) {
LLVMBuildZExt(comp_ctx->builder, result, I32_TYPE, "to_i32"))) {
HANDLE_FAILURE("LLVMBuildZExt");
goto fail;
}
@ -162,22 +79,61 @@ bool
aot_compile_simd_i8x16_all_true(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_all_true(comp_ctx, func_ctx, V128_i8x16_TYPE, INT8_TYPE,
"llvm.experimental.vector.reduce.add.v16i8");
return simd_all_true(comp_ctx, func_ctx, e_int_all_true_v16i8);
}
bool
aot_compile_simd_i16x8_all_true(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_all_true(comp_ctx, func_ctx, V128_i16x8_TYPE, INT16_TYPE,
"llvm.experimental.vector.reduce.add.v8i16");
return simd_all_true(comp_ctx, func_ctx, e_int_all_true_v8i16);
}
bool
aot_compile_simd_i32x4_all_true(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_all_true(comp_ctx, func_ctx, V128_i32x4_TYPE, I32_TYPE,
"llvm.experimental.vector.reduce.add.v4i32");
return simd_all_true(comp_ctx, func_ctx, e_int_all_true_v4i32);
}
bool
aot_compile_simd_i64x2_all_true(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_all_true(comp_ctx, func_ctx, e_int_all_true_v2i64);
}
bool
aot_compile_simd_v128_any_true(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
LLVMTypeRef vector_type;
LLVMValueRef vector, result;
if (!(vector_type = LLVMVectorType(INT1_TYPE, 128))) {
return false;
}
if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"vector"))) {
goto fail;
}
if (!(result = aot_call_llvm_intrinsic(
comp_ctx, func_ctx, "llvm.vector.reduce.or.v128i1", INT1_TYPE,
&vector_type, 1, vector))) {
goto fail;
}
if (!(result =
LLVMBuildZExt(comp_ctx->builder, result, I32_TYPE, "to_i32"))) {
HANDLE_FAILURE("LLVMBuildZExt");
goto fail;
}
PUSH_I32(result);
return true;
fail:
return false;
}

View File

@ -12,18 +12,6 @@
extern "C" {
#endif
bool
aot_compile_simd_i8x16_any_true(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_i16x8_any_true(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_i32x4_any_true(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_i8x16_all_true(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
@ -36,6 +24,14 @@ bool
aot_compile_simd_i32x4_all_true(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_i64x2_all_true(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_v128_any_true(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
#ifdef __cplusplus
} /* end of extern "C" */
#endif

View File

@ -44,4 +44,119 @@ simd_bitcast_and_push_v128(const AOTCompContext *comp_ctx,
return true;
fail:
return false;
}
}
LLVMValueRef
simd_lane_id_to_llvm_value(AOTCompContext *comp_ctx, uint8 lane_id)
{
LLVMValueRef lane_indexes[] = {
LLVM_CONST(i32_zero), LLVM_CONST(i32_one),
LLVM_CONST(i32_two), LLVM_CONST(i32_three),
LLVM_CONST(i32_four), LLVM_CONST(i32_five),
LLVM_CONST(i32_six), LLVM_CONST(i32_seven),
LLVM_CONST(i32_eight), LLVM_CONST(i32_nine),
LLVM_CONST(i32_ten), LLVM_CONST(i32_eleven),
LLVM_CONST(i32_twelve), LLVM_CONST(i32_thirteen),
LLVM_CONST(i32_fourteen), LLVM_CONST(i32_fifteen),
};
return lane_id < 16 ? lane_indexes[lane_id] : NULL;
}
LLVMValueRef
simd_build_const_integer_vector(const AOTCompContext *comp_ctx,
const LLVMTypeRef element_type,
const int *element_value,
uint32 length)
{
LLVMValueRef vector = NULL;
LLVMValueRef *elements;
unsigned i;
if (!(elements = wasm_runtime_malloc(sizeof(LLVMValueRef) * length))) {
return NULL;
}
for (i = 0; i < length; i++) {
if (!(elements[i] =
LLVMConstInt(element_type, element_value[i], true))) {
HANDLE_FAILURE("LLVMConstInst");
goto fail;
}
}
if (!(vector = LLVMConstVector(elements, length))) {
HANDLE_FAILURE("LLVMConstVector");
goto fail;
}
fail:
wasm_runtime_free(elements);
return vector;
}
LLVMValueRef
simd_build_splat_const_integer_vector(const AOTCompContext *comp_ctx,
const LLVMTypeRef element_type,
const int64 element_value,
uint32 length)
{
LLVMValueRef vector = NULL, element;
LLVMValueRef *elements;
unsigned i;
if (!(elements = wasm_runtime_malloc(sizeof(LLVMValueRef) * length))) {
return NULL;
}
if (!(element = LLVMConstInt(element_type, element_value, true))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
for (i = 0; i < length; i++) {
elements[i] = element;
}
if (!(vector = LLVMConstVector(elements, length))) {
HANDLE_FAILURE("LLVMConstVector");
goto fail;
}
fail:
wasm_runtime_free(elements);
return vector;
}
LLVMValueRef
simd_build_splat_const_float_vector(const AOTCompContext *comp_ctx,
const LLVMTypeRef element_type,
const float element_value,
uint32 length)
{
LLVMValueRef vector = NULL, element;
LLVMValueRef *elements;
unsigned i;
if (!(elements = wasm_runtime_malloc(sizeof(LLVMValueRef) * length))) {
return NULL;
}
if (!(element = LLVMConstReal(element_type, element_value))) {
HANDLE_FAILURE("LLVMConstReal");
goto fail;
}
for (i = 0; i < length; i++) {
elements[i] = element;
}
if (!(vector = LLVMConstVector(elements, length))) {
HANDLE_FAILURE("LLVMConstVector");
goto fail;
}
fail:
wasm_runtime_free(elements);
return vector;
}

View File

@ -8,6 +8,13 @@
#include "../aot_compiler.h"
static inline bool
is_target_x86(AOTCompContext *comp_ctx)
{
return !strncmp(comp_ctx->target_arch, "x86_64", 6)
|| !strncmp(comp_ctx->target_arch, "i386", 4);
}
LLVMValueRef
simd_pop_v128_and_bitcast(const AOTCompContext *comp_ctx,
const AOTFuncContext *func_ctx,
@ -20,4 +27,24 @@ simd_bitcast_and_push_v128(const AOTCompContext *comp_ctx,
LLVMValueRef vector,
const char *name);
LLVMValueRef
simd_lane_id_to_llvm_value(AOTCompContext *comp_ctx, uint8 lane_id);
LLVMValueRef
simd_build_const_integer_vector(const AOTCompContext *comp_ctx,
const LLVMTypeRef element_type,
const int *element_value,
uint32 length);
LLVMValueRef
simd_build_splat_const_integer_vector(const AOTCompContext *comp_ctx,
const LLVMTypeRef element_type,
const int64 element_value,
uint32 length);
LLVMValueRef
simd_build_splat_const_float_vector(const AOTCompContext *comp_ctx,
const LLVMTypeRef element_type,
const float element_value,
uint32 length);
#endif /* _SIMD_COMMON_H_ */

View File

@ -160,6 +160,14 @@ aot_compile_simd_i32x4_compare(AOTCompContext *comp_ctx,
return interger_vector_compare(comp_ctx, func_ctx, cond, V128_i32x4_TYPE);
}
bool
aot_compile_simd_i64x2_compare(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
IntCond cond)
{
return interger_vector_compare(comp_ctx, func_ctx, cond, V128_i64x2_TYPE);
}
static bool
float_vector_compare(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,

View File

@ -27,6 +27,11 @@ aot_compile_simd_i32x4_compare(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
IntCond cond);
bool
aot_compile_simd_i64x2_compare(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
IntCond cond);
bool
aot_compile_simd_f32x4_compare(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,

View File

@ -3,6 +3,7 @@
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "simd_common.h"
#include "simd_construct_values.h"
#include "../aot_emit_exception.h"
#include "../interpreter/wasm_opcode.h"
@ -14,23 +15,19 @@ aot_compile_simd_v128_const(AOTCompContext *comp_ctx,
const uint8 *imm_bytes)
{
uint64 imm1, imm2;
LLVMValueRef undef, first_long, agg1, second_long, agg2;
LLVMValueRef first_long, agg1, second_long, agg2;
wasm_runtime_read_v128(imm_bytes, &imm1, &imm2);
if (!(undef = LLVMGetUndef(V128_i64x2_TYPE))) {
HANDLE_FAILURE("LLVMGetUndef");
goto fail;
}
/* %agg1 = insertelement <2 x i64> undef, i16 0, i64 ${*imm} */
if (!(first_long = I64_CONST(imm1))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(agg1 = LLVMBuildInsertElement(comp_ctx->builder, undef, first_long,
I32_ZERO, "agg1"))) {
if (!(agg1 =
LLVMBuildInsertElement(comp_ctx->builder, LLVM_CONST(i64x2_undef),
first_long, I32_ZERO, "agg1"))) {
HANDLE_FAILURE("LLVMBuildInsertElement");
goto fail;
}
@ -48,7 +45,6 @@ aot_compile_simd_v128_const(AOTCompContext *comp_ctx,
}
PUSH_V128(agg2);
return true;
fail:
return false;
@ -57,134 +53,88 @@ fail:
bool
aot_compile_simd_splat(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint8 splat_opcode)
uint8 opcode)
{
LLVMValueRef value, undef, base, mask, new_vector, result;
LLVMTypeRef all_zero_ty;
uint32 opcode_index = opcode - SIMD_i8x16_splat;
LLVMValueRef value = NULL, base, new_vector;
LLVMValueRef undefs[] = {
LLVM_CONST(i8x16_undef), LLVM_CONST(i16x8_undef),
LLVM_CONST(i32x4_undef), LLVM_CONST(i64x2_undef),
LLVM_CONST(f32x4_undef), LLVM_CONST(f64x2_undef),
};
LLVMValueRef masks[] = {
LLVM_CONST(i32x16_zero), LLVM_CONST(i32x8_zero),
LLVM_CONST(i32x4_zero), LLVM_CONST(i32x2_zero),
LLVM_CONST(i32x4_zero), LLVM_CONST(i32x2_zero),
};
switch (splat_opcode) {
switch (opcode) {
case SIMD_i8x16_splat:
{
LLVMValueRef input;
POP_I32(input);
/* trunc i32 %input to i8 */
if (!(value = LLVMBuildTrunc(comp_ctx->builder, input, INT8_TYPE,
"trunc"))) {
HANDLE_FAILURE("LLVMBuildTrunc");
goto fail;
}
undef = LLVMGetUndef(V128_i8x16_TYPE);
if (!(all_zero_ty = LLVMVectorType(I32_TYPE, 16))) {
HANDLE_FAILURE("LLVMVectorType");
goto fail;
}
value =
LLVMBuildTrunc(comp_ctx->builder, input, INT8_TYPE, "trunc");
break;
}
case SIMD_i16x8_splat:
{
LLVMValueRef input;
POP_I32(input);
/* trunc i32 %input to i16 */
if (!(value = LLVMBuildTrunc(comp_ctx->builder, input, INT16_TYPE,
"trunc"))) {
HANDLE_FAILURE("LLVMBuildTrunc");
goto fail;
}
undef = LLVMGetUndef(V128_i16x8_TYPE);
if (!(all_zero_ty = LLVMVectorType(I32_TYPE, 8))) {
HANDLE_FAILURE("LLVMVectorType");
goto fail;
}
value =
LLVMBuildTrunc(comp_ctx->builder, input, INT16_TYPE, "trunc");
break;
}
case SIMD_i32x4_splat:
{
POP_I32(value);
undef = LLVMGetUndef(V128_i32x4_TYPE);
if (!(all_zero_ty = LLVMVectorType(I32_TYPE, 4))) {
HANDLE_FAILURE("LLVMVectorType");
goto fail;
}
break;
}
case SIMD_i64x2_splat:
{
POP(value, VALUE_TYPE_I64);
undef = LLVMGetUndef(V128_i64x2_TYPE);
if (!(all_zero_ty = LLVMVectorType(I32_TYPE, 2))) {
HANDLE_FAILURE("LLVMVectorType");
goto fail;
}
break;
}
case SIMD_f32x4_splat:
{
POP(value, VALUE_TYPE_F32);
undef = LLVMGetUndef(V128_f32x4_TYPE);
if (!(all_zero_ty = LLVMVectorType(I32_TYPE, 4))) {
HANDLE_FAILURE("LLVMVectorType");
goto fail;
}
break;
}
case SIMD_f64x2_splat:
{
POP(value, VALUE_TYPE_F64);
undef = LLVMGetUndef(V128_f64x2_TYPE);
if (!(all_zero_ty = LLVMVectorType(I32_TYPE, 2))) {
HANDLE_FAILURE("LLVMVectorType");
goto fail;
}
break;
}
default:
{
bh_assert(0);
goto fail;
break;
}
}
if (!undef) {
HANDLE_FAILURE("LVMGetUndef");
if (!value) {
goto fail;
}
/* insertelement <n x ty> undef, ty %value, i32 0 */
if (!(base = LLVMBuildInsertElement(comp_ctx->builder, undef, value,
I32_ZERO, "base"))) {
if (!(base =
LLVMBuildInsertElement(comp_ctx->builder, undefs[opcode_index],
value, I32_ZERO, "base"))) {
HANDLE_FAILURE("LLVMBuildInsertElement");
goto fail;
}
/* <n x i32> zeroinitializer */
if (!(mask = LLVMConstNull(all_zero_ty))) {
HANDLE_FAILURE("LLVMConstNull");
goto fail;
}
/* shufflevector <ty1> %base, <ty2> undef, <n x i32> zeroinitializer */
if (!(new_vector = LLVMBuildShuffleVector(comp_ctx->builder, base, undef,
mask, "new_vector"))) {
if (!(new_vector = LLVMBuildShuffleVector(
comp_ctx->builder, base, undefs[opcode_index], masks[opcode_index],
"new_vector"))) {
HANDLE_FAILURE("LLVMBuildShuffleVector");
goto fail;
}
/* bitcast <ty> <value> to <2 x i64> */
if (!(result = LLVMBuildBitCast(comp_ctx->builder, new_vector,
V128_i64x2_TYPE, "ret"))) {
HANDLE_FAILURE("LLVMBuidlCast");
goto fail;
}
/* push result into the stack */
PUSH_V128(result);
return true;
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, new_vector,
"result");
fail:
return false;
}

File diff suppressed because it is too large Load Diff

View File

@ -23,27 +23,77 @@ aot_compile_simd_i16x8_narrow_i32x4(AOTCompContext *comp_ctx,
bool is_signed);
bool
aot_compile_simd_i16x8_widen_i8x16(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool is_low,
bool is_signed);
aot_compile_simd_i32x4_narrow_i64x2(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool is_signed);
bool
aot_compile_simd_i32x4_widen_i16x8(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool is_low,
bool is_signed);
aot_compile_simd_i16x8_extend_i8x16(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool is_low,
bool is_signed);
bool
aot_compile_simd_i32x4_extend_i16x8(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool is_low,
bool is_signed);
bool
aot_compile_simd_i64x2_extend_i32x4(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool lower_half,
bool is_signed);
bool
aot_compile_simd_i32x4_trunc_sat_f32x4(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool is_signed);
bool
aot_compile_simd_i32x4_trunc_sat_f64x2(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool is_signed);
bool
aot_compile_simd_f32x4_convert_i32x4(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool is_signed);
bool
aot_compile_simd_f64x2_convert_i32x4(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool is_signed);
bool
aot_compile_simd_i16x8_extadd_pairwise_i8x16(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool is_signed);
bool
aot_compile_simd_i32x4_extadd_pairwise_i16x8(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool is_signed);
bool
aot_compile_simd_i16x8_q15mulr_sat(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_i16x8_extmul_i8x16(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool is_low,
bool is_signed);
bool
aot_compile_simd_i32x4_extmul_i16x8(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool is_low,
bool is_signed);
bool
aot_compile_simd_i64x2_extmul_i32x4(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool lower_half,
bool is_signed);
#ifdef __cplusplus
} /* end of extern "C" */
#endif

View File

@ -9,111 +9,45 @@
#include "../aot_emit_numberic.h"
#include "../../aot/aot_runtime.h"
static LLVMValueRef
simd_v128_float_cmp(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
FloatArithmetic arith_op,
LLVMValueRef lhs,
LLVMValueRef rhs)
{
LLVMValueRef result;
LLVMRealPredicate op;
op = FLOAT_MIN == arith_op ? LLVMRealULT : LLVMRealUGT;
if (!(result = LLVMBuildFCmp(comp_ctx->builder, op, lhs, rhs, "cmp"))) {
HANDLE_FAILURE("LLVMBuildFCmp");
goto fail;
}
if (!(result =
LLVMBuildSelect(comp_ctx->builder, result, lhs, rhs, "select"))) {
HANDLE_FAILURE("LLVMBuildSelect");
goto fail;
}
return result;
fail:
return NULL;
}
static bool
simd_v128_float_arith(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
FloatArithmetic arith_op,
LLVMTypeRef vector_type)
{
LLVMValueRef lhs, rhs, result;
LLVMValueRef lhs, rhs, result = NULL;
if (!(rhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"rhs"))) {
goto fail;
}
if (!(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"lhs"))) {
goto fail;
if (!(rhs =
simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, "rhs"))
|| !(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"lhs"))) {
return false;
}
switch (arith_op) {
case FLOAT_ADD:
if (!(result =
LLVMBuildFAdd(comp_ctx->builder, lhs, rhs, "sum"))) {
HANDLE_FAILURE("LLVMBuildFAdd");
goto fail;
}
result = LLVMBuildFAdd(comp_ctx->builder, lhs, rhs, "sum");
break;
case FLOAT_SUB:
if (!(result = LLVMBuildFSub(comp_ctx->builder, lhs, rhs,
"difference"))) {
HANDLE_FAILURE("LLVMBuildFSub");
goto fail;
}
result = LLVMBuildFSub(comp_ctx->builder, lhs, rhs, "difference");
break;
case FLOAT_MUL:
if (!(result =
LLVMBuildFMul(comp_ctx->builder, lhs, rhs, "product"))) {
HANDLE_FAILURE("LLVMBuildFMul");
goto fail;
}
result = LLVMBuildFMul(comp_ctx->builder, lhs, rhs, "product");
break;
case FLOAT_DIV:
if (!(result =
LLVMBuildFDiv(comp_ctx->builder, lhs, rhs, "quotient"))) {
HANDLE_FAILURE("LLVMBuildFDiv");
goto fail;
}
break;
case FLOAT_MIN:
if (!(result = simd_v128_float_cmp(comp_ctx, func_ctx, FLOAT_MIN,
lhs, rhs))) {
goto fail;
}
break;
case FLOAT_MAX:
if (!(result = simd_v128_float_cmp(comp_ctx, func_ctx, FLOAT_MAX,
lhs, rhs))) {
goto fail;
}
result = LLVMBuildFDiv(comp_ctx->builder, lhs, rhs, "quotient");
break;
default:
result = NULL;
bh_assert(0);
break;
return false;
}
if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE,
"ret"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
if (!result) {
HANDLE_FAILURE(
"LLVMBuildFAdd/LLVMBuildFSub/LLVMBuildFMul/LLVMBuildFDiv");
return false;
}
/* push result into the stack */
PUSH_V128(result);
return true;
fail:
return false;
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
}
bool
@ -139,30 +73,19 @@ simd_v128_float_neg(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
LLVMTypeRef vector_type)
{
LLVMValueRef number, result;
LLVMValueRef vector, result;
if (!(number = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"number"))) {
goto fail;
if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"vector"))) {
return false;
}
if (!(result = LLVMBuildFNeg(comp_ctx->builder, number, "neg"))) {
if (!(result = LLVMBuildFNeg(comp_ctx->builder, vector, "neg"))) {
HANDLE_FAILURE("LLVMBuildFNeg");
goto fail;
return false;
}
if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE,
"ret"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
/* push result into the stack */
PUSH_V128(result);
return true;
fail:
return false;
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
}
bool
@ -178,119 +101,310 @@ aot_compile_simd_f64x2_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
}
static bool
simd_v128_float_intrinsic(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
LLVMTypeRef vector_type,
const char *intrinsic)
simd_float_intrinsic(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
LLVMTypeRef vector_type,
const char *intrinsic)
{
LLVMValueRef number, result;
LLVMValueRef vector, result;
LLVMTypeRef param_types[1] = { vector_type };
if (!(number = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"number"))) {
goto fail;
if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"vector"))) {
return false;
}
if (!(result = aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic, vector_type,
param_types, 1, number))) {
if (!(result =
aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic, vector_type,
param_types, 1, vector))) {
HANDLE_FAILURE("LLVMBuildCall");
goto fail;
return false;
}
if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE,
"ret"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
/* push result into the stack */
PUSH_V128(result);
return true;
fail:
return false;
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
}
bool
aot_compile_simd_f32x4_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE,
"llvm.fabs.v4f32");
return simd_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE,
"llvm.fabs.v4f32");
}
bool
aot_compile_simd_f64x2_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE,
"llvm.fabs.v2f64");
return simd_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE,
"llvm.fabs.v2f64");
}
bool
aot_compile_simd_f32x4_round(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE,
"llvm.round.v4f32");
}
bool
aot_compile_simd_f64x2_round(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE,
"llvm.round.v2f64");
}
bool
aot_compile_simd_f32x4_sqrt(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE,
"llvm.sqrt.v4f32");
return simd_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE,
"llvm.sqrt.v4f32");
}
bool
aot_compile_simd_f64x2_sqrt(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE,
"llvm.sqrt.v2f64");
return simd_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE,
"llvm.sqrt.v2f64");
}
bool
aot_compile_simd_f32x4_ceil(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE,
"llvm.ceil.v4f32");
return simd_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE,
"llvm.ceil.v4f32");
}
bool
aot_compile_simd_f64x2_ceil(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE,
"llvm.ceil.v2f64");
return simd_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE,
"llvm.ceil.v2f64");
}
bool
aot_compile_simd_f32x4_floor(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
aot_compile_simd_f32x4_floor(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE,
"llvm.floor.v4f32");
return simd_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE,
"llvm.floor.v4f32");
}
bool
aot_compile_simd_f64x2_floor(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
aot_compile_simd_f64x2_floor(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE,
"llvm.floor.v2f64");
return simd_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE,
"llvm.floor.v2f64");
}
bool
aot_compile_simd_f32x4_trunc(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
aot_compile_simd_f32x4_trunc(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE,
"llvm.trunc.v4f32");
return simd_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE,
"llvm.trunc.v4f32");
}
bool
aot_compile_simd_f64x2_trunc(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
aot_compile_simd_f64x2_trunc(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE,
"llvm.trunc.v2f64");
return simd_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE,
"llvm.trunc.v2f64");
}
bool
aot_compile_simd_f32x4_nearest(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
aot_compile_simd_f32x4_nearest(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE,
"llvm.rint.v4f32");
return simd_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE,
"llvm.rint.v4f32");
}
bool
aot_compile_simd_f64x2_nearest(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
aot_compile_simd_f64x2_nearest(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE,
"llvm.rint.v2f64");
return simd_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE,
"llvm.rint.v2f64");
}
static bool
simd_float_cmp(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
FloatArithmetic arith_op,
LLVMTypeRef vector_type)
{
LLVMValueRef lhs, rhs, result;
LLVMRealPredicate op = FLOAT_MIN == arith_op ? LLVMRealULT : LLVMRealUGT;
if (!(rhs =
simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, "rhs"))
|| !(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"lhs"))) {
return false;
}
if (!(result = LLVMBuildFCmp(comp_ctx->builder, op, lhs, rhs, "cmp"))) {
HANDLE_FAILURE("LLVMBuildFCmp");
return false;
}
if (!(result =
LLVMBuildSelect(comp_ctx->builder, result, lhs, rhs, "select"))) {
HANDLE_FAILURE("LLVMBuildSelect");
return false;
}
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
}
/*TODO: sugggest non-IA platforms check with "llvm.minimum.*" and "llvm.maximum.*" firstly */
bool
aot_compile_simd_f32x4_min_max(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool run_min)
{
return simd_float_cmp(comp_ctx, func_ctx, run_min ? FLOAT_MIN : FLOAT_MAX,
V128_f32x4_TYPE);
}
bool
aot_compile_simd_f64x2_min_max(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool run_min)
{
return simd_float_cmp(comp_ctx, func_ctx, run_min ? FLOAT_MIN : FLOAT_MAX,
V128_f64x2_TYPE);
}
static bool
simd_float_pmin_max(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
LLVMTypeRef vector_type,
const char *intrinsic)
{
LLVMValueRef lhs, rhs, result;
LLVMTypeRef param_types[2];
param_types[0] = vector_type;
param_types[1] = vector_type;
if (!(rhs =
simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, "rhs"))
|| !(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"lhs"))) {
return false;
}
if (!(result =
aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic, vector_type,
param_types, 2, lhs, rhs))) {
return false;
}
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
}
bool
aot_compile_simd_f32x4_pmin_pmax(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool run_min)
{
return simd_float_pmin_max(comp_ctx, func_ctx, V128_f32x4_TYPE,
run_min ? "llvm.minnum.v4f32"
: "llvm.maxnum.v4f32");
}
bool
aot_compile_simd_f64x2_pmin_pmax(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool run_min)
{
return simd_float_pmin_max(comp_ctx, func_ctx, V128_f64x2_TYPE,
run_min ? "llvm.minnum.v2f64"
: "llvm.maxnum.v2f64");
}
bool
aot_compile_simd_f64x2_demote(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
LLVMValueRef vector, elem_0, elem_1, result;
if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
V128_f64x2_TYPE, "vector"))) {
return false;
}
if (!(elem_0 = LLVMBuildExtractElement(comp_ctx->builder, vector,
LLVM_CONST(i32_zero), "elem_0"))
|| !(elem_1 = LLVMBuildExtractElement(
comp_ctx->builder, vector, LLVM_CONST(i32_one), "elem_1"))) {
HANDLE_FAILURE("LLVMBuildExtractElement");
return false;
}
/* fptrunc <f64> elem to <f32> */
if (!(elem_0 = LLVMBuildFPTrunc(comp_ctx->builder, elem_0, F32_TYPE,
"elem_0_trunc"))
|| !(elem_1 = LLVMBuildFPTrunc(comp_ctx->builder, elem_1, F32_TYPE,
"elem_1_trunc"))) {
HANDLE_FAILURE("LLVMBuildFPTrunc");
return false;
}
if (!(result = LLVMBuildInsertElement(
comp_ctx->builder, LLVM_CONST(f32x4_vec_zero), elem_0,
LLVM_CONST(i32_zero), "new_vector_0"))
|| !(result =
LLVMBuildInsertElement(comp_ctx->builder, result, elem_1,
LLVM_CONST(i32_one), "new_vector_1"))) {
HANDLE_FAILURE("LLVMBuildInsertElement");
return false;
}
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
}
bool
aot_compile_simd_f32x4_promote(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
LLVMValueRef vector, elem_0, elem_1, result;
if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
V128_f32x4_TYPE, "vector"))) {
return false;
}
if (!(elem_0 = LLVMBuildExtractElement(comp_ctx->builder, vector,
LLVM_CONST(i32_zero), "elem_0"))
|| !(elem_1 = LLVMBuildExtractElement(
comp_ctx->builder, vector, LLVM_CONST(i32_one), "elem_1"))) {
HANDLE_FAILURE("LLVMBuildExtractElement");
return false;
}
/* fpext <f32> elem to <f64> */
if (!(elem_0 =
LLVMBuildFPExt(comp_ctx->builder, elem_0, F64_TYPE, "elem_0_ext"))
|| !(elem_1 = LLVMBuildFPExt(comp_ctx->builder, elem_1, F64_TYPE,
"elem_1_ext"))) {
HANDLE_FAILURE("LLVMBuildFPExt");
return false;
}
if (!(result = LLVMBuildInsertElement(
comp_ctx->builder, LLVM_CONST(f64x2_vec_zero), elem_0,
LLVM_CONST(i32_zero), "new_vector_0"))
|| !(result =
LLVMBuildInsertElement(comp_ctx->builder, result, elem_1,
LLVM_CONST(i32_one), "new_vector_1"))) {
HANDLE_FAILURE("LLVMBuildInsertElement");
return false;
}
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
}

View File

@ -35,34 +35,80 @@ bool
aot_compile_simd_f64x2_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
bool
aot_compile_simd_f32x4_sqrt(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
aot_compile_simd_f32x4_round(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_f64x2_sqrt(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
aot_compile_simd_f64x2_round(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_f32x4_ceil(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
aot_compile_simd_f32x4_sqrt(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_f64x2_ceil(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
aot_compile_simd_f64x2_sqrt(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_f32x4_floor(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
aot_compile_simd_f32x4_ceil(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_f64x2_floor(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
aot_compile_simd_f64x2_ceil(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_f32x4_trunc(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
aot_compile_simd_f32x4_floor(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_f64x2_trunc(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
aot_compile_simd_f64x2_floor(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_f32x4_nearest(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
aot_compile_simd_f32x4_trunc(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_f64x2_nearest(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
aot_compile_simd_f64x2_trunc(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_f32x4_nearest(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_f64x2_nearest(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_f32x4_min_max(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool run_min);
bool
aot_compile_simd_f64x2_min_max(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool run_min);
bool
aot_compile_simd_f32x4_pmin_pmax(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool run_min);
bool
aot_compile_simd_f64x2_pmin_pmax(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
bool run_min);
bool
aot_compile_simd_f64x2_demote(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_f32x4_promote(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
#ifdef __cplusplus
} /* end of extern "C" */

View File

@ -9,59 +9,41 @@
#include "../../aot/aot_runtime.h"
static bool
simd_v128_integer_arith(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
V128Arithmetic arith_op,
LLVMValueRef lhs,
LLVMValueRef rhs)
simd_integer_arith(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
V128Arithmetic arith_op,
LLVMTypeRef vector_type)
{
LLVMValueRef result;
LLVMValueRef lhs, rhs, result = NULL;
if (!(rhs =
simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, "rhs"))
|| !(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"lhs"))) {
return false;
}
switch (arith_op) {
case V128_ADD:
if (!(result = LLVMBuildAdd(comp_ctx->builder, lhs, rhs, "sum"))) {
HANDLE_FAILURE("LLVMBuildAdd");
goto fail;
}
result = LLVMBuildAdd(comp_ctx->builder, lhs, rhs, "sum");
break;
case V128_SUB:
if (!(result =
LLVMBuildSub(comp_ctx->builder, lhs, rhs, "difference"))) {
HANDLE_FAILURE("LLVMBuildSub");
goto fail;
}
result = LLVMBuildSub(comp_ctx->builder, lhs, rhs, "difference");
break;
case V128_MUL:
if (!(result =
LLVMBuildMul(comp_ctx->builder, lhs, rhs, "product"))) {
HANDLE_FAILURE("LLVMBuildMul");
goto fail;
}
break;
case V128_NEG:
if (!(result = LLVMBuildNeg(comp_ctx->builder, lhs, "neg"))) {
HANDLE_FAILURE("LLVMBuildNeg");
goto fail;
}
result = LLVMBuildMul(comp_ctx->builder, lhs, rhs, "product");
break;
default:
result = NULL;
bh_assert(0);
HANDLE_FAILURE("Unsupport arith_op");
break;
}
if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE,
"ret"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
if (!result) {
HANDLE_FAILURE("LLVMBuildAdd/LLVMBuildSub/LLVMBuildMul");
return false;
}
/* push result into the stack */
PUSH_V128(result);
return true;
fail:
return false;
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
}
bool
@ -69,21 +51,7 @@ aot_compile_simd_i8x16_arith(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
V128Arithmetic arith_op)
{
LLVMValueRef lhs, rhs;
if (!(rhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i8x16_TYPE,
"rhs"))) {
goto fail;
}
if (!(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i8x16_TYPE,
"lhs"))) {
goto fail;
}
return simd_v128_integer_arith(comp_ctx, func_ctx, arith_op, lhs, rhs);
fail:
return false;
return simd_integer_arith(comp_ctx, func_ctx, arith_op, V128_i8x16_TYPE);
}
bool
@ -91,21 +59,7 @@ aot_compile_simd_i16x8_arith(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
V128Arithmetic arith_op)
{
LLVMValueRef lhs, rhs;
if (!(rhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i16x8_TYPE,
"rhs"))) {
goto fail;
}
if (!(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i16x8_TYPE,
"lhs"))) {
goto fail;
}
return simd_v128_integer_arith(comp_ctx, func_ctx, arith_op, lhs, rhs);
fail:
return false;
return simd_integer_arith(comp_ctx, func_ctx, arith_op, V128_i16x8_TYPE);
}
bool
@ -113,21 +67,7 @@ aot_compile_simd_i32x4_arith(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
V128Arithmetic arith_op)
{
LLVMValueRef lhs, rhs;
if (!(rhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i32x4_TYPE,
"rhs"))) {
goto fail;
}
if (!(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i32x4_TYPE,
"lhs"))) {
goto fail;
}
return simd_v128_integer_arith(comp_ctx, func_ctx, arith_op, lhs, rhs);
fail:
return false;
return simd_integer_arith(comp_ctx, func_ctx, arith_op, V128_i32x4_TYPE);
}
bool
@ -135,73 +75,354 @@ aot_compile_simd_i64x2_arith(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
V128Arithmetic arith_op)
{
LLVMValueRef lhs, rhs;
return simd_integer_arith(comp_ctx, func_ctx, arith_op, V128_i64x2_TYPE);
}
POP_V128(rhs);
POP_V128(lhs);
static bool
simd_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMTypeRef type)
{
LLVMValueRef vector, result;
return simd_v128_integer_arith(comp_ctx, func_ctx, arith_op, lhs, rhs);
fail:
return false;
if (!(vector =
simd_pop_v128_and_bitcast(comp_ctx, func_ctx, type, "vector"))) {
return false;
}
if (!(result = LLVMBuildNeg(comp_ctx->builder, vector, "neg"))) {
HANDLE_FAILURE("LLVMBuildNeg");
return false;
}
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
}
bool
aot_compile_simd_i8x16_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
LLVMValueRef number;
if (!(number = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
V128_i8x16_TYPE, "number"))) {
goto fail;
}
return simd_v128_integer_arith(comp_ctx, func_ctx, V128_NEG, number, NULL);
fail:
return false;
return simd_neg(comp_ctx, func_ctx, V128_i8x16_TYPE);
}
bool
aot_compile_simd_i16x8_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
LLVMValueRef number;
if (!(number = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
V128_i16x8_TYPE, "number"))) {
goto fail;
}
return simd_v128_integer_arith(comp_ctx, func_ctx, V128_NEG, number, NULL);
fail:
return false;
return simd_neg(comp_ctx, func_ctx, V128_i16x8_TYPE);
}
bool
aot_compile_simd_i32x4_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
LLVMValueRef number;
if (!(number = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
V128_i32x4_TYPE, "number"))) {
goto fail;
}
return simd_v128_integer_arith(comp_ctx, func_ctx, V128_NEG, number, NULL);
fail:
return false;
return simd_neg(comp_ctx, func_ctx, V128_i32x4_TYPE);
}
bool
aot_compile_simd_i64x2_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
LLVMValueRef number;
POP_V128(number);
return simd_v128_integer_arith(comp_ctx, func_ctx, V128_NEG, number, NULL);
fail:
return false;
return simd_neg(comp_ctx, func_ctx, V128_i64x2_TYPE);
}
bool
aot_compile_simd_i8x16_popcnt(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
LLVMValueRef vector, result;
if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
V128_i8x16_TYPE, "vector"))) {
return false;
}
if (!(result = aot_call_llvm_intrinsic(comp_ctx, func_ctx,
"llvm.ctpop.v16i8", V128_i8x16_TYPE,
&V128_i8x16_TYPE, 1, vector))) {
return false;
}
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
}
static bool
simd_v128_cmp(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
LLVMTypeRef vector_type,
V128Arithmetic arith_op,
bool is_signed)
{
LLVMValueRef lhs, rhs, result;
LLVMIntPredicate op;
if (!(rhs =
simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, "rhs"))
|| !(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"lhs"))) {
return false;
}
if (V128_MIN == arith_op) {
op = is_signed ? LLVMIntSLT : LLVMIntULT;
}
else {
op = is_signed ? LLVMIntSGT : LLVMIntUGT;
}
if (!(result = LLVMBuildICmp(comp_ctx->builder, op, lhs, rhs, "cmp"))) {
HANDLE_FAILURE("LLVMBuildICmp");
return false;
}
if (!(result =
LLVMBuildSelect(comp_ctx->builder, result, lhs, rhs, "select"))) {
HANDLE_FAILURE("LLVMBuildSelect");
return false;
}
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
}
bool
aot_compile_simd_i8x16_cmp(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
V128Arithmetic arith_op,
bool is_signed)
{
return simd_v128_cmp(comp_ctx, func_ctx, V128_i8x16_TYPE, arith_op,
is_signed);
}
bool
aot_compile_simd_i16x8_cmp(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
V128Arithmetic arith_op,
bool is_signed)
{
return simd_v128_cmp(comp_ctx, func_ctx, V128_i16x8_TYPE, arith_op,
is_signed);
}
bool
aot_compile_simd_i32x4_cmp(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
V128Arithmetic arith_op,
bool is_signed)
{
return simd_v128_cmp(comp_ctx, func_ctx, V128_i32x4_TYPE, arith_op,
is_signed);
}
/* llvm.abs.* */
static bool
simd_v128_abs(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
char *intrinsic,
LLVMTypeRef vector_type)
{
LLVMValueRef vector, result;
LLVMTypeRef param_types[] = { vector_type, INT1_TYPE };
if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"vec"))) {
return false;
}
if (!(result = aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic,
vector_type, param_types, 2, vector,
/* is_int_min_poison */
LLVM_CONST(i1_zero)))) {
return false;
}
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
}
bool
aot_compile_simd_i8x16_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
return simd_v128_abs(comp_ctx, func_ctx, "llvm.abs.v16i8",
V128_i8x16_TYPE);
}
bool
aot_compile_simd_i16x8_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
return simd_v128_abs(comp_ctx, func_ctx, "llvm.abs.v8i16",
V128_i16x8_TYPE);
}
bool
aot_compile_simd_i32x4_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
return simd_v128_abs(comp_ctx, func_ctx, "llvm.abs.v4i32",
V128_i32x4_TYPE);
}
bool
aot_compile_simd_i64x2_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
return simd_v128_abs(comp_ctx, func_ctx, "llvm.abs.v2i64",
V128_i64x2_TYPE);
}
enum integer_avgr_u {
e_avgr_u_i8x16,
e_avgr_u_i16x8,
e_avgr_u_i32x4,
};
/* TODO: try int_x86_mmx_pavg_b and int_x86_mmx_pavg_w */
/* (v1 + v2 + 1) / 2 */
static bool
simd_v128_avg(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
enum integer_avgr_u itype)
{
LLVMValueRef lhs, rhs, ones, result;
LLVMTypeRef vector_ext_type;
LLVMTypeRef vector_type[] = {
V128_i8x16_TYPE,
V128_i16x8_TYPE,
V128_i32x4_TYPE,
};
unsigned lanes[] = { 16, 8, 4 };
if (!(rhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
vector_type[itype], "rhs"))
|| !(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
vector_type[itype], "lhs"))) {
return false;
}
if (!(vector_ext_type = LLVMVectorType(I64_TYPE, lanes[itype]))) {
HANDLE_FAILURE("LLVMVectorType");
return false;
}
if (!(lhs = LLVMBuildZExt(comp_ctx->builder, lhs, vector_ext_type,
"zext_to_i64"))
|| !(rhs = LLVMBuildZExt(comp_ctx->builder, rhs, vector_ext_type,
"zext_to_i64"))) {
HANDLE_FAILURE("LLVMBuildZExt");
return false;
}
/* by default, add will do signed/unsigned overflow */
if (!(result = LLVMBuildAdd(comp_ctx->builder, lhs, rhs, "l_add_r"))) {
HANDLE_FAILURE("LLVMBuildAdd");
return false;
}
if (!(ones = simd_build_splat_const_integer_vector(comp_ctx, I64_TYPE, 1,
lanes[itype]))) {
return false;
}
if (!(result = LLVMBuildAdd(comp_ctx->builder, result, ones, "plus_1"))) {
HANDLE_FAILURE("LLVMBuildAdd");
return false;
}
if (!(result = LLVMBuildLShr(comp_ctx->builder, result, ones, "avg"))) {
HANDLE_FAILURE("LLVMBuildLShr");
return false;
}
if (!(result = LLVMBuildTrunc(comp_ctx->builder, result,
vector_type[itype], "to_orig_type"))) {
HANDLE_FAILURE("LLVMBuildTrunc");
return false;
}
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
}
bool
aot_compile_simd_i8x16_avgr_u(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_v128_avg(comp_ctx, func_ctx, e_avgr_u_i8x16);
}
bool
aot_compile_simd_i16x8_avgr_u(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_v128_avg(comp_ctx, func_ctx, e_avgr_u_i16x8);
}
bool
aot_compile_simd_i32x4_avgr_u(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_v128_avg(comp_ctx, func_ctx, e_avgr_u_i32x4);
}
bool
aot_compile_simd_i32x4_dot_i16x8(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
LLVMValueRef vec1, vec2, even_mask, odd_mask, zero, result;
LLVMTypeRef vector_ext_type;
LLVMValueRef even_element[] = {
LLVM_CONST(i32_zero),
LLVM_CONST(i32_two),
LLVM_CONST(i32_four),
LLVM_CONST(i32_six),
};
LLVMValueRef odd_element[] = {
LLVM_CONST(i32_one),
LLVM_CONST(i32_three),
LLVM_CONST(i32_five),
LLVM_CONST(i32_seven),
};
if (!(vec1 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i16x8_TYPE,
"vec1"))
|| !(vec2 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
V128_i16x8_TYPE, "vec2"))) {
return false;
}
if (!(vector_ext_type = LLVMVectorType(I32_TYPE, 8))) {
HANDLE_FAILURE("LLVMVectorType");
return false;
}
/* sext <v8i16> to <v8i32> */
if (!(vec1 = LLVMBuildSExt(comp_ctx->builder, vec1, vector_ext_type,
"vec1_v8i32"))
|| !(vec2 = LLVMBuildSExt(comp_ctx->builder, vec2, vector_ext_type,
"vec2_v8i32"))) {
HANDLE_FAILURE("LLVMBuildSExt");
return false;
}
if (!(result = LLVMBuildMul(comp_ctx->builder, vec1, vec2, "product"))) {
HANDLE_FAILURE("LLVMBuildMul");
return false;
}
/* pick elements with even indexes and odd indexes */
if (!(even_mask = LLVMConstVector(even_element, 4))
|| !(odd_mask = LLVMConstVector(odd_element, 4))) {
HANDLE_FAILURE("LLVMConstVector");
return false;
}
if (!(zero =
simd_build_splat_const_integer_vector(comp_ctx, I32_TYPE, 0, 8))) {
return false;
}
if (!(vec1 = LLVMBuildShuffleVector(comp_ctx->builder, result, zero,
even_mask, "even_result"))
|| !(vec2 = LLVMBuildShuffleVector(comp_ctx->builder, result, zero,
odd_mask, "odd_result"))) {
HANDLE_FAILURE("LLVMBuildShuffleVector");
return false;
}
if (!(result = LLVMBuildAdd(comp_ctx->builder, vec1, vec2, "new_vec"))) {
HANDLE_FAILURE("LLVMBuildAdd");
return false;
}
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
}

View File

@ -44,6 +44,56 @@ aot_compile_simd_i32x4_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
bool
aot_compile_simd_i64x2_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
bool
aot_compile_simd_i8x16_popcnt(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_i8x16_cmp(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
V128Arithmetic arith_op,
bool is_signed);
bool
aot_compile_simd_i16x8_cmp(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
V128Arithmetic arith_op,
bool is_signed);
bool
aot_compile_simd_i32x4_cmp(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
V128Arithmetic arith_op,
bool is_signed);
bool
aot_compile_simd_i8x16_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
bool
aot_compile_simd_i16x8_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
bool
aot_compile_simd_i32x4_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
bool
aot_compile_simd_i64x2_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
bool
aot_compile_simd_i8x16_avgr_u(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_i16x8_avgr_u(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_i32x4_avgr_u(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_i32x4_dot_i16x8(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
#ifdef __cplusplus
} /* end of extern "C" */
#endif

View File

@ -3,6 +3,7 @@
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "simd_common.h"
#include "simd_load_store.h"
#include "../aot_emit_exception.h"
#include "../aot_emit_memory.h"
@ -23,68 +24,23 @@ simd_load(AOTCompContext *comp_ctx,
if (!(maddr = aot_check_memory_overflow(comp_ctx, func_ctx, offset,
data_length))) {
HANDLE_FAILURE("aot_check_memory_overflow");
goto fail;
return NULL;
}
if (!(maddr = LLVMBuildBitCast(comp_ctx->builder, maddr, ptr_type,
"data_ptr"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
return NULL;
}
if (!(data = LLVMBuildLoad(comp_ctx->builder, maddr, "data"))) {
HANDLE_FAILURE("LLVMBuildLoad");
goto fail;
return NULL;
}
LLVMSetAlignment(data, 1);
return data;
fail:
return NULL;
}
/* data_length in bytes */
static LLVMValueRef
simd_splat(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
LLVMValueRef element,
LLVMTypeRef vectory_type,
unsigned lane_count)
{
LLVMValueRef undef, zeros, vector;
LLVMTypeRef zeros_type;
if (!(undef = LLVMGetUndef(vectory_type))) {
HANDLE_FAILURE("LLVMGetUndef");
goto fail;
}
if (!(zeros_type = LLVMVectorType(I32_TYPE, lane_count))) {
HANDLE_FAILURE("LVMVectorType");
goto fail;
}
if (!(zeros = LLVMConstNull(zeros_type))) {
HANDLE_FAILURE("LLVMConstNull");
goto fail;
}
if (!(vector = LLVMBuildInsertElement(comp_ctx->builder, undef, element,
I32_ZERO, "base"))) {
HANDLE_FAILURE("LLVMBuildInsertElement");
goto fail;
}
if (!(vector = LLVMBuildShuffleVector(comp_ctx->builder, vector, undef,
zeros, "vector"))) {
HANDLE_FAILURE("LLVMBuildShuffleVector");
goto fail;
}
return vector;
fail:
return NULL;
}
bool
@ -97,40 +53,10 @@ aot_compile_simd_v128_load(AOTCompContext *comp_ctx,
if (!(result =
simd_load(comp_ctx, func_ctx, align, offset, 16, V128_PTR_TYPE))) {
goto fail;
return false;
}
PUSH_V128(result);
return true;
fail:
return false;
}
bool
aot_compile_simd_v128_store(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 align,
uint32 offset)
{
LLVMValueRef maddr, value, result;
POP_V128(value);
if (!(maddr = aot_check_memory_overflow(comp_ctx, func_ctx, offset, 16)))
return false;
if (!(maddr = LLVMBuildBitCast(comp_ctx->builder, maddr, V128_PTR_TYPE,
"data_ptr"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
if (!(result = LLVMBuildStore(comp_ctx->builder, value, maddr))) {
HANDLE_FAILURE("LLVMBuildStore");
goto fail;
}
LLVMSetAlignment(result, 1);
return true;
fail:
@ -140,162 +66,272 @@ fail:
bool
aot_compile_simd_load_extend(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint8 load_opcode,
uint8 opcode,
uint32 align,
uint32 offset)
{
LLVMValueRef sub_vector, result;
LLVMTypeRef sub_vector_type, vector_type;
bool is_signed;
uint32 data_length;
switch (load_opcode) {
case SIMD_i16x8_load8x8_s:
case SIMD_i16x8_load8x8_u:
{
data_length = 8;
vector_type = V128_i16x8_TYPE;
is_signed = (load_opcode == SIMD_i16x8_load8x8_s);
if (!(sub_vector_type = LLVMVectorType(INT8_TYPE, 8))) {
HANDLE_FAILURE("LLVMVectorType");
goto fail;
}
break;
}
case SIMD_i32x4_load16x4_s:
case SIMD_i32x4_load16x4_u:
{
data_length = 8;
vector_type = V128_i32x4_TYPE;
is_signed = (load_opcode == SIMD_i32x4_load16x4_s);
if (!(sub_vector_type = LLVMVectorType(INT16_TYPE, 4))) {
HANDLE_FAILURE("LLVMVectorType");
goto fail;
}
break;
}
case SIMD_i64x2_load32x2_s:
case SIMD_i64x2_load32x2_u:
{
data_length = 8;
vector_type = V128_i64x2_TYPE;
is_signed = (load_opcode == SIMD_i64x2_load32x2_s);
if (!(sub_vector_type = LLVMVectorType(I32_TYPE, 2))) {
HANDLE_FAILURE("LLVMVectorType");
goto fail;
}
break;
}
default:
{
bh_assert(0);
goto fail;
}
}
uint32 opcode_index = opcode - SIMD_v128_load8x8_s;
bool signeds[] = { true, false, true, false, true, false };
LLVMTypeRef vector_types[] = {
V128_i16x8_TYPE, V128_i16x8_TYPE, V128_i32x4_TYPE,
V128_i32x4_TYPE, V128_i64x2_TYPE, V128_i64x2_TYPE,
};
LLVMTypeRef sub_vector_types[] = {
LLVMVectorType(INT8_TYPE, 8), LLVMVectorType(INT8_TYPE, 8),
LLVMVectorType(INT16_TYPE, 4), LLVMVectorType(INT16_TYPE, 4),
LLVMVectorType(I32_TYPE, 2), LLVMVectorType(I32_TYPE, 2),
};
LLVMTypeRef sub_vector_type = sub_vector_types[opcode_index];
/* to vector ptr type */
if (!(sub_vector_type = LLVMPointerType(sub_vector_type, 0))) {
if (!sub_vector_type
|| !(sub_vector_type = LLVMPointerType(sub_vector_type, 0))) {
HANDLE_FAILURE("LLVMPointerType");
goto fail;
return false;
}
if (!(sub_vector = simd_load(comp_ctx, func_ctx, align, offset,
data_length, sub_vector_type))) {
goto fail;
if (!(sub_vector = simd_load(comp_ctx, func_ctx, align, offset, 8,
sub_vector_type))) {
return false;
}
if (is_signed) {
if (signeds[opcode_index]) {
if (!(result = LLVMBuildSExt(comp_ctx->builder, sub_vector,
vector_type, "vector"))) {
vector_types[opcode_index], "vector"))) {
HANDLE_FAILURE("LLVMBuildSExt");
goto fail;
return false;
}
}
else {
if (!(result = LLVMBuildZExt(comp_ctx->builder, sub_vector,
vector_type, "vector"))) {
vector_types[opcode_index], "vector"))) {
HANDLE_FAILURE("LLVMBuildZExt");
goto fail;
return false;
}
}
if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE,
"result"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
PUSH_V128(result);
return true;
fail:
return false;
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
}
bool
aot_compile_simd_load_splat(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint8 load_opcode,
uint8 opcode,
uint32 align,
uint32 offset)
{
uint32 opcode_index = opcode - SIMD_v128_load8_splat;
LLVMValueRef element, result;
LLVMTypeRef element_ptr_type, vector_type;
unsigned data_length, lane_count;
LLVMTypeRef element_ptr_types[] = { INT8_PTR_TYPE, INT16_PTR_TYPE,
INT32_PTR_TYPE, INT64_PTR_TYPE };
uint32 data_lengths[] = { 1, 2, 4, 8 };
LLVMValueRef undefs[] = {
LLVM_CONST(i8x16_undef),
LLVM_CONST(i16x8_undef),
LLVM_CONST(i32x4_undef),
LLVM_CONST(i64x2_undef),
};
LLVMValueRef masks[] = {
LLVM_CONST(i32x16_zero),
LLVM_CONST(i32x8_zero),
LLVM_CONST(i32x4_zero),
LLVM_CONST(i32x2_zero),
};
switch (load_opcode) {
case SIMD_v8x16_load_splat:
data_length = 1;
lane_count = 16;
element_ptr_type = INT8_PTR_TYPE;
vector_type = V128_i8x16_TYPE;
break;
case SIMD_v16x8_load_splat:
data_length = 2;
lane_count = 8;
element_ptr_type = INT16_PTR_TYPE;
vector_type = V128_i16x8_TYPE;
break;
case SIMD_v32x4_load_splat:
data_length = 4;
lane_count = 4;
element_ptr_type = INT32_PTR_TYPE;
vector_type = V128_i32x4_TYPE;
break;
case SIMD_v64x2_load_splat:
data_length = 8;
lane_count = 2;
element_ptr_type = INT64_PTR_TYPE;
vector_type = V128_i64x2_TYPE;
break;
default:
bh_assert(0);
goto fail;
if (!(element = simd_load(comp_ctx, func_ctx, align, offset,
data_lengths[opcode_index],
element_ptr_types[opcode_index]))) {
return false;
}
if (!(element = simd_load(comp_ctx, func_ctx, align, offset, data_length,
element_ptr_type))) {
goto fail;
if (!(result =
LLVMBuildInsertElement(comp_ctx->builder, undefs[opcode_index],
element, I32_ZERO, "base"))) {
HANDLE_FAILURE("LLVMBuildInsertElement");
return false;
}
if (!(result = simd_splat(comp_ctx, func_ctx, element, vector_type,
lane_count))) {
goto fail;
if (!(result = LLVMBuildShuffleVector(comp_ctx->builder, result,
undefs[opcode_index],
masks[opcode_index], "vector"))) {
HANDLE_FAILURE("LLVMBuildShuffleVector");
return false;
}
if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE,
"result"))) {
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
}
bool
aot_compile_simd_load_lane(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint8 opcode,
uint32 align,
uint32 offset,
uint8 lane_id)
{
LLVMValueRef element, vector;
uint32 opcode_index = opcode - SIMD_v128_load8_lane;
uint32 data_lengths[] = { 1, 2, 4, 8 };
LLVMTypeRef element_ptr_types[] = { INT8_PTR_TYPE, INT16_PTR_TYPE,
INT32_PTR_TYPE, INT64_PTR_TYPE };
LLVMTypeRef vector_types[] = { V128_i8x16_TYPE, V128_i16x8_TYPE,
V128_i32x4_TYPE, V128_i64x2_TYPE };
LLVMValueRef lane = simd_lane_id_to_llvm_value(comp_ctx, lane_id);
if (!(vector = simd_pop_v128_and_bitcast(
comp_ctx, func_ctx, vector_types[opcode_index], "src"))) {
return false;
}
if (!(element = simd_load(comp_ctx, func_ctx, align, offset,
data_lengths[opcode_index],
element_ptr_types[opcode_index]))) {
return false;
}
if (!(vector = LLVMBuildInsertElement(comp_ctx->builder, vector, element,
lane, "dst"))) {
HANDLE_FAILURE("LLVMBuildInsertElement");
return false;
}
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, vector, "result");
}
bool
aot_compile_simd_load_zero(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint8 opcode,
uint32 align,
uint32 offset)
{
LLVMValueRef element, result, mask;
uint32 opcode_index = opcode - SIMD_v128_load32_zero;
uint32 data_lengths[] = { 4, 8 };
LLVMTypeRef element_ptr_types[] = { INT32_PTR_TYPE, INT64_PTR_TYPE };
LLVMValueRef zero[] = {
LLVM_CONST(i32x4_vec_zero),
LLVM_CONST(i64x2_vec_zero),
};
LLVMValueRef undef[] = {
LLVM_CONST(i32x4_undef),
LLVM_CONST(i64x2_undef),
};
uint32 mask_length[] = { 4, 2 };
LLVMValueRef mask_element[][4] = {
{ LLVM_CONST(i32_zero), LLVM_CONST(i32_four), LLVM_CONST(i32_five),
LLVM_CONST(i32_six) },
{ LLVM_CONST(i32_zero), LLVM_CONST(i32_two) },
};
if (!(element = simd_load(comp_ctx, func_ctx, align, offset,
data_lengths[opcode_index],
element_ptr_types[opcode_index]))) {
return false;
}
if (!(result =
LLVMBuildInsertElement(comp_ctx->builder, undef[opcode_index],
element, I32_ZERO, "vector"))) {
HANDLE_FAILURE("LLVMBuildInsertElement");
return false;
}
/* fill in other lanes with zero */
if (!(mask = LLVMConstVector(mask_element[opcode_index],
mask_length[opcode_index]))) {
HANDLE_FAILURE("LLConstVector");
return false;
}
if (!(result = LLVMBuildShuffleVector(comp_ctx->builder, result,
zero[opcode_index], mask,
"fill_in_zero"))) {
HANDLE_FAILURE("LLVMBuildShuffleVector");
return false;
}
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
}
/* data_length in bytes */
static bool
simd_store(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 align,
uint32 offset,
uint32 data_length,
LLVMValueRef value,
LLVMTypeRef value_ptr_type)
{
LLVMValueRef maddr, result;
if (!(maddr = aot_check_memory_overflow(comp_ctx, func_ctx, offset,
data_length)))
return false;
if (!(maddr = LLVMBuildBitCast(comp_ctx->builder, maddr, value_ptr_type,
"data_ptr"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
return false;
}
PUSH_V128(result);
if (!(result = LLVMBuildStore(comp_ctx->builder, value, maddr))) {
HANDLE_FAILURE("LLVMBuildStore");
return false;
}
LLVMSetAlignment(result, 1);
return true;
}
bool
aot_compile_simd_v128_store(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 align,
uint32 offset)
{
LLVMValueRef value;
POP_V128(value);
return simd_store(comp_ctx, func_ctx, align, offset, 16, value,
V128_PTR_TYPE);
fail:
return false;
}
bool
aot_compile_simd_store_lane(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint8 opcode,
uint32 align,
uint32 offset,
uint8 lane_id)
{
LLVMValueRef element, vector;
uint32 data_lengths[] = { 1, 2, 4, 8 };
LLVMTypeRef element_ptr_types[] = { INT8_PTR_TYPE, INT16_PTR_TYPE,
INT32_PTR_TYPE, INT64_PTR_TYPE };
uint32 opcode_index = opcode - SIMD_v128_store8_lane;
LLVMTypeRef vector_types[] = { V128_i8x16_TYPE, V128_i16x8_TYPE,
V128_i32x4_TYPE, V128_i64x2_TYPE };
LLVMValueRef lane = simd_lane_id_to_llvm_value(comp_ctx, lane_id);
if (!(vector = simd_pop_v128_and_bitcast(
comp_ctx, func_ctx, vector_types[opcode_index], "src"))) {
return false;
}
if (!(element = LLVMBuildExtractElement(comp_ctx->builder, vector, lane,
"element"))) {
HANDLE_FAILURE("LLVMBuildExtractElement");
return false;
}
return simd_store(comp_ctx, func_ctx, align, offset,
data_lengths[opcode_index], element,
element_ptr_types[opcode_index]);
}

View File

@ -18,26 +18,49 @@ aot_compile_simd_v128_load(AOTCompContext *comp_ctx,
uint32 align,
uint32 offset);
bool
aot_compile_simd_v128_store(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 align,
uint32 offset);
bool
aot_compile_simd_load_extend(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint8 load_opcode,
uint8 opcode,
uint32 align,
uint32 offset);
bool
aot_compile_simd_load_splat(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint8 load_opcode,
uint8 opcode,
uint32 align,
uint32 offset);
bool
aot_compile_simd_load_lane(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint8 opcode,
uint32 align,
uint32 offset,
uint8 lane_id);
bool
aot_compile_simd_load_zero(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint8 opcode,
uint32 align,
uint32 offset);
bool
aot_compile_simd_v128_store(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 align,
uint32 offset);
bool
aot_compile_simd_store_lane(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint8 opcode,
uint32 align,
uint32 offset,
uint8 lane_id);
#ifdef __cplusplus
} /* end of extern "C" */
#endif

View File

@ -9,46 +9,32 @@
#include "../../aot/aot_runtime.h"
static bool
simd_v128_integer_arith(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
LLVMTypeRef vector_type,
char *intrinsics_s_u[2],
bool is_signed)
simd_sat_int_arith(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
LLVMTypeRef vector_type,
const char *intrinsics)
{
LLVMValueRef lhs, rhs, result;
LLVMTypeRef param_types[2];
if (!(rhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"rhs"))) {
goto fail;
}
if (!(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"lhs"))) {
goto fail;
if (!(rhs =
simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, "rhs"))
|| !(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"lhs"))) {
return false;
}
param_types[0] = vector_type;
param_types[1] = vector_type;
if (!(result = aot_call_llvm_intrinsic(
comp_ctx, func_ctx, is_signed ? intrinsics_s_u[0] : intrinsics_s_u[1],
vector_type, param_types, 2, lhs, rhs))) {
if (!(result =
aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsics,
vector_type, param_types, 2, lhs, rhs))) {
HANDLE_FAILURE("LLVMBuildCall");
goto fail;
return false;
}
if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE,
"ret"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
/* push result into the stack */
PUSH_V128(result);
return true;
fail:
return false;
return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
}
bool
@ -57,27 +43,14 @@ aot_compile_simd_i8x16_saturate(AOTCompContext *comp_ctx,
V128Arithmetic arith_op,
bool is_signed)
{
char *intrinsics[2] = { 0 };
bool result = false;
switch (arith_op) {
case V128_ADD:
intrinsics[0] = "llvm.sadd.sat.v16i8";
intrinsics[1] = "llvm.uadd.sat.v16i8";
result = simd_v128_integer_arith(
comp_ctx, func_ctx, V128_i8x16_TYPE, intrinsics, is_signed);
break;
case V128_SUB:
intrinsics[0] = "llvm.ssub.sat.v16i8";
intrinsics[1] = "llvm.usub.sat.v16i8";
result = simd_v128_integer_arith(
comp_ctx, func_ctx, V128_i8x16_TYPE, intrinsics, is_signed);
break;
default:
bh_assert(0);
break;
}
char *intrinsics[][2] = {
{ "llvm.sadd.sat.v16i8", "llvm.uadd.sat.v16i8" },
{ "llvm.ssub.sat.v16i8", "llvm.usub.sat.v16i8" },
};
return result;
return simd_sat_int_arith(comp_ctx, func_ctx, V128_i8x16_TYPE,
is_signed ? intrinsics[arith_op][0]
: intrinsics[arith_op][1]);
}
bool
@ -86,282 +59,28 @@ aot_compile_simd_i16x8_saturate(AOTCompContext *comp_ctx,
V128Arithmetic arith_op,
bool is_signed)
{
char *intrinsics[2] = { 0 };
bool result = false;
switch (arith_op) {
case V128_ADD:
intrinsics[0] = "llvm.sadd.sat.v8i16";
intrinsics[1] = "llvm.uadd.sat.v8i16";
result = simd_v128_integer_arith(
comp_ctx, func_ctx, V128_i16x8_TYPE, intrinsics, is_signed);
break;
case V128_SUB:
intrinsics[0] = "llvm.ssub.sat.v8i16";
intrinsics[1] = "llvm.usub.sat.v8i16";
result = simd_v128_integer_arith(
comp_ctx, func_ctx, V128_i16x8_TYPE, intrinsics, is_signed);
break;
default:
bh_assert(0);
break;
}
char *intrinsics[][2] = {
{ "llvm.sadd.sat.v8i16", "llvm.uadd.sat.v8i16" },
{ "llvm.ssub.sat.v8i16", "llvm.usub.sat.v8i16" },
};
return result;
}
static bool
simd_v128_cmp(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
LLVMTypeRef vector_type,
V128Arithmetic arith_op,
bool is_signed)
{
LLVMValueRef lhs, rhs, result;
LLVMIntPredicate op;
if (!(rhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"rhs"))) {
goto fail;
}
if (!(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"lhs"))) {
goto fail;
}
if (V128_MIN == arith_op) {
op = is_signed ? LLVMIntSLT : LLVMIntULT;
}
else {
op = is_signed ? LLVMIntSGT : LLVMIntUGT;
}
if (!(result = LLVMBuildICmp(comp_ctx->builder, op, lhs, rhs, "cmp"))) {
HANDLE_FAILURE("LLVMBuildICmp");
goto fail;
}
if (!(result =
LLVMBuildSelect(comp_ctx->builder, result, lhs, rhs, "select"))) {
HANDLE_FAILURE("LLVMBuildSelect");
goto fail;
}
if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE,
"ret"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
/* push result into the stack */
PUSH_V128(result);
return true;
fail:
return false;
return simd_sat_int_arith(comp_ctx, func_ctx, V128_i16x8_TYPE,
is_signed ? intrinsics[arith_op][0]
: intrinsics[arith_op][1]);
}
bool
aot_compile_simd_i8x16_cmp(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
V128Arithmetic arith_op,
bool is_signed)
aot_compile_simd_i32x4_saturate(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
V128Arithmetic arith_op,
bool is_signed)
{
return simd_v128_cmp(comp_ctx, func_ctx, V128_i8x16_TYPE, arith_op,
is_signed);
char *intrinsics[][2] = {
{ "llvm.sadd.sat.v4i32", "llvm.uadd.sat.v4i32" },
{ "llvm.ssub.sat.v4i32", "llvm.usub.sat.v4i32" },
};
return simd_sat_int_arith(comp_ctx, func_ctx, V128_i16x8_TYPE,
is_signed ? intrinsics[arith_op][0]
: intrinsics[arith_op][1]);
}
bool
aot_compile_simd_i16x8_cmp(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
V128Arithmetic arith_op,
bool is_signed)
{
return simd_v128_cmp(comp_ctx, func_ctx, V128_i16x8_TYPE, arith_op,
is_signed);
}
bool
aot_compile_simd_i32x4_cmp(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
V128Arithmetic arith_op,
bool is_signed)
{
return simd_v128_cmp(comp_ctx, func_ctx, V128_i32x4_TYPE, arith_op,
is_signed);
}
static bool
simd_v128_abs(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
LLVMTypeRef vector_type)
{
LLVMValueRef vector, negs, zeros, cond, result;
if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"vec"))) {
goto fail;
}
if (!(negs = LLVMBuildNeg(comp_ctx->builder, vector, "neg"))) {
HANDLE_FAILURE("LLVMBuildNeg");
goto fail;
}
if (!(zeros = LLVMConstNull(vector_type))) {
HANDLE_FAILURE("LLVMConstNull");
goto fail;
}
if (!(cond = LLVMBuildICmp(comp_ctx->builder, LLVMIntSGE, vector, zeros,
"ge_zero"))) {
HANDLE_FAILURE("LLVMBuildICmp");
goto fail;
}
if (!(result = LLVMBuildSelect(comp_ctx->builder, cond, vector, negs,
"select"))) {
HANDLE_FAILURE("LLVMBuildSelect");
goto fail;
}
if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE,
"ret"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
/* push result into the stack */
PUSH_V128(result);
return true;
fail:
return false;
}
bool
aot_compile_simd_i8x16_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
return simd_v128_abs(comp_ctx, func_ctx, V128_i8x16_TYPE);
}
bool
aot_compile_simd_i16x8_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
return simd_v128_abs(comp_ctx, func_ctx, V128_i16x8_TYPE);
}
bool
aot_compile_simd_i32x4_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
return simd_v128_abs(comp_ctx, func_ctx, V128_i32x4_TYPE);
}
/* (v1 + v2 + 1) / 2 */
static bool
simd_v128_avg(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
LLVMTypeRef vector_type,
LLVMTypeRef element_type,
unsigned lane_width)
{
LLVMValueRef lhs, rhs, undef, zeros, ones, result;
LLVMTypeRef ext_type;
if (!(rhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"rhs"))) {
goto fail;
}
if (!(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
"lhs"))) {
goto fail;
}
if (!(ext_type = LLVMVectorType(I32_TYPE, lane_width))) {
HANDLE_FAILURE("LLVMVectorType");
goto fail;
}
if (!(lhs = LLVMBuildZExt(comp_ctx->builder, lhs, ext_type, "left_ext"))) {
HANDLE_FAILURE("LLVMBuildZExt");
goto fail;
}
if (!(rhs =
LLVMBuildZExt(comp_ctx->builder, rhs, ext_type, "right_ext"))) {
HANDLE_FAILURE("LLVMBuildZExt");
goto fail;
}
if (!(undef = LLVMGetUndef(ext_type))) {
HANDLE_FAILURE("LLVMGetUndef");
goto fail;
}
if (!(zeros = LLVMConstNull(ext_type))) {
HANDLE_FAILURE("LLVMConstNull");
goto fail;
}
if (!(ones = LLVMConstInt(I32_TYPE, 1, true))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(ones = LLVMBuildInsertElement(comp_ctx->builder, undef, ones,
I32_ZERO, "base_ones"))) {
HANDLE_FAILURE("LLVMBuildInsertElement");
goto fail;
}
if (!(ones = LLVMBuildShuffleVector(comp_ctx->builder, ones, undef, zeros,
"ones"))) {
HANDLE_FAILURE("LLVMBuildShuffleVector");
goto fail;
}
if (!(result = LLVMBuildAdd(comp_ctx->builder, lhs, rhs, "a_add_b"))) {
HANDLE_FAILURE("LLVMBuildAdd");
goto fail;
}
if (!(result = LLVMBuildAdd(comp_ctx->builder, result, ones, "plus_1"))) {
HANDLE_FAILURE("LLVMBuildAdd");
goto fail;
}
if (!(result = LLVMBuildLShr(comp_ctx->builder, result, ones, "avg"))) {
HANDLE_FAILURE("LLVMBuildLShr");
goto fail;
}
if (!(result = LLVMBuildTrunc(comp_ctx->builder, result, vector_type,
"avg_trunc"))) {
HANDLE_FAILURE("LLVMBuildTrunc");
goto fail;
}
if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE,
"ret"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
/* push result into the stack */
PUSH_V128(result);
return true;
fail:
return false;
}
bool
aot_compile_simd_i8x16_avgr_u(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_v128_avg(comp_ctx, func_ctx, V128_i8x16_TYPE, INT8_TYPE, 16);
}
bool
aot_compile_simd_i16x8_avgr_u(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx)
{
return simd_v128_avg(comp_ctx, func_ctx, V128_i16x8_TYPE, INT16_TYPE, 8);
}

View File

@ -25,40 +25,10 @@ aot_compile_simd_i16x8_saturate(AOTCompContext *comp_ctx,
bool is_signed);
bool
aot_compile_simd_i8x16_cmp(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
V128Arithmetic arith_op,
bool is_signed);
bool
aot_compile_simd_i16x8_cmp(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
V128Arithmetic arith_op,
bool is_signed);
bool
aot_compile_simd_i32x4_cmp(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
V128Arithmetic arith_op,
bool is_signed);
bool
aot_compile_simd_i8x16_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
bool
aot_compile_simd_i16x8_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
bool
aot_compile_simd_i32x4_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
bool
aot_compile_simd_i8x16_avgr_u(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_simd_i16x8_avgr_u(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
aot_compile_simd_i32x4_saturate(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
V128Arithmetic arith_op,
bool is_signed);
#ifdef __cplusplus
} /* end of extern "C" */
#endif

View File

@ -4053,44 +4053,35 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
case WASM_OP_SIMD_PREFIX:
{
/* TODO: shall we ceate a table to be friendly to branch prediction */
opcode = read_uint8(p);
if (SIMD_i8x16_eq <= opcode
&& opcode <= SIMD_f32x4_convert_i32x4_u) {
break;
}
/* follow the order of enum WASMSimdEXTOpcode in wasm_opcode.h */
switch (opcode) {
case SIMD_v128_load:
case SIMD_i16x8_load8x8_s:
case SIMD_i16x8_load8x8_u:
case SIMD_i32x4_load16x4_s:
case SIMD_i32x4_load16x4_u:
case SIMD_i64x2_load32x2_s:
case SIMD_i64x2_load32x2_u:
case SIMD_v8x16_load_splat:
case SIMD_v16x8_load_splat:
case SIMD_v32x4_load_splat:
case SIMD_v64x2_load_splat:
case SIMD_v128_load8x8_s:
case SIMD_v128_load8x8_u:
case SIMD_v128_load16x4_s:
case SIMD_v128_load16x4_u:
case SIMD_v128_load32x2_s:
case SIMD_v128_load32x2_u:
case SIMD_v128_load8_splat:
case SIMD_v128_load16_splat:
case SIMD_v128_load32_splat:
case SIMD_v128_load64_splat:
case SIMD_v128_store:
skip_leb_uint32(p, p_end); /* align */
skip_leb_uint32(p, p_end); /* offset */
/* memarg align */
skip_leb_uint32(p, p_end);
/* memarg offset*/
skip_leb_uint32(p, p_end);
break;
case SIMD_v128_const:
case SIMD_v8x16_shuffle:
/* immByte[16] immLaneId[16] */
CHECK_BUF1(p, p_end, 16);
p += 16;
break;
case SIMD_v8x16_swizzle:
case SIMD_i8x16_splat:
case SIMD_i16x8_splat:
case SIMD_i32x4_splat:
case SIMD_i64x2_splat:
case SIMD_f32x4_splat:
case SIMD_f64x2_splat:
break;
case SIMD_i8x16_extract_lane_s:
case SIMD_i8x16_extract_lane_u:
case SIMD_i8x16_replace_lane:
@ -4105,14 +4096,44 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
case SIMD_f32x4_replace_lane:
case SIMD_f64x2_extract_lane:
case SIMD_f64x2_replace_lane:
/* ImmLaneId */
CHECK_BUF(p, p_end, 1);
p++;
break;
case SIMD_v128_load8_lane:
case SIMD_v128_load16_lane:
case SIMD_v128_load32_lane:
case SIMD_v128_load64_lane:
case SIMD_v128_store8_lane:
case SIMD_v128_store16_lane:
case SIMD_v128_store32_lane:
case SIMD_v128_store64_lane:
/* memarg align */
skip_leb_uint32(p, p_end);
/* memarg offset*/
skip_leb_uint32(p, p_end);
/* ImmLaneId */
CHECK_BUF(p, p_end, 1);
p++;
break;
case SIMD_v128_load32_zero:
case SIMD_v128_load64_zero:
/* memarg align */
skip_leb_uint32(p, p_end);
/* memarg offset*/
skip_leb_uint32(p, p_end);
break;
default:
LOG_WARNING("WASM loader find block addr failed: "
"invalid opcode fd 0x%02x.", opcode);
return false;
/*
* since latest SIMD specific used almost every value
* from 0x00 to 0xff, the default branch will present all
* opcodes without imm
* https://github.com/WebAssembly/simd/blob/main/proposals/simd/NewOpcodes.md
*/
break;
}
break;
}
@ -5685,9 +5706,25 @@ check_simd_memory_access_align(uint8 opcode, uint32 align,
4, /* store */
};
bh_assert(opcode <= SIMD_v128_store);
uint8 mem_access_aligns_load_lane[] = {
0, 1, 2, 3, /* load lane */
0, 1, 2, 3, /* store lane */
2, 3 /* store zero */
};
if (align > mem_access_aligns[opcode - SIMD_v128_load]) {
if (!((opcode <= SIMD_v128_store)
|| (SIMD_v128_load8_lane <= opcode
&& opcode <= SIMD_v128_load64_zero))) {
set_error_buf(error_buf, error_buf_size,
"the opcode doesn't include memarg");
return false;
}
if ((opcode <= SIMD_v128_store
&& align > mem_access_aligns[opcode - SIMD_v128_load])
|| (SIMD_v128_load8_lane <= opcode && opcode <= SIMD_v128_load64_zero
&& align > mem_access_aligns_load_lane[opcode
- SIMD_v128_load8_lane])) {
set_error_buf(error_buf, error_buf_size,
"alignment must not be larger than natural");
return false;
@ -5731,6 +5768,24 @@ check_simd_access_lane(uint8 opcode, uint8 lane,
goto fail;
}
break;
case SIMD_v128_load8_lane:
case SIMD_v128_load16_lane:
case SIMD_v128_load32_lane:
case SIMD_v128_load64_lane:
case SIMD_v128_store8_lane:
case SIMD_v128_store16_lane:
case SIMD_v128_store32_lane:
case SIMD_v128_store64_lane:
case SIMD_v128_load32_zero:
case SIMD_v128_load64_zero:
{
uint8 max_lanes[] = { 16, 8, 4, 2, 16, 8, 4, 2, 4, 2 };
if (lane >= max_lanes[opcode - SIMD_v128_load8_lane]) {
goto fail;
}
break;
}
default:
goto fail;
}
@ -8038,21 +8093,21 @@ fail_data_cnt_sec_require:
#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
case WASM_OP_SIMD_PREFIX:
{
uint8 lane;
opcode = read_uint8(p);
/* follow the order of enum WASMSimdEXTOpcode in wasm_opcode.h */
switch (opcode) {
/* memory instruction */
case SIMD_v128_load:
case SIMD_i16x8_load8x8_s:
case SIMD_i16x8_load8x8_u:
case SIMD_i32x4_load16x4_s:
case SIMD_i32x4_load16x4_u:
case SIMD_i64x2_load32x2_s:
case SIMD_i64x2_load32x2_u:
case SIMD_v8x16_load_splat:
case SIMD_v16x8_load_splat:
case SIMD_v32x4_load_splat:
case SIMD_v64x2_load_splat:
case SIMD_v128_load8x8_s:
case SIMD_v128_load8x8_u:
case SIMD_v128_load16x4_s:
case SIMD_v128_load16x4_u:
case SIMD_v128_load32x2_s:
case SIMD_v128_load32x2_u:
case SIMD_v128_load8_splat:
case SIMD_v128_load16_splat:
case SIMD_v128_load32_splat:
case SIMD_v128_load64_splat:
{
CHECK_MEMORY();
@ -8064,7 +8119,6 @@ fail_data_cnt_sec_require:
read_leb_uint32(p, p_end, mem_offset); /* offset */
/* pop(i32 %i), push(v128 *result) */
POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_V128);
break;
}
@ -8081,18 +8135,19 @@ fail_data_cnt_sec_require:
read_leb_uint32(p, p_end, mem_offset); /* offset */
/* pop(v128 %value) */
POP_V128();
/* pop(i32 %i) */
POP_I32();
break;
}
/* basic operation */
case SIMD_v128_const:
{
CHECK_BUF1(p, p_end, 16);
p += 16;
PUSH_V128();
break;
}
case SIMD_v8x16_shuffle:
{
@ -8111,122 +8166,87 @@ fail_data_cnt_sec_require:
}
case SIMD_v8x16_swizzle:
{
POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
/* splat operation */
case SIMD_i8x16_splat:
case SIMD_i16x8_splat:
case SIMD_i32x4_splat:
POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_V128);
break;
case SIMD_i64x2_splat:
POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_V128);
break;
case SIMD_f32x4_splat:
POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_V128);
break;
case SIMD_f64x2_splat:
POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_V128);
{
uint8 pop_type[] = { VALUE_TYPE_I32, VALUE_TYPE_I32,
VALUE_TYPE_I32, VALUE_TYPE_I64,
VALUE_TYPE_F32, VALUE_TYPE_F64 };
POP_AND_PUSH(pop_type[opcode - SIMD_i8x16_splat],
VALUE_TYPE_V128);
break;
}
/* lane operation */
case SIMD_i8x16_extract_lane_s:
case SIMD_i8x16_extract_lane_u:
case SIMD_i8x16_replace_lane:
case SIMD_i16x8_extract_lane_s:
case SIMD_i16x8_extract_lane_u:
case SIMD_i32x4_extract_lane:
CHECK_BUF(p, p_end, 1);
lane = read_uint8(p);
if (!check_simd_access_lane(opcode, lane, error_buf,
error_buf_size)) {
goto fail;
}
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_I32);
break;
case SIMD_i64x2_extract_lane:
CHECK_BUF(p, p_end, 1);
lane = read_uint8(p);
if (!check_simd_access_lane(opcode, lane, error_buf,
error_buf_size)) {
goto fail;
}
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_I64);
break;
case SIMD_f32x4_extract_lane:
CHECK_BUF(p, p_end, 1);
lane = read_uint8(p);
if (!check_simd_access_lane(opcode, lane, error_buf,
error_buf_size)) {
goto fail;
}
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_F32);
break;
case SIMD_f64x2_extract_lane:
CHECK_BUF(p, p_end, 1);
lane = read_uint8(p);
if (!check_simd_access_lane(opcode, lane, error_buf,
error_buf_size)) {
goto fail;
}
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_F64);
break;
case SIMD_i8x16_replace_lane:
case SIMD_i16x8_replace_lane:
case SIMD_i32x4_extract_lane:
case SIMD_i32x4_replace_lane:
CHECK_BUF(p, p_end, 1);
lane = read_uint8(p);
if (!check_simd_access_lane(opcode, lane, error_buf,
error_buf_size)) {
goto fail;
}
POP_I32();
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
case SIMD_i64x2_extract_lane:
case SIMD_i64x2_replace_lane:
CHECK_BUF(p, p_end, 1);
lane = read_uint8(p);
if (!check_simd_access_lane(opcode, lane, error_buf,
error_buf_size)) {
goto fail;
}
POP_I64();
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
case SIMD_f32x4_extract_lane:
case SIMD_f32x4_replace_lane:
CHECK_BUF(p, p_end, 1);
lane = read_uint8(p);
if (!check_simd_access_lane(opcode, lane, error_buf,
error_buf_size)) {
goto fail;
}
POP_F32();
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
case SIMD_f64x2_extract_lane:
case SIMD_f64x2_replace_lane:
{
uint8 lane;
/* clang-format off */
uint8 replace[] = {
/*i8x16*/ 0x0, 0x0, VALUE_TYPE_I32,
/*i16x8*/ 0x0, 0x0, VALUE_TYPE_I32,
/*i32x4*/ 0x0, VALUE_TYPE_I32,
/*i64x2*/ 0x0, VALUE_TYPE_I64,
/*f32x4*/ 0x0, VALUE_TYPE_F32,
/*f64x2*/ 0x0, VALUE_TYPE_F64,
};
uint8 push_type[] = {
/*i8x16*/ VALUE_TYPE_I32, VALUE_TYPE_I32,
VALUE_TYPE_V128,
/*i16x8*/ VALUE_TYPE_I32, VALUE_TYPE_I32,
VALUE_TYPE_V128,
/*i32x4*/ VALUE_TYPE_I32, VALUE_TYPE_V128,
/*i64x2*/ VALUE_TYPE_I64, VALUE_TYPE_V128,
/*f32x4*/ VALUE_TYPE_F32, VALUE_TYPE_V128,
/*f64x2*/ VALUE_TYPE_F64, VALUE_TYPE_V128,
};
/* clang-format on */
CHECK_BUF(p, p_end, 1);
lane = read_uint8(p);
if (!check_simd_access_lane(opcode, lane, error_buf,
error_buf_size)) {
goto fail;
}
POP_F64();
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
if (replace[opcode - SIMD_i8x16_extract_lane_s]) {
if (!(wasm_loader_pop_frame_ref(
loader_ctx,
replace[opcode - SIMD_i8x16_extract_lane_s],
error_buf, error_buf_size)))
goto fail;
}
POP_AND_PUSH(
VALUE_TYPE_V128,
push_type[opcode - SIMD_i8x16_extract_lane_s]);
break;
}
/* i8x16 compare operation */
case SIMD_i8x16_eq:
case SIMD_i8x16_ne:
case SIMD_i8x16_lt_s:
@ -8237,6 +8257,7 @@ fail_data_cnt_sec_require:
case SIMD_i8x16_le_u:
case SIMD_i8x16_ge_s:
case SIMD_i8x16_ge_u:
/* i16x8 compare operation */
case SIMD_i16x8_eq:
case SIMD_i16x8_ne:
case SIMD_i16x8_lt_s:
@ -8247,6 +8268,7 @@ fail_data_cnt_sec_require:
case SIMD_i16x8_le_u:
case SIMD_i16x8_ge_s:
case SIMD_i16x8_ge_u:
/* i32x4 compare operation */
case SIMD_i32x4_eq:
case SIMD_i32x4_ne:
case SIMD_i32x4_lt_s:
@ -8257,122 +8279,318 @@ fail_data_cnt_sec_require:
case SIMD_i32x4_le_u:
case SIMD_i32x4_ge_s:
case SIMD_i32x4_ge_u:
/* f32x4 compare operation */
case SIMD_f32x4_eq:
case SIMD_f32x4_ne:
case SIMD_f32x4_lt:
case SIMD_f32x4_gt:
case SIMD_f32x4_le:
case SIMD_f32x4_ge:
/* f64x2 compare operation */
case SIMD_f64x2_eq:
case SIMD_f64x2_ne:
case SIMD_f64x2_lt:
case SIMD_f64x2_gt:
case SIMD_f64x2_le:
case SIMD_f64x2_ge:
{
POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
/* v128 operation */
case SIMD_v128_not:
{
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_v128_and:
case SIMD_v128_andnot:
case SIMD_v128_or:
case SIMD_v128_xor:
{
POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_v128_bitselect:
{
POP_V128();
POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_v128_any_true:
{
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_I32);
break;
}
/* Load Lane Operation */
case SIMD_v128_load8_lane:
case SIMD_v128_load16_lane:
case SIMD_v128_load32_lane:
case SIMD_v128_load64_lane:
case SIMD_v128_store8_lane:
case SIMD_v128_store16_lane:
case SIMD_v128_store32_lane:
case SIMD_v128_store64_lane:
{
uint8 lane;
CHECK_MEMORY();
read_leb_uint32(p, p_end, align); /* align */
if (!check_simd_memory_access_align(
opcode, align, error_buf, error_buf_size)) {
goto fail;
}
read_leb_uint32(p, p_end, mem_offset); /* offset */
CHECK_BUF(p, p_end, 1);
lane = read_uint8(p);
if (!check_simd_access_lane(opcode, lane, error_buf,
error_buf_size)) {
goto fail;
}
POP_V128();
POP_I32();
if (opcode < SIMD_v128_store8_lane) {
PUSH_V128();
}
break;
}
case SIMD_v128_load32_zero:
case SIMD_v128_load64_zero:
{
CHECK_MEMORY();
read_leb_uint32(p, p_end, align); /* align */
if (!check_simd_memory_access_align(
opcode, align, error_buf, error_buf_size)) {
goto fail;
}
read_leb_uint32(p, p_end, mem_offset); /* offset */
POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_V128);
break;
}
/* Float conversion */
case SIMD_f32x4_demote_f64x2_zero:
case SIMD_f64x2_promote_low_f32x4_zero:
{
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
/* i8x16 Operation */
case SIMD_i8x16_abs:
case SIMD_i8x16_neg:
case SIMD_i8x16_popcnt:
{
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_i8x16_all_true:
case SIMD_i8x16_bitmask:
{
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_I32);
break;
}
case SIMD_i8x16_narrow_i16x8_s:
case SIMD_i8x16_narrow_i16x8_u:
{
POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_f32x4_ceil:
case SIMD_f32x4_floor:
case SIMD_f32x4_trunc:
case SIMD_f32x4_nearest:
case SIMD_f64x2_ceil:
case SIMD_f64x2_floor:
case SIMD_f64x2_trunc:
case SIMD_f64x2_nearest:
case SIMD_v128_not:
case SIMD_i8x16_abs:
case SIMD_i8x16_neg:
case SIMD_i16x8_abs:
case SIMD_i16x8_neg:
case SIMD_i32x4_abs:
case SIMD_i32x4_neg:
case SIMD_i64x2_neg:
case SIMD_f32x4_abs:
case SIMD_f32x4_neg:
case SIMD_f32x4_sqrt:
case SIMD_f64x2_abs:
case SIMD_f64x2_neg:
case SIMD_f64x2_sqrt:
case SIMD_i16x8_widen_low_i8x16_s:
case SIMD_i16x8_widen_high_i8x16_s:
case SIMD_i16x8_widen_low_i8x16_u:
case SIMD_i16x8_widen_high_i8x16_u:
case SIMD_i32x4_widen_low_i16x8_s:
case SIMD_i32x4_widen_high_i16x8_s:
case SIMD_i32x4_widen_low_i16x8_u:
case SIMD_i32x4_widen_high_i16x8_u:
case SIMD_i32x4_trunc_sat_f32x4_s:
case SIMD_i32x4_trunc_sat_f32x4_u:
case SIMD_f32x4_convert_i32x4_s:
case SIMD_f32x4_convert_i32x4_u:
{
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
case SIMD_v128_bitselect:
POP_V128();
POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
case SIMD_i8x16_any_true:
case SIMD_i8x16_all_true:
case SIMD_i8x16_bitmask:
case SIMD_i16x8_any_true:
case SIMD_i16x8_all_true:
case SIMD_i16x8_bitmask:
case SIMD_i32x4_any_true:
case SIMD_i32x4_all_true:
case SIMD_i32x4_bitmask:
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_I32);
break;
}
case SIMD_i8x16_shl:
case SIMD_i8x16_shr_s:
case SIMD_i8x16_shr_u:
case SIMD_i16x8_shl:
case SIMD_i16x8_shr_s:
case SIMD_i16x8_shr_u:
case SIMD_i32x4_shl:
case SIMD_i32x4_shr_s:
case SIMD_i32x4_shr_u:
case SIMD_i64x2_shl:
case SIMD_i64x2_shr_s:
case SIMD_i64x2_shr_u:
{
POP_I32();
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_i8x16_narrow_i16x8_s:
case SIMD_i8x16_narrow_i16x8_u:
case SIMD_i16x8_narrow_i32x4_s:
case SIMD_i16x8_narrow_i32x4_u:
case SIMD_v128_and:
case SIMD_v128_andnot:
case SIMD_v128_or:
case SIMD_v128_xor:
case SIMD_i8x16_add:
case SIMD_i8x16_add_saturate_s:
case SIMD_i8x16_add_saturate_u:
case SIMD_i8x16_add_sat_s:
case SIMD_i8x16_add_sat_u:
case SIMD_i8x16_sub:
case SIMD_i8x16_sub_saturate_s:
case SIMD_i8x16_sub_saturate_u:
case SIMD_i8x16_sub_sat_s:
case SIMD_i8x16_sub_sat_u:
{
POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_f64x2_ceil:
case SIMD_f64x2_floor:
{
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_i8x16_min_s:
case SIMD_i8x16_min_u:
case SIMD_i8x16_max_s:
case SIMD_i8x16_max_u:
{
POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_f64x2_trunc:
{
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_i8x16_avgr_u:
{
POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_i16x8_extadd_pairwise_i8x16_s:
case SIMD_i16x8_extadd_pairwise_i8x16_u:
case SIMD_i32x4_extadd_pairwise_i16x8_s:
case SIMD_i32x4_extadd_pairwise_i16x8_u:
/* i16x8 operation */
case SIMD_i16x8_abs:
case SIMD_i16x8_neg:
{
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_i16x8_q15mulr_sat_s:
{
POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_i16x8_all_true:
case SIMD_i16x8_bitmask:
{
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_I32);
break;
}
case SIMD_i16x8_narrow_i32x4_s:
case SIMD_i16x8_narrow_i32x4_u:
{
POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_i16x8_extend_low_i8x16_s:
case SIMD_i16x8_extend_high_i8x16_s:
case SIMD_i16x8_extend_low_i8x16_u:
case SIMD_i16x8_extend_high_i8x16_u:
{
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_i16x8_shl:
case SIMD_i16x8_shr_s:
case SIMD_i16x8_shr_u:
{
POP_I32();
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_i16x8_add:
case SIMD_i16x8_add_saturate_s:
case SIMD_i16x8_add_saturate_u:
case SIMD_i16x8_add_sat_s:
case SIMD_i16x8_add_sat_u:
case SIMD_i16x8_sub:
case SIMD_i16x8_sub_saturate_s:
case SIMD_i16x8_sub_saturate_u:
case SIMD_i16x8_sub_sat_s:
case SIMD_i16x8_sub_sat_u:
{
POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_f64x2_nearest:
{
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_i16x8_mul:
case SIMD_i16x8_min_s:
case SIMD_i16x8_min_u:
case SIMD_i16x8_max_s:
case SIMD_i16x8_max_u:
case SIMD_i16x8_avgr_u:
case SIMD_i16x8_extmul_low_i8x16_s:
case SIMD_i16x8_extmul_high_i8x16_s:
case SIMD_i16x8_extmul_low_i8x16_u:
case SIMD_i16x8_extmul_high_i8x16_u:
{
POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
/* i32x4 operation */
case SIMD_i32x4_abs:
case SIMD_i32x4_neg:
{
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_i32x4_all_true:
case SIMD_i32x4_bitmask:
{
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_I32);
break;
}
case SIMD_i32x4_narrow_i64x2_s:
case SIMD_i32x4_narrow_i64x2_u:
{
POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_i32x4_extend_low_i16x8_s:
case SIMD_i32x4_extend_high_i16x8_s:
case SIMD_i32x4_extend_low_i16x8_u:
case SIMD_i32x4_extend_high_i16x8_u:
{
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_i32x4_shl:
case SIMD_i32x4_shr_s:
case SIMD_i32x4_shr_u:
{
POP_I32();
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_i32x4_add:
case SIMD_i32x4_sub:
case SIMD_i32x4_mul:
@ -8380,31 +8598,137 @@ fail_data_cnt_sec_require:
case SIMD_i32x4_min_u:
case SIMD_i32x4_max_s:
case SIMD_i32x4_max_u:
case SIMD_i32x4_dot_i16x8_s:
case SIMD_i32x4_avgr_u:
case SIMD_i32x4_extmul_low_i16x8_s:
case SIMD_i32x4_extmul_high_i16x8_s:
case SIMD_i32x4_extmul_low_i16x8_u:
case SIMD_i32x4_extmul_high_i16x8_u:
{
POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
/* i64x2 operation */
case SIMD_i64x2_abs:
case SIMD_i64x2_neg:
{
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_i64x2_all_true:
case SIMD_i64x2_bitmask:
{
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_I32);
break;
}
case SIMD_i64x2_extend_low_i32x4_s:
case SIMD_i64x2_extend_high_i32x4_s:
case SIMD_i64x2_extend_low_i32x4_u:
case SIMD_i64x2_extend_high_i32x4_u:
{
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_i64x2_shl:
case SIMD_i64x2_shr_s:
case SIMD_i64x2_shr_u:
{
POP_I32();
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_i64x2_add:
case SIMD_i64x2_sub:
case SIMD_i64x2_mul:
case SIMD_i64x2_eq:
case SIMD_i64x2_ne:
case SIMD_i64x2_lt_s:
case SIMD_i64x2_gt_s:
case SIMD_i64x2_le_s:
case SIMD_i64x2_ge_s:
case SIMD_i64x2_extmul_low_i32x4_s:
case SIMD_i64x2_extmul_high_i32x4_s:
case SIMD_i64x2_extmul_low_i32x4_u:
case SIMD_i64x2_extmul_high_i32x4_u:
{
POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
/* f32x4 operation */
case SIMD_f32x4_abs:
case SIMD_f32x4_neg:
case SIMD_f32x4_round:
case SIMD_f32x4_sqrt:
{
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_f32x4_add:
case SIMD_f32x4_sub:
case SIMD_f32x4_mul:
case SIMD_f32x4_div:
case SIMD_f32x4_min:
case SIMD_f32x4_max:
case SIMD_f32x4_pmin:
case SIMD_f32x4_pmax:
{
POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
/* f64x2 operation */
case SIMD_f64x2_abs:
case SIMD_f64x2_neg:
case SIMD_f64x2_round:
case SIMD_f64x2_sqrt:
{
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_f64x2_add:
case SIMD_f64x2_sub:
case SIMD_f64x2_mul:
case SIMD_f64x2_div:
case SIMD_f64x2_min:
case SIMD_f64x2_max:
case SIMD_f64x2_pmin:
case SIMD_f64x2_pmax:
{
POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
case SIMD_i32x4_trunc_sat_f32x4_s:
case SIMD_i32x4_trunc_sat_f32x4_u:
case SIMD_f32x4_convert_i32x4_s:
case SIMD_f32x4_convert_i32x4_u:
case SIMD_i32x4_trunc_sat_f64x2_s_zero:
case SIMD_i32x4_trunc_sat_f64x2_u_zero:
case SIMD_f64x2_convert_low_i32x4_s:
case SIMD_f64x2_convert_low_i32x4_u:
{
POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
break;
}
default:
{
if (error_buf != NULL) {
snprintf(error_buf, error_buf_size,
"WASM module load failed: "
"invalid opcode 0xfd %02x.", opcode);
"WASM module load failed: "
"invalid opcode 0xfd %02x.",
opcode);
}
goto fail;
}
}
break;
}

View File

@ -296,18 +296,18 @@ typedef enum WASMMiscEXTOpcode {
typedef enum WASMSimdEXTOpcode {
/* memory instruction */
SIMD_v128_load = 0x00,
SIMD_i16x8_load8x8_s = 0x01,
SIMD_i16x8_load8x8_u = 0x02,
SIMD_i32x4_load16x4_s = 0x03,
SIMD_i32x4_load16x4_u = 0x04,
SIMD_i64x2_load32x2_s = 0x05,
SIMD_i64x2_load32x2_u = 0x06,
SIMD_v8x16_load_splat = 0x07,
SIMD_v16x8_load_splat = 0x08,
SIMD_v32x4_load_splat = 0x09,
SIMD_v64x2_load_splat = 0x0a,
SIMD_v128_store = 0x0b,
SIMD_v128_load = 0x00,
SIMD_v128_load8x8_s = 0x01,
SIMD_v128_load8x8_u = 0x02,
SIMD_v128_load16x4_s = 0x03,
SIMD_v128_load16x4_u = 0x04,
SIMD_v128_load32x2_s = 0x05,
SIMD_v128_load32x2_u = 0x06,
SIMD_v128_load8_splat = 0x07,
SIMD_v128_load16_splat = 0x08,
SIMD_v128_load32_splat = 0x09,
SIMD_v128_load64_splat = 0x0a,
SIMD_v128_store = 0x0b,
/* basic operation */
SIMD_v128_const = 0x0c,
@ -391,107 +391,170 @@ typedef enum WASMSimdEXTOpcode {
SIMD_f64x2_ge = 0x4c,
/* v128 operation */
SIMD_v128_not = 0x4d,
SIMD_v128_and = 0x4e,
SIMD_v128_andnot = 0x4f,
SIMD_v128_or = 0x50,
SIMD_v128_xor = 0x51,
SIMD_v128_not = 0x4d,
SIMD_v128_and = 0x4e,
SIMD_v128_andnot = 0x4f,
SIMD_v128_or = 0x50,
SIMD_v128_xor = 0x51,
SIMD_v128_bitselect = 0x52,
SIMD_v128_any_true = 0x53,
/* Load Lane Operation */
SIMD_v128_load8_lane = 0x54,
SIMD_v128_load16_lane = 0x55,
SIMD_v128_load32_lane = 0x56,
SIMD_v128_load64_lane = 0x57,
SIMD_v128_store8_lane = 0x58,
SIMD_v128_store16_lane = 0x59,
SIMD_v128_store32_lane = 0x5a,
SIMD_v128_store64_lane = 0x5b,
SIMD_v128_load32_zero = 0x5c,
SIMD_v128_load64_zero = 0x5d,
/* Float conversion */
SIMD_f32x4_demote_f64x2_zero = 0x5e,
SIMD_f64x2_promote_low_f32x4_zero = 0x5f,
/* i8x16 Operation */
SIMD_i8x16_abs = 0x60,
SIMD_i8x16_neg = 0x61,
SIMD_i8x16_any_true = 0x62,
SIMD_i8x16_popcnt = 0x62,
SIMD_i8x16_all_true = 0x63,
SIMD_i8x16_bitmask = 0x64,
SIMD_i8x16_narrow_i16x8_s = 0x65,
SIMD_i8x16_narrow_i16x8_u = 0x66,
SIMD_f32x4_ceil = 0x67,
SIMD_f32x4_floor = 0x68,
SIMD_f32x4_trunc = 0x69,
SIMD_f32x4_nearest = 0x6a,
SIMD_i8x16_shl = 0x6b,
SIMD_i8x16_shr_s = 0x6c,
SIMD_i8x16_shr_u = 0x6d,
SIMD_i8x16_add = 0x6e,
SIMD_i8x16_add_saturate_s = 0x6f,
SIMD_i8x16_add_saturate_u = 0x70,
SIMD_i8x16_add_sat_s = 0x6f,
SIMD_i8x16_add_sat_u = 0x70,
SIMD_i8x16_sub = 0x71,
SIMD_i8x16_sub_saturate_s = 0x72,
SIMD_i8x16_sub_saturate_u = 0x73,
SIMD_i8x16_sub_sat_s = 0x72,
SIMD_i8x16_sub_sat_u = 0x73,
SIMD_f64x2_ceil = 0x74,
SIMD_f64x2_floor = 0x75,
SIMD_i8x16_min_s = 0x76,
SIMD_i8x16_min_u = 0x77,
SIMD_i8x16_max_s = 0x78,
SIMD_i8x16_max_u = 0x79,
SIMD_f64x2_trunc = 0x7a,
SIMD_i8x16_avgr_u = 0x7b,
SIMD_i16x8_extadd_pairwise_i8x16_s = 0x7c,
SIMD_i16x8_extadd_pairwise_i8x16_u = 0x7d,
SIMD_i32x4_extadd_pairwise_i16x8_s = 0x7e,
SIMD_i32x4_extadd_pairwise_i16x8_u = 0x7f,
/* i16x8 operation */
SIMD_i16x8_abs = 0x80,
SIMD_i16x8_neg = 0x81,
SIMD_i16x8_any_true = 0x82,
SIMD_i16x8_q15mulr_sat_s = 0x82,
SIMD_i16x8_all_true = 0x83,
SIMD_i16x8_bitmask = 0x84,
SIMD_i16x8_narrow_i32x4_s = 0x85,
SIMD_i16x8_narrow_i32x4_u = 0x86,
SIMD_i16x8_widen_low_i8x16_s = 0x87,
SIMD_i16x8_widen_high_i8x16_s = 0x88,
SIMD_i16x8_widen_low_i8x16_u = 0x89,
SIMD_i16x8_widen_high_i8x16_u = 0x8a,
SIMD_i16x8_extend_low_i8x16_s = 0x87,
SIMD_i16x8_extend_high_i8x16_s = 0x88,
SIMD_i16x8_extend_low_i8x16_u = 0x89,
SIMD_i16x8_extend_high_i8x16_u = 0x8a,
SIMD_i16x8_shl = 0x8b,
SIMD_i16x8_shr_s = 0x8c,
SIMD_i16x8_shr_u = 0x8d,
SIMD_i16x8_add = 0x8e,
SIMD_i16x8_add_saturate_s = 0x8f,
SIMD_i16x8_add_saturate_u = 0x90,
SIMD_i16x8_add_sat_s = 0x8f,
SIMD_i16x8_add_sat_u = 0x90,
SIMD_i16x8_sub = 0x91,
SIMD_i16x8_sub_saturate_s = 0x92,
SIMD_i16x8_sub_saturate_u = 0x93,
SIMD_i16x8_sub_sat_s = 0x92,
SIMD_i16x8_sub_sat_u = 0x93,
SIMD_f64x2_nearest = 0x94,
SIMD_i16x8_mul = 0x95,
SIMD_i16x8_min_s = 0x96,
SIMD_i16x8_min_u = 0x97,
SIMD_i16x8_max_s = 0x98,
SIMD_i16x8_max_u = 0x99,
/* placeholder = 0x9a */
SIMD_i16x8_avgr_u = 0x9b,
SIMD_i16x8_extmul_low_i8x16_s = 0x9c,
SIMD_i16x8_extmul_high_i8x16_s = 0x9d,
SIMD_i16x8_extmul_low_i8x16_u = 0x9e,
SIMD_i16x8_extmul_high_i8x16_u = 0x9f,
/* i32x4 operation */
SIMD_i32x4_abs = 0xa0,
SIMD_i32x4_neg = 0xa1,
SIMD_i32x4_any_true = 0xa2,
/* placeholder = 0xa2 */
SIMD_i32x4_all_true = 0xa3,
SIMD_i32x4_bitmask = 0xa4,
SIMD_i32x4_widen_low_i16x8_s = 0xa7,
SIMD_i32x4_widen_high_i16x8_s = 0xa8,
SIMD_i32x4_widen_low_i16x8_u = 0xa9,
SIMD_i32x4_widen_high_i16x8_u = 0xaa,
SIMD_i32x4_narrow_i64x2_s = 0xa5,
SIMD_i32x4_narrow_i64x2_u = 0xa6,
SIMD_i32x4_extend_low_i16x8_s = 0xa7,
SIMD_i32x4_extend_high_i16x8_s = 0xa8,
SIMD_i32x4_extend_low_i16x8_u = 0xa9,
SIMD_i32x4_extend_high_i16x8_u = 0xaa,
SIMD_i32x4_shl = 0xab,
SIMD_i32x4_shr_s = 0xac,
SIMD_i32x4_shr_u = 0xad,
SIMD_i32x4_add = 0xae,
SIMD_i32x4_add_sat_s = 0xaf,
SIMD_i32x4_add_sat_u = 0xb0,
SIMD_i32x4_sub = 0xb1,
SIMD_i32x4_sub_sat_s = 0xb2,
SIMD_i32x4_sub_sat_u = 0xb3,
/* placeholder = 0xb4 */
SIMD_i32x4_mul = 0xb5,
SIMD_i32x4_min_s = 0xb6,
SIMD_i32x4_min_u = 0xb7,
SIMD_i32x4_max_s = 0xb8,
SIMD_i32x4_max_u = 0xb9,
SIMD_i32x4_dot_i16x8_s = 0xba,
SIMD_i32x4_avgr_u = 0xbb,
SIMD_i32x4_extmul_low_i16x8_s = 0xbc,
SIMD_i32x4_extmul_high_i16x8_s = 0xbd,
SIMD_i32x4_extmul_low_i16x8_u = 0xbe,
SIMD_i32x4_extmul_high_i16x8_u = 0xbf,
/* i64x2 operation */
SIMD_i64x2_neg = 0xc1,
SIMD_i64x2_shl = 0xcb,
SIMD_i64x2_shr_s = 0xcc,
SIMD_i64x2_shr_u = 0xcd,
SIMD_i64x2_add = 0xce,
SIMD_i64x2_sub = 0xd1,
SIMD_i64x2_mul = 0xd5,
/* float ceil/floor/trunc/nearest */
SIMD_f32x4_ceil = 0xd8,
SIMD_f32x4_floor = 0xd9,
SIMD_f32x4_trunc = 0xda,
SIMD_f32x4_nearest = 0xdb,
SIMD_f64x2_ceil = 0xdc,
SIMD_f64x2_floor = 0xdd,
SIMD_f64x2_trunc = 0xde,
SIMD_f64x2_nearest = 0xdf,
SIMD_i64x2_abs = 0xc0,
SIMD_i64x2_neg = 0xc1,
/* placeholder = 0xc2 */
SIMD_i64x2_all_true = 0xc3,
SIMD_i64x2_bitmask = 0xc4,
/* placeholder = 0xc5 */
/* placeholder = 0xc6 */
SIMD_i64x2_extend_low_i32x4_s = 0xc7,
SIMD_i64x2_extend_high_i32x4_s = 0xc8,
SIMD_i64x2_extend_low_i32x4_u = 0xc9,
SIMD_i64x2_extend_high_i32x4_u = 0xca,
SIMD_i64x2_shl = 0xcb,
SIMD_i64x2_shr_s = 0xcc,
SIMD_i64x2_shr_u = 0xcd,
SIMD_i64x2_add = 0xce,
/* placeholder = 0xcf */
/* placeholder = 0xd0 */
SIMD_i64x2_sub = 0xd1,
/* placeholder = 0xd2 */
/* placeholder = 0xd3 */
/* placeholder = 0xd4 */
SIMD_i64x2_mul = 0xd5,
SIMD_i64x2_eq = 0xd6,
SIMD_i64x2_ne = 0xd7,
SIMD_i64x2_lt_s = 0xd8,
SIMD_i64x2_gt_s = 0xd9,
SIMD_i64x2_le_s = 0xda,
SIMD_i64x2_ge_s = 0xdb,
SIMD_i64x2_extmul_low_i32x4_s = 0xdc,
SIMD_i64x2_extmul_high_i32x4_s = 0xdd,
SIMD_i64x2_extmul_low_i32x4_u = 0xde,
SIMD_i64x2_extmul_high_i32x4_u = 0xdf,
/* f32x4 operation */
SIMD_f32x4_abs = 0xe0,
SIMD_f32x4_neg = 0xe1,
SIMD_f32x4_round = 0xe2,
SIMD_f32x4_sqrt = 0xe3,
SIMD_f32x4_add = 0xe4,
SIMD_f32x4_sub = 0xe5,
@ -499,10 +562,13 @@ typedef enum WASMSimdEXTOpcode {
SIMD_f32x4_div = 0xe7,
SIMD_f32x4_min = 0xe8,
SIMD_f32x4_max = 0xe9,
SIMD_f32x4_pmin = 0xea,
SIMD_f32x4_pmax = 0xeb,
/* f64x2 operation */
SIMD_f64x2_abs = 0xec,
SIMD_f64x2_neg = 0xed,
SIMD_f64x2_round = 0xee,
SIMD_f64x2_sqrt = 0xef,
SIMD_f64x2_add = 0xf0,
SIMD_f64x2_sub = 0xf1,
@ -510,12 +576,18 @@ typedef enum WASMSimdEXTOpcode {
SIMD_f64x2_div = 0xf3,
SIMD_f64x2_min = 0xf4,
SIMD_f64x2_max = 0xf5,
SIMD_f64x2_pmin = 0xf6,
SIMD_f64x2_pmax = 0xf7,
/* conversion operation */
SIMD_i32x4_trunc_sat_f32x4_s = 0xf8,
SIMD_i32x4_trunc_sat_f32x4_u = 0xf9,
SIMD_f32x4_convert_i32x4_s = 0xfa,
SIMD_f32x4_convert_i32x4_u = 0xfb,
SIMD_i32x4_trunc_sat_f32x4_s = 0xf8,
SIMD_i32x4_trunc_sat_f32x4_u = 0xf9,
SIMD_f32x4_convert_i32x4_s = 0xfa,
SIMD_f32x4_convert_i32x4_u = 0xfb,
SIMD_i32x4_trunc_sat_f64x2_s_zero = 0xfc,
SIMD_i32x4_trunc_sat_f64x2_u_zero = 0xfd,
SIMD_f64x2_convert_low_i32x4_s = 0xfe,
SIMD_f64x2_convert_low_i32x4_u = 0xff,
} WASMSimdEXTOpcode;
typedef enum WASMAtomicEXTOpcode {