Skip to content

Commit 9e3c6ac

Browse files
authored
Fix fast jit issues (#1193)
And implement several opcodes
1 parent b01ae11 commit 9e3c6ac

File tree

8 files changed

+435
-88
lines changed

8 files changed

+435
-88
lines changed

core/iwasm/fast-jit/cg/x86-64/jit_codegen_x86_64.cpp

Lines changed: 158 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,8 @@ typedef enum { ADD, SUB, MUL, DIV_S, REM_S, DIV_U, REM_U, MIN, MAX } ALU_OP;
238238
typedef enum { OR, XOR, AND } BIT_OP;
239239
/* Shift opcode */
240240
typedef enum { SHL, SHRS, SHRU, ROTL, ROTR } SHIFT_OP;
241+
/* Bitcount opcode */
242+
typedef enum { CLZ, CTZ, POPCNT } BITCOUNT_OP;
241243
/* Condition opcode */
242244
typedef enum { EQ, NE, GTS, GES, LTS, LES, GTU, GEU, LTU, LEU } COND_OP;
243245

@@ -2339,17 +2341,33 @@ alu_r_r_imm_i64(x86::Assembler &a, ALU_OP op, int32 reg_no_dst,
23392341
a.inc(regs_i64[reg_no_dst]);
23402342
else if (data == -1)
23412343
a.dec(regs_i64[reg_no_dst]);
2342-
else if (data != 0)
2343-
a.add(regs_i64[reg_no_dst], imm);
2344+
else if (data != 0) {
2345+
if (data >= INT32_MIN && data <= INT32_MAX) {
2346+
imm.setValue((int32)data);
2347+
a.add(regs_i64[reg_no_dst], imm);
2348+
}
2349+
else {
2350+
a.mov(regs_i64[REG_I64_FREE_IDX], imm);
2351+
a.add(regs_i64[reg_no_dst], regs_i64[REG_I64_FREE_IDX]);
2352+
}
2353+
}
23442354
break;
23452355
case SUB:
23462356
mov_r_to_r(a, JIT_REG_KIND_I64, reg_no_dst, reg_no_src);
23472357
if (data == -1)
23482358
a.inc(regs_i64[reg_no_dst]);
23492359
else if (data == 1)
23502360
a.dec(regs_i64[reg_no_dst]);
2351-
else if (data != 0)
2352-
a.sub(regs_i64[reg_no_dst], imm);
2361+
else if (data != 0) {
2362+
if (data >= INT32_MIN && data <= INT32_MAX) {
2363+
imm.setValue((int32)data);
2364+
a.sub(regs_i64[reg_no_dst], imm);
2365+
}
2366+
else {
2367+
a.mov(regs_i64[REG_I64_FREE_IDX], imm);
2368+
a.sub(regs_i64[reg_no_dst], regs_i64[REG_I64_FREE_IDX]);
2369+
}
2370+
}
23532371
break;
23542372
case MUL:
23552373
if (data == 0)
@@ -3696,44 +3714,6 @@ shift_r_r_to_r_i64(x86::Assembler &a, SHIFT_OP op, int32 reg_no_dst,
36963714
return false;
36973715
}
36983716

3699-
/**
3700-
* Encode int32 cmp operation of reg and data, and save result to reg
3701-
*
3702-
* @param a the assembler to emit the code
3703-
* @param op the opcode of cmp operation
3704-
* @param reg_no_dst the no of dst register
3705-
* @param reg_no_src the no of src register, as first operand
3706-
* @param data the immediate data, as the second operand
3707-
*
3708-
* @return true if success, false otherwise
3709-
*/
3710-
static bool
3711-
cmp_r_imm_i32(x86::Assembler &a, int32 reg_no_dst, int32 reg_no_src, int32 data)
3712-
{
3713-
Imm imm(data);
3714-
a.cmp(regs_i32[reg_no_src], imm);
3715-
return true;
3716-
}
3717-
3718-
/**
3719-
* Encode int32 cmp operation of reg and reg, and save result to reg
3720-
*
3721-
* @param a the assembler to emit the code
3722-
* @param op the opcode of cmp operation
3723-
* @param reg_no_dst the no of dst register
3724-
* @param reg_no1_src the no of src register, as first operand
3725-
* @param reg_no2_src the no of src register, as second operand
3726-
*
3727-
* @return true if success, false otherwise
3728-
*/
3729-
static bool
3730-
cmp_r_r_i32(x86::Assembler &a, int32 reg_no_dst, int32 reg_no1_src,
3731-
int32 reg_no2_src)
3732-
{
3733-
a.cmp(regs_i32[reg_no1_src], regs_i32[reg_no2_src]);
3734-
return true;
3735-
}
3736-
37373717
/**
37383718
* Encode int32 cmp operation of imm and imm, and save result to reg
37393719
*
@@ -3816,44 +3796,6 @@ cmp_r_r_to_r_i32(x86::Assembler &a, int32 reg_no_dst, int32 reg_no1_src,
38163796
return true;
38173797
}
38183798

3819-
/**
3820-
* Encode int64 cmp operation of reg and data, and save result to reg
3821-
*
3822-
* @param a the assembler to emit the code
3823-
* @param op the opcode of cmp operation
3824-
* @param reg_no_dst the no of dst register
3825-
* @param reg_no_src the no of src register, as first operand
3826-
* @param data the immediate data, as the second operand
3827-
*
3828-
* @return true if success, false otherwise
3829-
*/
3830-
static bool
3831-
cmp_r_imm_i64(x86::Assembler &a, int32 reg_no_dst, int32 reg_no_src, int64 data)
3832-
{
3833-
Imm imm(data);
3834-
a.cmp(regs_i64[reg_no_src], imm);
3835-
return true;
3836-
}
3837-
3838-
/**
3839-
* Encode int64 cmp operation of reg and reg, and save result to reg
3840-
*
3841-
* @param a the assembler to emit the code
3842-
* @param op the opcode of cmp operation
3843-
* @param reg_no_dst the no of dst register
3844-
* @param reg_no1_src the no of src register, as first operand
3845-
* @param reg_no2_src the no of src register, as second operand
3846-
*
3847-
* @return true if success, false otherwise
3848-
*/
3849-
static bool
3850-
cmp_r_r_i64(x86::Assembler &a, int32 reg_no_dst, int32 reg_no1_src,
3851-
int32 reg_no2_src)
3852-
{
3853-
a.cmp(regs_i64[reg_no1_src], regs_i64[reg_no2_src]);
3854-
return true;
3855-
}
3856-
38573799
/**
38583800
* Encode int64 cmp operation of imm and imm, and save result to reg
38593801
*
@@ -3913,7 +3855,15 @@ cmp_r_imm_to_r_i64(x86::Assembler &a, int32 reg_no_dst, int32 reg_no1_src,
39133855
int64 data2_src)
39143856
{
39153857
Imm imm(data2_src);
3916-
a.cmp(regs_i64[reg_no1_src], imm);
3858+
3859+
if (data2_src >= INT32_MIN && data2_src <= INT32_MAX) {
3860+
imm.setValue((int32)data2_src);
3861+
a.cmp(regs_i64[reg_no1_src], imm);
3862+
}
3863+
else {
3864+
a.mov(regs_i64[REG_I64_FREE_IDX], imm);
3865+
a.cmp(regs_i64[reg_no1_src], regs_i64[REG_I64_FREE_IDX]);
3866+
}
39173867
return true;
39183868
}
39193869

@@ -4621,6 +4571,120 @@ lower_shift(JitCompContext *cc, x86::Assembler &a, SHIFT_OP op, JitReg r0,
46214571
return false;
46224572
}
46234573

4574+
/**
4575+
* Encode int32 bitcount operation of reg, and save result to reg
4576+
*
4577+
* @param a the assembler to emit the code
4578+
* @param op the opcode of BITCOUNT operation
4579+
* @param reg_no_dst the no of register
4580+
* @param reg_no_src the reg no of first src register data
4581+
*
4582+
* @return true if success, false otherwise
4583+
*/
4584+
static bool
4585+
bitcount_r_to_r_i32(x86::Assembler &a, BITCOUNT_OP op, int32 reg_no_dst,
4586+
int32 reg_no_src)
4587+
{
4588+
switch (op) {
4589+
case CLZ:
4590+
a.lzcnt(regs_i32[reg_no_dst], regs_i32[reg_no_src]);
4591+
break;
4592+
case CTZ:
4593+
a.tzcnt(regs_i32[reg_no_dst], regs_i32[reg_no_src]);
4594+
break;
4595+
case POPCNT:
4596+
a.popcnt(regs_i32[reg_no_dst], regs_i32[reg_no_src]);
4597+
break;
4598+
default:
4599+
bh_assert(0);
4600+
return false;
4601+
}
4602+
return true;
4603+
}
4604+
4605+
/**
4606+
* Encode int64 bitcount operation of reg, and save result to reg
4607+
*
4608+
* @param a the assembler to emit the code
4609+
* @param op the opcode of BITCOUNT operation
4610+
* @param reg_no_dst the no of register
4611+
* @param reg_no_src the reg no of first src register data
4612+
*
4613+
* @return true if success, false otherwise
4614+
*/
4615+
static bool
4616+
bitcount_r_to_r_i64(x86::Assembler &a, BITCOUNT_OP op, int32 reg_no_dst,
4617+
int32 reg_no_src)
4618+
{
4619+
switch (op) {
4620+
case CLZ:
4621+
a.lzcnt(regs_i64[reg_no_dst], regs_i64[reg_no_src]);
4622+
break;
4623+
case CTZ:
4624+
a.tzcnt(regs_i64[reg_no_dst], regs_i64[reg_no_src]);
4625+
break;
4626+
case POPCNT:
4627+
a.popcnt(regs_i64[reg_no_dst], regs_i64[reg_no_src]);
4628+
break;
4629+
default:
4630+
bh_assert(0);
4631+
return false;
4632+
}
4633+
return true;
4634+
}
4635+
4636+
/**
4637+
* Encode insn bitcount: CLZ/CTZ/POPCNT r0, r1
4638+
* @param kind the data kind, such as I32, I64
4639+
* @param Type the data type, such as int32, int64
4640+
* @param type the abbreviation of data type, such as i32, i64
4641+
* @param op the opcode of bit operation
4642+
*/
4643+
#define BITCOUNT_R_R(kind, Type, type, op) \
4644+
do { \
4645+
int32 reg_no_dst; \
4646+
bool _ret = false; \
4647+
\
4648+
CHECK_EQKIND(r0, r1); \
4649+
CHECK_NCONST(r1); \
4650+
\
4651+
reg_no_dst = jit_reg_no(r0); \
4652+
if (!bitcount_r_to_r_##type(a, op, reg_no_dst, jit_reg_no(r1))) \
4653+
GOTO_FAIL; \
4654+
} while (0)
4655+
4656+
/**
4657+
* Encode bitcount insn, CLZ/CTZ/POPCNT r0, r1
4658+
*
4659+
* @param cc the compiler context
4660+
* @param a the assembler to emit the code
4661+
* @param op the opcode of bitcount operations
4662+
* @param r0 dst jit register that contains the dst operand info
4663+
* @param r1 src jit register that contains the src operand info
4664+
*
4665+
* @return true if success, false if failed
4666+
*/
4667+
static bool
4668+
lower_bitcount(JitCompContext *cc, x86::Assembler &a, BITCOUNT_OP op, JitReg r0,
4669+
JitReg r1)
4670+
{
4671+
switch (jit_reg_kind(r0)) {
4672+
case JIT_REG_KIND_I32:
4673+
BITCOUNT_R_R(I32, int32, i32, op);
4674+
break;
4675+
case JIT_REG_KIND_I64:
4676+
BITCOUNT_R_R(I64, int64, i64, op);
4677+
break;
4678+
default:
4679+
LOG_VERBOSE("Invalid reg type of bit: %d\n", jit_reg_kind(r0));
4680+
GOTO_FAIL;
4681+
}
4682+
4683+
return true;
4684+
fail:
4685+
return false;
4686+
}
4687+
46244688
/**
46254689
* Encode insn cmp: CMP r0, r1, r2
46264690
* @param kind the data kind, such as I32, I64, F32 and F64
@@ -5151,6 +5215,8 @@ lower_callnative(JitCompContext *cc, x86::Assembler &a, bh_list *jmp_info_list,
51515215
if (ret_reg) {
51525216
bh_assert((jit_reg_kind(ret_reg) == JIT_REG_KIND_I32
51535217
&& jit_reg_no(ret_reg) == REG_EAX_IDX)
5218+
|| (jit_reg_kind(ret_reg) == JIT_REG_KIND_I64
5219+
&& jit_reg_no(ret_reg) == REG_RAX_IDX)
51545220
|| (jit_reg_kind(ret_reg) == JIT_REG_KIND_F32
51555221
|| jit_reg_kind(ret_reg) == JIT_REG_KIND_F64
51565222
&& jit_reg_no(ret_reg) == 0));
@@ -5705,6 +5771,17 @@ jit_codegen_gen_native(JitCompContext *cc)
57055771
GOTO_FAIL;
57065772
break;
57075773

5774+
case JIT_OP_CLZ:
5775+
case JIT_OP_CTZ:
5776+
case JIT_OP_POPCNT:
5777+
LOAD_2ARGS();
5778+
if (!lower_bitcount(
5779+
cc, a,
5780+
(BITCOUNT_OP)(CLZ + (insn->opcode - JIT_OP_CLZ)),
5781+
r0, r1))
5782+
GOTO_FAIL;
5783+
break;
5784+
57085785
case JIT_OP_CMP:
57095786
LOAD_3ARGS();
57105787
if (!lower_cmp(cc, a, r0, r1, r2))

0 commit comments

Comments
 (0)