ARM eabi calling convention

When I compile this program

$ cat vararg1-main.c

typedef struct {
double d;
} S0;

S0 g1;

void foo0(int a, …);

int main(int argc, char **argv) {
S0 s0 = { 2.0 };

foo0(1, s0);

printf("%f\n", g1.d);

return 0;
}

with this command,

$ clang -target arm-none-linux-gnueabi-gcc -ccc-clang-archs armv7 -emit-llvm vararg1-main.c -S -o vararg1-main.ll -O3

I get this bitcode.

$ cat vararg1-main.ll

define arm_aapcscc i32 @main(i32 %argc, i8** nocapture %argv) nounwind {
entry:
%0 = load [2 x i32]* bitcast (%struct.S0* @main.s0 to [2 x i32]*), align 8
tail call arm_aapcscc void (i32, …)* @foo0(i32 1, [2 x i32] %0) nounwind
%1 = load double* getelementptr inbounds (%struct.S0* @g1, i32 0, i32 0), align 8, !tbaa !0
%call = tail call arm_aapcscc i32 (i8*, …)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), double %1) nounwind
ret i32 0
}

My understanding is that ARM eabi requires that structure S0 be 8-byte aligned when it is passed to function foo0, i.e. it should be passed in register r2 and r3.

Is there anything in the call to foo0 that informs the backend that %0 should be 8-byte aligned?

tail call arm_aapcscc void (i32, …)* @foo0(i32 1, [2 x i32] %0) nounwind

The load is 8-byte aligned.

-bw

Yes, I see the load is 8-byte aligned in the bit code.

My question was, assuming that arguments requiring double word alignment have to be passed in even/odd registers, how does the backend know that %0 has to be passed in register r2 and r3?

tail call arm_aapcscc void (i32, …)* @foo0(i32 1, [2 x i32] %0) nounwindt

It doesn’t seem that ARM backend can figure out that “[2 x i32] %0” was originally a structure consisting of a single double field. When I run llc, it looks like “%0” is being passed in register r1 and r2.

$ llc vararg1-main.ll -o -

ldr r0, .LCPI0_0
ldm r0, {r1, r2}

.LCPI0_0:
.long .Lmain.s0

.Lmain.s0:
.long 0 @ double 2.000000e+00

I am running tests to see if llc targeting mips can correctly compile a bitcode file generated by clang-arm.
One of the tests is failing, and I was wondering whether this could be a bug in arm-specific part of clang.

The attached files are the tests (reduced test case) I used.

vararg1-main.c (227 Bytes)

vararg1.c (255 Bytes)

See ARMCallingConv.td:113. The alignment of the arg is checked and if
it's 8-byte aligned, the proper registers are chosen.

deep

See ARMCallingConv.td:113. The alignment of the arg is checked and if
it's 8-byte aligned, the proper registers are chosen.

Are you sure? In this case, it looks like the frontend is translating the argument type to [2 x i32], so it's not going to have 8-byte alignment. This looks like a bug to me (but I haven't actually tried it).

See ARMCallingConv.td:113. The alignment of the arg is checked and if
it's 8-byte aligned, the proper registers are chosen.

Are you sure? In this case, it looks like the frontend is translating the argument type to [2 x i32], so it's not going to have 8-byte alignment. This looks like a bug to me (but I haven't actually tried it).

It seems this will work for double's only when passing inside GP regs,
but not for anything else...
Probably all the "alignment" logic needs to be moved upper to frontend...

See ARMCallingConv.td:113. The alignment of the arg is checked and if
it's 8-byte aligned, the proper registers are chosen.

Are you sure? In this case, it looks like the frontend is translating the argument type to [2 x i32], so it's not going to have 8-byte alignment. This looks like a bug to me (but I haven't actually tried it).

It seems this will work for double's only when passing inside GP regs,
but not for anything else...

Which is how llvm-gcc lowered this. This is a clang bug.

Probably all the "alignment" logic needs to be moved upper to frontend...

There have been several proposals to unify all this argument passing
logic, but most have focused on doing it later in the backend.

deep

Which is how llvm-gcc lowered this. This is a clang bug.

Probably all the "alignment" logic needs to be moved upper to frontend...

There have been several proposals to unify all this argument passing
logic, but most have focused on doing it later in the backend.

A long time ago I did this for ppc on llvm-gcc by adding dummy
arguments when passing in registers. When passing on the stack byval
can take an alignment.

deep

Cheers,
Rafael

I filed a bug report here.

http://llvm.org/bugs/show_bug.cgi?id=13562

Fixed in r161554; it was actually a recent regression.

-Eli