Closed llvmbot closed 2 years ago
mentioned in issue llvm/llvm-bugzilla-archive#13949
Fixed under r164228.
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; }
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