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 -- Rob Rix, Unknown Quantity Monochrome Industries
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=4246Apologies 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 -- Rob Rix, Unknown Quantity Monochrome Industries