[LLVMdev] Meaning of byval?

Duncan Sands
Sat, 07 Jan 2012 10:08:18 -0000

Hi Alon,

> The docs say "[byval] indicates that the pointer parameter should
> really be passed by value to the function. The attribute implies
> that a hidden copy of the pointee is made between the caller and
> the callee, so the callee is unable to modify the value in the
> callee."
>
> I am not sure what this means though - when I generate code
> from the LLVM assembly, do I need to do anything with byval?

yes, the pointee needs to be passed by-copy, which usually means on the
stack but could mean in a bunch of registers.

> Either in the calling location or in the called function?

The caller does the copy IIRC.  If you look at the .s file you should see
it happening.

  I've
> been trying to figure this out from generated LLVM assembly
> and it puzzles me.

You can't really figure it out from LLVM IR.  Look at final target assembler
(.s).

Ciao, Duncan.

>
> For example, this code
>
>            struct point
>            {
>              int x, y;
>            };
>
>            void dump(struct point p) {
>              p.x++; // should not modify
>              p.y++; // anything in the caller!
>              printf("dump: %d,%d\n", p.x, p.y);
>            }
>
>            int main( int argc, const char *argv[] ) {
>              point p = { 54, 2 };
>              printf("pre:  %d,%d\n", p.x, p.y);
>              dump(p);
>              return 0;
>            }
>
> when compiled with some LLVM optimization passes (not all),
> looks like this in main():
>
>    %p = alloca %struct.point, align 4              ; [#uses=5
type=%struct.point*]
>    %agg.tmp = alloca %struct.point, align 4        ; [#uses=1
type=%struct.point*]
>    [..]
>    %3 = bitcast %struct.point* %agg.tmp to i8*, !dbg !39 ; [#uses=1
type=i8*] [debug line = 18:13]
>    %4 = bitcast %struct.point* %p to i8*, !dbg !39 ; [#uses=1 type=i8*]
[debug line = 18:13]
>    call void @llvm.memcpy.p0i8.p0i8.i32(i8* %3, i8* %4, i32 8, i32 4, i1
false), !dbg !39 ; [debug line = 18:13]
>    call void @_Z4dump5point(%struct.point* byval align 4 %p), !dbg !39 ;
[debug line = 18:13]
>
> It looks like a copy is made in the caller, but the copy
> isn't used - instead the original is passed to the function.
> So this will not work properly unless the called function
> creates a copy. There is no explicit code created for this,
> but since it is tagged 'byval' an implementation can create
> a copy in the called function. Is that what I should do?
>
> Or, is it the responsibility of the caller to create a
> copy, and this will appear explicitly in the LLVM assembly?
> A copy does appear to be made in the code above, it just
> isn't used - is that a bug?
>
> I don't see this happen without optimizations - then
> the temporary copy is actually used. Is the problem then
> that I am running some, but not all LLVM optimization
> passes? In other words, is it possible for the opt tool
> to output code that doesn't work (without other passes
> being run later)? Or is there some meaning to byval that
> makes it valid - I guess it would have to mean that
> implementations need to create a copy in the called
> function?
>
> Best,
>    Alon Zakai
> _______________________________________________
> LLVM Developers mailing list
> LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev