Topic: optimize const T& parameter to T


Author: clamsd-news@yahoo.com
Date: Thu, 22 Feb 2007 06:42:51 GMT
Raw View
On Tue, 20 Feb 2007 12:05:50 CST, "W Karas" <wkaras@yahoo.com> wrote:

>On Feb 16, 7:48 pm, stephen.clam...@sun.com wrote:
>> On Fri, 16 Feb 2007 17:23:08 CST, "W Karas" <wka...@yahoo.com> wrote:
>> >Consider a source file that has (only) this:
>>
>> >template <typename T>
>> >void foo(const T &i);
>>
>> >void bar(int i) { foo(i); }
>>
>> >If it was compiled with optimization, is it unreasonable to expect it
>> >should generate the same object code (aside from differences in
>> >mangled names) as this file?
>
>> The compiler is in general not allowed to make that "optimization".
>
>Why do you put optimization in quotes?  What I suggest would
>make the resulting program smaller and faster.

But as I showed later, the optimization is not in general valid.

You could make any program smaller and faster by transforming it to

int main() { return 0; }

Would you call that an optimization? I wouldn't. Hence the quotes. :-)

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "W Karas" <wkaras@yahoo.com>
Date: Thu, 22 Feb 2007 08:57:31 CST
Raw View
On Feb 22, 1:42 am, clamsd-n...@yahoo.com wrote:
> On Tue, 20 Feb 2007 12:05:50 CST, "W Karas" <wka...@yahoo.com> wrote:
> >On Feb 16, 7:48 pm, stephen.clam...@sun.com wrote:
> >> On Fri, 16 Feb 2007 17:23:08 CST, "W Karas" <wka...@yahoo.com> wrote:
> >> >Consider a source file that has (only) this:
>
> >> >template <typename T>
> >> >void foo(const T &i);
>
> >> >void bar(int i) { foo(i); }
>
> >> >If it was compiled with optimization, is it unreasonable to expect it
> >> >should generate the same object code (aside from differences in
> >> >mangled names) as this file?
>
> >> The compiler is in general not allowed to make that "optimization".
>
> >Why do you put optimization in quotes?  What I suggest would
> >make the resulting program smaller and faster.
>
> But as I showed later, the optimization is not in general valid.

Sorry, I don't see that.  The optimization is valid I think for T a
primitive type or a class with no direct or indirect mutable
data members.  The Standard allows casting away const,
but does not guarantee it will work, as const data could
be in ROM or in text/read-only MMU pages.

I take your point about the aliasing, but better compilers
have option(s) that controls whether or not the
compiler should limit optimization to allow
for (generally undesirable types of) aliasing.  Doesn't
the Standard say that some aliasing situations may
not be portable?

>
> You could make any program smaller and faster by transforming it to
>
> int main() { return 0; }
>
> Would you call that an optimization? I wouldn't. Hence the quotes. :-)

In some cases, yes.  It's possible to write a program that has
millions of lines of code, but no observable behavior.

I'm a Solaris user, so it doesn't surprise me you're very careful
not to over-optimize :-) .

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: stephen.clamage@sun.com
Date: Thu, 22 Feb 2007 17:24:44 GMT
Raw View
On Thu, 22 Feb 2007 08:57:31 CST, "W Karas" <wkaras@yahoo.com> wrote:

>On Feb 22, 1:42 am, clamsd-n...@yahoo.com wrote:
>> On Tue, 20 Feb 2007 12:05:50 CST, "W Karas" <wka...@yahoo.com> wrote:
>> >On Feb 16, 7:48 pm, stephen.clam...@sun.com wrote:
>> >> On Fri, 16 Feb 2007 17:23:08 CST, "W Karas" <wka...@yahoo.com> wrote:
>> >> >Consider a source file that has (only) this:
>>
>> >> >template <typename T>
>> >> >void foo(const T &i);
>>
>> >> >void bar(int i) { foo(i); }
>>
>> >> >If it was compiled with optimization, is it unreasonable to expect it
>> >> >should generate the same object code (aside from differences in
>> >> >mangled names) as this file?
>>
>> >> The compiler is in general not allowed to make that "optimization".
>>
>> >Why do you put optimization in quotes?  What I suggest would
>> >make the resulting program smaller and faster.
>>
>> But as I showed later, the optimization is not in general valid.
>
>Sorry, I don't see that.  The optimization is valid I think for T a
>primitive type or a class with no direct or indirect mutable
>data members.

int k = 1;

void foo();

int f(const int& i)
{
   foo();
   cout << i;
}

/*
int g(int i)
{
   foo();
   cout << i;
}
*/

Your claim is that the compiler can transform the definition of f into
the function g, and change call sites accordingly.

Suppose we call f(k) and foo() modifies k. The modified and unmodified
versions of f have different observable behavior, so the
transformation is not valid. In this example, the compiler does not
know whether foo modifies k, or whether f will be called with k as an
argument.

As I said before, with whole-program analysis, the compiler can in
principle find call sites where the tranformation is valid, and
generate multiple versions of a function with reference parameters,
calling the appropriate version based on what it can prove is a safe
transformation.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "W Karas" <wkaras@yahoo.com>
Date: Fri, 23 Feb 2007 15:49:20 CST
Raw View
On Feb 22, 12:24 pm, stephen.clam...@sun.com wrote:
> On Thu, 22 Feb 2007 08:57:31 CST, "W Karas" <wka...@yahoo.com> wrote:
> >On Feb 22, 1:42 am, clamsd-n...@yahoo.com wrote:
> >> On Tue, 20 Feb 2007 12:05:50 CST, "W Karas" <wka...@yahoo.com> wrote:
> >> >On Feb 16, 7:48 pm, stephen.clam...@sun.com wrote:
> >> >> On Fri, 16 Feb 2007 17:23:08 CST, "W Karas" <wka...@yahoo.com> wrote:
> >> >> >Consider a source file that has (only) this:
>
> >> >> >template <typename T>
> >> >> >void foo(const T &i);
>
> >> >> >void bar(int i) { foo(i); }
>
> >> >> >If it was compiled with optimization, is it unreasonable to expect it
> >> >> >should generate the same object code (aside from differences in
> >> >> >mangled names) as this file?
>
> >> >> The compiler is in general not allowed to make that "optimization".
>
> >> >Why do you put optimization in quotes?  What I suggest would
> >> >make the resulting program smaller and faster.
>
> >> But as I showed later, the optimization is not in general valid.
>
> >Sorry, I don't see that.  The optimization is valid I think for T a
> >primitive type or a class with no direct or indirect mutable
> >data members.
>
> int k = 1;
>
> void foo();
>
> int f(const int& i)
> {
>    foo();
>    cout << i;
>
> }
>
> /*
> int g(int i)
> {
>    foo();
>    cout << i;}
>
> */
>
> Your claim is that the compiler can transform the definition of f into
> the function g, and change call sites accordingly.
>
> Suppose we call f(k) and foo() modifies k. The modified and unmodified
> versions of f have different observable behavior, so the
> transformation is not valid. In this example, the compiler does not
> know whether foo modifies k, or whether f will be called with k as an
> argument.

I still don't agree that this means my suggestion cannot be called
an optimization.  It just shows that it's in a category of aggressive
optimizations that can be broken by aliasing, and should not be
enabled by default.

The scenario you describe indicates that "const" doesn't really mean
constant, it actually means read-only.  If a hyothetical compiler
had a "--const-really-const" switch that allowed the compiler to
assume const variables are not changed by side effects, then
f() would have to be re-written as follows to work when this
switch was used:

void foo();

template <typename T>
class read_only
  {
    T &r;
  public:
    read_only(T &rr) : r(rr) { }
    operator T () { return(r); }
  }

int f(read_only<int> i)
{
   foo();
   cout << i;
}

(Except I can't remember now if conversion operators are considered
by function lookup, so it might have to be cout << i.val(); or
something.)


---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Mathias Gaunard <loufoque@gmail.com>
Date: Sun, 25 Feb 2007 13:05:14 CST
Raw View
stephen.clamage@sun.com wrote:

> int k = 1;
>
> void foo();
>
> int f(const int& i)
> {
>    foo();
>    cout << i;
> }
>
> /*
> int g(int i)
> {
>    foo();
>    cout << i;
> }
> */
>
> Your claim is that the compiler can transform the definition of f into
> the function g, and change call sites accordingly.
>
> Suppose we call f(k) and foo() modifies k. The modified and unmodified
> versions of f have different observable behavior

I don't see how that would be the case.
foo only has access to the global variable, independent from the one
provided to f or g.
Whatever foo does, I see no reason preventing to replace f with g.

Would you mind explaining, or giving an actual example?

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: jdennett@acm.org (James Dennett)
Date: Mon, 26 Feb 2007 07:30:37 GMT
Raw View
Mathias Gaunard wrote:
> stephen.clamage@sun.com wrote:
>
>> int k = 1;
>>
>> void foo();
>>
>> int f(const int& i)
>> {
>>    foo();
>>    cout << i;
>> }
>>
>> /*
>> int g(int i)
>> {
>>    foo();
>>    cout << i;
>> }
>> */
>>
>> Your claim is that the compiler can transform the definition of f into
>> the function g, and change call sites accordingly.
>>
>> Suppose we call f(k) and foo() modifies k. The modified and unmodified
>> versions of f have different observable behavior
>
> I don't see how that would be the case.
> foo only has access to the global variable, independent from the one
> provided to f or g.
> Whatever foo does, I see no reason preventing to replace f with g.
>
> Would you mind explaining, or giving an actual example?

The global variable may well be the one provided to f:

int foo()
{
  k = 0;
}

int main()
{
  f(k); // must print 0, as foo will set k to 0.
}

Clearly changing this to call g instead of f would
not be a valid transformation.  *If* the compiler
can prove that the argument to f is not aliased,
then it can make the transformation as there is
no way for code to tell the difference.  (That
would not be the case if f() used the identity
of the passed object.)

-- James

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: clamsd-news@yahoo.com
Date: Mon, 26 Feb 2007 15:43:12 GMT
Raw View
On Fri, 23 Feb 2007 15:49:20 CST, "W Karas" <wkaras@yahoo.com> wrote:

>On Feb 22, 12:24 pm, stephen.clam...@sun.com wrote:
>>
>> Your claim is that the compiler can transform the definition of f into
>> the function g, and change call sites accordingly.
>>
>> Suppose we call f(k) and foo() modifies k. The modified and unmodified
>> versions of f have different observable behavior, so the
>> transformation is not valid. In this example, the compiler does not
>> know whether foo modifies k, or whether f will be called with k as an
>> argument.
>
>I still don't agree that this means my suggestion cannot be called
>an optimization.  It just shows that it's in a category of aggressive
>optimizations that can be broken by aliasing, and should not be
>enabled by default.

OK, we just have different definitions of "optimization".

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: cbarron3@ix.netcom.com (Carl Barron)
Date: Mon, 26 Feb 2007 17:21:14 GMT
Raw View
Mathias Gaunard <loufoque@gmail.com> wrote:

> stephen.clamage@sun.com wrote:
>
> > int k = 1;
> >
> > void foo();
> >
> > int f(const int& i)
> > {
> >    foo();
> >    cout << i;
> > }
> >
> > /*
> > int g(int i)
> > {
> >    foo();
> >    cout << i;
> > }
> > */
> >
> > Your claim is that the compiler can transform the definition of f into
> > the function g, and change call sites accordingly.
> >
> > Suppose we call f(k) and foo() modifies k. The modified and unmodified
> > versions of f have different observable behavior
>
> I don't see how that would be the case.
> foo only has access to the global variable, independent from the one
> provided to f or g.
> Whatever foo does, I see no reason preventing to replace f with g.
>
> Would you mind explaining, or giving an actual example?
>
  simply:

  void foo() {k=2;}

  f(k) prints 2
  g(k) prints 1



---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Chris Jefferson" <4zumanga@gmail.com>
Date: Tue, 20 Feb 2007 10:38:39 CST
Raw View
On Feb 16, 11:23 pm, "W Karas" <wka...@yahoo.com> wrote:
> Consider a source file that has (only) this:
>
> template <typename T>
> void foo(const T &i);
>
> void bar(int i) { foo(i); }
>
> If it was compiled with optimization, is it unreasonable to expect it
> should generate the same object code (aside from differences in
> mangled names) as this file?
>
> template <typename T>
> void foo(T i);
>
> void bar(int i) { foo(i); }


The major problem is I believe the following code is valid, as long
the int being passed into the function was originally declared as non-
const. This kind of thing messes up most attempts to optimise with
const.

void foo(const int& i)
{ int& no_const = const_cast<int>(i);
  no_const++;
}

If you really care about this kind of thing, it's possible to write a
template wrapper which chooses if to pas a const T& or a T depending
on the type. I've written one myself, I'm not sure if boost contains
one which might be better written than mine :)


---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "W Karas" <wkaras@yahoo.com>
Date: Tue, 20 Feb 2007 12:05:50 CST
Raw View
On Feb 16, 7:48 pm, stephen.clam...@sun.com wrote:
> On Fri, 16 Feb 2007 17:23:08 CST, "W Karas" <wka...@yahoo.com> wrote:
> >Consider a source file that has (only) this:
>
> >template <typename T>
> >void foo(const T &i);
>
> >void bar(int i) { foo(i); }
>
> >If it was compiled with optimization, is it unreasonable to expect it
> >should generate the same object code (aside from differences in
> >mangled names) as this file?

Turns out that this optimization is not worth the bother, since the
issue it would solve is already solved by
boost::call_traits<T>::param_type

http://www.boost.org/libs/utility/call_traits.htm#examples

(although it might have been clearer to to call the
member type value_param_type).

>
> >template <typename T>
> >void foo(T i);
>
> >void bar(int i) { foo(i); }
>
> The compiler is in general not allowed to make that "optimization".

Why do you put optimization in quotes?  What I suggest would
make the resulting program smaller and faster.

>
> In the final program, there will be only one instance of
> foo<int>(const int&), or of foo<int>(int) if the compiler were allowed
> to make the optimization you suggest.
>
> Since the definition of the template is not visible in your example,
> to make the optimiziation, the compiler would have to choose in
> advance and for all time always to treat const T& as T when T is a
> simple type. Otherwise, some calls of the function  would not match
> the generated instance.
>
> A program could also provide
> template <typename T>
> void foo(T i);
> with a different definition of the function body. The compiler would
> then have generated conflicing definitions of functions with the same
> signature.
>
> OK, the compiler could have a secret: it could mangle the function
> name as if the parameter were const T&, but generate code as if the
> parameter were T. That would make life difficult for anyone trying to
> understand or use the compiler's ABI, but that's why compiler writers
> make the big bucks. :-)

Taking this one step further, you can solve the issue of inconsistent
optimization of compilation units:  mangle the names to also
encode any optimizations in the calling convention.  To avoid
really aggrevating link errors, you could generate different
object code for the definitions of functions for all possible
combinations of optimization.  Template bloat on
steroids.  The obvious solution to THAT (and many
other things) is for object files to be "mini-libraries"
where each definition is independently includable/
excludable/relocated.  But I've never seen a compiler
that does this.

>
> The next issue is whether a program could tell the difference if the
> compiler chose to treat const T& as T.
>
> Remember that the const T& declaration doesn't mean the object can't
> change in value. It means only that you are not allowed to change the
> value through that reference. Suppose a global variable were passed to
> foo, and it could change via side effects of functions called by foo.
> You then would get a difference in program behavior between treating
> the argument as a reference or as a value.

I think this implies that the optimization could more safely be
done if the paramter type is T&& rather than const T&, so you
get the extra credit.

.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "W Karas" <wkaras@yahoo.com>
Date: Fri, 16 Feb 2007 17:23:08 CST
Raw View
Consider a source file that has (only) this:

template <typename T>
void foo(const T &i);

void bar(int i) { foo(i); }

If it was compiled with optimization, is it unreasonable to expect it
should generate the same object code (aside from differences in
mangled names) as this file?

template <typename T>
void foo(T i);

void bar(int i) { foo(i); }

I tried with a couple of (oldish) compilers, and both steadfastly
refused to convert a const reference parameter to a value parameter.
Are there reasons why the optimization I'm wishing for would
violate the "as if" rule?  Is there an unofficial rule that if a
program is linked from several object files, it still has to
work right even if the object were compiled with different
levels of optimization?

The extra point question is, once the C++09 compilers role
out, would it make any difference to use a rvalue
reference rather than a const lvalue reference:

template <typename T>
void foo(T &&i);

void bar(int i) { foo(i); }

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: stephen.clamage@sun.com
Date: Fri, 16 Feb 2007 18:48:56 CST
Raw View
On Fri, 16 Feb 2007 17:23:08 CST, "W Karas" <wkaras@yahoo.com> wrote:

>Consider a source file that has (only) this:
>
>template <typename T>
>void foo(const T &i);
>
>void bar(int i) { foo(i); }
>
>If it was compiled with optimization, is it unreasonable to expect it
>should generate the same object code (aside from differences in
>mangled names) as this file?
>
>template <typename T>
>void foo(T i);
>
>void bar(int i) { foo(i); }

The compiler is in general not allowed to make that "optimization".

In the final program, there will be only one instance of
foo<int>(const int&), or of foo<int>(int) if the compiler were allowed
to make the optimization you suggest.

Since the definition of the template is not visible in your example,
to make the optimiziation, the compiler would have to choose in
advance and for all time always to treat const T& as T when T is a
simple type. Otherwise, some calls of the function  would not match
the generated instance.

A program could also provide
template <typename T>
void foo(T i);
with a different definition of the function body. The compiler would
then have generated conflicing definitions of functions with the same
signature.

OK, the compiler could have a secret: it could mangle the function
name as if the parameter were const T&, but generate code as if the
parameter were T. That would make life difficult for anyone trying to
understand or use the compiler's ABI, but that's why compiler writers
make the big bucks. :-)

The next issue is whether a program could tell the difference if the
compiler chose to treat const T& as T.

Remember that the const T& declaration doesn't mean the object can't
change in value. It means only that you are not allowed to change the
value through that reference. Suppose a global variable were passed to
foo, and it could change via side effects of functions called by foo.
You then would get a difference in program behavior between treating
the argument as a reference or as a value.

All that said, some of these considerations no longer apply if foo is
declared inline. In the course of substituting the body of the
function for the call, uses of the parameter change to a dereference
of the address of the actual argument.

That is, if the actual argument is x, a use of the parameter becomes
*&x, which the compiler usually can simplify to x. The difference here
is that the compiler knows everything about the function and the
context in which it is called, and can make safe simplifications case
by case inside the expansion of foo.

in principle, some of the same kinds of things can happen with
whole-program optimization, performed conceptually at link time. Often
that would mean generating different versions of foo, one taking a
value and one taking a reference, giving them names that cannot
conlict with anything else via reserved mangling affixes, and
adjusting all call sites.

I don't know of any compilers that do this kind of optimization for
value vs refrence parameters. I do know of compilers that do the
optimziation for inline functions.

---
Steve Clamage
Sun Microsystems

---
[ 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.comeaucomputing.com/csc/faq.html                      ]