Topic: proposal: use of CONST for deterministic functions (global reply)
Author: Barry Margolin <barmar@genuity.net>
Date: Thu, 7 Feb 2002 18:43:04 GMT Raw View
In article <O8r88.31774$5M4.994332@twister2.libero.it>,
Mycroft Holmes <holmes@technologist.REMOVEME.com> wrote:
>> Are there any languages
>> or compilers that provide a feature like this, so that the practical cost
>> and benefit can be assessed?
>
>I don't know, I don't think there are any.
>But this may be a reason to do it, rather than the opposite.
On the contrary. Language standardization committees are generally not the
proper place for innovations, they should prefer to codify existing
practices. Once there's experience with implementing and using a feature,
then it's time to set it in stone with a standard.
>> Do you really want to force all
>> compiler implementors to develop a complex feature that will only make a
>> difference for a fraction of a percent of programs?
>>
>
>no: I'd like the LANGUAGE to allow this.
>IF the compiler can, it will optimize the code (the same happens for the
>"register" keyword), otherwise it will ignore the modifier and treat the
>function as a common function.
That makes sense.
Why don't you petition your favorite compiler vendor to add it as an
extension? If there's a big call for it, they'll probably do it, and that
would provide impetus for getting it into the next revision of the
standard.
--
Barry Margolin, barmar@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: Barry Margolin <barmar@genuity.net>
Date: Fri, 8 Feb 2002 01:10:44 GMT Raw View
In article <8Zq88.31740$5M4.994171@twister2.libero.it>,
Mycroft Holmes <holmes@technologist.REMOVEME.com> wrote:
>
>
>> Will it really be enough ?
>
>yep.
>
>> What happens if you call 2 CONST functions from
>> within a CONST function because the net effect is CONST. You could go on
>> indefinitely like this in terms of compile-time analysis.
>
>if you think
>the 1st pass is an usual compilation (no: it's THE usual compilation).
>the second pass is just a... uhm, say a "find-and-replace"
>
>(in the 1st pass the compiler does not care about determinism, in the second
>instead it replaces all calls by their result - which he can get running the
>code it has just produced)
In other words, he's just asking that the compiler automatically do what he
would have done by writing a program to generate an #include file.
It's not extremely difficult, but given the way most compilers are
currently organized it would probably be a significant change to their
designs. If you were implementing a compiler from scratch it wouldn't be
that hard to accomodate it, but adding it to existing implementations would
be alot of work for relatively little gain.
--
Barry Margolin, barmar@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Adam H. Peterson" <ahp6@email.byu.edu>
Date: Fri, 8 Feb 2002 01:10:50 GMT Raw View
> Declaring a function to be deterministic *does* have a more useful
benefit:
> it can permit the traditional optimization of constant subexpression
> elimination. If you write 'x = sin(i) * sin(i);', it can transform it
into
> 'temp=sin(i); x = temp*temp;'. This is the kind of expression that's
> likely to be in an inner loop, and optimizations like this can then make a
> noticeable difference.
In order to do this, the function would also have to be assumed to have no
'significant' side effects other than the return value. This would need to
be true even if the function always returns the same value. The possible
scenarios for characterizing the ramifications for this I can see is:
1) It is unspecified how many times the function is called. Programs must
be robust to the function being called any number of times (from zero up to
an arbitrary number).
2) It is undefined for a function to perform any observable behaviors beyond
constructing the return value.
3) A constraint is imposed on the compiler to execute the function only once
for each set of parameters upon which it is invoked. (Or only once per
invocation in the code, or only once per invocation in a given function, or
something. Some constraint may be imposed.)
My guess is that the first scenario is most likely to be adopted, but it may
introduce some unintended portability problems.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: Barry Margolin <barmar@genuity.net>
Date: Fri, 8 Feb 2002 01:36:41 GMT Raw View
In article <a3ujt9$sf0$1@acs2.byu.edu>,
Adam H. Peterson <ahp6@email.byu.edu> wrote:
>> Declaring a function to be deterministic *does* have a more useful
>benefit:
>> it can permit the traditional optimization of constant subexpression
>> elimination. If you write 'x = sin(i) * sin(i);', it can transform it
>into
>> 'temp=sin(i); x = temp*temp;'. This is the kind of expression that's
>> likely to be in an inner loop, and optimizations like this can then make a
>> noticeable difference.
>
>In order to do this, the function would also have to be assumed to have no
>'significant' side effects other than the return value. This would need to
Of course. Why would you declare a function to be pure and deterministic
if this weren't the case?
>be true even if the function always returns the same value. The possible
>scenarios for characterizing the ramifications for this I can see is:
>
>1) It is unspecified how many times the function is called. Programs must
>be robust to the function being called any number of times (from zero up to
>an arbitrary number).
Probably should be no more than it would be called if it weren't declared
to be deterministic.
>2) It is undefined for a function to perform any observable behaviors beyond
>constructing the return value.
>
>3) A constraint is imposed on the compiler to execute the function only once
>for each set of parameters upon which it is invoked. (Or only once per
>invocation in the code, or only once per invocation in a given function, or
>something. Some constraint may be imposed.)
>
>My guess is that the first scenario is most likely to be adopted, but it may
>introduce some unintended portability problems.
The proposer has mentioned that he's not trying to require compilers to
precompile these calls, just ALLOW them to do so; it's like "register" and
"inline", which suggest particular optimizations to the compiler and imply
restrictions on the program, but don't actually constrain the compiler. So
the third scenario is not what's being suggested.
I think the first scenario is the right one. Otherwise, it would be a
problem if the function tries to report an error in exceptional cases.
Then again, maybe this *should* be undefined -- what should happen if the
compiler tries to run the function at compile time and it enters this
error-reporting code?
--
Barry Margolin, barmar@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Mycroft Holmes" <holmes@technologist.REMOVEME.com>
Date: Fri, 8 Feb 2002 16:03:33 GMT Raw View
> >no: I'd like the LANGUAGE to allow this.
> [...]
> On the contrary. Language standardization committees are generally not
the
> proper place for innovations, they should prefer to codify existing
> practices. Once there's experience with implementing and using a feature,
> then it's time to set it in stone with a standard.
I think you are right, but a successful standard imho has to be somehow
"open" and "predictive".
a std committee should "look ahead", abstract from practice and introduce
something which is harmless if unused (in other words: which can be safely
ignored) and ready for possible extensions tomorrow.
> Why don't you petition your favorite compiler vendor to add it as an
> extension?
uhm... they don't care about bugs, what makes you think they'll care about
new ideas?
--
The set of solutions is never empty.
Two solutions together form a new problem.
-- Mycroft Holmes
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: Barry Margolin <barmar@genuity.net>
Date: Fri, 8 Feb 2002 16:53:38 GMT Raw View
In article <ItM88.39664$nI1.1165218@twister1.libero.it>,
Mycroft Holmes <holmes@technologist.REMOVEME.com> wrote:
>> Why don't you petition your favorite compiler vendor to add it as an
>> extension?
>
>uhm... they don't care about bugs, what makes you think they'll care about
>new ideas?
They care about sales, don't they? Tell them you know of a potential
customers who'll purchase from whichever vendor first makes this feature
available.
Or find someone who likes the idea and is interested in adding it to GCC.
If you're the only person who wants this, then it's obviously not worth
anyone's effort. But if it's a popular idea, it shouldn't be that hard to
get it added to *some* compiler.
--
Barry Margolin, barmar@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Mycroft Holmes" <holmes@technologist.REMOVEME.com>
Date: Wed, 6 Feb 2002 16:15:26 GMT Raw View
> Even 2.0*5.0 is not guaranteed to be simplified at compile time.
> There standard specifically does NOTHING to require that the compiler
> be able to evaluate floating point math. This is particularly handy
indeed, this is the point in question here.
imho, the program should be free to decide what is pre-computed and what is
not.
I don't have a copy of the std, but I think that integers are always
simplified at compile time.
"int i = 4*5" compiles as "i=20"
if I grant the compiler that a function has no side effects, and depends
only on its args, I'd like also
double d = sin(2.0) to be precompiled.
> for the case of cross-compilers where the floating point architechture
> between the compiling nad the runtime machine might be markedly different.
*HOW* to compile it, well, it's definetly not up to me: if the compiler
likes, it can summon runtime machines, ancient gods (!) or email the formula
to the Normal School of Pisa and wait for an answer....
(see also my other post)
--
The set of solutions is never empty.
Two solutions together form a new problem.
-- Mycroft Holmes
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Mycroft Holmes" <holmes@technologist.REMOVEME.com>
Date: Wed, 6 Feb 2002 16:15:51 GMT Raw View
> So, how many passes are enough? Say you have a function (say sin) that
Two passes should be enough for everything: first you do a standard
compiling of all code, then you invoke separately some code you just
produced and replace some function call with this result.
Another example, say you have
double f( double x )
{
// a very very slow function
return result;
}
const double MyConst1 = f(2.0);
const double MyConst2 = f(-6.4);
// f is never called anymore
this program has a VERY slow startup, which is absolutely unnecessary.
Usually what we do is
1) make a command-line exe which calls f and saves a text file called
"myconst.h", something like:
file << "const double MyConst1" << f(2.0) << endl; // let's assume
default precision is enough
2) include "myconst.h" somewhere else.
> This semantic
> test actually fails for most functions that accept pointers as arguments.
I agree that implementing this idea may be hard for compiler manifacturers
(they don't seem able to implement templates...;).
They would have to check for inconsistencies in "attributes" and arguments
(your example -absolutely right-: pointers and determinism).
--
The set of solutions is never empty.
Two solutions together form a new problem.
-- Mycroft Holmes
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: Barry Margolin <barmar@genuity.net>
Date: Thu, 7 Feb 2002 04:36:10 GMT Raw View
In article <u2688.27968$nI1.871918@twister1.libero.it>,
Mycroft Holmes <holmes@technologist.REMOVEME.com> wrote:
>this program has a VERY slow startup, which is absolutely unnecessary.
This is true, but program startup is rarely a major bottleneck, so the
payoff for your proposed feature is not very much, and IMHO not worth the
extensive compiler support that it would require. Are there any languages
or compilers that provide a feature like this, so that the practical cost
and benefit can be assessed?
In the rare instances when startup time is an issue, the technique you
described (of writing a separate program to compute a lookup table that can
be #include'ed) is a simple solution. Do you really want to force all
compiler implementors to develop a complex feature that will only make a
difference for a fraction of a percent of programs?
Declaring a function to be deterministic *does* have a more useful benefit:
it can permit the traditional optimization of constant subexpression
elimination. If you write 'x = sin(i) * sin(i);', it can transform it into
'temp=sin(i); x = temp*temp;'. This is the kind of expression that's
likely to be in an inner loop, and optimizations like this can then make a
noticeable difference.
--
Barry Margolin, barmar@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Stephen Howe" <SPAMstephen.howeGUARD@tnsofres.com>
Date: Thu, 7 Feb 2002 04:38:52 GMT Raw View
"Mycroft Holmes" <holmes@technologist.REMOVEME.com> wrote in message
news:u2688.27968$nI1.871918@twister1.libero.it...
> > So, how many passes are enough? Say you have a function (say sin) that
>
> Two passes should be enough for everything: first you do a standard
> compiling of all code, then you invoke separately some code you just
> produced and replace some function call with this result.
Will it really be enough ? What happens if you call 2 CONST functions from
within a CONST function because the net effect is CONST. You could go on
indefinitely like this in terms of compile-time analysis.
// Another slow function
complex Airy1stKind( complex z )
{
:
return zresult;
}
// Another slow function
complex Airy2ndKind( complex z )
{
:
return zresult;
}
complex f( complex z )
{
:
return Airy1stKind(z) + Airy2ndKind(1.0 / z);
}
const complex MyConst1 = f(complex <double>(1.0, 2.0));
const complex MyConst2 = f(complex <double>(1.0, 3.0));
Stephen Howe
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Ken Hagan" <K.Hagan@thermoteknix.co.uk>
Date: Thu, 7 Feb 2002 04:40:39 GMT Raw View
Mycroft Holmes <holmes@technologist.REMOVEME.com> wrote...
>
> if I grant the compiler that a function has no side effects,
> and depends only on its args, I'd like also
> double d = sin(2.0) to be precompiled.
As I recall, the properties of floating point arithmetic may
be unknown until run-time, so the exact value of sin(2.0) is
not pre-compilable.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Ken Alverson" <Ken@Alverson.com>
Date: Thu, 7 Feb 2002 15:27:39 GMT Raw View
"Ken Hagan" <K.Hagan@thermoteknix.co.uk> wrote in message
news:a3se0u$1al49b$2@ID-94009.news.dfncis.de...
> Mycroft Holmes <holmes@technologist.REMOVEME.com> wrote...
> >
> > if I grant the compiler that a function has no side effects,
> > and depends only on its args, I'd like also
> > double d = sin(2.0) to be precompiled.
>
> As I recall, the properties of floating point arithmetic may
> be unknown until run-time, so the exact value of sin(2.0) is
> not pre-compilable.
Consider if (for whatever reason) sin(2.0) was used all over the place,
including loops. If the compiler knew sin was referentially transparent, it
could (without trying to calculate the value of sin(2.0) within the
compiler) create a global "const double __sin20_unique_name = sin(2.0)" and
substitute it in everywhere, greatly improving performance. The calculation
would still be performed at runtime on the target machine. Granted, the
programmer could do the same thing manually, but the same could be said
about inline.
Ken
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Mycroft Holmes" <holmes@technologist.REMOVEME.com>
Date: Thu, 7 Feb 2002 15:30:14 GMT Raw View
> Will it really be enough ?
yep.
> What happens if you call 2 CONST functions from
> within a CONST function because the net effect is CONST. You could go on
> indefinitely like this in terms of compile-time analysis.
if you think
the 1st pass is an usual compilation (no: it's THE usual compilation).
the second pass is just a... uhm, say a "find-and-replace"
(in the 1st pass the compiler does not care about determinism, in the second
instead it replaces all calls by their result - which he can get running the
code it has just produced)
--
The set of solutions is never empty.
Two solutions together form a new problem.
--
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Mycroft Holmes" <holmes@technologist.REMOVEME.com>
Date: Thu, 7 Feb 2002 18:27:40 GMT Raw View
> This is true, but program startup is rarely a major bottleneck, so the
> [....]
> Declaring a function to be deterministic *does* have a more useful
benefit:
> it can permit the traditional optimization of constant subexpression
> elimination.
I agree with you on that "rarely", because c++ is not a numerical math
language.
I disagree on that "rarely", because these situations occur in 99% of math
programs.
> payoff for your proposed feature is not very much, and IMHO not worth the
> extensive compiler support that it would require.
Of course, I'm not a compiler manifacturer.
I'd like to hear from one of them.
from a logical point of view, it's just a find-and-replace after the
computation.
> Are there any languages
> or compilers that provide a feature like this, so that the practical cost
> and benefit can be assessed?
I don't know, I don't think there are any.
But this may be a reason to do it, rather than the opposite.
> Do you really want to force all
> compiler implementors to develop a complex feature that will only make a
> difference for a fraction of a percent of programs?
>
no: I'd like the LANGUAGE to allow this.
IF the compiler can, it will optimize the code (the same happens for the
"register" keyword), otherwise it will ignore the modifier and treat the
function as a common function.
--
The set of solutions is never empty.
Two solutions together form a new problem.
-- Mycroft Holmes
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Mycroft Holmes" <holmes@technologist.REMOVEME.com>
Date: Tue, 5 Feb 2002 20:50:20 GMT Raw View
all the answers you gave are not generic enough, since:
a) you are allowed to use only integer types as template parameters (so no
floating point, no array, etc.).
b) macros are quite useless, because floating point expressions are not
granted to be simplified at compile time, for example
double d = sin(2.0);
is very likely to call sin at runtime (optimizations usually do integer
simplification, not f.p., and most times when they do, they give wrong
results :(
my function using 'int' was only an example.
the point is that the compiler should parse the source in more than 1-pass,
so:
1) it reads and compiles all the "const" functions
2) it reads and compiles the rest of the code, replacing any "const"
function call by its result
--
The set of solutions is never empty.
Two solutions together form a new problem.
-- Mycroft Holmes
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: Tue, 5 Feb 2002 21:16:53 GMT Raw View
Mycroft Holmes wrote:
> b) macros are quite useless, because floating point expressions are not
> granted to be simplified at compile time, for example
Even 2.0*5.0 is not guaranteed to be simplified at compile time.
There standard specifically does NOTHING to require that the compiler
be able to evaluate floating point math. This is particularly handy
for the case of cross-compilers where the floating point architechture
between the compiling nad the runtime machine might be markedly different.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Eric Hopper" <eric.hopper@tiecommerce.com>
Date: Tue, 5 Feb 2002 22:53:56 GMT Raw View
In article <wMM78.21229$5M4.691122@twister2.libero.it>, "Mycroft Holmes"
<holmes@technologist.removeme.com> wrote:
> the point is that the compiler should parse the source in more than
> 1-pass, so:
>
> 1) it reads and compiles all the "const" functions 2) it reads and
> compiles the rest of the code, replacing any "const" function call by
> its result
So, how many passes are enough? Say you have a function (say sin) that
depends on a const precomputed table that uses the fact function? I'm
sure I could think of examples that would require even more passes than
the three that it's up to now. The point is, there's no limit that will
guarantee that all const values will eventually be evaluate and stuck in
their proper places.
Now, your proposal is interesting from an optimizer standpoint. gcc/g++
used to (and may still) have some funky __attribute__ construct that
allowed the optimizer to remove redudant function calls. The attribute
thingy told the compiler that the function had no side effects and
depended directly on the value of its arguments, so if the same argument
values were passed in, the same result would be returned. This semantic
test actually fails for most functions that accept pointers as arguments.
But, for compile-time initialization of const values, there are some
pretty insurmountable problems with it.
--
Eric Hopper
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]