Skip to content

Conversation

@wenyongh
Copy link
Collaborator

@wenyongh wenyongh commented Jul 5, 2022

Merge below INSNs translated by wasm opcodes cmp + if or cmp + br_if:
CMP, SELECTcc, CMP, Bcc
into
CMP, Bcc
So as to reduce the instructions

if (insn && insn->prev && insn->prev->opcode == JIT_OP_CMP
&& insn->opcode >= JIT_OP_SELECTEQ && insn->opcode <= JIT_OP_SELECTLEU
&& *jit_insn_opnd(insn, 0) == cond
&& jit_reg_is_i32_const(cc, *jit_insn_opnd(insn, 2), 1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if there are i64 in SELECTcc ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be no i64 in SELECTcc in this case, if the opcodes are i64.cmpcc + if/br_if, the translated IRs should be CMP cmp_reg, i64_r0, i64_r1, SELECTcc i32_cond, cmp_reg, 1, 0. The i64 reg is in CMP IR but not SELECT cc IR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. Even i64 comparison would return i32 value

uint8 *frame_ip_end, uint32 label_type, uint32 param_count,
uint8 *param_types, uint32 result_count,
uint8 *result_types)
uint8 *result_types, bool merge_cmp_and_if)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought the merge action is by default. Why need to disable it ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the float/double comparison opcodes, we might translate them into calling native function instead, but not CMP + SELECTcc

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, shall we tell that by checking JIT_REG_KIND_XXX?

Copy link
Collaborator Author

@wenyongh wenyongh Jul 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just check whether the last two insns are CMP + SELECTcc, as in jit_frontend.c, we will check whether the i32/i64/f32/f64 cmp opcode is followed by br/br_if opcode, and only when yes, we pass merge_cmp_and_if = true to jit_compile_op_block. So in jit_compile_op_block, checking whether the last two insns are CMP + SELECTcc should be enough, the jit reg kind in CMP may be variable, but in SELECTcc, the reg kind of all registers should be i32:

CMP cmp_reg, i32_r0, i32_r1 (or, CMP cmp_reg, i64/f32/f64_r0, i64/f32/f64_r1)
SELECT i32_r2, cmp_reg, 1, 0

jit_basic_block_label(basic_block), 0))) {
jit_set_last_error(cc, "generate cond br failed");
goto fail;
if (insn_select && insn_cmp) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought get_last_cmp_and_selectcc will do the optimization. So, what does this if(){} do?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_last_cmp_and_selectcc just returns insn_select and insn_cmp found, here we replace insn_select with Bcc.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it.

stream = (char *)a.code()->sectionById(0)->buffer().data()
+ a.code()->sectionById(0)->buffer().size() - 6;
*(int32 *)(stream + 2) = offset;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a else branch to handle error?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error is handled in jit_codegen_gen_native, after generation machine code for each INSN, seem no need to handle it here?

            if (err_handler.err) {
                jit_set_last_error_v(cc,
                                     "failed to generate native code for JIT "
                                     "opcode 0x%02x, ErrorCode is %u",
                                     insn->opcode, err_handler.err);
                GOTO_FAIL;
            }

char *stream; \
Imm imm(INT32_MAX); \
a.jmp(imm); \
if (!err_handler->err) { \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What kind of scenario would lead to the error? L5322 and L5332 seem to suggest both situations are acceptable.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a.jmp(imm) may return error. The asmjit might calls re-alloc the memory of its code buffer, I tested cases with valgrind, and found that it sometimes reported that *(int32 *)(stream + 2) = _offset writes the old/obsolete memory before re-alloc, so I refactored the code. Another issue is that if a.jmp fails, we will write offset the invalid place.

@lum1n0us
Copy link
Contributor

lum1n0us commented Jul 7, 2022

LGTM

@wenyongh wenyongh merged commit de52901 into bytecodealliance:dev/fast_jit Jul 7, 2022
@wenyongh wenyongh deleted the opt_fast_jit_cmp_if branch July 11, 2022 04:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants