On Aug 26, 2014, at 1:35 AM, Richard Biener <richard.guent...@gmail.com> wrote:
> 
>> 8 The implicitly-defined copy constructor for class X performs a member-
>>  wise  copy of its subobjects.  The order of copying is the same as the
>>  order of initialization of bases and members in  a  user-defined  con-
>>  structor  (see  _class.base.init_).   Each  subobject is copied in the
>>  manner appropriate to its type
> 
> Thats quite specific ;)

I think you are making fun of it, but actually, it is very specific.  There are 
a ton of other words that back it up.  For example, you might have to print 
Hello World for each member copied.  The front end would generate calls to 
printf and those would be the semantics.  This last case is what happens in the 
general case of user defined copy constructors.  However, the case we care 
about is a narrow case when various front end specific bits are checked in the 
front end and we decide we can use memcpy to implement the copy or not.  The 
bits used to make that decision are front-end bits:

/* Nonzero for class type means that copy initialization of this type can use
   a bitwise copy.  */
#define TYPE_HAS_TRIVIAL_COPY_CTOR(NODE) ...

So, whenever this is true, we can use a bitwise copy (aka memcpy).  This is 
communicated to the middle end by the primitives generated.  If you want the 
middle end to generate the code, then this bit has to be communicated to the 
middle end.  The problem of course, if you want the middle end to generate the 
printf, then more of the C++ type/oobject system would have to be communicated.

> So after reading the std quotations I still think that if we want to
> fix anything
> here then we want to fix it in the frontends (only the C++ FE knows
> init order in the details required - though I suppose the description was for
> non-POD types where the FE may already do this).

Yes.  Or put other way, once you want to fix it in the middle end, you discover 
pulling on large amounts of code from the front end…  This is reasonable if one 
wants to share with other front ends that have similar rules and semantics, but 
then you want cooperating front-end people to figure out what to push down and 
how and why.  For example, we had to push exception handling down, if for no 
other reason, the optimizer had to be aware of it.

I’ll give you a concrete case where pushing down would be beneficial.  For 
example, there is a field in a structure that after lto optimization runs, we 
discover the semantics for the copy and decide then that the copy is trivial 
enough to do with a bitwise copy.  That can be pushed up (into 
TYPE_HAS_TRIVIAL_COPY_CTOR), and then all decisions based upon it 
(TYPE_HAS_TRIVIAL_COPY_CTOR ) can be redone and further optimized.

Why do this?  This type of optimization removes the abstraction penalty of code 
and allows people to write with more abstractions and yet not pay the price for 
those at runtime.  Not an unreasonable goal.  I mention this, just so someone 
might be able to see why one might want to do this.  I’m not arguing for it.

Reply via email to