JIT: Optimize range checks for a[i & C], a[i % c] and a[(i & c1)>>c2)] patterns by EgorBo · Pull Request #1644 · dotnet/runtime (original) (raw)

static ReadOnlySpan span => new byte[] { 1,2,3,4 };

byte Case1(int i) => span[i & 2]; byte Case2(int i) => span[i & (span.Length - 1)]; // "i & 3" byte Case3(int i) => span[(i & 10) >> 2]; // or << byte Case4(uint i) => span[(int)(i % 2)]; // only for unsigned i

This PR currently handles only &, % and >> operators with constant op2 and ignores actual range of op1 (always sets 0 as a lower limit and op2->IconValue() as an upper limit) to keep this PR simple and harmless.

Total bytes of diff: -133 (-0.00% of base)
    diff is an improvement.

Top file improvements by size (bytes):
         -69 : System.Private.CoreLib.dasm (-0.00% of base)
         -64 : System.Private.Uri.dasm (-0.07% of base)

2 total files with size differences (2 improved, 0 regressed), 107 unchanged.

Top method improvements by size (bytes):
         -69 (-8.61% of base) : System.Private.CoreLib.dasm - System.IO.Path:Populate83FileNameFromRandomBytes(long,int,System.Span`1[Char])
         -38 (-2.77% of base) : System.Private.Uri.dasm - System.UriHelper:EscapeStringToBuilder(System.ReadOnlySpan`1[Char],byref,System.ReadOnlySpan`1[Boolean],bool)
         -14 (-5.88% of base) : System.Private.Uri.dasm - System.UriHelper:EscapeAsciiChar(ushort,byref)
         -12 (-10.34% of base) : System.Private.Uri.dasm - <>c:<HexEscape>b__121_0(System.Span`1[Char],ushort):this

Top method improvements by size (percentage):
         -12 (-10.34% of base) : System.Private.Uri.dasm - <>c:<HexEscape>b__121_0(System.Span`1[Char],ushort):this
         -69 (-8.61% of base) : System.Private.CoreLib.dasm - System.IO.Path:Populate83FileNameFromRandomBytes(long,int,System.Span`1[Char])
         -14 (-5.88% of base) : System.Private.Uri.dasm - System.UriHelper:EscapeAsciiChar(ushort,byref)
         -38 (-2.77% of base) : System.Private.Uri.dasm - System.UriHelper:EscapeStringToBuilder(System.ReadOnlySpan`1[Char],byref,System.ReadOnlySpan`1[Boolean],bool)

4 total methods with size differences (4 improved, 0 regressed), 262165 unchanged.

The jit diff is quite small but there are few more places in the BCL where we can slightly tune and benefit from this opt, e.g.: here, also, see this comment. Also all [x % c] patterns require cast to uint.