-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Conversation
FYI. @CarolEidt, @mikedn, @dotnet/jit-contrib |
src/jit/emitxarch.cpp
Outdated
|
||
default: // Addressing mode [regBase + regIndex * Scale + const] | ||
{ | ||
instrDesc* id = nullptr; |
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 want to refactor this code separately (as part of https://github.com/dotnet/coreclr/issues/15828).
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.
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/jit/emitxarch.cpp
Outdated
// 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()) |
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 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...
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'm not sure about that either.
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.
Hmm, a contained dst
is likely rare in this code path. This might worth a separate investigation to avoid surprises.
src/jit/emitxarch.cpp
Outdated
if (memOp->isIndir()) | ||
{ | ||
GenTreeIndir* memIndir = memOp->AsIndir(); | ||
GenTree* memBase = memIndir->gtOp1; |
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 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
src/jit/emitxarch.cpp
Outdated
memBase = mem->gtOp1; | ||
if (src->IsCnsIntOrI() || src->IsCnsFltOrDbl()) | ||
{ | ||
cnsOp = src; |
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 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)
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 was not seeing the same failure in x86 Debug or Release.
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.
Looks like x86 Checked is still failing due to the stack spill. Will investigate sometime tomorrow.
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.
isUsedFromSpillTemp
needed to take precedence over everything else (including IsCns
and IsIndir
).
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... |
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) |
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.
LGTM Would love to get another review from @dotnet/jit-contrib
src/jit/emitxarch.cpp
Outdated
// 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()) |
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'm not sure about that either.
src/jit/emitxarch.cpp
Outdated
{ | ||
// dst can only be a reg or modrm |
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.
At this point it can only be memory, given the condition above.
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? |
@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). |
src/jit/emitxarch.cpp
Outdated
// We can only have one memory operand and only src can be a constant operand | ||
GenTree* memOp = nullptr; | ||
GenTree* cnsOp = nullptr; | ||
GenTree* otrOp = nullptr; |
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 guess otr is shorthand for other?
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.
Yes (happy to change if its confusing, I forgot I named it this).
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 vote for a rename (IMO, "otherOp" is fine; no need for all vars to be 5 characters long)
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.
fixed to be otherOp
tmpDsc = codeGen->getSpillTempDsc(src); | ||
} | ||
else if (dst->isUsedFromSpillTemp()) | ||
if (memOp != nullptr) |
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.
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()); |
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.
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
.
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.
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.
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.
Unless I'm just too tired to remember how to do this 😄
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.
Oops, missed the ||
.
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). |
Is there a doc on how to do this for Desktop? Is there an easy way to do this 'en-masse' for Core? |
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. |
Thanks @AndyAyersMS - I think that doing both coreclr and desktop diffs would be ideal validation (and is what I usually do for refactoring changes). |
Rebased onto HEAD for the jit-diff tests. |
(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.) |
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.
- Make sure you trigger a bunch of x86/x64 stress mode jobs.
- Seems like there could be more comments, maybe including examples. I guess there weren't many before.
src/jit/emitxarch.cpp
Outdated
@@ -2920,174 +2920,283 @@ void emitter::emitInsStoreLcl(instruction ins, emitAttr attr, GenTreeLclVarCommo | |||
|
|||
regNumber emitter::emitInsBinary(instruction ins, emitAttr attr, GenTree* dst, GenTree* src) |
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.
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.
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.
Added a function header.
src/jit/emitxarch.cpp
Outdated
// We can only have one memory operand and only src can be a constant operand | ||
GenTree* memOp = nullptr; | ||
GenTree* cnsOp = nullptr; | ||
GenTree* otrOp = nullptr; |
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 vote for a rename (IMO, "otherOp" is fine; no need for all vars to be 5 characters long)
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 |
Looks like |
FWIW I've got your branch and run jit-diff, there are no changes. |
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. |
Added a function header, some more detailed comments, and changed |
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. |
src/jit/emitxarch.cpp
Outdated
@@ -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); |
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.
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.
Okay:
|
Most of the Windows JITStress jobs are failing the |
The only non- |
https://github.com/dotnet/coreclr/issues/15924 is tracking the |
This finished. I had a few failures with a failure type of 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). |
@CarolEidt, @AndyAyersMS, @BruceForstall Is there any additional validation needed? As a summary (assuming I read all the logs correctly):
|
Opened #15932 I don't see the need for any further validation. |
Is there any other feedback, or does this look good to merge (@AndyAyersMS, @BruceForstall, @mikedn)? |
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.
LGTM. Thanks for the additional comments.
Merging. |
Resolves https://github.com/dotnet/coreclr/issues/15829