Returning a structure

I’m using the C API (with a few additions in a single cpp file) to write a compiler. In one part of my code, I want to build a function that returns a structure. The LLVM Assembly Language Reference Manual gives this as a possible return value:

ret { i32, i8 } { i32 4, i8 2 }

Meanwhile, compiling this C function:

Range make_range(Index location, Index length) {
  return (Range){ location, length };
}

reveals clang’s IR output to be quite a bit more complex:

  %struct._Range = type <{ i64, i64 }>

define void @make_range(%struct._Range* noalias sret %agg.result, i64 %location, i64 %length) nounwind {
  %1 = alloca %struct._Range ; <%struct._Range*> [#uses=2]
  %location.addr = alloca i64 ; <i64*> [#uses=2]
  %length.addr = alloca i64 ; <i64*> [#uses=2]
  %range = alloca %struct._Range, align 4 ; <%struct._Range*> [#uses=3]
  store i64 %location, i64* %location.addr
  store i64 %length, i64* %length.addr
  %2 = getelementptr %struct._Range* %range, i32 0, i32 0 ; <i64*> [#uses=1]
  %3 = load i64* %location.addr ; <i64> [#uses=1]
  store i64 %3, i64* %2
  %4 = getelementptr %struct._Range* %range, i32 0, i32 1 ; <i64*> [#uses=1]
  %5 = load i64* %length.addr ; <i64> [#uses=1]
  store i64 %5, i64* %4
  %6 = bitcast %struct._Range* %1 to i8* ; <i8*> [#uses=1]
  %7 = bitcast %struct._Range* %range to i8* ; <i8*> [#uses=1]
  call void @llvm.memcpy.i32(i8* %6, i8* %7, i32 16, i32 4)
  %8 = bitcast %struct._Range* %agg.result to i8* ; <i8*> [#uses=1]
  %9 = bitcast %struct._Range* %1 to i8* ; <i8*> [#uses=1]
  call void @llvm.memcpy.i32(i8* %8, i8* %9, i32 16, i32 4)
  ret void
}

If the Range type’s fields are i32 instead, then it returns a single i64 directly.

Returning a structure packed into a single i64 value or by reference in an argument would seem to be details of the platform’s ABI. Does my compiler really need to be aware of these details, or can I just return a structure as per the documentation quoted above?

If the latter case, how do I build that instruction with the builder? Attempts to use LLVMConstStruct are crashing, I assume because the arguments to it in my use are not actually constants (: A quick search through IRBuilder didn’t give me any clues either, so here I am (:

Thanks in advance for any help you can give me,

Sincerely,
Rob

Hi Rob,

I’m using the C API (with a few additions in a single cpp file) to write a compiler. In one part of my code, I want to build a function that returns a structure. The LLVM Assembly Language Reference Manual gives this as a possible return value:

ret { i32, i8 } { i32 4, i8 2 }

Meanwhile, compiling this C function:

Range make_range(Index location, Index length) {
  return (Range){ location, length };
}

reveals clang’s IR output to be quite a bit more complex:

  %struct._Range = type <{ i64, i64 }>

define void @make_range(%struct._Range* noalias sret %agg.result, i64 %location, i64 %length) nounwind {

that's because clang is doing something more complicated than you are: it is
producing a function that conforms to the platform ABI for passing parameters.
The platform ABI specifies in this case that the valued should be returned via
a special in-memory mechanism (thus the "sret" extra function parameter) rather
than in a bunch of registers (which is what you are doing). The whole "why does
the front-end have to worry about the ABI" discussion has occurred several times
on the mailing list (eg: yesterday), please search the archives.

Returning a structure packed into a single i64 value or by reference in an argument would seem to be details of the platform’s ABI. Does my compiler really need to be aware of these details, or can I just return a structure as per the documentation quoted above?

Yes, it needs to be aware of the details. There has been some discussion of
providing a helper library for doing this, see http://llvm.org/bugs/show_bug.cgi?id=4246

If the latter case, how do I build that instruction with the builder? Attempts to use LLVMConstStruct are crashing, I assume because the arguments to it in my use are not actually constants (: A quick search through IRBuilder didn’t give me any clues either, so here I am (:

What instruction, the funky return statement? You create a return statement for
which the argument is a Value of the appropriate struct type.

Ciao,

Duncan.

Hi Duncan,

Thanks for the response!

that's because clang is doing something more complicated than you are: it is
producing a function that conforms to the platform ABI for passing parameters.
The platform ABI specifies in this case that the valued should be returned via
a special in-memory mechanism (thus the "sret" extra function parameter) rather
than in a bunch of registers (which is what you are doing).

Right.

The whole "why does
the front-end have to worry about the ABI" discussion has occurred several times
on the mailing list (eg: yesterday), please search the archives.

Ah, indeed. I hadn’t exactly understood that in relation to this specific problem, likely due to skimming—mea culpa.

Returning a structure packed into a single i64 value or by reference in an argument would seem to be details of the platform’s ABI. Does my compiler really need to be aware of these details, or can I just return a structure as per the documentation quoted above?

Yes, it needs to be aware of the details. There has been some discussion of
providing a helper library for doing this, see http://llvm.org/bugs/show_bug.cgi?id=4246

Apologies in advance if this has been hashed over already—and of course, one should be aware that I know _absolutely nothing_ in this regard ( (: )—but perhaps at least some platform ABI details could be handled by an IR-to-IR transformation (a la one of the function passes), taking a function that returns some arbitrary structure via a return mechanism and changing it to use the platform ABI (returning via reference on the stack) instead?

Is that a total non-starter? My needs are relatively simple, as I’m not interfacing with arbitrary C functions, no var-args, or anything at all out of the ordinary. Literally the most complicated thing I need to do is return a structure.

If the latter case, how do I build that instruction with the builder? Attempts to use LLVMConstStruct are crashing, I assume because the arguments to it in my use are not actually constants (: A quick search through IRBuilder didn’t give me any clues either, so here I am (:

What instruction, the funky return statement? You create a return statement for
which the argument is a Value of the appropriate struct type.

In this case, I actually meant building the Value of the appropriate struct type. Is there a simpler way to build a structure than to alloca a struct and store things into its fields? Or is the “{ i32 1, i32 2 }” thing only possible for 100% constant structs (I expect the answer is yes, just looking for verification (: )?

Thanks again,
Rob

Hi Rob,

Apologies in advance if this has been hashed over already—and of course, one should be aware that I know _absolutely nothing_ in this regard ( (: )—but perhaps at least some platform ABI details could be handled by an IR-to-IR transformation (a la one of the function passes), taking a function that returns some arbitrary structure via a return mechanism and changing it to use the platform ABI (returning via reference on the stack) instead?

yes, this has be discussed many times already on the mailing list, and in
general it is not possible, sorry.

Is that a total non-starter? My needs are relatively simple, as I’m not interfacing with arbitrary C functions, no var-args, or anything at all out of the ordinary. Literally the most complicated thing I need to do is return a structure.

If this routine is only going to be called from code you generate, then you can
use whatever calling convention you like, for example you can just return your
struct in registers. Otherwise I'm afraid you are mistaken in thinking that
returning a struct is simple - in fact the ABI logic on (eg) x86-64 is really
horribly complicated for this.

In this case, I actually meant building the Value of the appropriate struct type. Is there a simpler way to build a structure than to alloca a struct and store things into its fields? Or is the “{ i32 1, i32 2 }” thing only possible for 100% constant structs (I expect the answer is yes, just looking for verification (: )?

Look in the docs for "first class aggregates". Check out this example:

struct R {
   long a;
   long b;
};

struct R f(long a, long b) {
   struct R A;
   A.a = a;
   A.b = b;
   return A;
}

->

%"struct R" = type { i64, i64 }

define %"struct R" @f(i64 %a, i64 %b) nounwind readnone {
entry:
   %mrv5 = insertvalue %"struct R" undef, i64 %a, 0 ; <%"struct R"> [#uses=1]
   %mrv6 = insertvalue %"struct R" %mrv5, i64 %b, 1 ; <%"struct R"> [#uses=1]
   ret %"struct R" %mrv6
}

Hi Duncan,

Thank you again for your clear and thorough response.

Apologies in advance if this has been hashed over already—and of course, one should be aware that I know _absolutely nothing_ in this regard ( (: )—but perhaps at least some platform ABI details could be handled by an IR-to-IR transformation (a la one of the function passes), taking a function that returns some arbitrary structure via a return mechanism and changing it to use the platform ABI (returning via reference on the stack) instead?

yes, this has be discussed many times already on the mailing list, and in
general it is not possible, sorry.

Okay, that’s pretty much what I expected.

If this routine is only going to be called from code you generate, then you can
use whatever calling convention you like, for example you can just return your
struct in registers. Otherwise I'm afraid you are mistaken in thinking that
returning a struct is simple - in fact the ABI logic on (eg) x86-64 is really
horribly complicated for this.

Ah, I wasn’t aware of the former detail. I believe I can arrange things to suit that, or alternatively _always_ return the structure in question via the stack.

In this case, I actually meant building the Value of the appropriate struct type. Is there a simpler way to build a structure than to alloca a struct and store things into its fields? Or is the “{ i32 1, i32 2 }” thing only possible for 100% constant structs (I expect the answer is yes, just looking for verification (: )?

Look in the docs for "first class aggregates". Check out this example:

<snip>

Perfect, this is exactly what I was looking for. Thank you once again for taking the time to answer my foolish questions (:

Gratefully,
Rob