Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Refactoring emitInsBinary #15836

Merged
merged 2 commits into from
Jan 19, 2018
Merged

Refactoring emitInsBinary #15836

merged 2 commits into from
Jan 19, 2018

Conversation

tannergooding
Copy link
Member

@tannergooding
Copy link
Member Author

FYI. @CarolEidt, @mikedn, @dotnet/jit-contrib


default: // Addressing mode [regBase + regIndex * Scale + const]
{
instrDesc* id = nullptr;
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 want to refactor this code separately (as part of https://github.com/dotnet/coreclr/issues/15828).

Copy link
Member Author

Choose a reason for hiding this comment

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

After this is refactored, we could also rename the method to genInsBinary and move it to Codegen, which may be a more appropriate place.

// src can be anything but both src and dst cannot be addr modes
// or at least cannot be contained addr modes
if (dst->isUsedFromMemory())
if (dst->isContained() || (dst->isLclField() && (dst->gtRegNum == REG_NA)) || dst->isUsedFromSpillTemp())
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 wasn't sure why dst isn't marked as contained for (dst->isLclField() && (dst->gtRegNum == REG_NA)) (see here for the old code), it seems to map to a GT_STORE_LCL_FLD and, being a store, I would have expected it to be containable...

Choose a reason for hiding this comment

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

I'm not sure about that either.

Copy link

@mikedn mikedn Jan 18, 2018

Choose a reason for hiding this comment

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

Hmm, a contained dst is likely rare in this code path. This might worth a separate investigation to avoid surprises.

if (memOp->isIndir())
{
GenTreeIndir* memIndir = memOp->AsIndir();
GenTree* memBase = memIndir->gtOp1;
Copy link
Member Author

@tannergooding tannergooding Jan 12, 2018

Choose a reason for hiding this comment

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

I kept the old name here, but I don't think memBase is appropriate.

There is also memIndir->Base() which returns something slightly different and which is used in emitHandleMemOp

memBase = mem->gtOp1;
if (src->IsCnsIntOrI() || src->IsCnsFltOrDbl())
{
cnsOp = src;
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 originally had a assert(!src->isUsedFromMemory() || src->IsCnsFltOrDbl()); right above this. However, it appears that on x86 Checked builds, we will sometimes spill a GT_CNS_INT to the stack.

See the failure here which reported:

Assert failure(PID 4672 [0x00001240], Thread: 4644 [0x1224]): Assertion failed '!src->isUsedFromMemory() || src->IsCnsFltOrDbl()' in 'System.Diagnostics.Tracing.EventProvider:WriteEvent(byref,int,int,int,ref):bool:this' (IL size 1225)

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 was not seeing the same failure in x86 Debug or Release.

Copy link
Member Author

Choose a reason for hiding this comment

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

Looks like x86 Checked is still failing due to the stack spill. Will investigate sometime tomorrow.

Copy link
Member Author

Choose a reason for hiding this comment

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

isUsedFromSpillTemp needed to take precedence over everything else (including IsCns and IsIndir).

@mikedn
Copy link

mikedn commented Jan 12, 2018

Hmm, I have to take a closer look when I have a bit more spare time. I had something a bit different in mind, it included moving this out of emitter to CodeGen. I wonder if I kept the branch where I experimented with this...

@tannergooding
Copy link
Member Author

it included moving this out of emitter to CodeGen

I mentioned doing that above, but think it should wait until after the address mode refactoring (https://github.com/dotnet/coreclr/issues/15828) happens (so that the emitter specific code can be contained to the emitter)

Copy link

@CarolEidt CarolEidt left a comment

Choose a reason for hiding this comment

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

LGTM Would love to get another review from @dotnet/jit-contrib

// src can be anything but both src and dst cannot be addr modes
// or at least cannot be contained addr modes
if (dst->isUsedFromMemory())
if (dst->isContained() || (dst->isLclField() && (dst->gtRegNum == REG_NA)) || dst->isUsedFromSpillTemp())

Choose a reason for hiding this comment

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

I'm not sure about that either.

{
// dst can only be a reg or modrm

Choose a reason for hiding this comment

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

At this point it can only be memory, given the condition above.

@CarolEidt
Copy link

ping @dotnet/jit-contrib - This is broadly used for xarch codegen, so I think it would be good to get a second review on it. Any takers?

@tannergooding
Copy link
Member Author

@CarolEidt, which additional jobs should be run to validate this?

I imagine we want to run all or most pri-1 tests, before merging, to get the additional validation (given the broad use).

// We can only have one memory operand and only src can be a constant operand
GenTree* memOp = nullptr;
GenTree* cnsOp = nullptr;
GenTree* otrOp = nullptr;
Copy link

Choose a reason for hiding this comment

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

I guess otr is shorthand for other?

Copy link
Member Author

@tannergooding tannergooding Jan 18, 2018

Choose a reason for hiding this comment

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

Yes (happy to change if its confusing, I forgot I named it this).

Choose a reason for hiding this comment

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

I vote for a rename (IMO, "otherOp" is fine; no need for all vars to be 5 characters long)

Copy link
Member Author

Choose a reason for hiding this comment

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

fixed to be otherOp

tmpDsc = codeGen->getSpillTempDsc(src);
}
else if (dst->isUsedFromSpillTemp())
if (memOp != nullptr)
Copy link

Choose a reason for hiding this comment

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

It might have been better to first handle the simple cases to get those out of the way quicker. As is now you have to scroll through all the memOp case to reach the rest.


case GT_LCL_VAR:
{
assert(memOp->IsRegOptional() || !emitComp->lvaTable[memOp->gtLclVar.gtLclNum].lvIsRegCandidate());
Copy link

Choose a reason for hiding this comment

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

It would be better to split this assert in two. The second condition should be moved after the assignment below so it can reuse varNum.

Copy link
Member Author

Choose a reason for hiding this comment

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

It's an || condition, so it can't be split... No matter how you do the memOp->IsRegOptional() check, it can fail on its own.

Copy link
Member Author

Choose a reason for hiding this comment

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

Unless I'm just too tired to remember how to do this 😄

Copy link

Choose a reason for hiding this comment

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

Oops, missed the ||.

@AndyAyersMS
Copy link
Member

If this is a pure refactoring, then you should verify the result is no-diff.

You can use jit-diffs for this in Core but I'd also recommend running the SPMI based diffs over in desktop as they give better all around coverage of the various jit modes (jit-diffs will only test R2R codegen).

@tannergooding
Copy link
Member Author

If this is a pure refactoring, then you should verify the result is no-diff.

Is there a doc on how to do this for Desktop? Is there an easy way to do this 'en-masse' for Core?

@AndyAyersMS
Copy link
Member

Jit-diff is described here. I generally do this with two enlistments, one built vs master, the other vs my change. You need both check and release builds.

For desktop I can send you pointers via email.

@CarolEidt
Copy link

Thanks @AndyAyersMS - I think that doing both coreclr and desktop diffs would be ideal validation (and is what I usually do for refactoring changes).

@tannergooding
Copy link
Member Author

Rebased onto HEAD for the jit-diff tests.

@BruceForstall
Copy link

(This is a poster child for CI-triggered all-platform all-architecture asm diffs, including superpmi asm diffs, which was once a goal but is not being worked on currently.)

Copy link

@BruceForstall BruceForstall left a comment

Choose a reason for hiding this comment

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

  1. Make sure you trigger a bunch of x86/x64 stress mode jobs.
  2. Seems like there could be more comments, maybe including examples. I guess there weren't many before.

@@ -2920,174 +2920,283 @@ void emitter::emitInsStoreLcl(instruction ins, emitAttr attr, GenTreeLclVarCommo

regNumber emitter::emitInsBinary(instruction ins, emitAttr attr, GenTree* dst, GenTree* src)

Choose a reason for hiding this comment

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

Since you've got this function in your head now, it would be useful to write a good (standard format) function header comment describing it.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added a function header.

// We can only have one memory operand and only src can be a constant operand
GenTree* memOp = nullptr;
GenTree* cnsOp = nullptr;
GenTree* otrOp = nullptr;

Choose a reason for hiding this comment

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

I vote for a rename (IMO, "otherOp" is fine; no need for all vars to be 5 characters long)

@mikedn
Copy link

mikedn commented Jan 18, 2018

which also brings about a shrinking of the Lcl frame size

Are you sure that the diffs you are doing have a proper baseline or whatever is what they are using? It seems strange for any change to emitInsBinary to have such an effect.

@tannergooding
Copy link
Member Author

Are you sure that the diffs you are doing have a proper baseline or whatever is what they are using? It seems strange for any change to emitInsBinary to have such an effect.

Looks like emitxarch had some extra changes in it that aren't in the current TFS baseline. I'll see if I can get it back to just the emitInsBinary changes

@mikedn
Copy link

mikedn commented Jan 18, 2018

FWIW I've got your branch and run jit-diff, there are no changes.

@AndyAyersMS
Copy link
Member

Ah, I should have mentioned that you need to be careful about ensuring that your TFS enlistment is synced to the same point as your GitHub enlistment. They are usually close but the mirroring can lag or get blocked at times.

@tannergooding
Copy link
Member Author

Added a function header, some more detailed comments, and changed otrOp to otherOp.

@tannergooding
Copy link
Member Author

Ok. No diffs for CoreCLR (tested on Windows against x64 and x86 for Checked and Released builds).

I think I'm doing something wrong for the Desktop diffs and am going to follow up to see if I can figure it out.

@@ -3033,7 +3033,6 @@ regNumber emitter::emitInsBinary(instruction ins, emitAttr attr, GenTree* dst, G
offset = 0;

// Ensure that all the GenTreeIndir values are set to their defaults.
assert(memBase->gtRegNum == REG_NA);
Copy link
Member Author

Choose a reason for hiding this comment

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

Assert was incorrect. Under JitStress=1 on Windows x64 Checked we had a few tests fail.

Validated that we still want to go the emit_R_S or emit_S_R route by checking the code-diff.

@tannergooding
Copy link
Member Author

Okay:

  • No diffs on CoreCLR
  • No diffs for SuperPMI on Desktop.
  • There was an incorrect assert that was hit under JitStress1 that I removed.
  • I am running the Desktop DDR suite for validation as well.

@tannergooding
Copy link
Member Author

tannergooding commented Jan 19, 2018

Most of the Windows JITStress jobs are failing the eventsourcetrace test, which looks new and looks like it is supposed to be skipped in most places (#15917)

@tannergooding
Copy link
Member Author

The only non-eventsourcetrace test failures I see are in x86 Checked jitstressregs8, which also is failing the non-pr jobs with the same (farthestRefPhysRegRecord != nullptr)

@tannergooding
Copy link
Member Author

https://github.com/dotnet/coreclr/issues/15924 is tracking the eventsourcetrace issue.

@tannergooding
Copy link
Member Author

I am running the Desktop DDR suite for validation as well.

This finished.

I had a few failures with a failure type of Deterministic 3:NoBaseline. (I think these can be ignored, based on the failure type)

There were also no diffs (I did have a network outage that failed the amd64chk diff run, as it couldn't find the file share for the baseline, but I had already ran these manually beforehand and saw no failures).

@tannergooding
Copy link
Member Author

@CarolEidt, @AndyAyersMS, @BruceForstall

Is there any additional validation needed?

As a summary (assuming I read all the logs correctly):

  • No diffs on CoreCLR or Desktop
  • Only test failures on Desktop look to be for Deterministic 3:NoBaseline
  • JitStress failures on CoreCLR are due to an external issue and only impact a single test(https://github.com/dotnet/coreclr/issues/15924)
    • The x86 JitStressRegs=8 had failures matching the runs against master (farthestRefPhysRegRecord != nullptr)

@CarolEidt
Copy link

The only non-eventsourcetrace test failures I see are in x86 Checked jitstressregs8, which also is failing the non-pr jobs with the same (farthestRefPhysRegRecord != nullptr)

Opened #15932

I don't see the need for any further validation.

@tannergooding
Copy link
Member Author

Is there any other feedback, or does this look good to merge (@AndyAyersMS, @BruceForstall, @mikedn)?

Copy link

@BruceForstall BruceForstall left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks for the additional comments.

@tannergooding
Copy link
Member Author

Merging.

@tannergooding tannergooding merged commit 9afce33 into dotnet:master Jan 19, 2018
@tannergooding tannergooding deleted the emitInsBinary branch May 30, 2018 04:14
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.

6 participants