-
Notifications
You must be signed in to change notification settings - Fork 749
Refine fast jit frontend: merge cmp and if/br_if #1267
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refine fast jit frontend: merge cmp and if/br_if #1267
Conversation
| 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) |
There was a problem hiding this comment.
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 ?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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 ?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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; | ||
| } |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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) { \ |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
|
LGTM |
Merge below INSNs translated by wasm opcodes
cmp + iforcmp + br_if:CMP, SELECTcc, CMP, Bcc
into
CMP, Bcc
So as to reduce the instructions