Emit JIT IR for wasm opcode SHL/SHRU/SHRS (#1097)

This commit is contained in:
liang.he 2022-04-19 16:24:37 +08:00 committed by GitHub
parent 166f12fef1
commit 94d6da28b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 284 additions and 3 deletions

View File

@ -2823,6 +2823,32 @@ static bool
shift_imm_imm_to_r_i32(x86::Assembler &a, SHIFT_OP op, int32 reg_no_dst,
int32 data1_src, int32 data2_src)
{
int32 data;
switch (op) {
case SHL:
{
data = data1_src << data2_src;
break;
}
case SHRS:
{
data = data1_src >> data2_src;
break;
}
case SHRU:
{
data = ((uint32)data1_src) >> data2_src;
break;
}
default:
{
bh_assert(0);
goto fail;
}
}
return mov_imm_to_r_i32(a, reg_no_dst, data);
fail:
return false;
}
@ -2861,6 +2887,34 @@ static bool
shift_r_imm_to_r_i32(x86::Assembler &a, SHIFT_OP op, int32 reg_no_dst,
int32 reg_no1_src, int32 data2_src)
{
/* SHL/SHA/SHR r/m32, imm8 */
Imm imm((uint8)data2_src);
switch (op) {
case SHL:
{
a.shl(regs_i32[reg_no1_src], imm);
break;
}
case SHRS:
{
a.sar(regs_i32[reg_no1_src], imm);
break;
}
case SHRU:
{
a.shr(regs_i32[reg_no1_src], imm);
break;
}
default:
{
bh_assert(0);
goto fail;
}
}
return mov_r_to_r_i32(a, reg_no_dst, reg_no1_src);
fail:
return false;
}
@ -2879,6 +2933,34 @@ static bool
shift_r_r_to_r_i32(x86::Assembler &a, SHIFT_OP op, int32 reg_no_dst,
int32 reg_no1_src, int32 reg_no2_src)
{
/* should be CL */
bh_assert(reg_no2_src == REG_ECX_IDX);
switch (op) {
case SHL:
{
a.shl(regs_i32[reg_no1_src], x86::cl);
break;
}
case SHRS:
{
a.sar(regs_i32[reg_no1_src], x86::cl);
break;
}
case SHRU:
{
a.shr(regs_i32[reg_no1_src], x86::cl);
break;
}
default:
{
bh_assert(0);
goto fail;
}
}
return mov_r_to_r_i32(a, reg_no_dst, reg_no1_src);
fail:
return false;
}
@ -2897,6 +2979,33 @@ static bool
shift_imm_imm_to_r_i64(x86::Assembler &a, SHIFT_OP op, int32 reg_no_dst,
int64 data1_src, int64 data2_src)
{
int64 data;
switch (op) {
case SHL:
{
data = data1_src << data2_src;
break;
}
case SHRS:
{
data = data1_src >> data2_src;
break;
}
case SHRU:
{
data = ((uint64)data1_src) >> data2_src;
break;
}
default:
{
bh_assert(0);
goto fail;
}
}
return mov_imm_to_r_i64(a, reg_no_dst, data);
fail:
return false;
}
@ -2935,6 +3044,34 @@ static bool
shift_r_imm_to_r_i64(x86::Assembler &a, SHIFT_OP op, int32 reg_no_dst,
int32 reg_no1_src, int64 data2_src)
{
/* SHL/SHA/SHR r/m64, imm8 */
Imm imm((uint8)data2_src);
switch (op) {
case SHL:
{
a.shl(regs_i64[reg_no1_src], imm);
break;
}
case SHRS:
{
a.sar(regs_i64[reg_no1_src], imm);
break;
}
case SHRU:
{
a.shr(regs_i64[reg_no1_src], imm);
break;
}
default:
{
bh_assert(0);
goto fail;
}
}
return mov_r_to_r_i64(a, reg_no_dst, reg_no1_src);
fail:
return false;
}
@ -2953,6 +3090,34 @@ static bool
shift_r_r_to_r_i64(x86::Assembler &a, SHIFT_OP op, int32 reg_no_dst,
int32 reg_no1_src, int32 reg_no2_src)
{
/* should be CL */
bh_assert(reg_no2_src == REG_ECX_IDX);
switch (op) {
case SHL:
{
a.shl(regs_i64[reg_no1_src], x86::cl);
break;
}
case SHRS:
{
a.sar(regs_i64[reg_no1_src], x86::cl);
break;
}
case SHRU:
{
a.shr(regs_i64[reg_no1_src], x86::cl);
break;
}
default:
{
bh_assert(0);
goto fail;
}
}
return mov_r_to_r_i64(a, reg_no_dst, reg_no1_src);
fail:
return false;
}
@ -3774,7 +3939,7 @@ fail:
bool _ret = false; \
\
CHECK_EQKIND(r0, r1); \
CHECK_KIND(r2, JIT_REG_KIND_I32); \
CHECK_KIND(r2, JIT_REG_KIND_##kind); \
memset(&data1, 0, sizeof(Type)); \
memset(&data2, 0, sizeof(Type)); \
\
@ -5127,10 +5292,14 @@ jit_codegen_get_hreg_by_name(const char *name)
{
if (strcmp(name, "eax") == 0)
return jit_reg_new(JIT_REG_KIND_I32, REG_EAX_IDX);
else if (strcmp(name, "ecx") == 0)
return jit_reg_new(JIT_REG_KIND_I32, REG_ECX_IDX);
else if (strcmp(name, "edx") == 0)
return jit_reg_new(JIT_REG_KIND_I32, REG_EDX_IDX);
else if (strcmp(name, "rax") == 0)
return jit_reg_new(JIT_REG_KIND_I64, REG_RAX_IDX);
else if (strcmp(name, "rcx") == 0)
return jit_reg_new(JIT_REG_KIND_I64, REG_RCX_IDX);
else if (strcmp(name, "rdx") == 0)
return jit_reg_new(JIT_REG_KIND_I64, REG_RDX_IDX);

View File

@ -472,16 +472,128 @@ jit_compile_op_i64_bitwise(JitCompContext *cc, IntBitwise bitwise_op)
return false;
}
static bool
compile_int_shift(JitCompContext *cc, IntShift shift_op, bool is_i32)
{
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
JitReg ecx_hreg = jit_codegen_get_hreg_by_name("ecx");
JitReg rcx_hreg = jit_codegen_get_hreg_by_name("rcx");
#endif
JitReg left, right, mod_right, res;
POP_INT(right);
POP_INT(left);
/* right modulo N */
if (jit_reg_is_const(right)) {
if (is_i32) {
int32 right_value = jit_cc_get_const_I32(cc, right);
right_value = right_value & 0x1f;
if (0 == right_value) {
res = left;
goto shortcut;
}
else {
mod_right = NEW_CONST(I32, right_value);
}
}
else {
int64 right_value = jit_cc_get_const_I64(cc, right);
right_value = right_value & 0x3f;
if (0 == right_value) {
res = left;
goto shortcut;
}
else {
mod_right = NEW_CONST(I64, right_value);
}
}
}
else {
if (is_i32) {
mod_right = jit_cc_new_reg_I32(cc);
GEN_INSN(AND, mod_right, right, NEW_CONST(I32, 0x1f));
}
else {
mod_right = jit_cc_new_reg_I64(cc);
GEN_INSN(AND, mod_right, right, NEW_CONST(I64, 0x3f));
}
}
/* do shift */
if (is_i32) {
res = jit_cc_new_reg_I32(cc);
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
GEN_INSN(MOV, ecx_hreg, mod_right);
#endif
}
else {
res = jit_cc_new_reg_I64(cc);
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
GEN_INSN(MOV, rcx_hreg, mod_right);
#endif
}
switch (shift_op) {
case INT_SHL:
{
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
GEN_INSN(SHL, res, left, is_i32 ? ecx_hreg : rcx_hreg);
#else
GEN_INSN(SHL, res, left, mod_right);
#endif
break;
}
case INT_SHR_S:
{
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
GEN_INSN(SHRS, res, left, is_i32 ? ecx_hreg : rcx_hreg);
#else
GEN_INSN(SHRS, res, left, mod_right);
#endif
break;
}
case INT_SHR_U:
{
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
GEN_INSN(SHRU, res, left, is_i32 ? ecx_hreg : rcx_hreg);
#else
GEN_INSN(SHRU, res, left, mod_right);
#endif
break;
}
default:
{
bh_assert(0);
goto fail;
}
}
/**
* Just to indicate that ecx is used, register allocator cannot spill
* it out. Especially when rcx is ued.
*/
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
GEN_INSN(MOV, ecx_hreg, ecx_hreg);
#endif
shortcut:
PUSH_INT(res);
return true;
fail:
return false;
}
bool
jit_compile_op_i32_shift(JitCompContext *cc, IntShift shift_op)
{
return false;
return compile_int_shift(cc, shift_op, true);
}
bool
jit_compile_op_i64_shift(JitCompContext *cc, IntShift shift_op)
{
return false;
return compile_int_shift(cc, shift_op, false);
}
bool