-
Notifications
You must be signed in to change notification settings - Fork 5.3k
JIT: Remove double-negation during morph phase #32000
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
Conversation
|
See if this helps. Windows x64-centric, but steps are fairly similar on other arches or on Linux (and/or you can use an altjit). cc @dotnet/jit-contrib -- we should have something like this in a more official place. running jit diffsSteps are
Presumes you have two clones of the runtime repo: base (on master) and diff (branched from same commit as master with only jit changes). You probably can get by with one runtime repo clone via Steps 1 and 2 don't need to be rerun when you are making incremental jit changes in the diff repo; just redo steps 3 and 4 to get new diffs. If you are also altering framework or vm code in your diff clone, things are more complex; in step 4 you must run base and diff independently, each in its respective core_root, and then run 1. obtain tools2. build base repo runtimeThen build the test environment only or optionally build the test environment and all the coreclr pri0 tests or optionally build the test environment and all the coreclr pri0 and pri1 tests Then build a checked runtime and test environment 3. build diff repo runtimeFirst time: Subsequently (when you've just changed jit files), you can skip the release build: 4. run jit-dffsThis is what I commonly run (PMI diffs across all FX). We should fix jit-diff so it can find core_root on its own. You can also use a checked runtime as the core_root, but it's considerably slower and you will see debug assert codegen in SPC. For other options try For instance, to look at diffs in a particular assembly (say test cases you've created): If you built tests in step 2 above, you can also diff over the tests, or just the benchmark subset. Diffing over all tests is sometimes a bit noisy, there are "expected failures", but they should be common to base and diff. |
|
I ended up following the steps mentioned by @EgorBo in: What I get is: $ ~/projects/public/jitutils/bin/jit-analyze -b /tmp/jitdiff/dasmset_1/base -d /tmp/jitdiff/dasmset_2/base -r -c 15
Found 5 files with textual diffs.
Summary of Code Size diffs:
(Lower is better)
Total bytes of diff: 0 (0.000% of base)
0 total files with Code Size differences (0 improved, 0 regressed), 161 unchanged.
0 total methods with Code Size differences (0 improved, 0 regressed), 291049 unchanged.
5 files had text diffs but no metric diffs.
System.Private.CoreLib.dasm had 2510 diffs
System.Private.Uri.dasm had 140 diffs
System.Diagnostics.Process.dasm had 70 diffs
System.Private.Xml.Linq.dasm had 58 diffs
System.Management.dasm had 4 diffsIs that the sort of output you accept/expect? I can also follow the instructions by @AndyAyersMS (I will do it anyway for practice). Also, the failing check isn't making a lot of sense to me. |
|
Yes, that's the kind of output we're looking for. It tells us there likely aren't any examples of this in the framework assemblies. So you might consider adding a new test, or adding an example of this to some existing test. Seems like |
Isn't it useful to normalize booleans (e.g. from pinvokes) to 0..1 ? However, it seems Roslyn already optimizes byte pinvoke_bool = 2; // e.g. a bool from a pinvoke
bool tmp = *(bool*) &pinvoke_bool;
tmp = !!tmp; // normalize
Console.WriteLine(*((byte*)&tmp)); // stil prints 2See another trick; |
As for adding a specific test, sure I'll give it a try. I assume it's OK if the test is part of the PR and then doesn't appear in the JIT diff? Kind of new to this, trying to wrap my head as to what is considered the standard procedure here. |
|
You can run jit diffs over all the tests but since we usually use the "before" runtime repo as the baseline, this won't show diffs in your newly added tests. But you may discover cases in already existing tests. I usually just run diffs on new tests in isolation, via the
You can separate the |
104a0cb to
42aff28
Compare
|
@damageboy, are you still working on this? |
Well, last I left this, there was little to do, but I forgot to push it in terms of discussion and pinging people. I can drop this, or try to restart for 6.0 |
|
@AndyAyersMS, how should @damageboy proceed? Thanks. |
|
I noticed that this pattern sometimes is used to blame jit for lack of peephole optimizations 😄 so would be nice to merge especially because the change is just a few lines of code |
|
The change itself looks fine, so please do restart. You will need to move the new test under |
42aff28 to
44b5e43
Compare
|
I've rebased everything but still having some build issues with the tests per-se. I'll give it another try on a different machine. The failing test on AZP seem... unrelated? How should I proceed? |
|
Also, since Roslyn optimizes double NOT I'd allow it in JIT too, something like this: case GT_NOT:
case GT_NEG:
// Remove double negation
if (op1->OperIs(oper))
{
return op1->AsOp()->gtGetOp1();
}
/* Any constant cases should have been folded earlier */
noway_assert(!op1->OperIsConst() || !opts.OptEnabled(CLFLG_CONSTANTFOLD) || optValnumCSE_phase);
break; |
906eb68 to
dc3c275
Compare
|
Thanks for the comments, @EgorBo. I think the current state of affairs addresses your feedback. |
|
Hi, I think I'm done with this. Let me know what you want me to do with this...? |
AndyAyersMS
left a comment
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.
Thanks for the updates. Left a few comments.
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.
You can just delete these lines -- then might as well move the <DebugType> up to the first property group.
<!-- Set to 'Full' if the Debug? column is marked in the spreadsheet. Leave blank otherwise. -->
<NoStandardLib>True</NoStandardLib>
<Noconfig>True</Noconfig>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<GCStressIncompatible>true</GCStressIncompatible>
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.
Sure thing, will do.
src/coreclr/src/jit/morph.cpp
Outdated
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.
Were you going to extend this to also cover NOT(NOT(...) ?
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.
Sure thing. Will do.
|
@AndyAyersMS: I've implemented the same logic for GT_NOT, but Roslyn is currently isn't generating MSIL that would trigger [MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
static bool NegationBool(bool value) => !value;How do you suggest I proceed? an MSIL based test? |
|
Here's a simple test case: using System;
using System.Runtime.CompilerServices;
class X
{
static int Not(int x) => ~x;
[MethodImpl(MethodImplOptions.NoInlining)]
static int NotNot(int x) => Not(Not(x));
public static int Main()
{
return NotNot(100);
}
}we currently produce ; Assembly listing for method X:NotNot(int):int
; Emitting BLENDED_CODE for X64 CPU with AVX - Windows
; optimized code
; rsp based frame
; partially interruptible
; Final local variable assignments
;
; V00 arg0 [V00,T00] ( 3, 3 ) int -> rcx
;# V01 OutArgs [V01 ] ( 1, 1 ) lclBlk ( 0) [rsp+0x00] "OutgoingArgSpace"
;* V02 tmp1 [V02 ] ( 0, 0 ) int -> zero-ref "Inlining Arg"
;
; Lcl frame size = 0
G_M60739_IG01:
;; bbWeight=1 PerfScore 0.00
G_M60739_IG02:
8BC1 mov eax, ecx
F7D0 not eax
F7D0 not eax
;; bbWeight=1 PerfScore 0.75
G_M60739_IG03:
C3 ret
;; bbWeight=1 PerfScore 1.00 |
0b6a12f to
b2827aa
Compare
|
@AndyAyersMS Thanks, I've tested this now locally, and I see the code triggered (e.g. during breakpoint) and working as expected, as well as JitDumps for the new test case in the For the test code: static bool Test3()
{
var x = DoubleNotInt(6);
var y =
DoubleNotInt(
DoubleNotInt(
DoubleNotInt(x)));
var z = DoubleNotInt(_dummyValueInt);
if (x == 6 && y == 6 && z == 6)
return true;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
static int NotInt(int value) => ~value;
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
static int DoubleNotInt(int value) => NotInt(NotInt(value));I now see the following as part of the new JitDump: Is there anything else you would like to see that you feel is missing? |
|
Thanks, this looks good. We've just made a bunch of automation investments to simplify some aspects of running diffs, so you are welcome to try using those (you'd need to merge your local branch up to the tip and possibly rebuild the jit). Running diffs should now be as simple as running from the root of the repo. I don't expect any diffs from your changes above, but you never know. |
AndyAyersMS
left a comment
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.
Thanks for the improvements!
|
Going to restart the failed test legs... not sure what is going on. Looks like lots of timeouts. |
|
Wondering if these failures are actually related. We're doing this optimization even for debug codegen which is probably not a great idea. You should add if ((oper == GT_NEG) && op1->OperIs(GT_NEG) && opts.OptimizationEnabled())also we know already if (op1->OperIs(GT_NEG) && opts.OptimizationEnabled())and perhaps follow Egor's suggestion and fold the NOT/NEG cases together, via if (op1->OperIs(oper) && opts.OptimizationEnabled()) |
Will do and report here.
Sounds good, will do. |
- fixes dotnet#13647 - Deals with arithmetic negation as well as bitwise-not - Co-authored with @EgorBo holding my hand :)
b2827aa to
ac46299
Compare
|
Latest looks good. I'd encourage you in the future to just let the PR accumulate commits. We require squash on merge so all this is just for PR purposes -- I find seeing the incremental progress helps me review things better. |
Sure. I'll also try to get the python superpmi.py thingy going, no such luck for now. |
Since the changes look good I'm going to merge. Keep us updated on how it's going with local testing and/or using the new spmi scripts; there may be some rough edges there we need to address. |
This is a continuation/redo of:
dotnet/coreclr#27779
I've tried figuring out how to run jit-diffs, but it isn't easy for me to figure out how to build the tests on which the jit-diff is supposed to run in the current/new runtime super-repo.
If anyone has proper links to any sample of how to get this done, I'll be happy to try and get some jit-diffing to work, and post results here.