llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.42k stars 11.74k forks source link

powerpc64 parameter passing of small structs does not match PPC64 ELF ABI #13999

Closed llvmbot closed 2 years ago

llvmbot commented 12 years ago
Bugzilla Link 13627
Resolution FIXED
Resolved on Sep 19, 2012 10:52
Version trunk
OS Linux
Reporter LLVM Bugzilla Contributor

Extended Description

On powerpc64-unknown-linux-gnu, passing of structs smaller than 8 bytes is not always compatible with the 64-bit PowerPC ELF Application Binary Interface Supplement (see http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html). From section 3.2.3: "An aggregate or union smaller than one doubleword in size is padded so that it appears in the least significant bits of the doubleword. All others are padded, if necessary, at their tail." So structs smaller than 8 bytes will be passed "right-adjusted" in a GPR.

Consider:

struct s { char c; short d; };

struct s test_struct_2 (struct s foo) { foo.c++; foo.d++; return foo; }

LLVM generates:

.L.test_struct_2: std 4, 56(1) lbz 5, 56(1) <-- c is at leftmost position in G#4 , should be 60(1) addi 5, 5, 1 stb 5, 56(1) addi 4, 1, 56 <-- d is four bytes left of correct, should be 60 here lhz 5, 2(4) addi 5, 5, 1 sth 5, 2(4) lwz 5, 56(1) sth 5, 2(3) srwi 5, 5, 16 sth 5, 0(3) std 3, -8(1) blr

Note that LLVM gets it right if "d" is omitted from the struct. "c" is then passed rightmost in G#4 :

.L.test_struct_1: stb 4, 59(1) lbz 5, 59(1) addi 5, 5, 1 stb 5, 59(1) lbz 5, 59(1) stb 5, 0(3) addi 4, 1, 59 std 4, -8(1) std 3, -16(1) blr

llvmbot commented 2 years ago

mentioned in issue llvm/llvm-bugzilla-archive#13949

llvmbot commented 12 years ago

Fixed under r164228.

llvmbot commented 12 years ago

Unions are likely padded on the right instead of the left when passed in registers. Example code that shows the problem:

union x { char c; short s; int j; };

union x test_union_1 (union x foo) { foo.c++; foo.s++; foo.j++; return foo; }