Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2022-04

x86: Efficiency of opposing CMOVs

7 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

J. Gareth Moreton

Hi everyone,

In the x86_64 assembly dumps, I frequently come across combinations such as the following:

    cmpl    %ebx,%edx
    cmovll    %ebx,%eax
    cmovnll    %edx,%eax

This is essentially the tertiary C operator "x = cond ? trueval : falseval", or in Pascal "if (cond) then x := trueval else x := falseval;".  However, because the CMOV instructions have exact opposite conditions, is it better to optimise it into this?

    movl    %ebx,%eax
    cmpl    %ebx,%edx
    cmovnll    %edx,%eax

It's smaller, but is it actually faster (or the same speed)?  At the very least, the two CMOV instructions depend on the CMP instruction being completed, but I'm not sure if the second CMOV depends on the first one being evaluated (because of %eax).  With the second block of code, the MOV and CMP instructions can execute simultaneously.

My educated guess tells me that MOV/CMP/CMOV(~c) is faster than CMP/CMOVc/CMOV(~c), but I haven't been able to find an authoritive source on this yet.

Gareth aka. Kit

This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus

Reply by email

Florian Klämpfl
to J. Gareth Moreton
Show quoted text 19 lines
Am 16.04.2022 um 06:49 schrieb J. Gareth Moreton via fpc-devel : Hi everyone, In the x86_64 assembly dumps, I frequently come across combinations such as the following: cmpl %ebx,%edx cmovll %ebx,%eax cmovnll %edx,%eax This is essentially the tertiary C operator "x = cond ? trueval : falseval", or in Pascal "if (cond) then x := trueval else x := falseval;". However, because the CMOV instructions have exact opposite conditions, is it better to optimise it into this? movl %ebx,%eax cmpl %ebx,%edx cmovnll %edx,%eax It's smaller, but is it actually faster (or the same speed)? At the very least, the two CMOV instructions depend on the CMP instruction being completed, but I'm not sure if the second CMOV depends on the first one being evaluated (because of %eax). With the second block of code, the MOV and CMP instructions can execute simultaneously. My educated guess tells me that MOV/CMP/CMOV(~c) is faster than CMP/CMOVc/CMOV(~c), but I haven't been able to find an authoritive source on this yet.

cmov is normally slow, so the latter should be slower, a brief test shows this also.

$ cat tbench1.pp
procedure p;
var
  a,b,c : array[0..100] of longint;
  i,j,e,f,g : longint;
begin
    for j:=low(a) to high(a) do
      begin
        a[j]:=random(10);
        b[j]:=random(10);
      end;
    for i:=1 to 10000000 do
      for j:=low(a) to high(a) do
        begin
          e:=a[j];
          f:=b[j];
          g:=e;
          if e<f then
            g:=f;
          c[j]:=g;
        end;
end;
begin
  p;
end.
$ time ./tbench1

real 0m0.752s
user 0m0.748s
sys 0m0.004s

$ cat tbench2.pp
procedure p;
var
  a,b,c : array[0..100] of longint;
  i,j,e,f,g : longint;
begin
    for j:=low(a) to high(a) do
      begin
        a[j]:=random(10);
        b[j]:=random(10);
      end;
    for i:=1 to 10000000 do
      for j:=low(a) to high(a) do
        begin
          e:=a[j];
          f:=b[j];
          if e<f then
            g:=f
          else
            g:=e;
          c[j]:=g;
        end;
end;
begin
  p;
end.
$ time ./tbench2

real 0m0.997s
user 0m0.997s
sys 0m0.000s

Reply by email

Florian Klämpfl
to Thorsten Otto
Show quoted text 8 lines
Am 16.04.2022 um 12:31 schrieb Thorsten Otto via fpc-devel : On Samstag, 16. April 2022 06:49:07 CEST J. Gareth Moreton via fpc-devel wrote: > but I haven't been able to find an authoritive > source on this yet. Did you check what for example GCC generates for similar C constructs? I don't think it uses cmov at all.

Why shouldn’t it? clang does the same as my quick tests recommends: https://godbolt.org/z/eWTvfcM8E

Reply by email

J. Gareth Moreton
to Florian Klämpfl

That answers that.  MOV/CMP/CMOV is faster than CMP/CMOV/CMOV. Thanks.

I've been finalising another peephole optimisation.  What started as a means to permit constants in CMOV instructions using a bit of trickery became almost an entire rewrite of the optimisation if only because I was struggling to remember which temporary variable was set to what (where have we heard this before?!).  I'm just running my tests then will make a merge request explaining all of the details.  But these are the following additions:

* Aligns are now properly removed with the labels around the JccMOV -> CMOV optimisations.
* JccMOV -> CMOV will now work with constants in some circumstances (although this won't be done under -Os as it adds extra instructions).
* If is found, everything except the MOV is removed if CMP and MOV contain the same operands (even if in reverse order), since regardless of the result of the condition, the end state is for the 2 operands (which might be registers, references or constants) to be identical (MOV is only called if they're not equal, and if MOV is not called, well, they're already equal!), so we might as well just call MOV (the optimisation uses MatchOperand to compare the operands, so if volatile references are used, the optimisation is not made).

Gareth aka. Kit

P.S. Thanks for the godbolt link Florian.  I just tried "return (a>b) ? a : b;" and it compiles to the same thing, using a MOV/CMP/CMOV triplet.  In other words, it tries to convert a CMOV to a MOV if it can.

Florian Klämpfl wrote 21 lines
> Am 16.04.2022 um 12:31 schrieb Thorsten Otto via fpc-devel > : > > On Samstag, 16. April 2022 06:49:07 CEST J. Gareth Moreton via > fpc-devel wrote: > > but I haven't been able to find an authoritive > > source on this yet. > > Did you check what for example GCC generates for similar C > constructs? I don't think it uses cmov at all. > Why shouldn’t it? clang does the same as my quick tests recommends: https://godbolt.org/z/eWTvfcM8E _______________________________________________ fpc-devel maillist https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus

Reply by email

J. Gareth Moreton
to J. Gareth Moreton

Should work now.  There's a weird quirk with certain kinds of references that get implicitly converted into immediates (constants) by the assembler, but since CMOV doesn't support immediates, they remain references and cause different code to be generated.  x86_64-linux passes on my computer now.

Gareth aka. Kit

J. Gareth Moreton wrote 9 lines
In the meantime, here's the new CMOV improvements.  This is another big one for the peephole optimizer on x86, although largely confined to just a few methods: https://gitlab.com/freepascal.org/fpc/source/-/merge_requests/198 Gareth aka. Kit
This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus

Reply by email