This is an archive of the discontinued LLVM Phabricator instance.

Fix small structures calling convention issue for some big endian architectures
ClosedPublic

Authored by spetrovic on Jun 22 2016, 9:35 AM.

Details

Summary

This patch fixes problem with passing structures and unions smaller than register as argument in variadic functions
on big endian architectures.
For example passing 3 chars in a structure as argument of variadic function LLVM is passing those chars
left-adjusted in register and trying to read them like they are right-adjusted, and that makes the problem.
I have changed reading of those arguments. Now LLVM reads them properly (left-adjusted). I detected
this problem on ARM32 big endian, MIPS32 big endian and MIPS64 big endian.

Diff Detail

Repository
rL LLVM

Event Timeline

spetrovic updated this revision to Diff 61557.Jun 22 2016, 9:35 AM
spetrovic retitled this revision from to Fix small structures calling convention issue for some big endian architectures.
spetrovic updated this object.
spetrovic added subscribers: cfe-commits, rankov, ivanbaev.
rjmccall edited edge metadata.Jun 22 2016, 11:21 AM

Hmm. On MIPS64, a slot is 64 bits, right? How is a float passed?

Oh, floats are promoted to doubles in varargs, of course, which neatly makes that an impossible situation.

My inclination is that the right condition here is that only integer types should be right-justified in their slot, but I'll admit to not having an easy example of a type for which your condition doesn't work.

dsanders edited edge metadata.Jun 23 2016, 3:33 AM

This change agrees with what I think the calling convention is and the documentation. However, I've hit quite a few discrepancies between the documented calling convention and the de-facto one implemented by gcc so I'm wary of going by that alone.

Have you tried putting the caller and callee side of this test in different compilation units and then linking a gcc-compiled caller with a clang-compiled callee (and then repeating that for the other three combinations) like the test generator in tools/clang/utils/ABITest does? Does this produce a program that executes correctly for all four combinations?

Hmm. On MIPS64, a slot is 64 bits, right? How is a float passed?

Oh, floats are promoted to doubles in varargs, of course, which neatly makes that an impossible situation.

My inclination is that the right condition here is that only integer types should be right-justified in their slot, but I'll admit to not having an easy example of a type for which your condition doesn't work.

Floats are left justified according to the 'MIPSproTM N32 ABI Handbook' (which also discusses the O32 and N64 ABI's) but I can't think of a test case that would expose a problem due to the promotion to double.

test/CodeGen/struct-union-BE.c
1–3 ↗(On Diff #61557)

Do we need %clang and -O2? Can we use %clang_cc1 and the default optimization level instead?

Yes, I tried all caller - callee combinations for ARM32 big endian and MIPS/MIPS64 big endian, and it works properly with this patch.

dsanders accepted this revision.Jun 23 2016, 5:35 AM
dsanders edited edge metadata.

In that case the MIPS side of this LGTM. Someone more familiar with ARM should approve it for ARM.

This revision is now accepted and ready to land.Jun 23 2016, 5:35 AM
john.brawn accepted this revision.Jun 23 2016, 6:43 AM
john.brawn edited edge metadata.

Looks OK from the ARM side as well.

This revision was automatically updated to reflect the committed changes.