On 8/8/12, Gabriel Dos Reis <g...@integrable-solutions.net> wrote:
> On Aug 8, 2012 Miles Bader <mi...@gnu.org> wrote:
> > Richard Guenther <richard.guent...@gmail.com> writes:
> > > > > > Constructors are allowed, but PODs are often passed
> > > > > > more efficiently.  That property seemed particularly
> > > > > > important for double_int.
> > > > >
> > > > > Show us the difference in timing.  Show us the generated
> > > > > code.  I can't imagine that it could ever matter.
> > > >
> > > > I'm also curious about that statement...  PODs don't really
> > > > seem to offer much advantage with modern compilers, except
> > > > in a few very specific cases (of which this doesn't seem
> > > > to be one), e.g. in unions.
> > >
> > > They make a difference for the by-value passing ABI.
> > > double-ints can be passed in two registers on most platforms.
> >
> > Sure, but that doesn't seem to depend on PODness -- non-PODs
> > can be passed in two registers as well, AFAICS...
> >
> > E.g., in the following:
> >
> > typedef long valtype;
> >
> > struct X { valtype x, y; };
> > struct Y { valtype x, y;
> > >  Y (valtype a, valtype b) : x (a), y (b) { }
> > };
> >
> > extern void fx (X x);
> > void test_x () {X x = { 1, 2 }; fx (x); }
> >
> > extern void fy (Y y);
> > void test_y () {Y y (1, 2); fy (y); }
> >
> > test_x and test_y use exactly the same calling sequence (and
> > contain exactly the same assembly code)...  [on x86-64]
>
> It is not PODness in the standard sense that matters.  It is
> podness from the ABI perspecitve: Y does not have a user-defined
> copy-constructor nor a desctructor; it is not a polymorphic type,
> so it is OK to pass in registers just like X.

Well, more specifically, the Itanium ABI says if the copy constructor
and the destructor are trivial, one passes the class in registers.
Other ABIs can make other choices.  Older ABIs often pass all
structs and classes indirectly.

The adding in inline versions of various special members into
the following code results in the following worst-case changes.

                        x86                     x86_64
instructions:           48 -> 69 = 144%         38 -> 53 = 139%
stack operations:        6 -> 10 = 167%          2 ->  6 = 300%
memory operations:      28 -> 38 = 136%         22 -> 28 = 127%

These numbers are not huge, particularly in context, but worth
considering.

In any event, the point is moot.  To implement the exact semantics of
current expressions using shwi_to_double_int and uhwi_to_double_int,
we cannot use constructors anyway.  So, there remains no immediate
reason to use any constructors.


struct type
{
#ifdef DEFAULT
  type ();
#endif
#ifdef INITIAL
  type (int);
#endif
#ifdef COPYCON
  type (const type &from)
        : field1 (from.field1),
          field2 (from.field2)
        {
        }
#endif
#ifdef DESTRUCT
  ~type ()
        {
        field1 = 0;
        field2 = 0;
        }
#endif
  type method (type);
  long int field1;
  long int field2;
};

extern type global;

void callee (type arg);

void function_caller ()
{
  type local (global);
  callee (local);
  callee (global);
}

void method_caller (type arg1, type arg2)
{
  type var1 (global);
  type var2 = arg2;
  arg1.method (arg2);
  var1.method (var2);
}

-- 
Lawrence Crowl

Reply via email to