Sign in Join

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

Mailing lists / fpc-devel / 2025-10

Constant eval (and dead code removal) - comparing 2 methods for being the same.

3 messages · 2 people · –

Reply by email Subscribe to this list Your subscription

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

Martin Frb

In the code

   if true then begin
     write(1);
   end
   else begin
     write(2);
   end;

the "else" block will not generate code (at least O2 and higher).

But

   TFoo = class
     procedure MyFoo;
   end;
   X = class(TFoo)
   end;
   //if @X.MyFoo = @TFoo.MyFoo then begin
   if @TFoo.MyFoo = @TFoo.MyFoo then begin
     write(1);
   end
   else begin
     write(2);
   end;

Does not detect this at compile time.

Note, that this is not on an instance, this is on the actual class => so it is known.

Is there any way to get that optimize the "else" block away (or the "then" if the compare goes the other way)?
I can't just compare the classes, as subclasses can have the same method (if it isn't overridden/reintroduced)

Background:
This seems useless in the above example.
But I want to to that in a generic, and I am testing if the method on the generic param is the same method as on a specific known class.

The best part is, that in the specialized generic (probably by the peephole opt) the asm goes
#  if @A.MyFoo = @TFoo.MyFoo then begin
    leaq    P$PROJECT1$_$TFOO_$__$$_MYFOO(%rip),%rax     cmpq    %rax,%rax
    jne    .Lj14

And rax is always equal to rax, so the conditional jump always does the same. But it still is a conditional jump (though I guess the branch prediction in the CPU will be overjoyed).

----------------------------------------------

program project1;
{$Mode objfpc}
type
   TFoo = class
     procedure MyFoo;
   end;
   TFoo2 = class
     procedure MyFoo;
   end;
   generic TBar<A> = class
     procedure MyBar;
   end;
procedure TFoo.MyFoo;
begin
   write;
end;
procedure TFoo2.MyFoo;
begin
   write;
end;
procedure TBar.MyBar;
begin
   if @A.MyFoo = @TFoo.MyFoo then begin
     write(1);
   end
   else begin
     write(2);
   end;
end;
type
   X = class(TFoo) end;
   TB1 = specialize TBar<TFoo>;
   TB2 = specialize TBar<TFoo2>;
procedure xyz;
begin
   //if @X.MyFoo = @TFoo.MyFoo then begin
   if @TFoo.MyFoo = @TFoo.MyFoo then begin
     write(1);
   end
   else begin
     write(2);
   end;
end;
procedure xyz2;
begin
   if true then begin
     write(1);
   end
   else begin
     write(2);
   end;
end;
var
   b1: TB1;
   b2: TB2;
begin
   xyz;
   xyz2;
   b1.MyBar;
   b2.MyBar;
end.

Reply by email

Florian Klämpfl
to Martin Frb
Show quoted text 36 lines
Am 01.10.2025 um 12:46 schrieb Martin Frb via fpc-devel : In the code if true then begin write(1); end else begin write(2); end; the "else" block will not generate code (at least O2 and higher). But TFoo = class procedure MyFoo; end; X = class(TFoo) end; //if @X.MyFoo = @TFoo.MyFoo then begin if @TFoo.MyFoo = @TFoo.MyFoo then begin write(1); end else begin write(2); end; Does not detect this at compile time. Note, that this is not on an instance, this is on the actual class => so it is known. Is there any way to get that optimize the "else" block away (or the "then" if the compare goes the other way)? I can't just compare the classes, as subclasses can have the same method (if it isn't overridden/reintroduced)

I added an optimization for this in dbf7ba4721f8336139e84a99c74b89025edc55c3. Can you please check if it works for your case?

Reply by email

Martin Frb
to Florian Klämpfl
Florian Klämpfl wrote
I added an optimization for this in dbf7ba4721f8336139e84a99c74b89025edc55c3. Can you please check if it works for your case?

Tested with different optimisation settings. Works perfect.

Thanks a lot.

Reply by email