This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: c++/6546: static const members optimization failure


Nathan Myers <ncm-nospam@cantrip.org> writes:

| On Fri, Jun 28, 2002 at 08:42:29AM +0200, Gabriel Dos Reis wrote:
| > Nathan Myers <ncm-nospam@cantrip.org> writes:
| > | I thought folks on this list should know about this.  In short, 
| > | the "will-not-fix" below means that on gcc-3.1, as in 3.0, and 
| > | maybe in 3.2 and beyond, in
| > | 
| > |   struct foo { static const int bar = 3; };
| > |   int f(int i) { return std::min(foo::bar, i); }
| > | 
| > | the compiler actually generates code to load the static value 
| > | for foo::bar from memory each time (twice, in the code above), 
| > | instead of using the manifest constant 3 in its place.  
| > 
| > I don't know why loading twice.  But I can understand loading once,
| > and I'm not sure I would qualify the behaviour as a bug.
| > 
| > std::min() expect an lvalue, foo::bar is such a thing, therefore its
| > the designated object's address is taken; thyen its definition is
| > required.  Anything after that is optimization, optimization that
| > can't change the semantics.  Therefore the definition is required.
| 
| Please study the case more carefully.

Not just I didn't agree with your conclusion means I didn't study the
case carefully or more carefully.

| The context is an inline 
| function expanded in a context that doesn't need an lvalue.

No.  Firstly the declaration of std::min is this:

  template<typename _Tp>
    inline const _Tp&
    min(const _Tp& __a, const _Tp& __b)

which clearly expects an lvalue (when an lvalue is not provided, a
temporary is created to hold the rvalue in order to satisfy that
requirement, but you already knew that).

Therefore at the point of function call, foo::bar has to be defined --
it is the compiler job to generate code in order to meet that
requirement. 

Inlining appears later.  But inlining doesn't mean that the semantics
restrictions can be violated.  Inlining isn't macro substitution.

After inlining, the compiler can do constant propagation and replace
foo::bar with its manifest value. But that doesn't invalidate previous
semantics restrictions.

|  In 
| fact, in gcc-2.95, the memory references were optimized away just 
| fine.

Well, actually GCC-2.95 wasn't conforming -- before the language got
changed. Which makes your argument moot.

|  The compiler was entirely justified in eliding the memory 
| references.  

The compiler can elide memory reference, but requiring foo::bar to be
defined is also a requirement of the language definition.  The fact
that it failed to do so was a bug.

| The result was faster, correct code.  This makes it 
| a regression.

I think you're confusin two things: 1) requiring foo::bar to be
defined and 2) missing opportunities to apply constant propagation.

Issue 1) is definitely mandated.
Issue 2) is a QoI that can be viewed as a regression. 

Using 2) in order to write codes that violate 1) is asking for trouble
and it isn't the compiler fault.  It is user's.

| Yes, it is conforming to do the memory reference.  That doesn't
| make it OK.  It just means instead of a conformance regression,
| we have a quality-of-implementation regression.  Neither is a
| good thing.  We're supposed to be getting better, not worse.
|  
| > | Furthermore, it insists on having a int foo::bar defined 
| > | someplace, creating a porting difficulty from other compilers 
| > | that don't.
| > 
| > Well, I think it is assuming the compiler will not require the
| > definition that is the non-portable assumption.
| 
| It is not assumptions that are at issue. 

Certainly, it is the assumption that is the issue.  You complained:

   Furthermore, it insists on having a int foo::bar defined 
   someplace, creating a porting difficulty from other compilers 
   that don't.

Since the assumption that the definition isn't required isn't valid,
it gives the conclusion no value.

[...]

| > | As an alternative, casting the value: 
| > | 
| > |   int g(int i) { return std::min(int(foo::bar), i); }
| > | 
| > | seems to work around the problem.
| > 
| > Indeed, that use doesn't need the address of the object, so the
| > compiler is free to apply any relevant optimization.
| 
| As noted, the definition of f() doesn't need the address either,
| because std::min() is an inline function in our library, and the
| entire context is locally visible to the compiler.

std::min being inline doesn't change the usual semantics restruction.
The constraints required by std::min are clear.  They need to be
satisfied as the consequences as well.

[...]

| Enough said.  When we get AST optimizations (whatever the heck they
| are) the regression will be probably be fixed.

Relying on optimizations to transmute semantics is fooling oneself.

-- Gaby


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]