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

Fix issue where resolution move would overwrite the source of operand of JCMP #48833

Merged
merged 3 commits into from
Mar 3, 2021

Conversation

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Feb 26, 2021
@kunalspathak
Copy link
Member Author

@dotnet/jit-contrib

@sandreenko sandreenko self-requested a review February 26, 2021 18:36
Base automatically changed from master to main March 1, 2021 09:08
@kunalspathak
Copy link
Member Author

@AndyAyersMS or @BruceForstall - can you please review this?

src/coreclr/jit/lsra.cpp Outdated Show resolved Hide resolved
@@ -8312,6 +8320,12 @@ void LinearScan::handleOutgoingCriticalEdges(BasicBlock* block)
GenTree* op1 = lastNode->gtGetOp1();
switchRegs |= genRegMask(op1->GetRegNum());

if (op1->OperIs(GT_COPY))
Copy link
Member

Choose a reason for hiding this comment

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

Are locals and copies the only special cases that might happen here?

Copy link
Member

Choose a reason for hiding this comment

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

Also switch_regs is not as descriptive as one might like, given that we now set it for things that are not switches.

Copy link
Member Author

Choose a reason for hiding this comment

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

That's the only ones I could think of. COPY are special because we defer the code generation until the consuming node like here:

case GT_COPY:
// This is handled at the time we call genConsumeReg() on the GT_COPY
break;

So in the test that I was investigating, the GT_COPY node's generation get deferred and happens after the generation of resolution move, at the time when the JCMP is generated.

Generating: N787 ( 34, 17) [000046] --CXGO------        t46 = *  CALLV vt-ind int    MiniBench.MyChannelWriter`1[Int32][System.Int32].TryWrite REG x0 $218
							GC regs: 100001 {x0 x20} => 100000 {x20}
Call: GCvars=0000000000000008 {V00}, gcrefRegs=100000 {x20}, byrefRegs=80000 {x19}
[15] Rec call GC vars = 0000000000000008
IN000f:                           blr     x21
                                                              /--*  t46    int    
Generating:                [000930] --CXGO------       t930 = *  COPY      int    REG x21 (currently: ***not unused***, should be unused)
Generating: N789 (  1,  2) [000047] -c----------        t47 =    CNS_INT   int    0 REG NA $40
; Generating: N001 (  1,  1) [000937] ------------       t937 =    LCL_VAR   byref  V00 this          x19 REG x19
                                                              /--*  t937   byref  
Generating: N002 (  2,  2) [000938] ------------       t938 = *  COPY      byref  REG x0 (currently: ***unused***, should be notunused)
IN0010:                           mov     x0, x19
							V00 in reg x19 is becoming dead  [000937]
							Live regs: 180000 {x19 x20} => 100000 {x20}
							Byref regs: 80000 {x19} => 0000 {}
							V00 in reg x0 is becoming live  [000938]
							Live regs: 100000 {x20} => 100001 {x0 x20}
							Byref regs: 0000 {} => 0001 {x0}
                                                              /--*  t930   int    
                                                              +--*  t47    int    
Generating: N791 ( 36, 20) [000048] CNE---XGO-N----              *  JCMP      void   REG NA
IN0011:                           mov     w21, w0
IN0012:                           cbnz    (LARGEJMP)L_M2478_BB37

Regarding switchRegs, I will rename it to consumedRegs.

// call METHOD
// ; mov w0, w19 <-- should not resolve in w0 here.
// mov w21, w0
// JCMP w21, BRANCH
Copy link
Member

Choose a reason for hiding this comment

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

Not obvious to me why the copy needs special casing here -- could we not insert the resolution move between the copy and jump?

Copy link
Member Author

Choose a reason for hiding this comment

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

Inserting the resolution move between the copy and jump should be fine for some cases, for example:

mov     w21, w0
mov     x0, x19  ; <-- resolution move
cbnz    w21, G_M2478_IG37

but when we generate code for JCMP, it is tied with the copy and so the resolution move happens before the copy/jmp, like this:

      mov     x0, x20
      ldr     x21, [x20]
      ldr     x21, [x21,#72]
      ldr     x21, [x21,#40]
      blr     x21
      mov     x0, x19   ; move resolution overwrites `x0` before it gets copied.
      mov     w21, w0
      cbnz    w21, G_M2478_IG37

G_M2478_IG05:              
      mov     x19, x0
      ....

Copy link
Member

Choose a reason for hiding this comment

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

Maybe add a comment that the GT_COPY gets special handling in codegen and is conceptually merged with the operation that consumes its result, so both its input and output regs must be excluded from the set available for resolution.

And only switches and jcmp have input regs (and so can be fed by copies), so those are the only block-ending branches that need special handling.

Which makes me wonder if we might need similar logic for switches. It looks like we don't check if the input regs for switches come from GT_COPY. Switches are rare enough that we might not have good stress coverage.

Copy link
Member Author

Choose a reason for hiding this comment

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

Maybe add a comment

Done.

wonder if we might need similar logic for switches

Possibly, but I am not confident to make that change before seeing a scenario, so lets postpone it for now.

@kunalspathak kunalspathak merged commit 30560e2 into dotnet:main Mar 3, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Apr 2, 2021
@JulieLeeMSFT JulieLeeMSFT added this to the 6.0.0 milestone Apr 15, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants