struct as a function argument

Hi everybody!

I recently started using llvm in a project on inferring additional
information about pointers based on their types, casts, etc. The
following simple example is giving me a headache :):

typedef struct {
  int a;
  short b, c;
  int d, e, f;
} foo;

void bar(foo f) {
  short s;
  s = f.b;
}

int main(void) {
  foo p;
  bar(p);
}

Because llvm doesn't allow structures and arrays to be passed as
arguments, the llvm intermediate format output for this C program
looks like this:
- the signature of function bar becomes void @bar(i64 %f.0.0, i64
%f.0.1, i32 %f.1)
- before the call to function bar, structure foo is casted to
structure { [2 x i64], i32 } and each element of that structure is
read into integer variables, which are then used as parameters for the
call
- in the beginning of function bar, the same process is repeated, just backwards

Is this the default llvm-gcc behaviour? Could it be changed somehow?
For instance, instead of casting a structure essentially to an array
of integers, one could maybe read the structure field by field, and
than pass those as arguments....

If the way llvm translates such function calls can't be changed, is
there any way to get the original function signature?

Thanks!

Cheers,
-- Zvonimir

Hi all,

I have the same problem. My guess is that when a structure
is passed as a parameter, you cast it into an array for optimization
reasons (less parameters, less stack space).

This is, certainly, a reasonable optimization, but makes
inter-procedural static analysis more complex. Is there a way to
disable it (my guess is that this should be doable by passing
some parameter to llvm-gcc)?

If there is no way to disable it, could anyone suggest where
should I look into the code and whether you would accept a
patch that would add an option that disables the optimization?

Thank you,

Hi all,

I have the same problem. My guess is that when a structure
is passed as a parameter, you cast it into an array for optimization
reasons (less parameters, less stack space).

This is not an optimization. This behavior is to be ABI complaint when emitting code for your OS.

That said, this is not a very good way to do this. Rafael is working on adding the 'byref' attribute which will support this much more gracefully in the future.

This is, certainly, a reasonable optimization, but makes
inter-procedural static analysis more complex. Is there a way to
disable it (my guess is that this should be doable by passing
some parameter to llvm-gcc)?

The easiest way to disable this is to hack it out of llvm-gcc. Change this (gcc/llvm-abi.h):

#ifndef LLVM_SHOULD_PASS_AGGREGATE_IN_INTEGER_REGS
#define LLVM_SHOULD_PASS_AGGREGATE_IN_INTEGER_REGS(X) \
    !isSingleElementStructOrArray(type)
#endif

to:

#undef LLVM_SHOULD_PASS_AGGREGATE_IN_INTEGER_REGS
#define LLVM_SHOULD_PASS_AGGREGATE_IN_INTEGER_REGS(X) 0

Note that you won't be able to mix and match .o files with GCC where structs are passed by value.

-Chris

Chris,

Thank you for quick reply. Much appreciated.

Domagoj

Thanks Chris!
Your suggestion helps....

-- Zvonimir

Me too :slight_smile:

As Chris reported, I am working at adding support for a "byval"
attribute that will make this more explicit on llvm IL and make it
possible to correctly implement all of the X86-64 ABI.

I have most of the code gen for X86 and X86-64 working. The only
missing part is the passing of structures with small alignments. I
hope to implement that this Friday.

After that I have to change the other backends and then the front ends.

Cheers,