Topic: Loop invariance
Author: zalman@netcom.com (Zalman Stern)
Date: 1998/08/26 Raw View
AllanW@my-dejanews.com wrote:
: My understanding is that this is what "volatile" is for.
: int myfunc() {
: MyClass &x = ...
: int a = x.someint;
: a += x.someint; // Can optimize to a += a
: x.somefunc();
: a += x.someint; // Can't optimize because x.somefunc() might
: // have modified someint
: MyClass volatile &y = ...
: a = y.someint;
: a += y.someint; // Cannot optimize, because y is volatile
: y.somefunc();
: a += y.someint; // Still can't optimize
: }
: This is correct, isn't it? If not, what *is* the point of volatile?
No. The volatile qualifier requires that all reads and writes to the object
which are implied by the text of the program (and this is more precisely
defined of course) actually happen. So if one writes the following code:
MyClass volatile &y = ...;
a = y.someint;
/* This function call intentionally omitted! */
a = y.someint;
The compiler better generate two loads from memory.
The const qualifier is indeed just a protection thing. It is to value
semantics what "private:" is to object security -- a nop. (Which is
not to say const and private are not useful.)
-Z-
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1998/08/17 Raw View
Siemel Naran wrote:
>
> On 14 Aug 1998 16:00:13 GMT, Christopher Eltschka
>
> >(BTW, mutable vector& doesn't make sense, since a reference cannot be
> >reseated, and the referenced item doesn't get "constified", that
> >is, even with a plain vector&, you'd be able to change the referenced
> >vector through a MyClass const.)
>
> In a future version of C++, it would be nice if
> "T&" in a non-const class becomes "T const&" in a const class
> "T" in a non-const class becomes "T const" in a const class
>
> This makes sense because the reference is supposed to be exactly the same as
> the object it refers to. And, it allows the compiler to do more aggressive
> optimizations.
I think this would break old code.
However, I would like to have a new keyword "constable" for
such a semantics:
class Foo
{
int i;
public:
void mutate() { ++i; }
};
class X
{
Foo& f1;
Foo constable& f2;
Foo* p1;
Foo constable* p2;
public:
void member() const
{
f1.mutate(); // Ok: f1 is not const
f2.mutate(); // Error: f2 is const in this context
p1->mutate(); // Ok: *p1 is not const
p2->mutate(); // Error: *p2 is const in this context
}
// ...
};
Note that non-constable members make sense as well (to point to
other objects which are not conceptually part of the const object)
The use and semantics of constable would be simple:
- constable can be used everywhere where const can be used
- If the object (or the access path) is const, "constable" is
equivalent to const; otherwise it is equivalent to (no cv-qualifier).
>
> >Well, I'd say it helps us less than it would seem.
> >But if an *object* is declared const, some more optimizations are
> >possible
> >(since changing *that* would be undefined behaviour).
>
> Not sure about line #1. But good point on lines #2 to #4.
> Also, if class MyClass contains a data member "const MyClass::vector&",
> then the optimizations should be possible anyway.
Well, line #1 is of course dependant on your expectations (what
"seems").
But one would usually expect more than one can. Look f.ex. at
the following definition:
// file: X.h
class X
{
int const& i;
public:
X(int const& ii): i(ii) {}
void mutate_i();
};
void cheat(int const& i);
// file: X.cc
#include "X.h"
#include <iostream>
void X::mutate_i()
{
cout << i;
cheat(i);
cout << i << endl;
}
One would expect the compiler to be able to optimize that, by
locally storing the value of i and reusing it.
However, the following program has well defined behaviour
and should print "12":
#include "X.h"
using namespace std;
void cheat(int const& i)
{
const_cast<int&>(i)=2;
}
int main()
{
int something=1;
X(something).mutate();
}
So you see, the compiler cannot optimize anything in mutate_i.
Moreover, i could reference a global variable, so even if i is
never actively exposed, the compiler cannot make any assumption
on the referenced variable (even an unsuspicious new could
change it, since you can override global new, or you can set
a new_handler).
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1998/08/17 Raw View
Christopher Eltschka <celtschk@physik.tu-muenchen.de> wrote:
>I would like to have a new keyword "constable" for
>such a semantics: ...
How about "sheriff"?
--
Nathan Myers
ncm@nospam.cantrip.org http://www.cantrip.org/
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: David R Tribble <david.tribble@noSPAM.central.beasys.com>
Date: 1998/08/17 Raw View
Christopher Eltschka wrote:
>> (BTW, mutable vector& doesn't make sense, since a reference cannot be
>> reseated, and the referenced item doesn't get "constified", that
>> is, even with a plain vector&, you'd be able to change the referenced
>> vector through a MyClass const.)
Siemel Naran wrote:
> In a future version of C++, it would be nice if
> "T&" in a non-const class becomes "T const&" in a const class
> "T" in a non-const class becomes "T const" in a const class
>
> This makes sense because the reference is supposed to be exactly the
> same as the object it refers to. And, it allows the compiler to do
> more aggressive optimizations.
Um, I disagree. This is very much like saying that a const object
shouldn't contain a pointer to a non-const object. A reference is
not exactly the same as the object it refers to; *access* through
the reference should reflect whether the object is const or not,
but the reference itself (or the object containing the reference)
is an independent thing. (And anyway, by definition, all references
are implicitly const, since they cannot be modified once they're
established. Which is not to say that the object they refer to
are always const.)
Even though you're saying that you want the object containing the
reference to be const, you're not saying anything about the
const-ness of the object it refers to. Indeed, in many cases,
the const-ness of the first object and the const-ness of the
referred-to object have no bearing on each other. They're two
separate objects, presumably with their own access semantics,
so making one be const shouldn't imply that the other is too.
-- David R. Tribble, dtribble@technologist.com --
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@fermi.ceg.uiuc.edu (Siemel Naran)
Date: 1998/08/17 Raw View
On 17 Aug 1998 16:50:18 GMT, Christopher Eltschka
>Siemel Naran wrote:
>> In a future version of C++, it would be nice if
>> "T&" in a non-const class becomes "T const&" in a const class
>> "T" in a non-const class becomes "T const" in a const class
>>
>> This makes sense because the reference is supposed to be exactly the same as
>> the object it refers to. And, it allows the compiler to do more aggressive
>> optimizations.
>I think this would break old code.
>However, I would like to have a new keyword "constable" for
>such a semantics:
It wouldn't break old code. If one wants "T&" in a non-const class to remain
as "T&" in a const class, one should use the keyword 'mutable' or declare
the object as a pointer "T *const".
The question is whether we want to treat pointers and references differently.
In retrospect, I don't think it's a good idea for compilers to do this by
default, because the distinction between pointers and references is mostly
stylistic. Your "constable" keyword is a good idea.
To me, pointers are good for expressing ownership. So
struct S { int* i; S() { i=new int(0); } ~S() { delete i; } };
is clearer than
struct S { int& i; S() { i=*(new int(0)); } ~S() { delete &i; } };
And references are good for referring to objects owned by another scope. So
struct S { int& i; S(int& i_) : i(i_) { } };
is clearer than
struct S { int* i; S(int& i_) : i(&i_) { } };
It's a coding style issue, I think. In any case, if we go with the above
coding style, then it makes sense for "T&" in a non-const class MyClass to
become "T const&" in a const class (const MyClass). It's like referencing
the T object through member functions "T& MyClass::get()" and
"const T& MyClass::get() const".
In any case, I doubt whether anyone is using non-const references in their
classes. It seems a little dangerous, as now there are two ways to change
the object -- either through the object itself, or through the reference
to the object.
>The use and semantics of constable would be simple:
>
>- constable can be used everywhere where const can be used
>- If the object (or the access path) is const, "constable" is
> equivalent to const; otherwise it is equivalent to (no cv-qualifier).
Sounds good. But instead of "constable" use "constify". The word
'constable' is a noun and means something like police officer.
The use of "constify" or whatever is mostly useful, I think, it the context
of for loops. It is simply a way of telling the compiler that it can treat
certain calculations as constants, and therefore hoist them out of the for
loop. It is intended to solve problems due to aliasing. It is useful for
numerical work. However, it won't hold up against multi-threading.
>class X
>{
> int const& i;
>void cheat(int const& i)
>{
> const_cast<int&>(i)=2;
>}
>void X::mutate_i()
>{
> cout << i;
> cheat(i);
> cout << i << endl;
>}
If a non-const version of the object is not available, the result of
const_cast is undefined. The classic example is
"const char c='c'; const char *pc=&c; *(const_cast<char*>(pc))='C';".
So in the above, I think that the implementation is justified in doing
either of these:
[X] throwing a segmentation fault on LINE1 of cheat(...)
[X] pre-computing i in LINE1 of X::mutate(...) and using this in LINE3,
therefore ignoring the mutated value of "i".
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Stephen Vavasis <vavasis@CS.Cornell.EDU>
Date: 1998/08/18 Raw View
Siemel Naran wrote:
> In a future version of C++, it would be nice if
> "T&" in a non-const class becomes "T const&" in a const class
> "T" in a non-const class becomes "T const" in a const class
>
You can get a similar effect using const_cast. Below is an example. I
don't know if this "idiom" has a name, but I use it in my code. This
use of const_cast is perfectly OK because you can "prove" that the T
object is not really const in the setting below.
-- Steve Vavasis
class T;
class ConstA {
protected:
const T& t;
public:
ConstA(const T& t1) : t(t1) { }
const T& get_t() {return t;}
// more operations that use a const T go here
};
class NonConstA : public ConstA {
public:
NonConstA(T& t1) : ConstA(t1) { }
T& get_t_nonconst() {return const_cast<T&>(t);}
// more operations that use a nonconst T go here
};
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1998/08/18 Raw View
Siemel Naran wrote:
>
> On 17 Aug 1998 16:50:18 GMT, Christopher Eltschka
> >Siemel Naran wrote:
>
> >> In a future version of C++, it would be nice if
> >> "T&" in a non-const class becomes "T const&" in a const class
> >> "T" in a non-const class becomes "T const" in a const class
> >>
> >> This makes sense because the reference is supposed to be exactly the same as
> >> the object it refers to. And, it allows the compiler to do more aggressive
> >> optimizations.
>
> >I think this would break old code.
> >However, I would like to have a new keyword "constable" for
> >such a semantics:
>
> It wouldn't break old code. If one wants "T&" in a non-const class to remain
> as "T&" in a const class, one should use the keyword 'mutable' or declare
> the object as a pointer "T *const".
If your rule were in effect, yes. Under the current rules, no.
Your rule changes the semantics of currently legal code. Therefore
it breaks that code. It's easy to fix, but code that must be fixed
is broken, no matter how easy the fix is.
[...]
> >The use and semantics of constable would be simple:
> >
> >- constable can be used everywhere where const can be used
> >- If the object (or the access path) is const, "constable" is
> > equivalent to const; otherwise it is equivalent to (no cv-qualifier).
>
> Sounds good. But instead of "constable" use "constify". The word
> 'constable' is a noun and means something like police officer.
Ah, now I understand Nathan Myers "sheriff" comment... ;-)
>
> The use of "constify" or whatever is mostly useful, I think, it the context
> of for loops. It is simply a way of telling the compiler that it can treat
> certain calculations as constants, and therefore hoist them out of the for
> loop. It is intended to solve problems due to aliasing. It is useful for
> numerical work. However, it won't hold up against multi-threading.
The use of constify would be useful for ensuring correctness esp.
for class implementations. In loops I don't see any advantage.
Indeed in positions where const gives an optimization advantage,
constify would not be applicable.
Indeed, allowing optimization to take advantage from const in
access paths rather than complete objects would only be possible
with changes to the C++ language:
- modifying an object through a casted-away const would have to be
made undefined even if the original object has not been const
- there would have to be a way to ensure that no directly or
indirectly called function has access to the object through
a non-const access path. I guess this is in general not possible
without a drastic change to the language.
A pointer or reference to constify would usually be used if the
pointed-to or referenced object is logically part of the class.
F.ex. it could be used with the "pimple idiom":
class X
{
class Ximpl;
Ximpl constify* pimpl; // make shure that we don'd accidentally
// call non-const Ximpl functions on const X
// (i.e. from X::member() const)
// ...
};
>
> >class X
> >{
> > int const& i;
>
> >void cheat(int const& i)
> >{
> > const_cast<int&>(i)=2;
> >}
>
> >void X::mutate_i()
> >{
> > cout << i;
> > cheat(i);
> > cout << i << endl;
> >}
Originally followed by:
int main()
{
int something=1;
X(something).mutate();
}
Note that "something" is not const.
>
> If a non-const version of the object is not available, the result of
> const_cast is undefined. The classic example is
> "const char c='c'; const char *pc=&c; *(const_cast<char*>(pc))='C';".
That's true; that's why the real object in my example ("something")
is *not* const.
>
> So in the above, I think that the implementation is justified in doing
> either of these:
>
> [X] throwing a segmentation fault on LINE1 of cheat(...)
> [X] pre-computing i in LINE1 of X::mutate(...) and using this in LINE3,
> therefore ignoring the mutated value of "i".
In the (complete) above example, any implementation doing that
would be non-conforming. "something" is a non-const int, and therefore
the complete behaviour of the program is well defined.
If you'd add a "const" to the definition of "something", you'd
be right - however, since in general the compiler doesn't know
if the object referenced by a const access path is always const,
no optimization can be done due to that constness. (Simple rule:
You cannot use knowledge you don't have.)
A const access path just says "you are not allowed to change this".
It does *not* guarantee that noone else changes it.
Also look at the following replacements for cheat and main:
int global;
void cheat(int const&)
{
++global;
}
int main()
{
X(global).mutate();
}
In this case, the value referenced by i will mutate without having
even a single const_cast in the whole program (the name cheat is
not really applicable here). Again, if X::mutate would cache the
value through the function call, the result would be in error.
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1998/08/18 Raw View
Christopher Eltschka <celtschk@physik.tu-muenchen.de> writes:
> However, I would like to have a new keyword "constable" for
> such a semantics:
> class X
> {
> Foo& f1;
> Foo constable& f2;
> Foo* p1;
> Foo constable* p2;
> public:
> void member() const
> {
> f1.mutate(); // Ok: f1 is not const
> f2.mutate(); // Error: f2 is const in this context
> p1->mutate(); // Ok: *p1 is not const
> p2->mutate(); // Error: *p2 is const in this context
> }
> // ...
> };
>
> Note that non-constable members make sense as well (to point to
> other objects which are not conceptually part of the const object)
Have a look at:
http://www.eleves.ens.fr:8080/home/bonnard/evol/dconst.html
and I wrote it some time ago !
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: AllanW@my-dejanews.com
Date: 1998/08/18 Raw View
In article <35D7ED0D.1AE32848@physik.tu-muenchen.de>,
Christopher Eltschka <celtschk@physik.tu-muenchen.de> wrote:
> However, I would like to have a new keyword "constable" for
> such a semantics:
struct enforcement;
struct crime {
float penalty()=0; // How much time (days)
// Special values for penalty()
const double death = 1e20; // Death penalty
const double warning = 0.0; // Just a warning
void perform(enforcement*&)=0; // Do the crime
};
struct enforcement {
void arrest(const crime*)=0; // Bust 'em
void report()=0; // Paperwork
virtual ~enforcement() {}
};
struct murder : public crime {
float penalty() { return death; }
// Kill an enforcement
void perform(enforcement*&e) { delete e; e=0; }
};
struct theft : public crime {
float usual_penalty;
theft() : usual_penalty(30) {} // Penalty is 30 days in jail
// Steal enforcement's identity (but don't kill him!)
void perform(enforcement*&e) { e=0; }
};
struct battery : public crime {
float usual_penalty;
battery() : usual_penalty(10) {} // Penalty is 10 days in jail
float penalty() { return usual_penalty; }
void perform(enforcement*&e) {
// First, mess with the enforcement officer's head
int*i = (int*)e; ++i[0];
// Now hack the computer, let's get off with a warning
usual_penalty = warning;
}
};
struct officer : public enforcement {
void arrest(crime*criminal) { /* ... */ }
void report() { /* ... */ }
};
struct lieutenant: public officer {
// Refine officer to do more paperwork, less field work, higher pay
};
struct ranger : public lieutenant {};
struct captain : public lieutenant { };
struct chief : public captain {};
struct sheriff : public captain {};
// U.S. Street Slang
typedef officer cop;
typedef officer the_man;
// Slang from other English-language countries
typedef officer constable;
typedef officer bobby;
typedef officer copper; // cop already accounted for
struct occupation {};
struct programmer: public occupation {
constable *c;
programmer() : c(new constable) {};
void bored() { murder m; m.perform(c); }
};
I was just thinking, some of these programmers have been getting
away with murder. Where's a constable when you really need one?
--
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.
-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp Create Your Own Free Member Forum
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@fermi.ceg.uiuc.edu (Siemel Naran)
Date: 1998/08/19 Raw View
On 18 Aug 1998 16:32:41 GMT, Christopher Eltschka
>Indeed, allowing optimization to take advantage from const in
>access paths rather than complete objects would only be possible
>with changes to the C++ language:
OK. I understand now. If struct S contains a const reference to an
object x, this is no gaurantee that x is const. There's just the
recommendation that S will try not to modify x. S can still modify
x through a const_cast. Alternatively, some external agent may
modify x. So computations arising from operations on the reference
to constant object x can not be cached.
>A pointer or reference to constify would usually be used if the
>pointed-to or referenced object is logically part of the class.
>F.ex. it could be used with the "pimple idiom":
struct X { int a,b; };
struct S { X constify *const x; void f() const; };
In a non-const member function, x has type "X *const".
In a const member function, x has type "X const *const".
So the "constify" is just there to help us enforce logical constancy
-- i.e. to help us get our code right. But we don't need a new
language feature to do this.
template <class T>
class smart_pointer
{
private:
T* ptr;
public:
smart_pointer(T (*)=0);
T* operator->();
const T* operator->() const;
//etc
};
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: AllanW@my-dejanews.com
Date: 1998/08/20 Raw View
In article <slrn6tm99m.gs6.sbnaran@fermi.ceg.uiuc.edu>,
sbnaran@KILL.uiuc.edu wrote:
>
>
> On 18 Aug 1998 16:32:41 GMT, Christopher Eltschka
>
> >Indeed, allowing optimization to take advantage from const in
> >access paths rather than complete objects would only be possible
> >with changes to the C++ language:
>
> OK. I understand now. If struct S contains a const reference to an
> object x, this is no gaurantee that x is const.
> [...] some external agent may
> modify x. So computations arising from operations on the reference
> to constant object x can not be cached.
My understanding is that this is what "volatile" is for.
int myfunc() {
MyClass &x = ...
int a = x.someint;
a += x.someint; // Can optimize to a += a
x.somefunc();
a += x.someint; // Can't optimize because x.somefunc() might
// have modified someint
MyClass volatile &y = ...
a = y.someint;
a += y.someint; // Cannot optimize, because y is volatile
y.somefunc();
a += y.someint; // Still can't optimize
}
This is correct, isn't it? If not, what *is* the point of volatile?
--
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.
-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp Create Your Own Free Member Forum
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1998/08/14 Raw View
Siemel Naran wrote:
>
> On 12 Aug 1998 16:47:37 GMT, James Kuyper <kuyper@wizard.net> wrote:
>
> >Moral 1: don't waste human time doing what computers do better.
>
> Right. But the computer is sometimes quite dumb. See below.
>
> >Moral 2: clients don't always know what they want until after you give
> >them what they said they wanted.
>
> :)
>
> I often use the coding style given below, but came to a startling conclusion
> when thinking about the STL and it's relationship to optimization.
>
> int action(const MyClass& m, const vector& v)
I assume, you meant vector<int>?
> {
> int sum=0;
> for (int i=0; i<v.size(); ++i)
> {
> int out = v[i] + m.val() + ( isodd(v[i]) ? m.odd():m.even() );
> sum+=out;
> }
> return sum;
> }
>
> We'd like this to become
>
> int action(const MyClass& m, const vector& v)
> {
> int sum=0;
>
> const int val=m.val(), odd=m.odd(), even=m.even();
> const int N=v.size();
> int const *const begin=&v[0];
> int const *const end =&v[N];
>
> for (int const* iter=begin; iter!=end; ++iter)
> {
> register int tmp=*iter;
> int out = tmp + val + ( isodd(tmp) ? odd:even );
> sum+=out;
> cout << out << ' ';
> }
>
> return sum;
> }
>
> But this can't happen even though we know that it probably should happen.
>
> [X] It is possible that variable "m" has a data member "mutable vector&"
> which refers to nothing other than the vector 'v' !
The compiler *must* have the definition of MyClass to call members.
Therefore it *knows* if there's a mutable member.
However, unfortunately casting away const and then modifying
the casted object is well defined as long as the object itself
is not const (IMHO this is a relict from the times before mutable,
where const_cast was used to achieve the same effect). Therefore
the compiler cannot assume const really meaning const here, *despite*
having complete knowledge over the class definition.
Also, MyClass might have indirect access to vector, say via
m.xy()->abc()->d[e][f]->get_vec();
and the access path may be non-const even if m is const.
(BTW, mutable vector& doesn't make sense, since a reference cannot be
reseated, and the referenced item doesn't get "constified", that
is, even with a plain vector&, you'd be able to change the referenced
vector through a MyClass const.)
>
> [X] Now it is possible that any of the functions MyClass::val(), etc change
> the vector -- resizing it, for example. So "v.size()" is not a for-loop
> constant, and neither are "v.begin()" and "v.end()". So the operator[]
> access "v[i]" must do the array dereferencing from scratch (i.e. do a
> multiply and add instead of just an add).
Correct.
>
> [X] For the same reason, we can't store v[i] in a register. The function
> call "m.val()" may change the values of the vector 'v', and so v[i]
> must be recomputed (which means it must be redereferenced).
>
> [X] The result of "m.odd()" and "m.val(),m.odd()" may be different because the
> call "m.val()" may change some numbers inside MyClass. So these values
> can't be precomputed.
Even for unchanged m, the values can be different on every call.
A valid implementation of MyClass::odd() would be f.ex.:
int MyClass::odd() const
{
static int change_every_call = 0;
return change_every_call++;
}
>
>
>
> Note that const doesn't buy us anything! We can't rely on the optimizer to
> do anything for us unless, of course, it does an impossibly thorough analysis
> of the program.
Well, I'd say it helps us less than it would seem.
But if an *object* is declared const, some more optimizations are
possible
(since changing *that* would be undefined behaviour).
[...]
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@bardeen.ceg.uiuc.edu (Siemel Naran)
Date: 1998/08/14 Raw View
On 14 Aug 1998 16:00:13 GMT, Christopher Eltschka
>(BTW, mutable vector& doesn't make sense, since a reference cannot be
>reseated, and the referenced item doesn't get "constified", that
>is, even with a plain vector&, you'd be able to change the referenced
>vector through a MyClass const.)
In a future version of C++, it would be nice if
"T&" in a non-const class becomes "T const&" in a const class
"T" in a non-const class becomes "T const" in a const class
This makes sense because the reference is supposed to be exactly the same as
the object it refers to. And, it allows the compiler to do more aggressive
optimizations.
>Well, I'd say it helps us less than it would seem.
>But if an *object* is declared const, some more optimizations are
>possible
>(since changing *that* would be undefined behaviour).
Not sure about line #1. But good point on lines #2 to #4.
Also, if class MyClass contains a data member "const MyClass::vector&",
then the optimizations should be possible anyway.
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James Kuyper <kuyper@wizard.net>
Date: 1998/08/12 Raw View
Alwyn wrote:
>
> James Kuyper wrote:
>
> > Detecting loop invariants is ordinary current
> > state-of-the-art, and explicitly pulling them out of the loop
> > unnecessarily complicates the code.
>
> Fair comment, but such hand optimisation is second-nature to me, perhaps
> because I spent years programming in Babbage assembly language.
>
> I once had a C++ compiler from a very famous company with an equally famous
> compiler writer, which made a complete hash of one of the standard
> optimisations.
I once worked on a project where, according to the client, performance
was irrelevant, while meeting the deadline with at least the minimum
required functionality was everything. We designed accordingly. A month
before delivery they saw our preliminary test results, and suddenly
decided that performance did matter. We had expected this, and had kept
a list of performance modifications that we had thought of but hadn't
had the resources to implement yet. However, instead of having us
implement those changes, an outside consultant was brought in. He turned
off all optimizations, and then found that by extracting a loop
invariant from the innermost loop of one function, he achieved a 20%
speed-up over the original program without optimization. When I insisted
that he compare performance with all safe optimizations turned on, he
sheepishly admitted that the difference vanished.
In the meantime, the single most important algorithm change that we had
not previously had time to implement, produced a speed-up by a factor of
6!
Moral 1: don't waste human time doing what computers do better.
Moral 2: clients don't always know what they want until after you give
them what they said they wanted.
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Jim McKelvey <mckelvey@bean.jpl.nasa.gov>
Date: 1998/08/12 Raw View
James Kuyper wrote:
>
> Alwyn Thomas wrote:
> >
> > Paul D. DeRocco wrote:
> >
> > A moderately competent programmer can see that at a glance, whereas it's
> > very difficult for even the cleverest compiler.
> >
> > Moral: Don't expect compilers to do optimisations for you that you can
> > easily do yourself in a high-level language like C++.
>
> My time is expensive, and the compiler's time is cheap. I shouldn't be
> wasting my time doing optimizations that are ordinary state-of-the-art
> for current compilers. I've got many better things to spend my time on,
> which current compilers can't do well, like overall algorithm design.
> This is particularly true if relying on those optimizations allows me to
> write my code in a manner that makes it easier for future programmers to
> understand and maintain. Detecting loop invariants is ordinary current
> state-of-the-art, and explicitly pulling them out of the loop
> unnecessarily complicates the code.
>
I'm not so much interested in smart compilers that can optimize out loop
invariance; I'd like to be able to TELL the compiler that a function may
be hoisted out of the loop.
Fortran can do this for functions like SIN and COS because they are
intrinsics, and Fortran knows everything about its intrinsics.
People who come to C/C++ from Fortran are usually amazed to learn that
functions like sin are not hoisted.
And I'm always seeing strlen treated as if it should be optimized away
magically.
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@bardeen.ceg.uiuc.edu (Siemel Naran)
Date: 1998/08/12 Raw View
On 12 Aug 1998 16:47:37 GMT, James Kuyper <kuyper@wizard.net> wrote:
>Moral 1: don't waste human time doing what computers do better.
Right. But the computer is sometimes quite dumb. See below.
>Moral 2: clients don't always know what they want until after you give
>them what they said they wanted.
:)
I often use the coding style given below, but came to a startling conclusion
when thinking about the STL and it's relationship to optimization.
int action(const MyClass& m, const vector& v)
{
int sum=0;
for (int i=0; i<v.size(); ++i)
{
int out = v[i] + m.val() + ( isodd(v[i]) ? m.odd():m.even() );
sum+=out;
}
return sum;
}
We'd like this to become
int action(const MyClass& m, const vector& v)
{
int sum=0;
const int val=m.val(), odd=m.odd(), even=m.even();
const int N=v.size();
int const *const begin=&v[0];
int const *const end =&v[N];
for (int const* iter=begin; iter!=end; ++iter)
{
register int tmp=*iter;
int out = tmp + val + ( isodd(tmp) ? odd:even );
sum+=out;
cout << out << ' ';
}
return sum;
}
But this can't happen even though we know that it probably should happen.
[X] It is possible that variable "m" has a data member "mutable vector&"
which refers to nothing other than the vector 'v' !
[X] Now it is possible that any of the functions MyClass::val(), etc change
the vector -- resizing it, for example. So "v.size()" is not a for-loop
constant, and neither are "v.begin()" and "v.end()". So the operator[]
access "v[i]" must do the array dereferencing from scratch (i.e. do a
multiply and add instead of just an add).
[X] For the same reason, we can't store v[i] in a register. The function
call "m.val()" may change the values of the vector 'v', and so v[i]
must be recomputed (which means it must be redereferenced).
[X] The result of "m.odd()" and "m.val(),m.odd()" may be different because the
call "m.val()" may change some numbers inside MyClass. So these values
can't be precomputed.
Note that const doesn't buy us anything! We can't rely on the optimizer to
do anything for us unless, of course, it does an impossibly thorough analysis
of the program.
The STL coding style forces us to think in the 'optimized' way, and yet it
is not as messy.
struct Function
{
const int val, odd, even;
Function(const MyClass&);
inline int operator(int oldvalue, int number)
{
return number+val+(isodd(number)?odd:even);
}
}
int action(const MyClass& m, const vector& v)
{
return accumulate(v.begin(),v.end(),0,Function(m));
}
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: miker3@ix.netcom.com (Michael Rubenstein)
Date: 1998/08/12 Raw View
On 12 Aug 1998 16:58:45 GMT, Jim McKelvey <mckelvey@bean.jpl.nasa.gov>
wrote:
>
>James Kuyper wrote:
>>
>> Alwyn Thomas wrote:
>> >
>> > Paul D. DeRocco wrote:
>> >
>> > A moderately competent programmer can see that at a glance, whereas it's
>> > very difficult for even the cleverest compiler.
>> >
>> > Moral: Don't expect compilers to do optimisations for you that you can
>> > easily do yourself in a high-level language like C++.
>>
>
>> My time is expensive, and the compiler's time is cheap. I shouldn't be
>> wasting my time doing optimizations that are ordinary state-of-the-art
>> for current compilers. I've got many better things to spend my time on,
>> which current compilers can't do well, like overall algorithm design.
>> This is particularly true if relying on those optimizations allows me to
>> write my code in a manner that makes it easier for future programmers to
>> understand and maintain. Detecting loop invariants is ordinary current
>> state-of-the-art, and explicitly pulling them out of the loop
>> unnecessarily complicates the code.
>>
>
>I'm not so much interested in smart compilers that can optimize out loop
>invariance; I'd like to be able to TELL the compiler that a function may
>be hoisted out of the loop.
>
>Fortran can do this for functions like SIN and COS because they are
>intrinsics, and Fortran knows everything about its intrinsics.
>
>People who come to C/C++ from Fortran are usually amazed to learn that
>functions like sin are not hoisted.
>
>And I'm always seeing strlen treated as if it should be optimized away
>magically.
Note that the C and C++ languages allow a compiler to recognize that
sin and cos are invariant and hoist them out of a loop. The compiler
knows (or could know) everything about the standard functions. Some
(many? most?) compiler writers have decided not to do this.
--
Michael M Rubenstein
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@bardeen.ceg.uiuc.edu (Siemel Naran)
Date: 1998/08/12 Raw View
On 12 Aug 1998 16:58:45 GMT, Jim McKelvey <mckelvey@bean.jpl.nasa.gov>
>People who come to C/C++ from Fortran are usually amazed to learn that
>functions like sin are not hoisted.
KAI does this. Maybe other compilers do it too. They should.
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/08/13 Raw View
James Kuyper wrote:
>
> Moral 2: clients don't always know what they want until after you give
> them what they said they wanted.
On the other hand, clients often don't realize what they want until
after you give them what you knew they wanted.
--
Ciao,
Paul
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: christian.bau@isltd.insignia.com (Christian Bau)
Date: 1998/08/13 Raw View
In article <35D05293.41C6@wizard.net>, James Kuyper <kuyper@wizard.net> wrote:
> I once worked on a project where, according to the client, performance
> was irrelevant, while meeting the deadline with at least the minimum
> required functionality was everything. We designed accordingly. A month
> before delivery they saw our preliminary test results, and suddenly
> decided that performance did matter. We had expected this, and had kept
> a list of performance modifications that we had thought of but hadn't
> had the resources to implement yet.
> However, instead of having us
> implement those changes, an outside consultant was brought in. He turned
> off all optimizations, and then found that by extracting a loop
> invariant from the innermost loop of one function, he achieved a 20%
> speed-up over the original program without optimization.
This is absolutely brilliant. I think I should become an optimisation
consultant. Looks like an easy way to make money. Now if he had managed to
get a 20% improvement over original with optimisations, then he might be
called competent (but in the situation you describe, still not worth the
money).
> When I insisted
> that he compare performance with all safe optimizations turned on, he
> sheepishly admitted that the difference vanished.
> In the meantime, the single most important algorithm change that we had
> not previously had time to implement, produced a speed-up by a factor of
> 6!
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: AllanW@my-dejanews.com
Date: 1998/08/11 Raw View
In article <35CF49B1.5C82C46D@dircon.co.uk>,
alwyn@dircon.co.uk wrote:
>
> James Kuyper wrote:
>
> > Detecting loop invariants is ordinary current
> > state-of-the-art, and explicitly pulling them out of the loop
> > unnecessarily complicates the code.
>
> Fair comment, but such hand optimisation is second-nature to me, perhaps
> because I spent years programming in Babbage assembly language.
Even in assembly languages, one can ordinarily ask the assembler
to do things that higher-level languages might call "optimization."
// C++
extern const int number = 31+28+31;
; Pseudo-Assembly language
number: .word 31+28+31
The object code will contain an integer with the value 90. The
addition was done at assembly time, rather than when the integer
is initialized.
> I once had a C++ compiler from a very famous company with an equally famous
> compiler writer, which made a complete hash of one of the standard
> optimisations.
If you're saying that you can't rely on the compiler to optimize
away bad algorithms, I don't think you'll find much opposition.
--
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.
-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp Create Your Own Free Member Forum
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1998/08/11 Raw View
Siemel Naran wrote:
> Is there an optimization such as loop compounding? For example
>
> double out1[N]; // N is const
> for (int i=0; i<N; i++) out1[i]=a [i]+b[i]; // a,b,c has type double [N]
> double out2[N];
> for (int i=0; i<N; i++) out2[i]=out1[i]+c[i];
>
> becomes
>
> double out[N]; // N is const
> for (int i=0; i<N; i++) out[i]=a[i]+b[i]+c[i];
>
> This is useful for a+b+c, where each variable is a vector of fixed size.
In this uninterresting particular case, yes. In general, no.
That's a problem with C/C++ and numerical programs. Solutions
are restrict, valarray and template expressions; references:
- the Blitz++ project: http://monet.uwaterloo.ca/blitz/
- the SL++ library: http://wwwinfo.cern.ch/~ldeniau/sl.html
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Alwyn Thomas <alwyn@dircon.co.uk>
Date: 1998/08/06 Raw View
Paul D. DeRocco wrote:
> There was some language that distinguished between functions
> and procedures, and enforced a rule that functions couldn't access
> anything outside themselves, other than to call other functions. It
> hardly seems worth the trouble, given how easy it is to recognize such
> situations and fix them by hand. I've never been that grateful for
> compilers that find loop invariants, because I never create loops with
> invariants in them.
A moderately competent programmer can see that at a glance, whereas it's
very difficult for even the cleverest compiler.
Moral: Don't expect compilers to do optimisations for you that you can
easily do yourself in a high-level language like C++.
Alwyn
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/08/07 Raw View
Zalman Stern wrote:
>
> This sentiment is largely counterproductive. (And if you write any
> significant amount of code, I doubt its strictly true. E.g.
> intermediate address calculations often result in invariants on some
> architectures.)
> Templates and inline functions also greatly increase the chance of
> invariant calculations. Breaking out the invariant part either hairs
> up an interface or destroys its encapsulation.
I doubt it's "largely" counterproductive. It may be "somewhat"
counterproductive. I think the cases where the compiler will make a
significant improvement over what an attentive programmer can do are
fairly uncommon.
Even in the case of templates or inlines, if a compiler can find a loop
invariant that wouldn't have existed had the template had a different
parameter, or had the function not been inline, that's a freebie, and
not something that we'd normally complain about the lack of.
Of course, I'm coming from the Borland world, and their compilers are
notoriously inefficient. I guess that's the source of my attitude: why
do they put so much effort into finding loop invariants, when they put
so little into keeping track of what values are cached in registers?
--
Ciao,
Paul
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/08/07 Raw View
Bill Leonard wrote:
>
> Actually, I don't think this definition is compatible with C, because
> the C standard requires that the math functions set errno, doesn't it?
> I'm not sure if C++ also requires that behavior or not. Anyway,
> whether the standard requires it or not, a lot of programs rely on it.
> So, in fact, sin and its cousins *do* have side effects.
But isn't errno a sticky variable that is only set when an error occurs,
and not cleared when one doesn't? In this case, sin(x) could still
reduce to an FSIN op-code, as long as there's a hardware exception
handler that sets errno.
--
Ciao,
Paul
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: David R Tribble <david.tribble@noSPAM.central.beasys.com>
Date: 1998/08/07 Raw View
Jim McKelvey wrote:
>> How do I declare sin to be constant for constant input?
Paul D. DeRocco wrote:
> You can't. There was some language that distinguished between
> functions
> and procedures, and enforced a rule that functions couldn't access
> anything outside themselves, other than to call other functions. It
> hardly seems worth the trouble, given how easy it is to recognize such
> situations and fix them by hand.
That language was ISO Pascal. Most compilers did not enforce this
constraint on functions, but some did (such as the TI/9000 DX-10
Pascal compiler, back in the early 80's). Which was a pain,
especially if you wanted to take the Software Tools approach (which
was borrowed from Unix) of coding all procedures as functions that
returned a pass/fail status. Not allowing functions to have any
side effects, i.e., to do anything substantial such as I/O, was a
real irritant to useful coding. (C and C++ do not suffer from
this limitation.)
OTOH, there were PL/1 compilers that were capable of removing
redundant calls to functions (which were passed identical arguments)
if the functions had no side effects, just like Jim alluded to.
You had to turn on a special compiler switch to enable this
optimization.
-- David R. Tribble, dtribble@technologist.com --
-- Win95: Start me up... You make a grown man cry...
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: AllanW@my-dejanews.com
Date: 1998/08/07 Raw View
Never? Even if it seems like most compilers can see it?
int days_in_first_qtr = 31+28+31; // instead of 90
Even that?
--
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.
-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp Create Your Own Free Member Forum
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Jim McKelvey <mckelvey@bean.jpl.nasa.gov>
Date: 1998/08/06 Raw View
Bill Leonard wrote:
>
> In article <35C67E63.69530B1C@ix.netcom.com>, "Paul D. DeRocco" <pderocco@ix.netcom.com> writes:
...
> Actually, I don't think this definition is compatible with C, because the C
> standard requires that the math functions set errno, doesn't it? I'm not
> sure if C++ also requires that behavior or not. Anyway, whether the
> standard requires it or not, a lot of programs rely on it. So, in fact,
> sin and its cousins *do* have side effects.
>
> > > How do I declare sin to be constant for constant input?
>
> We have considered providing a pragma for this kind of declaration. (I
> know, that's not a portable solution, I just wanted to mention it.)
> However, the "errno" requirement really gets in the way of that. Even if
> the compiler knows that the function yields a constant value for a given
> input, it also has to know whether or not you care about errno, and that
> requires inter-procedural analysis.
>
But if the function is constant, it will do the same thing to errno each
time: either set it to the same value on error, or leave it alone. So
the compiler does the equivalent of this:
for (i = 0; i < 5; i++)
{
x[i] = sin(0.1);
}
becomes:
// Preserve errno
const int __errno1 = errno;
// Precompute function, and preserve its errno status
errno = 0;
const double __temp = sin(0.1);
const int __errno2 = errno;
// Reset errno, because function has not yet been logically called
errno = __errno1;
for (i = 0; i < 5; i++)
{
x[i] = __temp;
if (__errno2 != 0)
{
errno = __errno2;
}
}
Then let the optimizer clean things up.
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Jerry Leichter <leichter@smarts.com>
Date: 1998/08/06 Raw View
| > > How do I declare sin to be constant for constant input?
|
| We have considered providing a pragma for this kind of declaration.
| (I know, that's not a portable solution, I just wanted to mention it.)
| However, the "errno" requirement really gets in the way of that. Even
| if the compiler knows that the function yields a constant value for a
| given input, it also has to know whether or not you care about errno,
| and that requires inter-procedural analysis.
Just as an interesting data point, the IBM xlc/xlC (C/C++ compilers) on
AIX provide a -qignerrno option, which "Allows the compiler to perform
optimizations that assume errno is not modified by system calls. ...
Library routines set errno .... This setting ... may be ignored by
specifying -qignerrno". (The compiler actually has a kind of "dead-man
switch", too - if you actually explicitly reference errno in a
compilation unit, the compiler will ignore your attempt to set
-qignerrno.)
-- Jerry
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Alwyn Thomas <alwyn@dircon.co.uk>
Date: 1998/08/08 Raw View
> Never? Even if it seems like most compilers can see it?
> int days_in_first_qtr = 31+28+31; // instead of 90
> Even that?
But I wouldn't regard that as an optimisation. I have a reasonable
expectation that the compiler will evaluate that arithmetical constant
expression for me as it compiles. After all, isn't that part of the
standard? (See, for instance, section 5.19 of CD2 on "Constant
expressions".)
Alwyn
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James Kuyper <kuyper@wizard.net>
Date: 1998/08/10 Raw View
Alwyn Thomas wrote:
>
> Paul D. DeRocco wrote:
>
> > There was some language that distinguished between functions
> > and procedures, and enforced a rule that functions couldn't access
> > anything outside themselves, other than to call other functions. It
> > hardly seems worth the trouble, given how easy it is to recognize such
> > situations and fix them by hand. I've never been that grateful for
> > compilers that find loop invariants, because I never create loops with
> > invariants in them.
>
> A moderately competent programmer can see that at a glance, whereas it's
> very difficult for even the cleverest compiler.
>
> Moral: Don't expect compilers to do optimisations for you that you can
> easily do yourself in a high-level language like C++.
My time is expensive, and the compiler's time is cheap. I shouldn't be
wasting my time doing optimizations that are ordinary state-of-the-art
for current compilers. I've got many better things to spend my time on,
which current compilers can't do well, like overall algorithm design.
This is particularly true if relying on those optimizations allows me to
write my code in a manner that makes it easier for future programmers to
understand and maintain. Detecting loop invariants is ordinary current
state-of-the-art, and explicitly pulling them out of the loop
unnecessarily complicates the code.
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@bardeen.ceg.uiuc.edu (Siemel Naran)
Date: 1998/08/10 Raw View
>My time is expensive, and the compiler's time is cheap. I shouldn't be
>wasting my time doing optimizations that are ordinary state-of-the-art
>for current compilers. I've got many better things to spend my time on,
>which current compilers can't do well, like overall algorithm design.
>This is particularly true if relying on those optimizations allows me to
>write my code in a manner that makes it easier for future programmers to
>understand and maintain. Detecting loop invariants is ordinary current
>state-of-the-art, and explicitly pulling them out of the loop
>unnecessarily complicates the code.
To help the compiler with optimizations, we should pass objects by
value to avoid aliasing problems, right? But what if the object
itself contains a pointer or reference?
Is there an optimization such as loop compounding? For example
double out1[N]; // N is const
for (int i=0; i<N; i++) out1[i]=a [i]+b[i]; // a,b,c has type double [N]
double out2[N];
for (int i=0; i<N; i++) out2[i]=out1[i]+c[i];
becomes
double out[N]; // N is const
for (int i=0; i<N; i++) out[i]=a[i]+b[i]+c[i];
This is useful for a+b+c, where each variable is a vector of fixed size.
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Alwyn <alwyn@dircon.co.uk>
Date: 1998/08/10 Raw View
James Kuyper wrote:
> Detecting loop invariants is ordinary current
> state-of-the-art, and explicitly pulling them out of the loop
> unnecessarily complicates the code.
Fair comment, but such hand optimisation is second-nature to me, perhaps
because I spent years programming in Babbage assembly language.
I once had a C++ compiler from a very famous company with an equally famous
compiler writer, which made a complete hash of one of the standard
optimisations.
Alwyn
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: AllanW@my-dejanews.com
Date: 1998/08/04 Raw View
In article <35C67E63.69530B1C@ix.netcom.com>,
"Paul D. DeRocco" <pderocco@ix.netcom.com> wrote:
> I've never been that grateful for
> compilers that find loop invariants, because I never create loops with
> invariants in them.
But this is learned behavior.
Five years ago, I would write code like this:
const int days_in_Q1 = 91; // 31+28+31;
instead of:
const int days_in_Q1 = 31+28+31;
because I knew that some compilers would do the addition at runtime.
The first line is trivially smaller and faster; by itself it won't make
any difference, but thousands of these tiny things throughout the
program could make a difference.
The catch was that the first method was error-prone (in fact, 31+28+31
is 90, not 91!) and harder to read (was that division, or a comment?).
Today, unless I'm working in "maximum portability" mode, I would write
the code the second way, and rely on the compiler to optimize it back
to the first one (but correctly).
-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp Create Your Own Free Member Forum
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: zalman@netcom.com (Zalman Stern)
Date: 1998/08/05 Raw View
Paul D. DeRocco (pderocco@ix.netcom.com) wrote:
: I've never been that grateful for
: compilers that find loop invariants, because I never create loops with
: invariants in them.
This sentiment is largely counterproductive. (And if you write any
significant amount of code, I doubt its strictly true. E.g. intermediate
address calculations often result in invariants on some architectures.)
Templates and inline functions also greatly increase the chance of
invariant calculations. Breaking out the invariant part either hairs up an
interface or destroys its encapsulation.
-Z-
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: bill@amber.ssd.csd.harris.com (Bill Leonard)
Date: 1998/08/05 Raw View
In article <35C67E63.69530B1C@ix.netcom.com>, "Paul D. DeRocco" <pderocco@ix.netcom.com> writes:
> Since sin is normally a library function, most C++ compilers will assume
> that it may have side effects, and call it five times. However, a
> compiler might define it in math.h as:
>
> inline double sin(double x) { return __sin__(x); }
>
> where __sin__ is an intrinsic function that represents (e.g.) a FSIN
> opcode. Then, it could notice that the FSIN could be pulled out of the
> loop. Borland isn't this smart.
Actually, I don't think this definition is compatible with C, because the C
standard requires that the math functions set errno, doesn't it? I'm not
sure if C++ also requires that behavior or not. Anyway, whether the
standard requires it or not, a lot of programs rely on it. So, in fact,
sin and its cousins *do* have side effects.
> > How do I declare sin to be constant for constant input?
We have considered providing a pragma for this kind of declaration. (I
know, that's not a portable solution, I just wanted to mention it.)
However, the "errno" requirement really gets in the way of that. Even if
the compiler knows that the function yields a constant value for a given
input, it also has to know whether or not you care about errno, and that
requires inter-procedural analysis.
--
Bill Leonard
Concurrent Computer Corporation
2101 W. Cypress Creek Road
Fort Lauderdale, FL 33309
Bill.Leonard@mail.ccur.com
These opinions and statements are my own and do not necessarily reflect the
opinions or positions of Concurrent Computer Corporation.
------------------------------------------------------------------------------
It doesn't matter which way you are headed if you're not going anywhere.
------------------------------------------------------------------------------
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/08/04 Raw View
Jim McKelvey wrote:
>
> Given a loop like:
>
> for (int i = 0; i < 5; i++)
> {
> x[i] = sin(0.5);
> }
>
> where the value of sin is constant for constant input.
>
> Under what circumstances can C++ hoist the sin call out of the loop?
Since sin is normally a library function, most C++ compilers will assume
that it may have side effects, and call it five times. However, a
compiler might define it in math.h as:
inline double sin(double x) { return __sin__(x); }
where __sin__ is an intrinsic function that represents (e.g.) a FSIN
opcode. Then, it could notice that the FSIN could be pulled out of the
loop. Borland isn't this smart.
> How do I declare sin to be constant for constant input?
You can't. There was some language that distinguished between functions
and procedures, and enforced a rule that functions couldn't access
anything outside themselves, other than to call other functions. It
hardly seems worth the trouble, given how easy it is to recognize such
situations and fix them by hand. I've never been that grateful for
compilers that find loop invariants, because I never create loops with
invariants in them.
--
Ciao,
Paul
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Jim McKelvey <mckelvey@bean.jpl.nasa.gov>
Date: 1998/08/01 Raw View
Given a loop like:
for (int i = 0; i < 5; i++)
{
x[i] = sin(0.5);
}
where the value of sin is constant for constant input.
Under what circumstances can C++ hoist the sin call out of the loop?
How do I declare sin to be constant for constant input?
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1998/08/02 Raw View
Jim McKelvey <mckelvey@bean.jpl.nasa.gov> writes:
>Given a loop like:
>for (int i = 0; i < 5; i++)
>{
> x[i] = sin(0.5);
>}
>where the value of sin is constant for constant input.
>Under what circumstances can C++ hoist the sin call out of the loop?
Let's assume that <math.h> or <cmath> has been included, and
that the sin function in the C library is being called.
The name "sin" as an external identifier is reserved, so the
compiler is always allowed to precompute the result as a constant,
or hoist the call out of the loop. Some compilers get that effect
in other ways. For example, on a CISC architecture the "sin"
function might get converted to a machine instruction, and the
optimizer could hoist that instruction out of the loop.
No compiler is obligated to perform any of these optimizations.
(They do not affect program meaning or correctness, and so are
entirely optional.)
>How do I declare sin to be constant for constant input?
You can't. You are not allowed in standard C++ to provide your own
declaration for any of the library functions -- you must include
the appropriate header. (In C you are allowed to provide a
declaration that matches the declaration in the standard, but not
in C++.)
Apart from that, there isn't any form of a function declaration
that says the output is always the same for a given input. You can
pull the function call out of the loop yourself, of course. Doing
so is likely to be about as efficient as if the compiler did its
own optimization, and will improve performance with compilers that
do not perform this optimization.
OTOH, I'd find out whether the optimization made any measureable
difference in program performance before contorting my source code.
--
Steve Clamage, stephen.clamage@sun.com
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: AllanW@my-dejanews.com
Date: 1998/08/03 Raw View
In article <35C1FD0B.6EF2@bean.jpl.nasa.gov>,
mckelvey@bean.jpl.nasa.gov wrote:
> Given a loop like:
>
> for (int i = 0; i < 5; i++)
> {
> x[i] = sin(0.5);
> }
>
> where the value of sin is constant for constant input.
>
> Under what circumstances can C++ hoist the sin call out of the loop?
Whenever the compiler can follow the "as-if" rule. That is, the result
has to be the same as if the sin() function had been called 5 times
with 5 different inputs.
> How do I declare sin to be constant for constant input?
There's no language-defined way to do this. Perhaps, like the
"inline" or "register" keywords which are compiler hints (the
compiler is allowed to ignore them), there could have been a
"calculator" keyword stating that a certain functions' output
can always be predicted from just the inputs (like a calculator
without a memory).
If the function is small enough, you could probably accomplish
what you want by inlining it. For instance:
inline int triple(int i) { return i+i+i; }
Even though the keyword doesn't mean exactly what you want,
still the compiler will evaluate the function for any given
input. So
x[i]=triple(i);
becomes
x[i]=i+i+i;
and sometimes then it can make further optimizations (such as
when i is constant or in a very small unrollable loop).
For the mathematical sin() function, though, depending on how
you implement it, it may be too large for most compilers to
inline. But I'm not certain what optimization it could do for
this case anyway, except perhaps
x[0] = sin(1);
x[1] = sin(2);
x[3] = sin(1);
x[4] = sin(2);
x[5] = sin(1);
which the compiler could rewrite:
x[0] = sin(1);
x[1] = sin(2);
x[3] = x[0];
x[4] = x[1];
x[5] = x[0];
...Of course, a competent programmer could make the same
rewrite...
-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp Create Your Own Free Member Forum
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]