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
begin
  SomeOtherProc(N * SomePureFunc(X));
end;

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
begin
  SomeOtherProc(N * R);
end;

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@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

_______________________________________________
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply via email to