https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86387
Bug ID: 86387 Summary: [RISCV][ABI] GCC fails to sign/zero-ext integers as necessary for return of int+fp structs in with hard-float ABIs Product: gcc Version: 9.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: target Assignee: unassigned at gcc dot gnu.org Reporter: asb at lowrisc dot org Target Milestone: --- The psABI is documented here: https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md Structs of containing one int and one fp value are passed in int+fp registers, as described here: """ A struct containing one floating-point real and one integer, in either order, is passed in a floating-point register and an integer register, with the integer zero- or sign-extended as though it were a scalar, provided the floating-point real is no more than FLEN bits wide and the integer is no more than XLEN bits wide, and at least one floating-point argument register and at least one integer argument register is available. Otherwise, it is passed according to the integer calling convention. """ Scalar sign/zero-extension is specified as "When passed in registers, scalars narrower than XLEN bits are widened according to the sign of their type up to 32 bits, then sign-extended to XLEN bits." As for return, the document states "Values are returned in the same manner as a first named argument of the same type would be passed." Assume a struct consisting of a uint8 and a float: struct s_u8_f { uint8_t i; float f; }; By the above rules if passed as the first argument to a function, we would expect to see i in a0 (zero-extended), and f in fa0. As specified above, we expect the same if this struct is returned by value. GCC does not sign or zero-extend as it should as demonstrated in the program below. $ cat foo.c #include <stdint.h> struct s_u8_f { uint8_t i; float f; }; struct s_i8_f { int8_t i; float f; }; struct s_u8_f should_zext_arg(int8_t i, float f) { struct s_u8_f s; s.i = i; s.f = f; return s; } struct s_i8_f should_sext_arg(uint8_t i, float f) { struct s_i8_f s; s.i = i; s.f = f; return s; } $ ./riscv32-unknown-elf-gcc -march=rv32imf -mabi=ilp32f foo.c -S -o - -O1 .file "foo.c" .option nopic .text .align 2 .globl should_zext_arg .type should_zext_arg, @function should_zext_arg: addi sp,sp,-32 addi sp,sp,32 jr ra .size should_zext_arg, .-should_zext_arg .align 2 .globl should_sext_arg .type should_sext_arg, @function should_sext_arg: addi sp,sp,-32 addi sp,sp,32 jr ra .size should_sext_arg, .-should_sext_arg .ident "GCC: (GNU) 9.0.0 20180703 (experimental)"