4

Is it possible to pass structure by parameter ?

Is it compatible with the C abi ?

[edit]

Basically, I would like to have a C++ POD which would contain two members (the structure would be a fat pointer, with a pointer and an integer), and be able to pass this structure as function parameter in call instructions (even when calling C code).

I'm not using fat pointer now (the pointer and the integer are each in a different function parameter), and I would like to know if it's possible before starting a pretty big refactoring !

Simon Germain
  • 6,834
  • 1
  • 27
  • 42
Maël Nison
  • 7,055
  • 7
  • 46
  • 77

3 Answers3

2

You can do this.

You can figure out what the LLVM code is for sample C by copying and pasting the C code into LLVM's online demo at http://llvm.org/demo/index.cgi.

If you copy and paste the code at codepad.org in, you'll see that LLVM generates the following for myFunction:

define void @_Z10myFunction10MyStruct_t(i8* %myStructAsParam.coerce0, i32     %myStructAsParam.coerce1) nounwind uwtable {
  %1 = tail call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([23 x i8]* @.str, i64 0, i64 0), i8* %myStructAsParam.coerce0, i32 %myStructAsParam.coerce1)
  ret void
}

Of course, if you look at the call you'll notice that no copy is being made. It's up to the calling function to do that. If we write a small C function:

void myCallingFunction(MyStruct_t *foobar)
{
  myFunction(*foobar);
}

We can see that the LLVM bitcode generated for myCallingFunction is:

define void @_Z17myCallingFunctionP10MyStruct_t(%struct.MyStruct_t* nocapture %foobar)   nounwind uwtable {
  %foobar.0 = getelementptr inbounds %struct.MyStruct_t* %foobar, i64 0, i32 0
  %tmp = load i8** %foobar.0, align 8
  %foobar.1 = getelementptr inbounds %struct.MyStruct_t* %foobar, i64 0, i32 1
  %tmp1 = load i32* %foobar.1, align 8
  %1 = tail call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([23 x i8]* @.str, i64 0, i64 0), i8* %tmp, i32 %tmp1) nounwind
  ret void
}

The calling function makes a copy of the struct, and then passes in the address of the copy.

razeh
  • 2,725
  • 1
  • 20
  • 27
0

This is not possible in LLVM today in a way that is reliably compatible with the C language's ABI and calling conventions.

It is possible to do this by using LLVM's aggregates types, but that doesn't provide any stable or specific ABI. These are also not the best supported of LLVM's features, especially in complex cases or on function boundaries. But the simple POD-ish use case you describe should work.

For more details on the C-language compatibility challenges, see my answer to a related SO question here: https://stackoverflow.com/a/75002581/552038

Chandler Carruth
  • 3,011
  • 1
  • 18
  • 26
-2

Absolutely, you can. Here's an example:

struct MyStruct_t {
    char *charPointer;
    int number;
};

void myFunction(MyStruct_t myStructAsParam) {

    printf("String: %s, Number: %i", myStructAsParam.charPointer, myStructAsParam.number);
    // Your stuff here.
}
Simon Germain
  • 6,834
  • 1
  • 27
  • 42
  • Your myStructAsParam is a pointer, but you are using the '.' operator, what's the correct thing ? To be clear, I'm looking for passing myStructAsParam as a value, not a pointer (http://codepad.org/H4Az2uKK). – Maël Nison Oct 06 '12 at 02:07