What can be done with copy constructors / post blits

Johannes Pfau nospam at example.com
Fri Mar 1 06:55:55 PST 2013


Am Fri, 01 Mar 2013 15:09:11 +0100
schrieb "monarch_dodra" <monarchdodra at gmail.com>:

> On Friday, 1 March 2013 at 13:59:08 UTC, Johannes Pfau wrote:
> > When trying to implement non-POD types for gdc some time ago I 
> > asked on
> > the dmd mailing list what the backend is actually supposed to 
> > do for
> > non-POD types. Walter answered that they should never be passed 
> > in
> > registers:
> >
> > --------------------------
> >> Wouldn't it be legal to still pass non-PODs in registers when 
> >> calling
> >> functions and only copying them back to the stack if the 
> >> address is
> >> needed? As we pass structs by value anyway, how could this be
> >> problematic?
> >>
> >
> > No, not allowed. Consider why there are copy constructors, and 
> > what
> > they do.
> > --------------------------
> >
> > Now that's probably because of my weak C++ background, but what 
> > can you
> > do with copy constructors that would break if the compiler 
> > passed the
> > non-POD type in a register to a function?
> >
> > Note: If I interpret this assembly properly dmd does do exactly 
> > what
> > I proposed and what's illegal according to Walter:
> >
> > D:   https://gist.github.com/jpf91/5064703
> > ASM: https://gist.github.com/jpf91/5064764
> 
> Unsure what "pass in register" means. As in storing the data 
> before calling the function in a register, as opposed to the 
> stack?
> 
> In C++, if you ever copy or move anything, then a CC must be 
> called. Because of this, I'd say you can't place a non POD in a 
> register, because that would imply CC'ing the thing just to place 
> it in said register.

Because of that the GCC backend complains a lot when trying to fit D
Non-PODS into that C++ model: The backend refuses to create any
temporaries, move anything etc. I'll probably have to ask on the GCC
mailing list what to do about this, it seems there's no good solution
right now. (Maybe C++11 move semantics can help)

> 
> In D, it is a little different, because you are allowed to move 
> stuff in-memory without ever calling the CC. This is "D move 
> semantics", and it works because D bans internal pointers. 
> Because of this, I'd say you can pass by register.

The rules in DMD are a little weird though:

* For normal functions the value is passed in registers, but for
  varargs functions it's passed on the stack! Any idea what could be
  different here? (This is actually a bug in gdc right now cause gdc
  passes those in registers even to varargs functions)

* DMD never returns a value in a register. It uses the hidden reference
  trick described in the SysV ABI:
  
  func(A* storage)
  {
     *storage = result_value;
  }

  instead of simply returning A by value. Any idea why this is
  necessary?

> 
> Maybe Walter gave you his "reflex" C++ reply, and didn't realize 
> that D relaxed semantics changed the rules?

Yep, internal pointers was the only thing which I though could break,
but isn't allowed in D anyway. 

That's what I thought, maybe I'll have to ask again. Pass in register
in this case means putting the value into a specific register before
calling the function, not on the stack (memory). The details are
described in the SYSv x86_64 ABI.

The important difference here is that a value passed on the stack has
an address, a value passed in a register not. GCC has a notion of an
ADRESSABLE type which is then probably not useful for gdc as it's too
strict, it always prevents passing these types in registers (and
produces many errors ;-).





More information about the Digitalmars-d-learn mailing list