-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
[mono][interp] Expand bblocks reordering with common patterns to facilitate propagation of values #80362
[mono][interp] Expand bblocks reordering with common patterns to facilitate propagation of values #80362
Conversation
…o callers bblocks. The known patterns are: branch: a single conditional or unconditional branch instruction. ldc; branch or compare; branch: a load instruction or compare instruction followed by a conditional or unconditional branch instruction. ldc; compare; branch: a load instruction followed by a compare instruction and a conditional or unconditional branch instruction.
Tagging subscribers to this area: @BrzVlad Issue DetailsThis PR expands bblocks reordering with the following common patterns:
For example, the following pattern could be inlined into callers bblocks:
This PR reorders the code to look like:
The code is further optimized by constants folding and superins.
|
@@ -8438,16 +8538,16 @@ interp_reorder_bblocks (TransformData *td) | |||
i++; | |||
} | |||
} | |||
} else if (first->opcode == MINT_BR) { |
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.
Why is there a change to this separate optimization here ? We can also get rid of special casing MINT_BR in interp_inline_into_callers
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.
No need, reverted.
InterpInst *first = interp_first_ins (bb); | ||
InterpInst *second = first ? interp_next_ins(first) : NULL; | ||
InterpInst *third = second ? interp_next_ins(second) : NULL; | ||
|
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.
Maybe compiler is smart enough. But you could avoid checking for non null with every single if like:
if (!first) return;
...
checking patterns with first instruction
...
if (!second) return;
...
checking patterns with first and second instructions
...
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.
Good point, updated.
* - `compare; branch`: a compare instruction followed by a unary conditional branch. | ||
* - `ldc; compare; branch`: a load instruction followed by a compare instruction and a unary conditional branch. | ||
*/ | ||
static gboolean |
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 think the return value of cond_ins
is rather unnecessary. It could instead directly return the lookup vars.
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.
Good point, updated.
InterpInst *dest_ins = interp_prev_ins(last_ins); | ||
|
||
// Copy a pattern into caller bb | ||
while (src_ins) { |
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.
This copying here seems a bit hard to follow and unnatural. We could instead just copy all instructions one by one, from interp_first_ins (bb)
to the end of the in_bb
(after we got rid of the ending MINT_BR
).
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.
Updated. When copying instructions,MINT_LDC_I4
has ins->data [1]
variable and there is a conditional statement for such cases. Other option is to iterate through ins->data
but it could make the runtime slower.
… Copy a branch pattern into callers bblocks.
if (!second) | ||
return NULL; | ||
// pattern `ldc; unop conditional branch` | ||
if (MINT_IS_LDC(first->opcode) |
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.
This pattern is redundant and it is probably not reached anyway. ldc
+ brtrue/false
is already resolved to br.s
or optimized out.
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.
Good point. Removed.
return second; | ||
} | ||
// pattern `compare; unop conditional branch` | ||
if (MINT_IS_COMPARE(first->opcode) |
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.
Do you have a C# example where this case leads to better codegen ? I think we should stick to cases that we can see in practice, and not overdo it with duplicating code.
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 don't have such example. Agree, keep it simple and clean.
{ | ||
InterpInst *prev_ins = interp_prev_ins(cond_ins); | ||
int var1 = -1, var2 = -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.
I feel like declaring the lookup vars here is not really the best. It doesn't correctly (strictly speaking) initializes the lookup vars. For example in some of the patterns, we know the value of one of the sregs from the existing bblock (ldc
+ compare
/condbr
), in which case we should only look for the unkown var. Also we can set these lookup vars directly in interp_inline_into_callers
, as we check the patterns, without having these separate checks.
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.
Good idea, updated.
as with the other PR there is a lot of missing space before |
Thanks for the heads up. Failures seem to be relevant. |
…otlarmilos/runtime into improvement/inline-branch-into-callers
while (copy_ins) { | ||
InterpInst *new_ins = interp_insert_ins_bb (td, in_bb, in_bb->last_ins, copy_ins->opcode); | ||
new_ins->dreg = copy_ins->dreg; | ||
new_ins->sregs[0] = copy_ins->sregs[0]; |
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.
space before [
new_ins->dreg = copy_ins->dreg; | ||
new_ins->sregs[0] = copy_ins->sregs[0]; | ||
if (mono_interp_op_sregs[copy_ins->opcode] > 1) | ||
new_ins->sregs[1] = copy_ins->sregs[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.
space before [
@@ -8441,7 +8511,7 @@ interp_reorder_bblocks (TransformData *td) | |||
} | |||
} | |||
} else if (first->opcode == MINT_BR) { | |||
// All bblocks jumping into this bblock can jump directly into the br target | |||
// All bblocks jumping into this bblock can jump directly into the br target only if it is a single instruction in a bb |
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 comment addition seems confusing. Did you mean to say since it is the single instruction of the bb
?
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.
Updated. It was confusing and left over from previous changes.
This PR expands bblocks reordering with the following common patterns:
branch
: a branch instruction (either MINT_IS_CONDITIONAL_BRANCH or MINT_BR).ldc; branch
: a load instruction followed by a binary conditional branch.ldc; compare; branch
: a load instruction followed by a compare instruction and a unary conditional branch.For example, the following pattern could be inlined into callers bblocks:
This PR reorders the code to look like:
The code is further optimized by constants folding and superins.
Draft PR should confirm if the runtime works as expected.