Skip to content

Commit a9658c2

Browse files
authored
Implement reference-types opcodes for fast jit (#1249)
1 parent 1a826f3 commit a9658c2

File tree

6 files changed

+470
-124
lines changed

6 files changed

+470
-124
lines changed

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

Lines changed: 139 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,36 @@ typedef enum { CLZ, CTZ, POPCNT } BITCOUNT_OP;
246246
/* Condition opcode */
247247
typedef enum { EQ, NE, GTS, GES, LTS, LES, GTU, GEU, LTU, LEU } COND_OP;
248248

249+
typedef union _cast_float_to_integer {
250+
float f;
251+
uint32 i;
252+
} cast_float_to_integer;
253+
254+
typedef union _cast_double_to_integer {
255+
double d;
256+
uint64 i;
257+
} cast_double_to_integer;
258+
259+
static uint32
260+
local_log2(uint32 data)
261+
{
262+
uint32 ret = 0;
263+
while (data >>= 1) {
264+
ret++;
265+
}
266+
return ret;
267+
}
268+
269+
static uint64
270+
local_log2l(uint64 data)
271+
{
272+
uint64 ret = 0;
273+
while (data >>= 1) {
274+
ret++;
275+
}
276+
return ret;
277+
}
278+
249279
/* Jmp type */
250280
typedef enum JmpType {
251281
JMP_DST_LABEL, /* jmp to dst label */
@@ -1157,7 +1187,8 @@ static bool
11571187
mov_imm_to_r_f32(x86::Assembler &a, int32 reg_no, float data)
11581188
{
11591189
/* imm -> gp -> xmm */
1160-
Imm imm(*(uint32 *)&data);
1190+
cast_float_to_integer v = { .f = data };
1191+
Imm imm(v.i);
11611192
a.mov(regs_i32[REG_I32_FREE_IDX], imm);
11621193
a.movd(regs_float[reg_no], regs_i32[REG_I32_FREE_IDX]);
11631194
return true;
@@ -1193,7 +1224,8 @@ mov_r_to_r_f32(x86::Assembler &a, int32 reg_no_dst, int32 reg_no_src)
11931224
static bool
11941225
mov_imm_to_r_f64(x86::Assembler &a, int32 reg_no, double data)
11951226
{
1196-
Imm imm(*(uint64 *)&data);
1227+
cast_double_to_integer v = { .d = data };
1228+
Imm imm(v.i);
11971229
a.mov(regs_i64[REG_I32_FREE_IDX], imm);
11981230
/* REG_I32_FREE_IDX == REG_I64_FREE_IDX */
11991231
a.movq(regs_float[reg_no], regs_i64[REG_I64_FREE_IDX]);
@@ -2266,19 +2298,10 @@ alu_r_r_imm_i32(x86::Assembler &a, ALU_OP op, int32 reg_no_dst,
22662298
else if (data == 1) {
22672299
mov_r_to_r(a, JIT_REG_KIND_I32, reg_no_dst, reg_no_src);
22682300
}
2269-
else if (data == 2) {
2301+
else if (data > 0 && (data & (data - 1)) == 0x0) {
22702302
mov_r_to_r(a, JIT_REG_KIND_I32, reg_no_dst, reg_no_src);
2271-
imm.setValue(1);
2272-
a.shl(regs_i32[reg_no_dst], imm);
2273-
}
2274-
else if (data == 4) {
2275-
mov_r_to_r(a, JIT_REG_KIND_I32, reg_no_dst, reg_no_src);
2276-
imm.setValue(2);
2277-
a.shl(regs_i32[reg_no_dst], imm);
2278-
}
2279-
else if (data == 8) {
2280-
mov_r_to_r(a, JIT_REG_KIND_I32, reg_no_dst, reg_no_src);
2281-
imm.setValue(3);
2303+
data = (int32)local_log2(data);
2304+
imm.setValue(data);
22822305
a.shl(regs_i32[reg_no_dst], imm);
22832306
}
22842307
else {
@@ -2539,6 +2562,81 @@ alu_r_r_to_r_i32(x86::Assembler &a, ALU_OP op, int32 reg_no_dst,
25392562
return alu_r_r_r_i32(a, op, reg_no_dst, reg_no1_src, reg_no2_src);
25402563
}
25412564

2565+
/**
2566+
* Encode int64 alu operation of reg and reg, and save result to reg
2567+
*
2568+
* @param a the assembler to emit the code
2569+
* @param op the opcode of ALU operation
2570+
* @param reg_no_dst the no of register, as first operand, and save result
2571+
* @param reg_no_src the no of register, as the second operand
2572+
*
2573+
* @return true if success, false otherwise
2574+
*/
2575+
static bool
2576+
alu_r_r_r_i64(x86::Assembler &a, ALU_OP op, int32 reg_no_dst, int32 reg_no1_src,
2577+
int32 reg_no2_src)
2578+
{
2579+
switch (op) {
2580+
case ADD:
2581+
if (reg_no_dst != reg_no2_src) {
2582+
mov_r_to_r(a, JIT_REG_KIND_I64, reg_no_dst, reg_no1_src);
2583+
a.add(regs_i64[reg_no_dst], regs_i64[reg_no2_src]);
2584+
}
2585+
else
2586+
a.add(regs_i64[reg_no2_src], regs_i64[reg_no1_src]);
2587+
break;
2588+
case SUB:
2589+
if (reg_no_dst != reg_no2_src) {
2590+
mov_r_to_r(a, JIT_REG_KIND_I64, reg_no_dst, reg_no1_src);
2591+
a.sub(regs_i64[reg_no_dst], regs_i64[reg_no2_src]);
2592+
}
2593+
else {
2594+
a.sub(regs_i64[reg_no2_src], regs_i64[reg_no1_src]);
2595+
a.neg(regs_i64[reg_no2_src]);
2596+
}
2597+
break;
2598+
case MUL:
2599+
if (reg_no_dst != reg_no2_src) {
2600+
mov_r_to_r(a, JIT_REG_KIND_I64, reg_no_dst, reg_no1_src);
2601+
a.imul(regs_i64[reg_no_dst], regs_i64[reg_no2_src]);
2602+
}
2603+
else
2604+
a.imul(regs_i64[reg_no2_src], regs_i64[reg_no1_src]);
2605+
break;
2606+
case DIV_S:
2607+
case REM_S:
2608+
bh_assert(reg_no1_src == REG_RAX_IDX);
2609+
if (op == DIV_S) {
2610+
bh_assert(reg_no_dst == REG_RAX_IDX);
2611+
}
2612+
else {
2613+
bh_assert(reg_no_dst == REG_RDX_IDX);
2614+
}
2615+
/* signed extend rax to rdx:rax */
2616+
a.cqo();
2617+
a.idiv(regs_i64[reg_no2_src]);
2618+
break;
2619+
case DIV_U:
2620+
case REM_U:
2621+
bh_assert(reg_no1_src == REG_RAX_IDX);
2622+
if (op == DIV_U) {
2623+
bh_assert(reg_no_dst == REG_RAX_IDX);
2624+
}
2625+
else {
2626+
bh_assert(reg_no_dst == REG_RDX_IDX);
2627+
}
2628+
/* unsigned extend rax to rdx:rax */
2629+
a.xor_(regs_i64[REG_RDX_IDX], regs_i64[REG_RDX_IDX]);
2630+
a.div(regs_i64[reg_no2_src]);
2631+
break;
2632+
default:
2633+
bh_assert(0);
2634+
break;
2635+
}
2636+
2637+
return true;
2638+
}
2639+
25422640
/**
25432641
* Encode int64 alu operation of reg and data, and save result to reg
25442642
*
@@ -2600,23 +2698,23 @@ alu_r_r_imm_i64(x86::Assembler &a, ALU_OP op, int32 reg_no_dst,
26002698
else if (data == 1) {
26012699
mov_r_to_r(a, JIT_REG_KIND_I64, reg_no_dst, reg_no_src);
26022700
}
2603-
else if (data == 2) {
2604-
mov_r_to_r(a, JIT_REG_KIND_I64, reg_no_dst, reg_no_src);
2605-
imm.setValue(1);
2606-
a.shl(regs_i64[reg_no_dst], imm);
2607-
}
2608-
else if (data == 4) {
2701+
else if (data > 0 && (data & (data - 1)) == 0x0) {
26092702
mov_r_to_r(a, JIT_REG_KIND_I64, reg_no_dst, reg_no_src);
2610-
imm.setValue(2);
2703+
data = (int64)local_log2l(data);
2704+
imm.setValue(data);
26112705
a.shl(regs_i64[reg_no_dst], imm);
26122706
}
2613-
else if (data == 8) {
2614-
mov_r_to_r(a, JIT_REG_KIND_I64, reg_no_dst, reg_no_src);
2615-
imm.setValue(3);
2616-
a.shl(regs_i64[reg_no_dst], imm);
2707+
else if (INT32_MIN <= data && data <= INT32_MAX) {
2708+
a.imul(regs_i64[reg_no_dst], regs_i64[reg_no_src], imm);
26172709
}
26182710
else {
2619-
a.imul(regs_i64[reg_no_dst], regs_i64[reg_no_src], imm);
2711+
mov_imm_to_r_i64(
2712+
a, reg_no_dst == reg_no_src ? REG_I64_FREE_IDX : reg_no_dst,
2713+
data);
2714+
alu_r_r_r_i64(a, op, reg_no_dst,
2715+
reg_no_dst == reg_no_src ? REG_I64_FREE_IDX
2716+
: reg_no_dst,
2717+
reg_no_src);
26202718
}
26212719
break;
26222720
case DIV_S:
@@ -2655,81 +2753,6 @@ alu_r_r_imm_i64(x86::Assembler &a, ALU_OP op, int32 reg_no_dst,
26552753
return true;
26562754
}
26572755

2658-
/**
2659-
* Encode int64 alu operation of reg and reg, and save result to reg
2660-
*
2661-
* @param a the assembler to emit the code
2662-
* @param op the opcode of ALU operation
2663-
* @param reg_no_dst the no of register, as first operand, and save result
2664-
* @param reg_no_src the no of register, as the second operand
2665-
*
2666-
* @return true if success, false otherwise
2667-
*/
2668-
static bool
2669-
alu_r_r_r_i64(x86::Assembler &a, ALU_OP op, int32 reg_no_dst, int32 reg_no1_src,
2670-
int32 reg_no2_src)
2671-
{
2672-
switch (op) {
2673-
case ADD:
2674-
if (reg_no_dst != reg_no2_src) {
2675-
mov_r_to_r(a, JIT_REG_KIND_I64, reg_no_dst, reg_no1_src);
2676-
a.add(regs_i64[reg_no_dst], regs_i64[reg_no2_src]);
2677-
}
2678-
else
2679-
a.add(regs_i64[reg_no2_src], regs_i64[reg_no1_src]);
2680-
break;
2681-
case SUB:
2682-
if (reg_no_dst != reg_no2_src) {
2683-
mov_r_to_r(a, JIT_REG_KIND_I64, reg_no_dst, reg_no1_src);
2684-
a.sub(regs_i64[reg_no_dst], regs_i64[reg_no2_src]);
2685-
}
2686-
else {
2687-
a.sub(regs_i64[reg_no2_src], regs_i64[reg_no1_src]);
2688-
a.neg(regs_i64[reg_no2_src]);
2689-
}
2690-
break;
2691-
case MUL:
2692-
if (reg_no_dst != reg_no2_src) {
2693-
mov_r_to_r(a, JIT_REG_KIND_I64, reg_no_dst, reg_no1_src);
2694-
a.imul(regs_i64[reg_no_dst], regs_i64[reg_no2_src]);
2695-
}
2696-
else
2697-
a.imul(regs_i64[reg_no2_src], regs_i64[reg_no1_src]);
2698-
break;
2699-
case DIV_S:
2700-
case REM_S:
2701-
bh_assert(reg_no1_src == REG_RAX_IDX);
2702-
if (op == DIV_S) {
2703-
bh_assert(reg_no_dst == REG_RAX_IDX);
2704-
}
2705-
else {
2706-
bh_assert(reg_no_dst == REG_RDX_IDX);
2707-
}
2708-
/* signed extend rax to rdx:rax */
2709-
a.cqo();
2710-
a.idiv(regs_i64[reg_no2_src]);
2711-
break;
2712-
case DIV_U:
2713-
case REM_U:
2714-
bh_assert(reg_no1_src == REG_RAX_IDX);
2715-
if (op == DIV_U) {
2716-
bh_assert(reg_no_dst == REG_RAX_IDX);
2717-
}
2718-
else {
2719-
bh_assert(reg_no_dst == REG_RDX_IDX);
2720-
}
2721-
/* unsigned extend rax to rdx:rax */
2722-
a.xor_(regs_i64[REG_RDX_IDX], regs_i64[REG_RDX_IDX]);
2723-
a.div(regs_i64[reg_no2_src]);
2724-
break;
2725-
default:
2726-
bh_assert(0);
2727-
break;
2728-
}
2729-
2730-
return true;
2731-
}
2732-
27332756
/**
27342757
* Encode int64 alu operation of imm and imm, and save result to reg
27352758
*
@@ -3025,7 +3048,8 @@ alu_r_imm_to_r_f32(x86::Assembler &a, ALU_OP op, int32 reg_no_dst,
30253048
/* imm -> m32 */
30263049
x86::Mem cache = x86::dword_ptr(regs_i64[hreg_info->exec_env_hreg_index],
30273050
offsetof(WASMExecEnv, jit_cache));
3028-
Imm imm(*(uint32 *)&data2_src);
3051+
cast_float_to_integer v = { .f = data2_src };
3052+
Imm imm(v.i);
30293053
mov_imm_to_m(a, cache, imm, 4);
30303054

30313055
mov_r_to_r_f32(a, reg_no_dst, reg_no1_src);
@@ -3214,7 +3238,8 @@ alu_r_imm_to_r_f64(x86::Assembler &a, ALU_OP op, int32 reg_no_dst,
32143238
/* imm -> m64 */
32153239
x86::Mem cache = x86::qword_ptr(regs_i64[hreg_info->exec_env_hreg_index],
32163240
offsetof(WASMExecEnv, jit_cache));
3217-
Imm imm(*(uint64 *)&data2_src);
3241+
cast_double_to_integer v = { .d = data2_src };
3242+
Imm imm(v.i);
32183243
mov_imm_to_m(a, cache, imm, 8);
32193244

32203245
mov_r_to_r_f64(a, reg_no_dst, reg_no1_src);
@@ -3822,7 +3847,8 @@ shift_r_r_to_r_i32(x86::Assembler &a, SHIFT_OP op, int32 reg_no_dst,
38223847
int32 reg_no1_src, int32 reg_no2_src)
38233848
{
38243849
/* should be CL */
3825-
bh_assert(reg_no2_src == REG_ECX_IDX);
3850+
if (reg_no2_src != REG_ECX_IDX)
3851+
return false;
38263852

38273853
mov_r_to_r_i32(a, reg_no_dst, reg_no1_src);
38283854

@@ -4019,7 +4045,8 @@ shift_r_r_to_r_i64(x86::Assembler &a, SHIFT_OP op, int32 reg_no_dst,
40194045
int32 reg_no1_src, int32 reg_no2_src)
40204046
{
40214047
/* should be CL */
4022-
bh_assert(reg_no2_src == REG_ECX_IDX);
4048+
if (reg_no2_src != REG_ECX_IDX)
4049+
return false;
40234050

40244051
mov_r_to_r_i64(a, reg_no_dst, reg_no1_src);
40254052

@@ -5845,7 +5872,8 @@ cast_r_i64_to_r_f64(x86::Assembler &a, int32 reg_no_dst, int32 reg_no_src)
58455872
static bool
58465873
cast_imm_f32_to_r_i32(x86::Assembler &a, int32 reg_no, float data)
58475874
{
5848-
return mov_imm_to_r_i32(a, reg_no, *(uint32 *)&data);
5875+
cast_float_to_integer v = { .f = data };
5876+
return mov_imm_to_r_i32(a, reg_no, v.i);
58495877
}
58505878

58515879
/**
@@ -5876,7 +5904,8 @@ cast_r_f32_to_r_i32(x86::Assembler &a, int32 reg_no_dst, int32 reg_no_src)
58765904
static bool
58775905
cast_imm_f64_to_r_i64(x86::Assembler &a, int32 reg_no, double data)
58785906
{
5879-
return mov_imm_to_r_i64(a, reg_no, *(uint64 *)&data);
5907+
cast_double_to_integer v = { .d = data };
5908+
return mov_imm_to_r_i64(a, reg_no, v.i);
58805909
}
58815910

58825911
/**
@@ -6475,6 +6504,9 @@ jit_codegen_dump_native(void *begin_addr, void *end_addr)
64756504
os_printf("\n");
64766505
dump_native((char *)begin_addr, (char *)end_addr - (char *)begin_addr);
64776506
os_printf("\n");
6507+
#else
6508+
(void)begin_addr;
6509+
(void)end_addr;
64786510
#endif
64796511
}
64806512

core/iwasm/fast-jit/fe/jit_emit_function.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,23 +365,43 @@ jit_compile_op_call_indirect(JitCompContext *cc, uint32 type_idx,
365365
return false;
366366
}
367367

368+
#if WASM_ENABLE_REF_TYPES != 0
368369
bool
369-
jit_compile_op_ref_null(JitCompContext *cc)
370+
jit_compile_op_ref_null(JitCompContext *cc, uint32 ref_type)
370371
{
372+
PUSH_I32(NEW_CONST(I32, NULL_REF));
373+
(void)ref_type;
374+
return true;
375+
fail:
371376
return false;
372377
}
373378

374379
bool
375380
jit_compile_op_ref_is_null(JitCompContext *cc)
376381
{
382+
JitReg ref, res;
383+
384+
POP_I32(ref);
385+
386+
GEN_INSN(CMP, cc->cmp_reg, ref, NEW_CONST(I32, NULL_REF));
387+
res = jit_cc_new_reg_I32(cc);
388+
GEN_INSN(SELECTEQ, res, cc->cmp_reg, NEW_CONST(I32, 1), NEW_CONST(I32, 0));
389+
PUSH_I32(res);
390+
391+
return true;
392+
fail:
377393
return false;
378394
}
379395

380396
bool
381397
jit_compile_op_ref_func(JitCompContext *cc, uint32 func_idx)
382398
{
399+
PUSH_I32(NEW_CONST(I32, func_idx));
400+
return true;
401+
fail:
383402
return false;
384403
}
404+
#endif
385405

386406
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
387407
bool

0 commit comments

Comments
 (0)