Skip to content

Conversation

@EgorBo
Copy link
Member

@EgorBo EgorBo commented Apr 29, 2020

I am not a codegen expert and just trying to learn this stuff through mistakes and your feedback. I wonder if this is a correct way to optimize y=x<0 to y=x>>31 (when y is not a jump condition - in that case test is used)

static bool Test_sbyte(sbyte a) => a < 0;
static bool Test_short(short a) => a < 0;
static bool Test_int(int a) => a < 0;
static bool Test_long(long a) => a < 0;

Before

; Method Test_sbyte(byte):bool
       480FBEC1             movsx    rax, cl
       85C0                 test     eax, eax
       0F9CC0               setl     al
       0FB6C0               movzx    rax, al
       C3                   ret      
; Total bytes of code: 13

; Method Test_short(short):bool
       480FBFC1             movsx    rax, cx
       85C0                 test     eax, eax
       0F9CC0               setl     al
       0FB6C0               movzx    rax, al
       C3                   ret      
; Total bytes of code: 13

; Method Test_int(int):bool
       85C9                 test     ecx, ecx
       0F9CC0               setl     al
       0FB6C0               movzx    rax, al
       C3                   ret      
; Total bytes of code: 9

; Method Test_long(long):bool
       4885C9               test     rcx, rcx
       0F9CC0               setl     al
       0FB6C0               movzx    rax, al
       C3                   ret      
; Total bytes of code: 10

After

; Method Test_sbyte(byte):bool
       480FBEC1             movsx    rax, cl
       C1E81F               shr      eax, 31
       C3                   ret      
; Total bytes of code: 8

; Method Test_short(short):bool
       480FBFC1             movsx    rax, cx
       C1E81F               shr      eax, 31
       C3                   ret      
; Total bytes of code: 8

; Method Test_int(int):bool
       488BC1               mov      rax, rcx
       C1E81F               shr      eax, 31
       C3                   ret      
; Total bytes of code: 7

; Method Test_long(long):bool
       488BC1               mov      rax, rcx
       48C1E83F             shr      rax, 63
       C3                   ret      
; Total bytes of code: 8

jit-diff (-f -pmi)

C:\prj>jit-diff diff --output C:\prj\jitdiffs -f --core_root C:\prj\runtime-1\artifacts\tests\coreclr\Windows_NT.x64.Release\Tests\Core_Root --base C:\prj\runtime-1\artifacts\bin\coreclr\Windows_NT.x64.Checked_base --diff C:\prj\runtime-1\artifacts\bin\coreclr\Windows_NT.x64.Checked --pmi
Beginning PMI CodeSize Diffs for System.Private.CoreLib.dll, framework assemblies
/ Finished 267/267 Base 267/267 Diff [345.4 sec]
Completed PMI CodeSize Diffs for System.Private.CoreLib.dll, framework assemblies in 345.57s
Diffs (if any) can be viewed by comparing: C:\prj\jitdiffs\dasmset_4\base C:\prj\jitdiffs\dasmset_4\diff
Analyzing CodeSize diffs...
Found 76 files with textual diffs.
PMI CodeSize Diffs for System.Private.CoreLib.dll, framework assemblies for  default jit
Summary of Code Size diffs:
(Lower is better)
Total bytes of diff: -2451 (-0.00% of base)
    diff is an improvement.
Top file improvements (bytes):
        -282 : System.Private.CoreLib.dasm (-0.01% of base)
        -244 : Microsoft.CodeAnalysis.dasm (-0.01% of base)
        -224 : Microsoft.CodeAnalysis.CSharp.dasm (-0.01% of base)
        -208 : System.Collections.Immutable.dasm (-0.02% of base)
        -179 : System.Collections.dasm (-0.04% of base)
        -173 : System.Runtime.Numerics.dasm (-0.24% of base)
        -112 : Microsoft.CodeAnalysis.VisualBasic.dasm (-0.00% of base)
         -96 : Newtonsoft.Json.dasm (-0.01% of base)
         -96 : System.Linq.dasm (-0.01% of base)
         -92 : System.Data.Common.dasm (-0.01% of base)
         -59 : FSharp.Core.dasm (-0.00% of base)
         -45 : System.Security.Cryptography.Primitives.dasm (-0.13% of base)
         -42 : System.Memory.dasm (-0.02% of base)
         -33 : System.Reflection.MetadataLoadContext.dasm (-0.02% of base)
         -32 : System.Linq.Parallel.dasm (-0.00% of base)
         -26 : System.Configuration.ConfigurationManager.dasm (-0.01% of base)
         -26 : System.Linq.Expressions.dasm (-0.00% of base)
         -24 : System.Data.OleDb.dasm (-0.01% of base)
         -23 : System.IO.Compression.dasm (-0.03% of base)
         -23 : xunit.runner.utility.netcoreapp10.dasm (-0.01% of base)
75 total files with Code Size differences (75 improved, 0 regressed), 192 unchanged.
Top method improvements (bytes):
         -45 (-1.71% of base) : Microsoft.CodeAnalysis.CSharp.dasm - Binder:CheckConstantBounds(byte,Decimal):bool
         -35 (-0.85% of base) : System.Security.Cryptography.Primitives.dasm - AsymmetricAlgorithm:ExportArray(ReadOnlySpan`1,PbeParameters,TryExportPbe`1):ref (7 methods)
         -30 (-17.86% of base) : Microsoft.CodeAnalysis.dasm - <>c__DisplayClass27_0:<GetSyntaxNodesToAnalyze>b__0(SyntaxNode):bool:this (6 methods)
         -30 (-4.71% of base) : System.Runtime.Numerics.dasm - BigInteger:op_Multiply(BigInteger,BigInteger):BigInteger
         -28 (-1.48% of base) : Newtonsoft.Json.dasm - JsonTextWriter:DoWriteValueAsync(Nullable`1,CancellationToken):Task:this (15 methods)
         -26 (-6.68% of base) : Microsoft.CodeAnalysis.dasm - ConstantValue:get_IsNegativeNumeric():bool:this
         -23 (-1.93% of base) : System.IO.Compression.dasm - Zip64ExtraField:TryGetZip64BlockFromGenericExtraField(ZipGenericExtraField,bool,bool,bool,bool,byref):bool
         -21 (-20.00% of base) : System.Collections.Concurrent.dasm - WorkStealingQueue:get_IsEmpty():bool:this (7 methods)
         -21 (-2.95% of base) : System.Collections.dasm - SortedList`2:System.Collections.IDictionary.Contains(Object):bool:this (7 methods)
         -21 (-6.98% of base) : System.Collections.dasm - SortedList`2:ContainsValue(long):bool:this (7 methods)
         -21 (-8.11% of base) : System.Collections.dasm - ValueList:Contains(long):bool:this (7 methods)
         -21 (-1.75% of base) : System.Collections.Immutable.dasm - ImmutableArray`1:System.Collections.IList.Contains(Object):bool:this (7 methods)
         -21 (-2.56% of base) : System.Collections.Immutable.dasm - Builder:System.Collections.IList.Contains(Object):bool:this (7 methods)
         -21 (-0.36% of base) : System.Collections.Immutable.dasm - Enumerator:.ctor(Node,Builder,int,int,bool):this (7 methods)
         -21 (-1.73% of base) : System.Linq.dasm - EnumerableHelpers:TryGetCount(IEnumerable`1,byref):bool (7 methods)
         -21 (-6.98% of base) : System.Linq.dasm - Grouping`2:System.Collections.Generic.ICollection<TElement>.Contains(long):bool:this (7 methods)
         -21 (-0.38% of base) : System.Linq.Parallel.dasm - NullableDecimalMinMaxAggregationOperatorEnumerator`1:MoveNextCore(byref):bool:this (7 methods)
         -21 (-1.42% of base) : System.Private.CoreLib.dasm - HashSet`1:IsSubsetOf(IEnumerable`1):bool:this (7 methods)
         -18 (-0.19% of base) : Microsoft.CodeAnalysis.dasm - AnalyzerExecutor:ExecuteCodeBlockActionsCore(IEnumerable`1,IEnumerable`1,IEnumerable`1,DiagnosticAnalyzer,SyntaxNode,ISymbol,ImmutableArray`1,SemanticModel,Func`2,CodeBlockAnalyzerStateData):this (6 methods)
         -18 (-0.69% of base) : Microsoft.CodeAnalysis.dasm - AnalyzerExecutor:ExecuteSyntaxNodeActions(IEnumerable`1,IDictionary`2,SemanticModel,Func`2,Action`1,SyntaxNodeAnalyzerStateData):this (6 methods)
Top method improvements (percentages):
          -6 (-33.33% of base) : System.Private.CoreLib.dasm - Double:IsNegative(double):bool
          -5 (-31.25% of base) : System.Private.CoreLib.dasm - Half:IsNegative(Half):bool
          -5 (-31.25% of base) : System.Private.CoreLib.dasm - Single:IsNegative(float):bool
          -5 (-22.73% of base) : System.Private.CoreLib.dasm - Decimal:op_LessThan(Decimal,Decimal):bool
          -5 (-22.73% of base) : System.Private.Xml.Linq.dasm - XNode:IsBefore(XNode):bool:this
          -5 (-22.73% of base) : System.Runtime.Numerics.dasm - BigInteger:op_LessThan(BigInteger,BigInteger):bool
         -10 (-22.73% of base) : System.Runtime.Numerics.dasm - BigInteger:op_LessThan(BigInteger,long):bool (2 methods)
         -21 (-20.00% of base) : System.Collections.Concurrent.dasm - WorkStealingQueue:get_IsEmpty():bool:this (7 methods)
          -5 (-17.86% of base) : Microsoft.CodeAnalysis.CSharp.dasm - <>c__DisplayClass153_0:<FilterOverriddenOrHiddenMethods>b__0(MethodSymbol):bool:this
         -30 (-17.86% of base) : Microsoft.CodeAnalysis.dasm - <>c__DisplayClass27_0:<GetSyntaxNodesToAnalyze>b__0(SyntaxNode):bool:this (6 methods)
          -5 (-17.86% of base) : xunit.execution.dotnet.dasm - XunitTestClassRunner:<CreateClassFixtureAsync>b__11_0(IAsyncLifetime):bool:this
         -10 (-16.13% of base) : System.Runtime.Numerics.dasm - BigInteger:op_GreaterThan(long,BigInteger):bool (2 methods)
          -5 (-15.62% of base) : System.ComponentModel.Composition.dasm - CatalogChangeProxy:<GetExports>b__5_0(Tuple`2):bool:this
          -3 (-13.64% of base) : Microsoft.Extensions.Primitives.dasm - StringValues:System.Collections.Generic.ICollection<System.String>.Contains(String):bool:this
          -3 (-13.64% of base) : System.Collections.dasm - SortedList`2:ContainsKey(__Canon):bool:this
          -3 (-13.64% of base) : System.Collections.dasm - SortedList`2:ContainsKey(int):bool:this
          -3 (-13.64% of base) : System.Collections.dasm - SortedList`2:ContainsKey(Vector`1):bool:this
          -3 (-13.64% of base) : System.Collections.dasm - SortedList`2:ContainsKey(long):bool:this
          -3 (-13.64% of base) : System.ComponentModel.Composition.dasm - WeakReferenceCollection`1:Contains(__Canon):bool:this
          -3 (-13.64% of base) : System.Data.Common.dasm - ConstraintCollection:Contains(String):bool:this
666 total methods with Code Size differences (666 improved, 0 regressed), 258004 unchanged.
Completed analysis in 34.73s

@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 29, 2020
@a-tk-by
Copy link

a-tk-by commented Apr 30, 2020

Since .NET uses eax register in x64 mode to return boolean you don't need to extend cl/cx register to rax. eax is enough, so there is no need for 48 prefix in opcode.

@BruceForstall
Copy link
Contributor

@dotnet/jit-contrib

@EgorBo
Copy link
Member Author

EgorBo commented Sep 21, 2020

New jit-diff (there are no regressions):

C:\prj>jit-diff diff --output C:\prj\jitdiffs -f --core_root C:\prj\runtime-1\artifacts\tests\coreclr\Windows_NT.x64.Release\Tests\Core_Root --base C:\prj\runtime-1\artifacts\bin\coreclr\Windows_NT.x64.Checked_base --diff C:\prj\runtime-1\artifacts\bin\coreclr\Windows_NT.x64.Checked --pmi
Beginning PMI CodeSize Diffs for System.Private.CoreLib.dll, framework assemblies
/ Finished 267/267 Base 267/267 Diff [345.4 sec]
Completed PMI CodeSize Diffs for System.Private.CoreLib.dll, framework assemblies in 345.57s
Diffs (if any) can be viewed by comparing: C:\prj\jitdiffs\dasmset_4\base C:\prj\jitdiffs\dasmset_4\diff
Analyzing CodeSize diffs...
Found 76 files with textual diffs.
PMI CodeSize Diffs for System.Private.CoreLib.dll, framework assemblies for  default jit
Summary of Code Size diffs:
(Lower is better)
Total bytes of diff: -2451 (-0.00% of base)
    diff is an improvement.
Top file improvements (bytes):
        -282 : System.Private.CoreLib.dasm (-0.01% of base)
        -244 : Microsoft.CodeAnalysis.dasm (-0.01% of base)
        -224 : Microsoft.CodeAnalysis.CSharp.dasm (-0.01% of base)
        -208 : System.Collections.Immutable.dasm (-0.02% of base)
        -179 : System.Collections.dasm (-0.04% of base)
        -173 : System.Runtime.Numerics.dasm (-0.24% of base)
        -112 : Microsoft.CodeAnalysis.VisualBasic.dasm (-0.00% of base)
         -96 : Newtonsoft.Json.dasm (-0.01% of base)
         -96 : System.Linq.dasm (-0.01% of base)
         -92 : System.Data.Common.dasm (-0.01% of base)
         -59 : FSharp.Core.dasm (-0.00% of base)
         -45 : System.Security.Cryptography.Primitives.dasm (-0.13% of base)
         -42 : System.Memory.dasm (-0.02% of base)
         -33 : System.Reflection.MetadataLoadContext.dasm (-0.02% of base)
         -32 : System.Linq.Parallel.dasm (-0.00% of base)
         -26 : System.Configuration.ConfigurationManager.dasm (-0.01% of base)
         -26 : System.Linq.Expressions.dasm (-0.00% of base)
         -24 : System.Data.OleDb.dasm (-0.01% of base)
         -23 : System.IO.Compression.dasm (-0.03% of base)
         -23 : xunit.runner.utility.netcoreapp10.dasm (-0.01% of base)
75 total files with Code Size differences (75 improved, 0 regressed), 192 unchanged.
Top method improvements (bytes):
         -45 (-1.71% of base) : Microsoft.CodeAnalysis.CSharp.dasm - Binder:CheckConstantBounds(byte,Decimal):bool
         -35 (-0.85% of base) : System.Security.Cryptography.Primitives.dasm - AsymmetricAlgorithm:ExportArray(ReadOnlySpan`1,PbeParameters,TryExportPbe`1):ref (7 methods)
         -30 (-17.86% of base) : Microsoft.CodeAnalysis.dasm - <>c__DisplayClass27_0:<GetSyntaxNodesToAnalyze>b__0(SyntaxNode):bool:this (6 methods)
         -30 (-4.71% of base) : System.Runtime.Numerics.dasm - BigInteger:op_Multiply(BigInteger,BigInteger):BigInteger
         -28 (-1.48% of base) : Newtonsoft.Json.dasm - JsonTextWriter:DoWriteValueAsync(Nullable`1,CancellationToken):Task:this (15 methods)
         -26 (-6.68% of base) : Microsoft.CodeAnalysis.dasm - ConstantValue:get_IsNegativeNumeric():bool:this
         -23 (-1.93% of base) : System.IO.Compression.dasm - Zip64ExtraField:TryGetZip64BlockFromGenericExtraField(ZipGenericExtraField,bool,bool,bool,bool,byref):bool
         -21 (-20.00% of base) : System.Collections.Concurrent.dasm - WorkStealingQueue:get_IsEmpty():bool:this (7 methods)
         -21 (-2.95% of base) : System.Collections.dasm - SortedList`2:System.Collections.IDictionary.Contains(Object):bool:this (7 methods)
         -21 (-6.98% of base) : System.Collections.dasm - SortedList`2:ContainsValue(long):bool:this (7 methods)
         -21 (-8.11% of base) : System.Collections.dasm - ValueList:Contains(long):bool:this (7 methods)
         -21 (-1.75% of base) : System.Collections.Immutable.dasm - ImmutableArray`1:System.Collections.IList.Contains(Object):bool:this (7 methods)
         -21 (-2.56% of base) : System.Collections.Immutable.dasm - Builder:System.Collections.IList.Contains(Object):bool:this (7 methods)
         -21 (-0.36% of base) : System.Collections.Immutable.dasm - Enumerator:.ctor(Node,Builder,int,int,bool):this (7 methods)
         -21 (-1.73% of base) : System.Linq.dasm - EnumerableHelpers:TryGetCount(IEnumerable`1,byref):bool (7 methods)
         -21 (-6.98% of base) : System.Linq.dasm - Grouping`2:System.Collections.Generic.ICollection<TElement>.Contains(long):bool:this (7 methods)
         -21 (-0.38% of base) : System.Linq.Parallel.dasm - NullableDecimalMinMaxAggregationOperatorEnumerator`1:MoveNextCore(byref):bool:this (7 methods)
         -21 (-1.42% of base) : System.Private.CoreLib.dasm - HashSet`1:IsSubsetOf(IEnumerable`1):bool:this (7 methods)
         -18 (-0.19% of base) : Microsoft.CodeAnalysis.dasm - AnalyzerExecutor:ExecuteCodeBlockActionsCore(IEnumerable`1,IEnumerable`1,IEnumerable`1,DiagnosticAnalyzer,SyntaxNode,ISymbol,ImmutableArray`1,SemanticModel,Func`2,CodeBlockAnalyzerStateData):this (6 methods)
         -18 (-0.69% of base) : Microsoft.CodeAnalysis.dasm - AnalyzerExecutor:ExecuteSyntaxNodeActions(IEnumerable`1,IDictionary`2,SemanticModel,Func`2,Action`1,SyntaxNodeAnalyzerStateData):this (6 methods)
Top method improvements (percentages):
          -6 (-33.33% of base) : System.Private.CoreLib.dasm - Double:IsNegative(double):bool
          -5 (-31.25% of base) : System.Private.CoreLib.dasm - Half:IsNegative(Half):bool
          -5 (-31.25% of base) : System.Private.CoreLib.dasm - Single:IsNegative(float):bool
          -5 (-22.73% of base) : System.Private.CoreLib.dasm - Decimal:op_LessThan(Decimal,Decimal):bool
          -5 (-22.73% of base) : System.Private.Xml.Linq.dasm - XNode:IsBefore(XNode):bool:this
          -5 (-22.73% of base) : System.Runtime.Numerics.dasm - BigInteger:op_LessThan(BigInteger,BigInteger):bool
         -10 (-22.73% of base) : System.Runtime.Numerics.dasm - BigInteger:op_LessThan(BigInteger,long):bool (2 methods)
         -21 (-20.00% of base) : System.Collections.Concurrent.dasm - WorkStealingQueue:get_IsEmpty():bool:this (7 methods)
          -5 (-17.86% of base) : Microsoft.CodeAnalysis.CSharp.dasm - <>c__DisplayClass153_0:<FilterOverriddenOrHiddenMethods>b__0(MethodSymbol):bool:this
         -30 (-17.86% of base) : Microsoft.CodeAnalysis.dasm - <>c__DisplayClass27_0:<GetSyntaxNodesToAnalyze>b__0(SyntaxNode):bool:this (6 methods)
          -5 (-17.86% of base) : xunit.execution.dotnet.dasm - XunitTestClassRunner:<CreateClassFixtureAsync>b__11_0(IAsyncLifetime):bool:this
         -10 (-16.13% of base) : System.Runtime.Numerics.dasm - BigInteger:op_GreaterThan(long,BigInteger):bool (2 methods)
          -5 (-15.62% of base) : System.ComponentModel.Composition.dasm - CatalogChangeProxy:<GetExports>b__5_0(Tuple`2):bool:this
          -3 (-13.64% of base) : Microsoft.Extensions.Primitives.dasm - StringValues:System.Collections.Generic.ICollection<System.String>.Contains(String):bool:this
          -3 (-13.64% of base) : System.Collections.dasm - SortedList`2:ContainsKey(__Canon):bool:this
          -3 (-13.64% of base) : System.Collections.dasm - SortedList`2:ContainsKey(int):bool:this
          -3 (-13.64% of base) : System.Collections.dasm - SortedList`2:ContainsKey(Vector`1):bool:this
          -3 (-13.64% of base) : System.Collections.dasm - SortedList`2:ContainsKey(long):bool:this
          -3 (-13.64% of base) : System.ComponentModel.Composition.dasm - WeakReferenceCollection`1:Contains(__Canon):bool:this
          -3 (-13.64% of base) : System.Data.Common.dasm - ConstraintCollection:Contains(String):bool:this
666 total methods with Code Size differences (666 improved, 0 regressed), 258004 unchanged.
Completed analysis in 34.73s

@EgorBo
Copy link
Member Author

EgorBo commented Sep 22, 2020

@CarolEidt should be better now: x86 support is checked, x>=0 case is added, PR is green.

Copy link
Contributor

@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 - thanks @EgorBo !

@sandreenko
Copy link
Contributor

sandreenko commented Nov 25, 2020

I suspect this change has broken such CMP in minopts:

N004 (  1,  1) [000002] ------------         t2 =    CNS_INT   int    -1 REG rax
N006 (  1,  1) [000001] -c----------         t1 =    CNS_INT   int    0 REG NA
                                                  /--*  t2     int    
                                                  +--*  t1     int    
N008 (  6,  3) [000003] N--------U--         t3 = *  GE        int    REG rax // note that it is unsigned, the expected value is true

the generated code is:

IN0001:        mov      eax, -1 // 0xFFFF
IN0002:        not      eax // 0x0000
IN0003:        shr      eax, 31 // 0x0000 where we expect 0x0001

This was found during library stress runs: #42719

I have attached a minimal repo
Runtime_42719.txt

@EgorBo could you please take a look?

@EgorBo
Copy link
Member Author

EgorBo commented Nov 25, 2020

Sure! I'm taking a look now.

@ghost ghost locked as resolved and limited conversation to collaborators Dec 25, 2020
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.

6 participants