Skip to content

JIT: Transform SELECT(x < 0, C - 1, C) to SAR(x, 31) + C#125549

Open
BoyBaykiller wants to merge 6 commits intodotnet:mainfrom
BoyBaykiller:transform-select-to-sar-add
Open

JIT: Transform SELECT(x < 0, C - 1, C) to SAR(x, 31) + C#125549
BoyBaykiller wants to merge 6 commits intodotnet:mainfrom
BoyBaykiller:transform-select-to-sar-add

Conversation

@BoyBaykiller
Copy link
Contributor

@BoyBaykiller BoyBaykiller commented Mar 14, 2026

This pattern saves 2 registers (or 1 when the immed can't be contained on arm) and is a code size reduction.
In the special case of C = 0 it becomes a single sar.

Examples:

void Example1(int relop1)
{
    int x = (relop1 < 0) ? 4 : 5;
    Consume(x);
}
G_M000_IG02:                ;; offset=0x0000
       mov      ecx, 4
       mov      eax, 5
       test     edx, edx
       cmovge   ecx, eax

G_M000_IG03:                ;; offset=0x000F
       tail.jmp [Consume(int)]
; Total bytes of code: 21
G_M10187_IG02:  ;; offset=0x0000
       sar      edx, 31
       lea      ecx, [rdx+0x05]

G_M10187_IG03:  ;; offset=0x0006
       tail.jmp [Consume(int)]
; Total bytes of code: 12

int Example2(int result)
{
    return (result < 0) ? int.MaxValue : int.MinValue;
}
G_M000_IG02:                ;; offset=0x0000
       mov      eax, 0x7FFFFFFF
       mov      ecx, 0xFFFFFFFF80000000
       test     edx, edx
       cmovge   eax, ecx

G_M000_IG03:                ;; offset=0x000F
       ret      
; Total bytes of code: 16
G_M35951_IG02:  ;; offset=0x0000
       mov      eax, edx
       sar      eax, 31
       add      eax, 0xFFFFFFFF80000000

G_M35951_IG03:  ;; offset=0x000A
       ret      
; Total bytes of code: 11

@github-actions github-actions bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Mar 14, 2026
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Mar 14, 2026
@jakobbotsch
Copy link
Member

@copilot Use the performance benchmark skill to create micro benchmarks for this pattern

@jakobbotsch
Copy link
Member

@EgorBot -linux_amd -osx_arm64

   using BenchmarkDotNet.Attributes;
   using BenchmarkDotNet.Running;
   using System.Runtime.CompilerServices;
   
   BenchmarkSwitcher.FromAssembly(typeof(Bench).Assembly).Run(args);
   
   public class Bench
   {
       private int[] _values = default!;
   
       [GlobalSetup]
       public void Setup()
       {
           var rng = new Random(42);
           _values = new int[1024];
           for (int i = 0; i < _values.Length; i++)
               _values[i] = rng.Next(-1000, 1000);
       }
   
       [Benchmark]
       public int SelectLtZero_ConstOffset()
       {
           int sum = 0;
           int[] arr = _values;
           for (int i = 0; i < arr.Length; i++)
               sum += LtZero_Offset(arr[i]);
           return sum;
       }
   
       [Benchmark]
       public int SelectGeZero_ConstOffset()
       {
           int sum = 0;
           int[] arr = _values;
           for (int i = 0; i < arr.Length; i++)
               sum += GeZero_Offset(arr[i]);
           return sum;
       }
   
       [Benchmark]
       public int SelectLtZero_ZeroBase()
       {
           int sum = 0;
           int[] arr = _values;
           for (int i = 0; i < arr.Length; i++)
               sum += LtZero_ZeroBase(arr[i]);
           return sum;
       }
   
       [MethodImpl(MethodImplOptions.NoInlining)]
       private static int LtZero_Offset(int x) => x < 0 ? 41 : 42;
   
       [MethodImpl(MethodImplOptions.NoInlining)]
       private static int GeZero_Offset(int x) => x >= 0 ? 42 : 41;
   
       [MethodImpl(MethodImplOptions.NoInlining)]
       private static int LtZero_ZeroBase(int x) => x < 0 ? -1 : 0;
   }

* remove nodes at once
* remove duplicate MakeSrcContained
@BoyBaykiller BoyBaykiller marked this pull request as ready for review March 15, 2026 23:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants