Topic: Elimination of named objects?


Author: mat@mole-end.matawan.nj.us
Date: Fri, 16 Dec 1994 05:08:23 GMT
Raw View
In article <smeyersD0K5D8.636@netcom.com>, smeyers@netcom.com (Scott Meyers) writes:
> In article <JASON.94Dec6124552@phydeaux.cygnus.com> jason@cygnus.com (Jason Merrill) writes:

> However, this changes the semantics of the object, because the return value
> will be destructed later than the local object.  Also, the return value is
> an unnamed object (what I always thought was called a "temporary") and can
> clearly be eliminated, especially in contexts like this:

>   Complex a = x + y;

> Now the destructor for the local object sum won't be invoked until a is
> destructed, which is possibly much later.  Again, think of what would
> happen if sum offered trace-like behavior.
>
> As I said earlier, I'm all for the as-if rule, so if what the ARM is really
> saying is that named objects can be optimized out of existence as long as
> nobody can tell, I'm a happy man.  The ARM doesn't say that about sum,
> however:  it says sum can be eliminated entirely.  Perhaps there is an
> underlying assumption that sum's semantics correspond to those of the
> default constructors, destructor, and assignment operators?

Yes.  And the language implementation is allowed to optimize away
intermediate temporaries, even if the constructors or destructors have
visible side effects (such at trace output).
--
 (This man's opinions are his own.)
 From mole-end    Mark Terribile
 mat@mole-end.matawan.nj.us, Somewhere in Matawan, NJ
 (Training and consulting in C, C++, UNIX, etc.)




Author: davisonj@en.ecn.purdue.edu (John M Davison)
Date: 12 Dec 1994 20:39:23 GMT
Raw View
        In article <JASON.94Dec9161014@phydeaux.cygnus.com> jason@cygnus.com
(Jason Merrill) writes:

>From the latest Working Paper:
>
>  3.6.2  Automatic storage duration                     [basic.stc.auto]
>
>3 A  named  automatic  object with a constructor or destructor with side
>  effects may not be destroyed before the end of its block, nor  may  it
>  be eliminated even if it appears to be unused.

        This brings up a concern I have with the C++ return mechanism; I am
sure that this has been brought up before, but I find it hard to understand why
the aspect of C++ that I am about to mention has been allowed to remain in the
language.

        A simple String or Vector object, for example, is typically going to
have some memory management code in its constructor and destructor.  The
existence of this code produces side effects which will prevent, for example,
the copy constructor invocation in a "return" statement from being optimized
out.  Thus, unless the programmer throws in some hacks to detect simple copies
in run time and make both of the objects point to the same data, thus avoiding
the bulk of the copy operation, lots of unnecessary copies must take place.

        The only way I can see around this is by doing something similar to
what is done in C+@: having an implicit (or perhaps explicitly declared via
some new keyword) "return value" object.

        Has there been any debate about this?  What conclusions were reached?
--
John Davison
Electronic Mail: davisonj@ecn.purdue.edu
WWW Home Page: <http://en.ecn.purdue.edu:20002/~davisonj/HomePage.html>




Author: jason@cygnus.com (Jason Merrill)
Date: Tue, 13 Dec 1994 20:01:08 GMT
Raw View
>>>>> John M Davison <davisonj@en.ecn.purdue.edu> writes:

>         A simple String or Vector object, for example, is typically going
> to have some memory management code in its constructor and destructor.
> The existence of this code produces side effects which will prevent, for
> example, the copy constructor invocation in a "return" statement from
> being optimized out.  Thus, unless the programmer throws in some hacks to
> detect simple copies in run time and make both of the objects point to
> the same data, thus avoiding the bulk of the copy operation, lots of
> unnecessary copies must take place.

I think that a compiler could probably get away with not considering memory
management to be a side effect.

Jason




Author: smeyers@netcom.com (Scott Meyers)
Date: Tue, 6 Dec 1994 08:19:38 GMT
Raw View
I was rereading section 12.1.1c of the ARM, and I noticed for the first
time that it implies that named objects can be eliminated by a
compiler.  The example it gives is this:

  Matrix operator+(const Matrix& a1, const Matrix& a2)
  {
    Matrix sum;
    ...
    return sum;
  }

The commentary reads in part:

  A smarter implementation will note that the local variable sum is
  redundant and eliminate it...

I have always been under the impression that named objects could not be
eliminated by the compiler, though, now that I look for it, I can't
find any such guarantee in the ARM.  In fact, the old "trace object"
trick relied on the fact that the compiler couldn't eliminate such
objects:

  void someFunction()
  {
    Trace t("someFunction");              // Trace ctor prints out that
                                          // someFunction has been enetered
    ...
  }                                       // Trace dtor prints out that
                                          // someFunction has been exited

If the compiler is allowed to eliminate named objects, what are the
rules determining when it can do so?  Are they the same as the rules
for eliminating temporaries?  If so, what does that say about objects
like transactions that function primarily through constructor and
destructor side-effects?

I'd like to believe that the ARM is mistaken and named objects can
never be eliminated.  If that is the case, however, it has a
significant impact on how programmers should write certain kinds of
functions.  For example:

  class Complex {
  private:
    int r, i;
  public:
    Complex(int realPart, int imagPart);
    Complex& operator+=(const Complex&);
    ...
  friend Complex operator+(const Complex&, const Complex&);
  };

  Complex operator+(const Complex& a, const Complex& b)  // version 1
  {
    Complex result = a;
    return result += b;
  }

  Complex operator+(const Complex& a, const Complex& b)  // version 2
  {
    return Complex(a.r+b.r, a.i+b.i);
  }

If named objects cannot be eliminated, version 1 of operator+ must
construct and destroy the object result.  Version 2 uses no named
object, but instead creates and returns an unnamed object.  If my belief
is correct and named objects cannot be eliminated by the compiler,
version 2 can be significantly more efficient, because there is no need
to create any local object.  If my belief is incorrect, both versions
might be equally efficient, but I then wonder which of the objects I
explicitly introduce into my program will actually be created.

What does the current draft say about this?

Scott





Author: pkt@lpi.liant.com (Scott Turner)
Date: Tue, 6 Dec 1994 16:11:47 GMT
Raw View
In article <smeyersD0Dr4q.FoG@netcom.com>, smeyers@netcom.com (Scott
Meyers) wrote:

> I'd like to believe that the ARM is mistaken and named objects can
> never be eliminated.

> What does the current draft say about this?

The working paper says, in 3.6.1 [basic.stc.static] paragraph 2:

   Note that if an object of static storage duration has initialization
   or a destructor with side effects, it shall not be eliminated even
   if it appears to be unused.

But there's also a note which says that some pending committee action
on the "as if" rule would have an impact on the paragraph.  I don't
know what that's about, but I hardly think it could change the longstanding
rule about not eliminating static objects.

When the subject has come up, discussion within the committee has supported
the return value optimization which eliminates an object.  A few compilers
implement it.
--
Scott Turner
Liant Software Corp., Framingham, Massachusetts, USA
pkt@lpi.liant.com




Author: jbuck@synopsys.com (Joe Buck)
Date: 6 Dec 1994 18:36:52 GMT
Raw View
In article <smeyersD0Dr4q.FoG@netcom.com>, smeyers@netcom.com (Scott
Meyers) wrote:
>> I'd like to believe that the ARM is mistaken and named objects can
>> never be eliminated.
>> What does the current draft say about this?

pkt@lpi.liant.com (Scott Turner) writes:
>The working paper says, in 3.6.1 [basic.stc.static] paragraph 2:
>
>   Note that if an object of static storage duration has initialization
>   or a destructor with side effects, it shall not be eliminated even
>   if it appears to be unused.
>
>But there's also a note which says that some pending committee action
>on the "as if" rule would have an impact on the paragraph.

The "as if" rule basically says you can do whatever you want if no one
can tell.  So a statement consistent with "as if" would read

   Note that if an object of static storage duration has initialization
   or a destructor with side effects, these side effects shall not be
   eliminated even the object appears to be unused.

This would mean that a smart enough compiler might be able to eliminate
some of the work for the construction and destruction of such an object,
as long as any side effects that affect the rest of the program still
take place.

On the other hand, those that count on static objects to store SCCS or
RCS version strings might object if compiler writers get aggressive
about static object elimination.



--
-- Joe Buck  <jbuck@synopsys.com> (not speaking for Synopsys, Inc)
Phone: +1 415 694 1729




Author: jason@cygnus.com (Jason Merrill)
Date: Tue, 6 Dec 1994 20:45:52 GMT
Raw View
>>>>> Scott Meyers <smeyers@netcom.com> writes:

> I was rereading section 12.1.1c of the ARM, and I noticed for the first
> time that it implies that named objects can be eliminated by a
> compiler.  The example it gives is this:

>   Matrix operator+(const Matrix& a1, const Matrix& a2)
>   {
>     Matrix sum;
>     ...
>     return sum;
>   }

> The commentary reads in part:

>   A smarter implementation will note that the local variable sum is
>   redundant and eliminate it...

> I have always been under the impression that named objects could not be
> eliminated by the compiler, though, now that I look for it, I can't
> find any such guarantee in the ARM.  In fact, the old "trace object"
> trick relied on the fact that the compiler couldn't eliminate such
> objects:

I think you misunderstand the commentary.  The point is not that sum can go
away altogether, but rather that it can live in the return value slot, so
that the 'return' is a no-op.

Jason




Author: smeyers@netcom.com (Scott Meyers)
Date: Tue, 6 Dec 1994 19:34:27 GMT
Raw View
In article <pkt-0612941111470001@138.52.2.129> pkt@lpi.liant.com (Scott Turner) writes:
| In article <smeyersD0Dr4q.FoG@netcom.com>, smeyers@netcom.com (Scott
| Meyers) wrote:
|
| > I'd like to believe that the ARM is mistaken and named objects can
| > never be eliminated.
|
| > What does the current draft say about this?
|
| The working paper says, in 3.6.1 [basic.stc.static] paragraph 2:
|
|    Note that if an object of static storage duration has initialization
|    or a destructor with side effects, it shall not be eliminated even
|    if it appears to be unused.

Note, however, that in the example I posted (which is from the ARM), the
object in question isn't static, it's auto.

| But there's also a note which says that some pending committee action
| on the "as if" rule would have an impact on the paragraph.  I don't
| know what that's about, but I hardly think it could change the longstanding
| rule about not eliminating static objects.
|
| When the subject has come up, discussion within the committee has supported
| the return value optimization which eliminates an object.  A few compilers
| implement it.

I support the return value optimization, I just don't support a compiler's
right to eliminate objects I deliberately introduced into my program.  I
also support the "as if" rule, so I don't care if a compiler wreaks havoc
with my objects in a way I can't detect.

Scott






Author: warrens@ix.netcom.com (Warren Seltzer)
Date: 7 Dec 1994 10:28:39 GMT
Raw View
 jbuck@synopsys.com (Joe Buck) writes:

>On the other hand, those that count on static objects to store SCCS or
>RCS version strings might object if compiler writers get aggressive
>about static object elimination.

1. Sounds like a requirement for another keyword, to act like DC of
assembler.  In embedded programming, it is normal to use the compiler,
or some other tool, as a means of initializing memory.  For example,
loading interrupt vectors, loading peripheral registers, letting other
bodies of code know where you are, and even writing small assembler
routines into memory.

2. I believe that "const" was, at one point in time, perhaps several
years ago, brought up to meet this need.  But that was probably for
ANSI C.  Could "const" still be used this way, or do people believe that
having optimizers eliminate "unreferenced" constants is too important ?

3. Has Scott's question been answered ?

 Warren S.





Author: smeyers@netcom.com (Scott Meyers)
Date: Fri, 9 Dec 1994 19:12:44 GMT
Raw View
In article <JASON.94Dec6124552@phydeaux.cygnus.com> jason@cygnus.com (Jason Merrill) writes:
| I think you misunderstand the commentary.  The point is not that sum can go
| away altogether, but rather that it can live in the return value slot, so
| that the 'return' is a no-op.

However, this changes the semantics of the object, because the return value
will be destructed later than the local object.  Also, the return value is
an unnamed object (what I always thought was called a "temporary") and can
clearly be eliminated, especially in contexts like this:

  Complex a = x + y;

Now the destructor for the local object sum won't be invoked until a is
destructed, which is possibly much later.  Again, think of what would
happen if sum offered trace-like behavior.

As I said earlier, I'm all for the as-if rule, so if what the ARM is really
saying is that named objects can be optimized out of existence as long as
nobody can tell, I'm a happy man.  The ARM doesn't say that about sum,
however:  it says sum can be eliminated entirely.  Perhaps there is an
underlying assumption that sum's semantics correspond to those of the
default constructors, destructor, and assignment operators?

Scott





Author: jason@cygnus.com (Jason Merrill)
Date: Sat, 10 Dec 1994 00:10:14 GMT
Raw View