Boost logo

Boost :

Subject: Re: [boost] [move] new rvalue reference emulation
From: Jeffrey Lee Hellrung, Jr. (jeffrey.hellrung_at_[hidden])
Date: 2011-04-05 01:14:29


On Mon, Apr 4, 2011 at 3:33 PM, Dave Abrahams <dave_at_[hidden]> wrote:

> At Mon, 4 Apr 2011 10:36:29 -0700,
> Jeffrey Lee Hellrung, Jr. wrote:
>
[...]

> > an alternate rvalue
> > reference emulation, one which allows rvalues ***of any arbitrary
> > (move-emulation-enabled) type*** to be captured in C++03 and identified
> as
> > rvalues, rather than references-to-const (there is a drawback, though,
> which
> > I'll get to below; as usual, there's no "free lunch").
>
> I'm actually not sure there's no free lunch...
>

I also forgot to mention that (obviously) this precludes polymorphic return
types :( At least, I don't see how they can be supported...

> Instead of using rv<T>& to capture arbitrary rvalues, I'll use a
> > kind of type-erased emulated rvalue reference, generic_rv<...> (for
>
> I think you should spell out "..." as "F, Result" in any descriptions
> or it just gets confusing. "Is he talking about variadic templates,"
> I wondered?
>

Ai, good suggestion...I have yet to move to a compiler supporting variadic
templates.

> lack of a better name at the moment), which will just store a void
> > pointer to the original, pre-type-erased object. Of course, we need
> > some way to recover the object back from the void pointer, and
> > that's what the "..." template parameters are for. This is where
> > the (unfortunate) runtime overhead comes in, as some dispatching
> > mechanism (e.g., function pointers) needs to be used to effect the
> > recovery of the original, pre-type-erased object.
>
> First, did you try this with function references instead of function
> pointers?
>

Now I did. Will provide assembly listing below. It looks like it doesn't
get inlined :(

Next, which compilers did you try this on?
>

MSVC9 only.

I've found that when everything is inlined and flow analysis allows
> the compiler to "see" the source of function pointers/references, many
> compilers can turn an indirect call into a direct one.
>

Perhaps GCC will do better. I'll try to generate the assembly output in
that case...

> The important
> > difference between rv<T> and generic_rv<...> is that there's no T in
> > the template parameter list "..." of generic_rv; more to the point,
> > its template parameters are not deduced within the context of
> > binding function arguments of some_fn, hence the compiler will be
> > allowed to look for conversions from arbitrary rvalues to
> > generic_rv<...>. Hopefully that gives enough of an introduction to
> > the idea. Further details are probably best left to a code snippet.
> >
> > Comments? Specifically, should this be considered as an addition to
> > Boost.Move's current emulation framework?
>
> Yes!
>

I appreciate your enthusiasm, Dave :)

I've attached generic_rv_test.cpp and generic_rv_test.asm. I've also
reproduced the relevant assembly listings below, as generated by MSVC9.
First, the assembly listing for the member function
generic_rv<some_fn,void>::cast_forward<X>:

; COMDAT ??$cast_forward_at_UX@@@?$generic_rv_at_Usome_fn@@X@@SAXUsome_fn@
@QAX_at_Z
_TEXT SEGMENT
_f$ = 8 ; size = 1
_p$ = 12 ; size = 4
??$cast_forward_at_UX@@@?$generic_rv_at_Usome_fn@@X@@SAXUsome_fn@@QAX_at_Z PROC ;
generic_rv<some_fn,void>::cast_forward<X>, COMDAT

; 41 : static Result cast_forward(F f, void* const p)

    mov eax, DWORD PTR __imp_?endl_at_std@@YAAAV?$basic_ostream_at_DU
?$char_traits_at_D@std@@@1_at_AAV21@@Z
    mov ecx, DWORD PTR __imp_?cout_at_std@@3V?$basic_ostream_at_DU
?$char_traits_at_D@std@@@1_at_A
    push eax
    push OFFSET ??_C@_0CC_at_IOIEODGA
@some_fn?3?3operator?$CI?$CJ?$CIrv?$DMT?$DO?$CG?$CJ?5cons@
    push ecx
    call ??$?6U?$char_traits_at_D@std@@@std@@YAAAV?$basic_ostream_at_DU
?$char_traits_at_D@std@@@0_at_AAV10@PBD_at_Z ; std::operator<<<std::char_traits<char>
>
    add esp, 8
    mov ecx, eax
    call DWORD PTR __imp_??6?$basic_ostream_at_DU?$char_traits_at_D@std@@@std@
@QAEAAV01_at_P6AAAV01@AAV01@@Z_at_Z

; 42 : { return f(static_cast< rv<T>& >(*static_cast< T* >(p))); }

    ret 0
??$cast_forward_at_UX@@@?$generic_rv_at_Usome_fn@@X@@SAXUsome_fn@@QAX_at_Z ENDP ;
generic_rv<some_fn,void>::cast_forward<X>
; Function compile flags: /Ogtpy
_TEXT ENDS

Looks like a direct to call to printing to std::cout. Next, the assembly
listing for the expression some_fn()(make<X>()):

    lea ecx, DWORD PTR $T25928[esp+8]
    mov BYTE PTR $T25927[esp+8], 0
    mov edx, DWORD PTR $T25927[esp+8]
    push ecx
    push edx
    call ??$cast_forward_at_UX@@@?$generic_rv_at_Usome_fn@@X@@SAXUsome_fn@
@QAX_at_Z ; generic_rv<some_fn,void>::cast_forward<X>

This appears to call generic_rv<some_fn,void>::cast_forward<X>. I don't
know, is this basically the code that invokes the function reference?
(Might have to dig through the asm file to answer that.)

Lastly, the assembly listing for the expression some_fn()(static_cast<
rv<X>& >(make<X>())):

    mov eax, DWORD PTR __imp_?endl_at_std@@YAAAV?$basic_ostream_at_DU
?$char_traits_at_D@std@@@1_at_AAV21@@Z
    add esp, 8
    push eax
    push ecx
    mov ecx, DWORD PTR __imp_?cout_at_std@@3V?$basic_ostream_at_DU
?$char_traits_at_D@std@@@1_at_A
    push OFFSET ??_C@_0CC_at_IOIEODGA
@some_fn?3?3operator?$CI?$CJ?$CIrv?$DMT?$DO?$CG?$CJ?5cons@
    push ecx
    call ??$?6U?$char_traits_at_D@std@@@std@@YAAAV?$basic_ostream_at_DU
?$char_traits_at_D@std@@@0_at_AAV10@PBD_at_Z ; std::operator<<<std::char_traits<char>
>
    add esp, 12 ; 0000000cH
    mov ecx, eax
    call DWORD PTR __imp_??6?$basic_ostream_at_DU?$char_traits_at_D@std@@@std@
@QAEAAV01_at_P6AAAV01@AAV01@@Z_at_Z

Ouch...that gets completely inlined, unlike the previous case...

- Jeff





Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk