[fpc-devel] Question on updating FPC packages
J. Gareth Moreton
gareth at moreton-family.com
Sat Oct 26 20:03:46 CEST 2019
With my experiments on i386 anx x86_64 (without the alignment changes)
the complex record is always passed by reference, but without const, the
function prologue then makes a copy of it on the function's local stack,
which is then referenced to in the rest of the function. Whether or not
const is present or not, the same reference is passed into the function
unmodified (the compiled assembly language is no different).
I think in a way, Florian and I have slightly different views. I don't
trust the compiler to make the most optimal code (i.e. a lazy
compiler... I didn't want to say that Florian's compiler was inefficient
until he himself said it!), so I try to give it hints where I can, and
inserting "const" modifiers seems harmless enough since this has been a
documented Pascal feature for decades, and most of the functions don't
modify the parameter, so adding "const" just enforces it on the
compiler's side.
Granted, I do seek to make improvements to the compiler where possible,
and it's something I enjoy doing. In the case of 'auto-const', I
imagine it could be done at the node level, detecting that a parameter
is only read from and never written to, but there may still be traps
where you modify it without meaning to and causing inefficiencies. Case
in point, I had to make one small change to the "cth" function because
it reused the parameter as a temporary variable. Originally, it was this:
function cth (z : complex) : complex;
{ hyberbolic complex tangent }
{ th(x) = sinh(x) / cosh(x) }
{ cosh(x) > 1 qq x }
var temp: complex;
begin
temp := cch(z);
z := csh(z);
cth := z / temp;
end;
I changed it to the following because specifying "const" caused a
compiler error:
function cth (const z : complex) : complex;
{ hyberbolic complex tangent }
{ th(x) = sinh(x) / cosh(x) }
{ cosh(x) > 1 qq x }
var temp, hsinz : complex;
begin
temp := cch(z);
hsinz := csh(z);
cth := hsinz / temp;
end;
I'm assuming there's a good reason as to why it can't simply be written
as "cth := csh(z) / cch(z);" (and it looks easier to auto-inline),
although currently that reason eludes me.
I don't think the compiler can be made smart and safe enough to
auto-align something like the complex type to take full advantage of the
System V ABI, and vectorcall is not the default Win64 calling convention
(and the default convention is a little badly-designed if I'm allowed to
say, since it doesn't vectorise anything at all). Plus other platforms
may have more restrictive memory availability and coarse alignment is
not desired since it causes wastage. Granted, when it comes to
increased maintainability, the little tricks required to align the
complex type while keeping the same field names is very tricky to
understand and get correct (hence my suggestion of a distinct "align ##"
modifier at the end of the type declaration, but that's another story).
I think the question of whether a micro-optimisation increases
maintainability is fairly subjective and can only be determined on a
case-by-case basis. In my mind, if someone has done the optimisation
and the code is still relatively clean, then it's okay to merge so long
as everyone accepts it and it's fully tested.
Gareth aka. Kit
On 26/10/2019 18:02, Sven Barth via fpc-devel wrote:
> Am 26.10.2019 um 18:51 schrieb J. Gareth Moreton:
>> The "const" suggestion was made by a third party, and while I went
>> out of my way to ensure the functions aren't changed in Pascal code,
>> Florian pointed out that it could break existing assembler code.
>> Maybe I'm being a bit stubborn or unreasonable, I'm not sure, but in
>> my eyes, using assembly language to directly call the uComplex
>> functions and operators seems rather unrealistic. I figured if
>> you're writing in assembly language, especially if you're using
>> vector registers, you'd be using your own code to play around with
>> complex numbers. Plus I figured that if you're developing on a
>> non-x86_64 platform, the only thing that's different are the 'const'
>> modifiers, which I don't think changes the way you actually call the
>> function, regardless of platform. Am I right in this?
>
> It totally depends on how "const" is implemented for the particular
> target. On some there might not be any difference on others there
> might be a similar difference as for x86, namely that something is
> passed as a reference instead of a copy.
>
>> I guess a more fundamental question I should ask, and this might be
>> terribly naïve of me, is this: when you call some function F(x:
>> TType), is there a situation where calling F(const x: TType) produces
>> different machine code or where a particular actual parameter becomes
>> illegal? Note I'm talking about how you call the function, not how
>> the function itself is compiled.
>
> Didn't you provide the example yourself with your changes to the
> uComplex unit? There are cases (especially with records) where "x" is
> passed as a copy on the stack and "const x" is passed as a reference.
>
> Regards,
> Sven
> _______________________________________________
> fpc-devel maillist - fpc-devel at lists.freepascal.org
> 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
More information about the fpc-devel
mailing list