- Notifications
You must be signed in to change notification settings - Fork5.2k
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
AndyAyersMS commentedFeb 9, 2020
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. |
damageboy commentedFeb 10, 2020
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 15Found 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 diffsSystem.Private.Uri.dasm had 140 diffsSystem.Diagnostics.Process.dasm had 70 diffsSystem.Private.Xml.Linq.dasm had 58 diffsSystem.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, thefailing check isn't making a lot of sense to me. |
AndyAyersMS commentedFeb 10, 2020
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 |
EgorBo commentedFeb 10, 2020 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Isn't it useful to normalize booleans (e.g. from pinvokes) to 0..1 ? However, it seemsRoslyn already optimizes bytepinvoke_bool=2;// e.g. a bool from a pinvokebooltmp=*(bool*)&pinvoke_bool;tmp=!!tmp;// normalizeConsole.WriteLine(*((byte*)&tmp));// stil prints 2 See anothertrick; |
damageboy commentedFeb 10, 2020
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. |
AndyAyersMS commentedFeb 10, 2020
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 |
stephentoub commentedSep 18, 2020
@damageboy, are you still working on this? |
damageboy commentedSep 18, 2020
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 |
stephentoub commentedSep 18, 2020
@AndyAyersMS, how should@damageboy proceed? Thanks. |
EgorBo commentedSep 18, 2020
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 |
AndyAyersMS commentedSep 18, 2020
The change itself looks fine, so please do restart. You will need to move the new test under |
damageboy commentedSep 19, 2020
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? |
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
EgorBo commentedSep 19, 2020 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Also, since Roslyn optimizes double NOT I'd allow it in JIT too, something like this: caseGT_NOT:caseGT_NEG:// Remove double negationif (op1->OperIs(oper)) {returnop1->AsOp()->gtGetOp1(); }/* Any constant cases should have been folded earlier */noway_assert(!op1->OperIsConst()|| !opts.OptEnabled(CLFLG_CONSTANTFOLD)||optValnumCSE_phase);break; |
906eb68 todc3c275Comparedamageboy commentedSep 21, 2020
Thanks for the comments,@EgorBo. I think the current state of affairs addresses your feedback. |
damageboy commentedSep 21, 2020
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 coverNOT(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.
damageboy commentedSep 22, 2020
@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)]staticboolNegationBool(boolvalue)=>!value; How do you suggest I proceed? an MSIL based test? |
AndyAyersMS commentedSep 22, 2020
Here's a simple test case: usingSystem;usingSystem.Runtime.CompilerServices;classX{staticintNot(intx)=>~x;[MethodImpl(MethodImplOptions.NoInlining)]staticintNotNot(intx)=>Not(Not(x));publicstaticintMain(){returnNotNot(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 = 0G_M60739_IG01: ;; bbWeight=1 PerfScore 0.00G_M60739_IG02: 8BC1moveax,ecx F7D0noteax F7D0noteax ;; bbWeight=1 PerfScore 0.75G_M60739_IG03: C3ret ;; bbWeight=1 PerfScore 1.00 |
0b6a12f tob2827aaComparedamageboy commentedSep 23, 2020
@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: staticboolTest3(){varx=DoubleNotInt(6);vary=DoubleNotInt(DoubleNotInt(DoubleNotInt(x)));varz=DoubleNotInt(_dummyValueInt);if(x==6&&y==6&&z==6)returntrue;returnfalse;}[MethodImpl(MethodImplOptions.AggressiveOptimization|MethodImplOptions.AggressiveInlining)]staticintNotInt(intvalue)=>~value;[MethodImpl(MethodImplOptions.AggressiveOptimization|MethodImplOptions.AggressiveInlining)]staticintDoubleNotInt(intvalue)=>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? |
AndyAyersMS commentedSep 23, 2020
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!
AndyAyersMS commentedSep 23, 2020
Going to restart the failed test legs... not sure what is going on. Looks like lots of timeouts. |
AndyAyersMS commentedSep 24, 2020
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()) |
damageboy commentedSep 24, 2020
Will do and report here.
Sounds good, will do. |
-fixesdotnet#13647- Deals with arithmetic negation as well as bitwise-not- Co-authored with@EgorBo holding my hand :)
AndyAyersMS commentedSep 24, 2020
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. |
damageboy commentedSep 24, 2020
Sure. I'll also try to get the python superpmi.py thingy going, no such luck for now. |
AndyAyersMS commentedSep 24, 2020
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.