| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738 |
- /*
- * Copyright (C) 2019 Intel Corporation. All rights reserved.
- * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- */
- #include "simd_conversions.h"
- #include "simd_common.h"
- #include "../aot_emit_exception.h"
- #include "../aot_emit_numberic.h"
- #include "../../aot/aot_runtime.h"
- static bool
- simd_integer_narrow_x86(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
- LLVMTypeRef in_vector_type, LLVMTypeRef out_vector_type,
- const char *instrinsic)
- {
- LLVMValueRef vector1, vector2, result;
- LLVMTypeRef param_types[2] = { in_vector_type, in_vector_type };
- if (!(vector2 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
- in_vector_type, "vec2"))
- || !(vector1 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
- in_vector_type, "vec1"))) {
- return false;
- }
- if (!(result = aot_call_llvm_intrinsic(comp_ctx, func_ctx, instrinsic,
- out_vector_type, param_types, 2,
- vector1, vector2))) {
- HANDLE_FAILURE("LLVMBuildCall");
- return false;
- }
- return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
- }
- enum integer_sat_type {
- e_sat_i16x8 = 0,
- e_sat_i32x4,
- e_sat_i64x2,
- e_sat_i32x8,
- };
- static LLVMValueRef
- simd_saturate(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
- enum integer_sat_type itype, LLVMValueRef vector,
- LLVMValueRef min, LLVMValueRef max, bool is_signed)
- {
- LLVMValueRef result;
- LLVMTypeRef vector_type;
- LLVMTypeRef param_types[][2] = {
- { V128_i16x8_TYPE, V128_i16x8_TYPE },
- { V128_i32x4_TYPE, V128_i32x4_TYPE },
- { V128_i64x2_TYPE, V128_i64x2_TYPE },
- { 0 },
- };
- const char *smin_intrinsic[] = {
- "llvm.smin.v8i16",
- "llvm.smin.v4i32",
- "llvm.smin.v2i64",
- "llvm.smin.v8i32",
- };
- const char *umin_intrinsic[] = {
- "llvm.umin.v8i16",
- "llvm.umin.v4i32",
- "llvm.umin.v2i64",
- "llvm.umin.v8i32",
- };
- const char *smax_intrinsic[] = {
- "llvm.smax.v8i16",
- "llvm.smax.v4i32",
- "llvm.smax.v2i64",
- "llvm.smax.v8i32",
- };
- const char *umax_intrinsic[] = {
- "llvm.umax.v8i16",
- "llvm.umax.v4i32",
- "llvm.umax.v2i64",
- "llvm.umax.v8i32",
- };
- if (e_sat_i32x8 == itype) {
- if (!(vector_type = LLVMVectorType(I32_TYPE, 8))) {
- HANDLE_FAILURE("LLVMVectorType");
- return NULL;
- }
- param_types[itype][0] = vector_type;
- param_types[itype][1] = vector_type;
- }
- if (!(result = aot_call_llvm_intrinsic(
- comp_ctx, func_ctx,
- is_signed ? smin_intrinsic[itype] : umin_intrinsic[itype],
- param_types[itype][0], param_types[itype], 2, vector, max))
- || !(result = aot_call_llvm_intrinsic(
- comp_ctx, func_ctx,
- is_signed ? smax_intrinsic[itype] : umax_intrinsic[itype],
- param_types[itype][0], param_types[itype], 2, result, min))) {
- return NULL;
- }
- return result;
- }
- static bool
- simd_integer_narrow_common(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
- enum integer_sat_type itype, bool is_signed)
- {
- LLVMValueRef vec1, vec2, min, max, mask, result;
- LLVMTypeRef in_vector_type[] = { V128_i16x8_TYPE, V128_i32x4_TYPE,
- V128_i64x2_TYPE };
- LLVMTypeRef min_max_type[] = { INT16_TYPE, I32_TYPE, I64_TYPE };
- LLVMTypeRef trunc_type[3] = { 0 };
- uint8 length[] = { 8, 4, 2 };
- int64 smin[] = { 0xff80, 0xffFF8000, 0xffFFffFF80000000 };
- int64 umin[] = { 0x0, 0x0, 0x0 };
- int64 smax[] = { 0x007f, 0x00007fff, 0x000000007fFFffFF };
- int64 umax[] = { 0x00ff, 0x0000ffff, 0x00000000ffFFffFF };
- LLVMValueRef mask_element[] = {
- 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),
- };
- if (!(trunc_type[0] = LLVMVectorType(INT8_TYPE, 8))
- || !(trunc_type[1] = LLVMVectorType(INT16_TYPE, 4))
- || !(trunc_type[2] = LLVMVectorType(I32_TYPE, 2))) {
- HANDLE_FAILURE("LLVMVectorType");
- return false;
- }
- if (!(vec2 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
- in_vector_type[itype], "vec2"))
- || !(vec1 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
- in_vector_type[itype], "vec1"))) {
- return false;
- }
- if (!(max = simd_build_splat_const_integer_vector(
- comp_ctx, min_max_type[itype],
- is_signed ? smax[itype] : umax[itype], length[itype]))
- || !(min = simd_build_splat_const_integer_vector(
- comp_ctx, min_max_type[itype],
- is_signed ? smin[itype] : umin[itype], length[itype]))) {
- return false;
- }
- /* Refer to:
- * https://github.com/WebAssembly/spec/blob/main/proposals/simd/SIMD.md#integer-to-integer-narrowing
- * Regardless of the whether the operation is signed or unsigned, the input
- * lanes are interpreted as signed integers.
- */
- if (!(vec1 = simd_saturate(comp_ctx, func_ctx, e_sat_i16x8, vec1, min, max,
- true))
- || !(vec2 = simd_saturate(comp_ctx, func_ctx, e_sat_i16x8, vec2, min,
- max, true))) {
- return false;
- }
- /* trunc */
- if (!(vec1 = LLVMBuildTrunc(comp_ctx->builder, vec1, trunc_type[itype],
- "vec1_trunc"))
- || !(vec2 = LLVMBuildTrunc(comp_ctx->builder, vec2, trunc_type[itype],
- "vec2_trunc"))) {
- HANDLE_FAILURE("LLVMBuildTrunc");
- return false;
- }
- /* combine */
- if (!(mask = LLVMConstVector(mask_element, (length[itype] << 1)))) {
- HANDLE_FAILURE("LLVMConstInt");
- return false;
- }
- if (!(result = LLVMBuildShuffleVector(comp_ctx->builder, vec1, vec2, mask,
- "vec_shuffle"))) {
- HANDLE_FAILURE("LLVMBuildShuffleVector");
- return false;
- }
- return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
- }
- bool
- aot_compile_simd_i8x16_narrow_i16x8(AOTCompContext *comp_ctx,
- AOTFuncContext *func_ctx, bool is_signed)
- {
- if (is_target_x86(comp_ctx)) {
- return simd_integer_narrow_x86(
- comp_ctx, func_ctx, V128_i16x8_TYPE, V128_i8x16_TYPE,
- is_signed ? "llvm.x86.sse2.packsswb.128"
- : "llvm.x86.sse2.packuswb.128");
- }
- else {
- return simd_integer_narrow_common(comp_ctx, func_ctx, e_sat_i16x8,
- is_signed);
- }
- }
- bool
- aot_compile_simd_i16x8_narrow_i32x4(AOTCompContext *comp_ctx,
- AOTFuncContext *func_ctx, bool is_signed)
- {
- if (is_target_x86(comp_ctx)) {
- return simd_integer_narrow_x86(comp_ctx, func_ctx, V128_i32x4_TYPE,
- V128_i16x8_TYPE,
- is_signed ? "llvm.x86.sse2.packssdw.128"
- : "llvm.x86.sse41.packusdw");
- }
- else {
- return simd_integer_narrow_common(comp_ctx, func_ctx, e_sat_i32x4,
- is_signed);
- }
- }
- enum integer_extend_type {
- e_ext_i8x16,
- e_ext_i16x8,
- e_ext_i32x4,
- };
- static LLVMValueRef
- simd_integer_extension(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
- enum integer_extend_type itype, LLVMValueRef vector,
- bool lower_half, bool is_signed)
- {
- LLVMValueRef mask, sub_vector, result;
- LLVMValueRef bits[] = {
- 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),
- };
- LLVMTypeRef out_vector_type[] = { V128_i16x8_TYPE, V128_i32x4_TYPE,
- V128_i64x2_TYPE };
- LLVMValueRef undef[] = { LLVM_CONST(i8x16_undef), LLVM_CONST(i16x8_undef),
- LLVM_CONST(i32x4_undef) };
- uint32 sub_vector_length[] = { 8, 4, 2 };
- if (!(mask = lower_half ? LLVMConstVector(bits, sub_vector_length[itype])
- : LLVMConstVector(bits + sub_vector_length[itype],
- sub_vector_length[itype]))) {
- HANDLE_FAILURE("LLVMConstVector");
- return false;
- }
- /* retrieve the low or high half */
- if (!(sub_vector = LLVMBuildShuffleVector(comp_ctx->builder, vector,
- undef[itype], mask, "half"))) {
- HANDLE_FAILURE("LLVMBuildShuffleVector");
- return false;
- }
- if (is_signed) {
- if (!(result = LLVMBuildSExt(comp_ctx->builder, sub_vector,
- out_vector_type[itype], "sext"))) {
- HANDLE_FAILURE("LLVMBuildSExt");
- return false;
- }
- }
- else {
- if (!(result = LLVMBuildZExt(comp_ctx->builder, sub_vector,
- out_vector_type[itype], "zext"))) {
- HANDLE_FAILURE("LLVMBuildZExt");
- return false;
- }
- }
- return result;
- }
- static bool
- simd_integer_extension_wrapper(AOTCompContext *comp_ctx,
- AOTFuncContext *func_ctx,
- enum integer_extend_type itype, bool lower_half,
- bool is_signed)
- {
- LLVMValueRef vector, result;
- LLVMTypeRef in_vector_type[] = { V128_i8x16_TYPE, V128_i16x8_TYPE,
- V128_i32x4_TYPE };
- if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
- in_vector_type[itype], "vec"))) {
- return false;
- }
- if (!(result = simd_integer_extension(comp_ctx, func_ctx, itype, vector,
- lower_half, is_signed))) {
- return false;
- }
- return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
- }
- bool
- aot_compile_simd_i16x8_extend_i8x16(AOTCompContext *comp_ctx,
- AOTFuncContext *func_ctx, bool lower_half,
- bool is_signed)
- {
- return simd_integer_extension_wrapper(comp_ctx, func_ctx, e_ext_i8x16,
- lower_half, is_signed);
- }
- bool
- aot_compile_simd_i32x4_extend_i16x8(AOTCompContext *comp_ctx,
- AOTFuncContext *func_ctx, bool lower_half,
- bool is_signed)
- {
- return simd_integer_extension_wrapper(comp_ctx, func_ctx, e_ext_i16x8,
- lower_half, is_signed);
- }
- bool
- aot_compile_simd_i64x2_extend_i32x4(AOTCompContext *comp_ctx,
- AOTFuncContext *func_ctx, bool lower_half,
- bool is_signed)
- {
- return simd_integer_extension_wrapper(comp_ctx, func_ctx, e_ext_i32x4,
- lower_half, is_signed);
- }
- static LLVMValueRef
- simd_trunc_sat(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
- const char *intrinsics, LLVMTypeRef in_vector_type,
- LLVMTypeRef out_vector_type)
- {
- LLVMValueRef vector, result;
- LLVMTypeRef param_types[] = { in_vector_type };
- if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, in_vector_type,
- "vector"))) {
- return false;
- }
- if (!(result = aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsics,
- out_vector_type, param_types, 1,
- vector))) {
- return false;
- }
- return result;
- }
- bool
- aot_compile_simd_i32x4_trunc_sat_f32x4(AOTCompContext *comp_ctx,
- AOTFuncContext *func_ctx, bool is_signed)
- {
- LLVMValueRef result;
- if (!(result = simd_trunc_sat(comp_ctx, func_ctx,
- is_signed ? "llvm.fptosi.sat.v4i32.v4f32"
- : "llvm.fptoui.sat.v4i32.v4f32",
- V128_f32x4_TYPE, V128_i32x4_TYPE))) {
- return false;
- }
- return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
- }
- bool
- aot_compile_simd_i32x4_trunc_sat_f64x2(AOTCompContext *comp_ctx,
- AOTFuncContext *func_ctx, bool is_signed)
- {
- LLVMValueRef result, zero, mask;
- LLVMTypeRef out_vector_type;
- LLVMValueRef lanes[] = {
- LLVM_CONST(i32_zero),
- LLVM_CONST(i32_one),
- LLVM_CONST(i32_two),
- LLVM_CONST(i32_three),
- };
- if (!(out_vector_type = LLVMVectorType(I32_TYPE, 2))) {
- HANDLE_FAILURE("LLVMVectorType");
- return false;
- }
- if (!(result = simd_trunc_sat(comp_ctx, func_ctx,
- is_signed ? "llvm.fptosi.sat.v2i32.v2f64"
- : "llvm.fptoui.sat.v2i32.v2f64",
- V128_f64x2_TYPE, out_vector_type))) {
- return false;
- }
- if (!(zero = LLVMConstNull(out_vector_type))) {
- HANDLE_FAILURE("LLVMConstNull");
- return false;
- }
- /* v2i32 -> v4i32 */
- if (!(mask = LLVMConstVector(lanes, 4))) {
- HANDLE_FAILURE("LLVMConstVector");
- return false;
- }
- if (!(result = LLVMBuildShuffleVector(comp_ctx->builder, result, zero, mask,
- "extend"))) {
- HANDLE_FAILURE("LLVMBuildShuffleVector");
- return false;
- }
- return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
- }
- static LLVMValueRef
- simd_integer_convert(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
- bool is_signed, LLVMValueRef vector,
- LLVMTypeRef out_vector_type)
- {
- LLVMValueRef result;
- result = is_signed ? LLVMBuildSIToFP(comp_ctx->builder, vector,
- out_vector_type, "converted")
- : LLVMBuildUIToFP(comp_ctx->builder, vector,
- out_vector_type, "converted");
- if (!result) {
- HANDLE_FAILURE("LLVMBuildSIToFP/LLVMBuildUIToFP");
- }
- return result;
- }
- bool
- aot_compile_simd_f32x4_convert_i32x4(AOTCompContext *comp_ctx,
- AOTFuncContext *func_ctx, bool is_signed)
- {
- LLVMValueRef vector, result;
- if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
- V128_i32x4_TYPE, "vec"))) {
- return false;
- }
- if (!(result = simd_integer_convert(comp_ctx, func_ctx, is_signed, vector,
- V128_f32x4_TYPE))) {
- return false;
- }
- return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
- }
- bool
- aot_compile_simd_f64x2_convert_i32x4(AOTCompContext *comp_ctx,
- AOTFuncContext *func_ctx, bool is_signed)
- {
- LLVMValueRef vector, mask, result;
- LLVMValueRef lanes[] = {
- LLVM_CONST(i32_zero),
- LLVM_CONST(i32_one),
- };
- LLVMTypeRef out_vector_type;
- if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
- V128_i32x4_TYPE, "vec"))) {
- return false;
- }
- if (!(out_vector_type = LLVMVectorType(F64_TYPE, 4))) {
- HANDLE_FAILURE("LLVMVectorType");
- return false;
- }
- if (!(result = simd_integer_convert(comp_ctx, func_ctx, is_signed, vector,
- out_vector_type))) {
- return false;
- }
- /* v4f64 -> v2f64 */
- if (!(mask = LLVMConstVector(lanes, 2))) {
- HANDLE_FAILURE("LLVMConstVector");
- return false;
- }
- if (!(result = LLVMBuildShuffleVector(comp_ctx->builder, result, result,
- mask, "trunc"))) {
- HANDLE_FAILURE("LLVMBuildShuffleVector");
- return false;
- }
- return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
- }
- static bool
- simd_extadd_pairwise(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
- LLVMTypeRef in_vector_type, LLVMTypeRef out_vector_type,
- bool is_signed)
- {
- LLVMValueRef vector, even_mask, odd_mask, sub_vector_even, sub_vector_odd,
- result;
- LLVMValueRef even_element[] = {
- LLVM_CONST(i32_zero), LLVM_CONST(i32_two), LLVM_CONST(i32_four),
- LLVM_CONST(i32_six), LLVM_CONST(i32_eight), LLVM_CONST(i32_ten),
- LLVM_CONST(i32_twelve), LLVM_CONST(i32_fourteen),
- };
- LLVMValueRef odd_element[] = {
- LLVM_CONST(i32_one), LLVM_CONST(i32_three),
- LLVM_CONST(i32_five), LLVM_CONST(i32_seven),
- LLVM_CONST(i32_nine), LLVM_CONST(i32_eleven),
- LLVM_CONST(i32_thirteen), LLVM_CONST(i32_fifteen),
- };
- /* assumption about i16x8 from i8x16 and i32x4 from i16x8 */
- uint8 mask_length = V128_i16x8_TYPE == out_vector_type ? 8 : 4;
- if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, in_vector_type,
- "vector"))) {
- return false;
- }
- if (!(even_mask = LLVMConstVector(even_element, mask_length))
- || !(odd_mask = LLVMConstVector(odd_element, mask_length))) {
- HANDLE_FAILURE("LLVMConstVector");
- return false;
- }
- /* shuffle a <16xi8> vector to two <8xi8> vectors */
- if (!(sub_vector_even = LLVMBuildShuffleVector(
- comp_ctx->builder, vector, vector, even_mask, "pick_even"))
- || !(sub_vector_odd = LLVMBuildShuffleVector(
- comp_ctx->builder, vector, vector, odd_mask, "pick_odd"))) {
- HANDLE_FAILURE("LLVMBuildShuffleVector");
- return false;
- }
- /* sext/zext <8xi8> to <8xi16> */
- if (is_signed) {
- if (!(sub_vector_even =
- LLVMBuildSExt(comp_ctx->builder, sub_vector_even,
- out_vector_type, "even_sext"))
- || !(sub_vector_odd =
- LLVMBuildSExt(comp_ctx->builder, sub_vector_odd,
- out_vector_type, "odd_sext"))) {
- HANDLE_FAILURE("LLVMBuildSExt");
- return false;
- }
- }
- else {
- if (!(sub_vector_even =
- LLVMBuildZExt(comp_ctx->builder, sub_vector_even,
- out_vector_type, "even_zext"))
- || !(sub_vector_odd =
- LLVMBuildZExt(comp_ctx->builder, sub_vector_odd,
- out_vector_type, "odd_zext"))) {
- HANDLE_FAILURE("LLVMBuildZExt");
- return false;
- }
- }
- if (!(result = LLVMBuildAdd(comp_ctx->builder, sub_vector_even,
- sub_vector_odd, "sum"))) {
- HANDLE_FAILURE("LLVMBuildAdd");
- return false;
- }
- return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
- }
- bool
- aot_compile_simd_i16x8_extadd_pairwise_i8x16(AOTCompContext *comp_ctx,
- AOTFuncContext *func_ctx,
- bool is_signed)
- {
- return simd_extadd_pairwise(comp_ctx, func_ctx, V128_i8x16_TYPE,
- V128_i16x8_TYPE, is_signed);
- }
- bool
- aot_compile_simd_i32x4_extadd_pairwise_i16x8(AOTCompContext *comp_ctx,
- AOTFuncContext *func_ctx,
- bool is_signed)
- {
- return simd_extadd_pairwise(comp_ctx, func_ctx, V128_i16x8_TYPE,
- V128_i32x4_TYPE, is_signed);
- }
- bool
- aot_compile_simd_i16x8_q15mulr_sat(AOTCompContext *comp_ctx,
- AOTFuncContext *func_ctx)
- {
- LLVMValueRef lhs, rhs, pad, offset, min, max, result;
- LLVMTypeRef vector_ext_type;
- if (!(rhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i16x8_TYPE,
- "rhs"))
- || !(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
- V128_i16x8_TYPE, "lhs"))) {
- return false;
- }
- if (!(vector_ext_type = LLVMVectorType(I32_TYPE, 8))) {
- HANDLE_FAILURE("LLVMVectorType");
- return false;
- }
- if (!(lhs = LLVMBuildSExt(comp_ctx->builder, lhs, vector_ext_type,
- "lhs_v8i32"))
- || !(rhs = LLVMBuildSExt(comp_ctx->builder, rhs, vector_ext_type,
- "rhs_v8i32"))) {
- HANDLE_FAILURE("LLVMBuildSExt");
- return false;
- }
- /* 0x4000 and 15*/
- if (!(pad = simd_build_splat_const_integer_vector(comp_ctx, I32_TYPE,
- 0x4000, 8))
- || !(offset = simd_build_splat_const_integer_vector(comp_ctx, I32_TYPE,
- 15, 8))) {
- return false;
- }
- /* TODO: looking for x86 intrinsics about integer"fused multiply-and-add" */
- /* S.SignedSaturate((x * y + 0x4000) >> 15) */
- if (!(result = LLVMBuildMul(comp_ctx->builder, lhs, rhs, "mul"))) {
- HANDLE_FAILURE("LLVMBuildMul");
- return false;
- }
- if (!(result = LLVMBuildAdd(comp_ctx->builder, result, pad, "add"))) {
- HANDLE_FAILURE("LLVMBuildAdd");
- return false;
- }
- if (!(result = LLVMBuildAShr(comp_ctx->builder, result, offset, "ashr"))) {
- HANDLE_FAILURE("LLVMBuildAShr");
- return false;
- }
- if (!(min = simd_build_splat_const_integer_vector(comp_ctx, I32_TYPE,
- 0xffff8000, 8))
- || !(max = simd_build_splat_const_integer_vector(comp_ctx, I32_TYPE,
- 0x00007fff, 8))) {
- return false;
- }
- /* sat after trunc will let *sat* part be optimized */
- if (!(result = simd_saturate(comp_ctx, func_ctx, e_sat_i32x8, result, min,
- max, true))) {
- return false;
- }
- if (!(result = LLVMBuildTrunc(comp_ctx->builder, result, V128_i16x8_TYPE,
- "down_to_v8i16"))) {
- HANDLE_FAILURE("LLVMBuidlTrunc");
- return false;
- }
- return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
- }
- enum integer_extmul_type {
- e_i16x8_extmul_i8x16,
- e_i32x4_extmul_i16x8,
- e_i64x2_extmul_i32x4,
- };
- static bool
- simd_integer_extmul(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
- bool lower_half, bool is_signed,
- enum integer_extmul_type itype)
- {
- LLVMValueRef vec1, vec2, result;
- enum integer_extend_type ext_type[] = {
- e_ext_i8x16,
- e_ext_i16x8,
- e_ext_i32x4,
- };
- LLVMTypeRef in_vector_type[] = {
- V128_i8x16_TYPE,
- V128_i16x8_TYPE,
- V128_i32x4_TYPE,
- };
- if (!(vec1 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
- in_vector_type[itype], "vec1"))
- || !(vec2 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
- in_vector_type[itype], "vec2"))) {
- return false;
- }
- if (!(vec1 = simd_integer_extension(comp_ctx, func_ctx, ext_type[itype],
- vec1, lower_half, is_signed))
- || !(vec2 = simd_integer_extension(comp_ctx, func_ctx, ext_type[itype],
- vec2, lower_half, is_signed))) {
- return false;
- }
- if (!(result = LLVMBuildMul(comp_ctx->builder, vec1, vec2, "product"))) {
- return false;
- }
- return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
- }
- bool
- aot_compile_simd_i16x8_extmul_i8x16(AOTCompContext *comp_ctx,
- AOTFuncContext *func_ctx, bool lower_half,
- bool is_signed)
- {
- return simd_integer_extmul(comp_ctx, func_ctx, lower_half, is_signed,
- e_i16x8_extmul_i8x16);
- }
- bool
- aot_compile_simd_i32x4_extmul_i16x8(AOTCompContext *comp_ctx,
- AOTFuncContext *func_ctx, bool lower_half,
- bool is_signed)
- {
- return simd_integer_extmul(comp_ctx, func_ctx, lower_half, is_signed,
- e_i32x4_extmul_i16x8);
- }
- bool
- aot_compile_simd_i64x2_extmul_i32x4(AOTCompContext *comp_ctx,
- AOTFuncContext *func_ctx, bool lower_half,
- bool is_signed)
- {
- return simd_integer_extmul(comp_ctx, func_ctx, lower_half, is_signed,
- e_i64x2_extmul_i32x4);
- }
|