Import SIMD feature and add some workload samples (#438)

This commit is contained in:
Wenyong Huang
2020-11-05 18:15:15 +08:00
committed by GitHub
parent 667282eea9
commit a3074df21b
84 changed files with 7780 additions and 318 deletions

View File

@ -21,6 +21,10 @@ wasm_type_to_llvm_type(AOTLLVMTypes *llvm_types, uint8 wasm_type)
return llvm_types->float32_type;
case VALUE_TYPE_F64:
return llvm_types->float64_type;
#if WASM_ENABLE_SIMD != 0
case VALUE_TYPE_V128:
return llvm_types->i64x2_vec_type;
#endif
case VALUE_TYPE_VOID:
return llvm_types->void_type;
}
@ -444,6 +448,31 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
}
}
offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_16bytes)
- offsetof(AOTMemoryInstance, memory_data.ptr));
if (!(func_ctx->mem_info[0].mem_bound_check_16bytes =
LLVMBuildInBoundsGEP(comp_ctx->builder, mem_info_base,
&offset, 1, "bound_check_16bytes_offset"))) {
aot_set_last_error("llvm build in bounds gep failed");
return false;
}
if (!(func_ctx->mem_info[0].mem_bound_check_16bytes =
LLVMBuildBitCast(comp_ctx->builder,
func_ctx->mem_info[0].mem_bound_check_16bytes,
bound_check_type, "bound_check_16bytes_ptr"))) {
aot_set_last_error("llvm build bit cast failed");
return false;
}
if (mem_space_unchanged) {
if (!(func_ctx->mem_info[0].mem_bound_check_16bytes =
LLVMBuildLoad(comp_ctx->builder,
func_ctx->mem_info[0].mem_bound_check_16bytes,
"bound_check_16bytes"))) {
aot_set_last_error("llvm build load failed");
return false;
}
}
return true;
}
@ -676,6 +705,11 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx,
case VALUE_TYPE_F64:
local_value = F64_ZERO;
break;
#if WASM_ENABLE_SIMD != 0
case VALUE_TYPE_V128:
local_value = V128_ZERO;
break;
#endif
default:
bh_assert(0);
break;
@ -814,23 +848,55 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context)
basic_types->float32_ptr_type = LLVMPointerType(basic_types->float32_type, 0);
basic_types->float64_ptr_type = LLVMPointerType(basic_types->float64_type, 0);
basic_types->i8x16_vec_type = LLVMVectorType(basic_types->int8_type, 16);
basic_types->i16x8_vec_type = LLVMVectorType(basic_types->int16_type, 8);
basic_types->i32x4_vec_type = LLVMVectorType(basic_types->int32_type, 4);
basic_types->i64x2_vec_type = LLVMVectorType(basic_types->int64_type, 2);
basic_types->f32x4_vec_type = LLVMVectorType(basic_types->float32_type, 4);
basic_types->f64x2_vec_type = LLVMVectorType(basic_types->float64_type, 2);
basic_types->v128_type = basic_types->i64x2_vec_type;
basic_types->v128_ptr_type = LLVMPointerType(basic_types->v128_type, 0);
return (basic_types->int8_ptr_type
&& basic_types->int16_ptr_type
&& basic_types->int32_ptr_type
&& basic_types->int64_ptr_type
&& basic_types->float32_ptr_type
&& basic_types->float64_ptr_type
&& basic_types->i8x16_vec_type
&& basic_types->i16x8_vec_type
&& basic_types->i32x4_vec_type
&& basic_types->i64x2_vec_type
&& basic_types->f32x4_vec_type
&& basic_types->f64x2_vec_type
&& basic_types->meta_data_type) ? true : false;
}
static bool
aot_create_llvm_consts(AOTLLVMConsts *consts, AOTCompContext *comp_ctx)
{
LLVMValueRef i64_consts[2];
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);
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);
}
}
consts->i32_one = I32_CONST(1);
consts->i32_two = I32_CONST(2);
consts->i32_three = I32_CONST(3);
@ -850,6 +916,12 @@ aot_create_llvm_consts(AOTLLVMConsts *consts, AOTCompContext *comp_ctx)
&& 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
@ -1014,7 +1086,7 @@ aot_create_comp_context(AOTCompData *comp_data,
/*LLVMTypeRef elem_types[8];*/
struct LLVMMCJITCompilerOptions jit_options;
LLVMTargetRef target;
char *triple = NULL, *triple_jit = NULL, *triple_norm, *arch, *abi;
char *triple = NULL, *triple_norm, *arch, *abi;
char *cpu = NULL, *features, buf[128];
char *triple_norm_new = NULL, *cpu_new = NULL;
char *err = NULL, *fp_round= "round.tonearest", *fp_exce = "fpexcept.strict";
@ -1065,7 +1137,12 @@ aot_create_comp_context(AOTCompData *comp_data,
if (option->enable_tail_call)
comp_ctx->enable_tail_call = true;
if (option->enable_simd)
comp_ctx->enable_simd = true;
if (option->is_jit_mode) {
char *triple_jit = NULL;
/* Create LLVM execution engine */
LLVMInitializeMCJITCompilerOptions(&jit_options, sizeof(jit_options));
jit_options.OptLevel = LLVMCodeGenLevelAggressive;
@ -1186,7 +1263,8 @@ aot_create_comp_context(AOTCompData *comp_data,
if (!cpu)
cpu = "";
}
else { /* triple is NULL, cpu isn't NULL */
else {
/* triple is NULL, cpu isn't NULL */
snprintf(buf, sizeof(buf),
"target isn't specified for cpu %s.", cpu);
aot_set_last_error(buf);
@ -1283,6 +1361,23 @@ aot_create_comp_context(AOTCompData *comp_data,
}
}
if (option->enable_simd) {
char *tmp;
bool ret;
if (!(tmp = LLVMGetTargetMachineCPU(comp_ctx->target_machine))) {
aot_set_last_error("get CPU from Target Machine fail");
goto fail;
}
ret = aot_check_simd_compatibility(comp_ctx->target_arch, tmp);
LLVMDisposeMessage(tmp);
if (!ret) {
aot_set_last_error("SIMD compatibility check failed");
goto fail;
}
}
if (!(target_data_ref =
LLVMCreateTargetDataLayout(comp_ctx->target_machine))) {
aot_set_last_error("create LLVM target data layout failed.");
@ -1349,11 +1444,13 @@ aot_create_comp_context(AOTCompData *comp_data,
fail:
if (triple_norm_new)
LLVMDisposeMessage(triple_norm_new);
if (cpu_new)
LLVMDisposeMessage(cpu_new);
if (!ret)
aot_destroy_comp_context(comp_ctx);
return ret;
}
@ -1567,3 +1664,144 @@ aot_checked_addr_list_destroy(AOTFuncContext *func_ctx)
func_ctx->checked_addr_list = NULL;
}
bool
aot_build_zero_function_ret(AOTCompContext *comp_ctx,
AOTFuncType *func_type)
{
LLVMValueRef ret = NULL;
if (func_type->result_count) {
switch (func_type->types[func_type->param_count]) {
case VALUE_TYPE_I32:
ret = LLVMBuildRet(comp_ctx->builder, I32_ZERO);
break;
case VALUE_TYPE_I64:
ret = LLVMBuildRet(comp_ctx->builder, I64_ZERO);
break;
case VALUE_TYPE_F32:
ret = LLVMBuildRet(comp_ctx->builder, F32_ZERO);
break;
case VALUE_TYPE_F64:
ret = LLVMBuildRet(comp_ctx->builder, F64_ZERO);
break;
#if WASM_ENABLE_SIMD != 0
case VALUE_TYPE_V128:
ret = LLVMBuildRet(comp_ctx->builder, V128_ZERO);
break;
#endif
default:
bh_assert(0);
}
}
else {
ret = LLVMBuildRetVoid(comp_ctx->builder);
}
if (!ret) {
aot_set_last_error("llvm build ret failed.");
return false;
}
return true;
}
static LLVMValueRef
__call_llvm_intrinsic(const AOTCompContext *comp_ctx,
const char *name,
LLVMTypeRef ret_type,
LLVMTypeRef *param_types,
int param_count,
LLVMValueRef *param_values)
{
LLVMValueRef func, ret;
LLVMTypeRef func_type;
/* Declare llvm intrinsic function if necessary */
if (!(func = LLVMGetNamedFunction(comp_ctx->module, name))) {
if (!(func_type = LLVMFunctionType(ret_type, param_types,
(uint32)param_count, false))) {
aot_set_last_error("create LLVM function type failed.");
return NULL;
}
if (!(func = LLVMAddFunction(comp_ctx->module, name, func_type))) {
aot_set_last_error("add LLVM function failed.");
return NULL;
}
}
/* Call the LLVM intrinsic function */
if (!(ret = LLVMBuildCall(comp_ctx->builder, func, param_values,
(uint32)param_count, "call"))) {
aot_set_last_error("llvm build call failed.");
return NULL;
}
return ret;
}
LLVMValueRef
aot_call_llvm_intrinsic(const AOTCompContext *comp_ctx,
const char *name,
LLVMTypeRef ret_type,
LLVMTypeRef *param_types,
int param_count,
...)
{
LLVMValueRef *param_values, ret;
va_list argptr;
uint64 total_size;
int i = 0;
/* Create param values */
total_size = sizeof(LLVMValueRef) * (uint64)param_count;
if (total_size >= UINT32_MAX
|| !(param_values = wasm_runtime_malloc((uint32)total_size))) {
aot_set_last_error("allocate memory for param values failed.");
return false;
}
/* Load each param value */
va_start(argptr, param_count);
while (i < param_count)
param_values[i++] = va_arg(argptr, LLVMValueRef);
va_end(argptr);
ret = __call_llvm_intrinsic(comp_ctx, name, ret_type, param_types,
param_count, param_values);
wasm_runtime_free(param_values);
return ret;
}
LLVMValueRef
aot_call_llvm_intrinsic_v(const AOTCompContext *comp_ctx,
const char *name,
LLVMTypeRef ret_type,
LLVMTypeRef *param_types,
int param_count,
va_list param_value_list)
{
LLVMValueRef *param_values, ret;
uint64 total_size;
int i = 0;
/* Create param values */
total_size = sizeof(LLVMValueRef) * (uint64)param_count;
if (total_size >= UINT32_MAX
|| !(param_values = wasm_runtime_malloc((uint32)total_size))) {
aot_set_last_error("allocate memory for param values failed.");
return false;
}
/* Load each param value */
while (i < param_count)
param_values[i++] = va_arg(param_value_list, LLVMValueRef);
ret = __call_llvm_intrinsic(comp_ctx, name, ret_type, param_types,
param_count, param_values);
wasm_runtime_free(param_values);
return ret;
}