[fpc-devel] Pure function development

J. Gareth Moreton gareth at moreton-family.com
Wed Apr 29 22:08:11 CEST 2020

Constant propagation is only really beneficial for inline functions, 
although there is some crossover with pure functions. I was more meaning 
a system of tracking and storing these constants, or rather how they 
manipulate variables throughout a pure function.

I've also found some annoying limitations with constant propagation that 
leads to a lot of dead code.  The biggest example of this is in the 
compiler itself with the peephole optimizer's debug messages that are 
meant to be dummied out in a release build.  The string concatenation 
functions are still called, because the compiler can't see that the 
individual string fragments, which come from other functions, are 
constant ("StrConst1 + StrConst2" is otherwise concatenated at 
compile-time).  Pure functions will help here, although admittedly with 
this example, I might consider re-evaluating how strings are 
concatenated in the node passes, since if there are more than 3 parts to 
concatenate, it's built in a way that doesn't give the compiler a chance 
to merge adjacent string constants, among other things.

The main thing with pure functions is that constant propagation is far 
more in-depth, and that its result can be assigned to a constant (e.g. 
const RootPi: Double = Gamma(0.5);", if Gamma is defined as "function 
Gamma(const N: Double): Double; pure;"... the value of the function is 
computed at compile-time and only its result is stored in the binary).  
There are also some optimisations you can potentially make in the 
knowledge that a pure function doesn't have any side-effects.  For 
example, if N, X and Count are Integers:

for N := 0 to Count - 1 do
   SomeOtherProc(N * SomePureFunc(X));

Here, because X is not modified by the for-loop, the entire call to 
SomePureFunc can be moved outside of the for-loop and its result stored 
for re-use - that is, the equivalent of:

R := SomePureFunc(X);
for N := 0 to Count - 1 do
   SomeOtherProc(N * R);

Even though the value of X is unknown, because pure functions have no 
side-effects, it is guaranteed to give the same output for a given input.

The C++ equivalent of this functionality is the 'constexpr' directive.

To get back to my original question, I'm going to be using TConstValue 
for now for most things, and using its ability to store pointers and 
lengths for more complex things like records, arrays and strings.  
Thanks for the suggestion Sven.

Gareth aka. Kit

On 29/04/2020 18:46, Jonas Maebe wrote:
> On 29/04/2020 13:41, J. Gareth Moreton wrote:
>> Thanks for the response.  Yes, this is all inside the compiler.
>> Basically I need a means to keep track of the internal state of a
>> function as I step through the nodes (a process I call 'node
>> emulation'), namely local variables, parameters (if they're not const,
>> they're basically just like local variables), and the function Result
>> and out parameters.  Since these may be all sorts of things like
>> integers, floating-point values, strings or record types, I need a
>> system that can handle all of these value types. I figure the compiler
>> has an existing structure somewhere, but I'm not sure what it is.
> It's called constant propagation. -Ooconstprop enables this, but the
> current support is very limited.
> Jonas
> _______________________________________________
> 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.

More information about the fpc-devel mailing list