Skip to content
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

Merged

Conversation

kotlarmilos
Copy link
Member

@kotlarmilos kotlarmilos commented Jan 9, 2023

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:

BB8:
     ldc.i4.0 [var1 <- nil],
     br.s BB1
BB5:
     ldc.i4.1 [var2 <- nil],
     cgt.i4 [var3 <- var1 var2],
     brfalse.i4.s [nil <- var3] BB2
BB3:
     ldstr

This PR reorders the code to look like:

BB8:
     ldc.i4.0 [var1 <- nil],
     ldc.i4.1 [var2 <- nil],
     cgt.i4 [var3 <- var1 var2],
     brfalse.i4.s [nil <- var3] BB2
BB11:
     br             [nil <- nil], BB3

The code is further optimized by constants folding and superins.

Draft PR should confirm if the runtime works as expected.

…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.
@kotlarmilos kotlarmilos added this to the 8.0.0 milestone Jan 9, 2023
@kotlarmilos kotlarmilos self-assigned this Jan 9, 2023
@ghost
Copy link

ghost commented Jan 9, 2023

Tagging subscribers to this area: @BrzVlad
See info in area-owners.md if you want to be subscribed.

Issue Details

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.
  • 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.

For example, the following pattern could be inlined into callers bblocks:

BB8:
     ldc.i4.0 [var1 <- nil],
     br.s BB1
BB5:
     ldc.i4.1 [var2 <- nil],
     cgt.i4 [var3 <- var1 var2],
     brfalse.i4.s [nil <- var3] BB2
BB3:
     ldstr

This PR reorders the code to look like:

BB8:
     ldc.i4.0 [var1 <- nil],
     ldc.i4.1 [var2 <- nil],
     cgt.i4 [var3 <- var1 var2],
     brfalse.i4.s [nil <- var3] BB2
BB11:
     br             [nil <- nil], BB3

The code is further optimized by constants folding and superins.

Author: kotlarmilos
Assignees: kotlarmilos
Labels:

area-Codegen-Interpreter-mono

Milestone: 8.0.0

@kotlarmilos kotlarmilos changed the title Expand bblocks reordering with common patterns to facilitate propagation of values [mono][interp] Expand bblocks reordering with common patterns to facilitate propagation of values Jan 9, 2023
@@ -8438,16 +8538,16 @@ interp_reorder_bblocks (TransformData *td)
i++;
}
}
} else if (first->opcode == MINT_BR) {
Copy link
Member

@BrzVlad BrzVlad Jan 9, 2023

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

Copy link
Member Author

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;

Copy link
Member

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
...

Copy link
Member Author

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
Copy link
Member

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.

Copy link
Member Author

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) {
Copy link
Member

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).

Copy link
Member Author

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)
Copy link
Member

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.

Copy link
Member Author

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)
Copy link
Member

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.

Copy link
Member Author

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;
Copy link
Member

@BrzVlad BrzVlad Jan 11, 2023

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.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good idea, updated.

@BrzVlad
Copy link
Member

BrzVlad commented Jan 11, 2023

as with the other PR there is a lot of missing space before (

@kotlarmilos
Copy link
Member Author

as with the other PR there is a lot of missing space before (

Thanks for the heads up. Failures seem to be relevant.

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];
Copy link
Member

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];
Copy link
Member

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
Copy link
Member

@BrzVlad BrzVlad Jan 14, 2023

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 ?

Copy link
Member Author

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.

@kotlarmilos kotlarmilos merged commit c0447bc into dotnet:main Jan 16, 2023
@kotlarmilos kotlarmilos deleted the improvement/inline-branch-into-callers branch January 16, 2023 13:40
@ghost ghost locked as resolved and limited conversation to collaborators Feb 15, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants