title: Java Math.abs(int) optimizations, why this code 6x times slower?
body: <p>As you may know, <code>Math.abs(Integer.MIN_VALUE) == Integer.MIN_VALUE</code> and to prevent a negative value, the <code>safeAbs</code> method was implemented in my project:</p>
  
  <pre class="lang-java prettyprint-override"><code>    public static int safeAbs(int i) {
          i = Math.abs(i);
  
          return i &lt; 0 ? 0 : i;
      }
  </code></pre>
  
  <p>I compared the performance with the following one:</p>
  
  <pre class="lang-java prettyprint-override"><code>    public static int safeAbs(int i) {
          return i == Integer.MIN_VALUE ? 0 : Math.abs(i);
      }
  </code></pre>
  
  <p>And the first one is almost 6x times slower than the second (the second one performance is almost the same as "pure" Math.abs(int)). From my point of view, there is no significant difference in bytecode, but I guess the difference is present in the JIT "assembly" code:</p>
  
  <p>"slow" version:</p>
  
  <pre><code>  0x00007f0149119720: mov     %eax,0xfffffffffffec000(%rsp)
    0x00007f0149119727: push    %rbp
    0x00007f0149119728: sub     $0x20,%rsp
    0x00007f014911972c: test    %esi,%esi
    0x00007f014911972e: jl      0x7f0149119734
    0x00007f0149119730: mov     %esi,%eax
    0x00007f0149119732: jmp     0x7f014911973c
    0x00007f0149119734: neg     %esi
    0x00007f0149119736: test    %esi,%esi
    0x00007f0149119738: jl      0x7f0149119748
    0x00007f014911973a: mov     %esi,%eax
    0x00007f014911973c: add     $0x20,%rsp
    0x00007f0149119740: pop     %rbp
    0x00007f0149119741: test    %eax,0x1772e8b9(%rip)  ;   {poll_return}
    0x00007f0149119747: retq
    0x00007f0149119748: mov     %esi,(%rsp)
    0x00007f014911974b: mov     $0xffffff65,%esi
    0x00007f0149119750: nop
    0x00007f0149119753: callq   0x7f01490051a0    ; OopMap{off=56}
                                                  ;*ifge
                                                  ; - math.FastAbs::safeAbsSlow@6 (line 16)
                                                  ;   {runtime_call}
    0x00007f0149119758: callq   0x7f015f521d20    ;   {runtime_call}
  </code></pre>
  
  <p>"normal" version:</p>
  
  <pre><code>  # {method} {0x00007f31acf28cd8} 'safeAbsFast' '(I)I' in 'math/FastAbs'
    # parm0:    rsi       = int
    #           [sp+0x30]  (sp of caller)
    0x00007f31b08c7360: mov     %eax,0xfffffffffffec000(%rsp)
    0x00007f31b08c7367: push    %rbp
    0x00007f31b08c7368: sub     $0x20,%rsp
    0x00007f31b08c736c: cmp     $0x80000000,%esi
    0x00007f31b08c7372: je      0x7f31b08c738e
    0x00007f31b08c7374: mov     %esi,%r10d
    0x00007f31b08c7377: neg     %r10d
    0x00007f31b08c737a: test    %esi,%esi
    0x00007f31b08c737c: mov     %esi,%eax
    0x00007f31b08c737e: cmovl   %r10d,%eax
    0x00007f31b08c7382: add     $0x20,%rsp
    0x00007f31b08c7386: pop     %rbp
    0x00007f31b08c7387: test    %eax,0x162c2c73(%rip)  ;   {poll_return}
    0x00007f31b08c738d: retq
    0x00007f31b08c738e: mov     %esi,(%rsp)
    0x00007f31b08c7391: mov     $0xffffff65,%esi
    0x00007f31b08c7396: nop
    0x00007f31b08c7397: callq   0x7f31b07b11a0    ; OopMap{off=60}
                                                  ;*if_icmpne
                                                  ; - math.FastAbs::safeAbsFast@3 (line 17)
                                                  ;   {runtime_call}
    0x00007f31b08c739c: callq   0x7f31c5863d20    ;   {runtime_call}
  </code></pre>
  
  <p>Benchmark code:</p>
  
  <pre class="lang-java prettyprint-override"><code>@BenchmarkMode(Mode.AverageTime)
  @Fork(value = 1, jvmArgsAppend = {"-Xms3g", "-Xmx3g", "-server"})
  @OutputTimeUnit(TimeUnit.NANOSECONDS)
  @State(Scope.Benchmark)
  @Threads(1)
  @Warmup(iterations = 10)
  @Measurement(iterations = 10)
  public class SafeAbsMicroBench {
  
      @State(Scope.Benchmark)
      public static class Data {
          final int len = 10_000_000; 
  
          final int[] values = new int[len];
  
          @Setup(Level.Trial)
          public void setup() {
              // preparing 10 million random integers without MIN_VALUE
              for (int i = 0; i &lt; len; i++) {
                  int val;
  
                  do {
                      val = ThreadLocalRandom.current().nextInt();
                  } while (val == Integer.MIN_VALUE);
  
                  values[i] = val;
              }
          }
      }
  
      @Benchmark
      public int safeAbsSlow(Data data) {
          int sum = 0;
  
          for (int i = 0; i &lt; data.len; i++)
              sum += safeAbsSlow(data.values[i]);
  
          return sum;
      }
  
      @Benchmark
      public int safeAbsFast(Data data) {
          int sum = 0;
  
          for (int i = 0; i &lt; data.len; i++)
              sum += safeAbsFast(data.values[i]);
  
          return sum;
      }
  
      private int safeAbsSlow(int i) {
          i = Math.abs(i);
  
          return i &lt; 0 ? 0 : i;
      }
  
      private int safeAbsFast(int i) {
          return i == Integer.MIN_VALUE ? 0 : Math.abs(i);
      }
  
      public static void main(String[] args) throws RunnerException {
          final Options options = new OptionsBuilder()
              .include(SafeAbsMicroBench.class.getSimpleName())
              .build();
  
          new Runner(options).run();
      }
  }
  </code></pre>
  
  <p>Results (Linux x86-64, 7820HQ, checked on oracle jdk 8 and 11 with pretty similar results).</p>
  
  <pre><code>Benchmark                      Mode  Cnt         Score        Error  Units
  SafeAbsMicroBench.safeAbsFast  avgt   10   6435155.516 ±  47130.767  ns/op
  SafeAbsMicroBench.safeAbsSlow  avgt   10  35646411.744 ± 776173.621  ns/op
  </code></pre>
  
  <p>Can someone explain why the first code is significantly slower than the second one?</p>