https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127810

            Bug ID: 127810
           Summary: RV32 Incorrect inlining of struct field access on
                    union
           Product: gcc
           Version: 16.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: [email protected]
  Target Milestone: ---

GCC 16.2.0 from the extra/riscv64-elf-newlib Arch package.

Test case:
---------------------------------------
#define DIVISOR 30000000U

typedef union
{
    struct
    {
        unsigned char pad0;
        unsigned char target;
        unsigned char pad1;
    } s;
    unsigned int w;
} my_union;

volatile unsigned int data = 0xff01ff;

unsigned char extract_field()
{
    my_union cs = {.w = data};
    return cs.s.target;
}

unsigned int convert_val(unsigned int val)
{
    unsigned long long tmp = ((unsigned long long)val << 33) / (unsigned long
long)DIVISOR;
    return (unsigned int)(tmp / 2);
}

int main() {
    // Expected result: extract_field() == 0x01     -> u == 143      & 0xff =
exit code 143
    // Unexpected result: extract_field() == 0xff01 -> u == 9345992  & 0xff =
exit code 200

    unsigned int u =
        convert_val(extract_field());

    return u;
}
---------------------------------------

Command line and output:
---------------------------------------
riscv64-elf-gcc -v -save-temps -Wall -Wextra -march=rv32imac -mabi=ilp32 -O2
mwe.c -o mwe
Using built-in specs.
COLLECT_GCC=riscv64-elf-gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/riscv64-elf/16.2.0/lto-wrapper
Target: riscv64-elf
Configured with: /build/riscv64-elf-gcc/src/gcc-16.2.0/configure
--target=riscv64-elf --prefix=/usr --with-sysroot=/usr/riscv64-elf
--with-native-system-header-dir=/include --libexecdir=/usr/lib
--enable-languages=c,c++ --enable-threads=single --enable-plugins
--enable-multilib --enable-libgcc --disable-libgomp --disable-libquadmath
--disable-libffi --disable-libssp --disable-libmudflap --disable-decimal-float
--disable-libstdcxx-pch --disable-nls --disable-shared --disable-tls
--with-newlib --with-gnu-as --with-gnu-ld --with-system-zlib
--with-headers=/usr/riscv64-elf/include --with-python-dir=share/gcc-riscv64-elf
--with-gmp --with-mpfr --with-mpc --with-isl --with-libelf
--enable-gnu-indirect-function --with-pkgversion='Arch Linux Repositories'
--with-bugurl=https://gitlab.archlinux.org/archlinux/packaging/packages/riscv64-elf-gcc/-/issues
Thread model: single
Supported LTO compression algorithms: zlib zstd
gcc version 16.2.0 (Arch Linux Repositories) 
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-Wextra' '-march=rv32imac'
'-mabi=ilp32' '-O2' '-o' 'mwe' '-misa-spec=20191213'
'-march=rv32imac_zmmul_zaamo_zalrsc_zca'
 /usr/lib/gcc/riscv64-elf/16.2.0/cc1 -E -quiet -v -imultilib rv32imac/ilp32
mwe.c -march=rv32imac -mabi=ilp32 -misa-spec=20191213
-march=rv32imac_zmmul_zaamo_zalrsc_zca -Wall -Wextra -O2 -fpch-preprocess -o
mwe.i
ignoring nonexistent directory "/usr/riscv64-elf/usr/local/include"
ignoring duplicate directory "/usr/riscv64-elf/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/riscv64-elf/16.2.0/include
 /usr/lib/gcc/riscv64-elf/16.2.0/include-fixed
 /usr/lib/gcc/riscv64-elf/16.2.0/../../../../riscv64-elf/include
End of search list.
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-Wextra' '-march=rv32imac'
'-mabi=ilp32' '-O2' '-o' 'mwe' '-misa-spec=20191213'
'-march=rv32imac_zmmul_zaamo_zalrsc_zca'
 /usr/lib/gcc/riscv64-elf/16.2.0/cc1 -fpreprocessed mwe.i -quiet -dumpbase
mwe.c -dumpbase-ext .c -march=rv32imac -mabi=ilp32 -misa-spec=20191213
-march=rv32imac_zmmul_zaamo_zalrsc_zca -O2 -Wall -Wextra -version -o mwe.s
GNU C23 (Arch Linux Repositories) version 16.2.0 (riscv64-elf)
        compiled by GNU C version 16.2.1 20260810, GMP version 6.3.0, MPFR
version 4.2.2, MPC version 1.4.1, isl version isl-0.28-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 124f6cb1a76ad5a7e253787b2e4451b5
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-Wextra' '-march=rv32imac'
'-mabi=ilp32' '-O2' '-o' 'mwe' '-misa-spec=20191213'
'-march=rv32imac_zmmul_zaamo_zalrsc_zca'
 /usr/lib/gcc/riscv64-elf/16.2.0/../../../../riscv64-elf/bin/as -v
--traditional-format -march=rv32imac -march=rv32imac_zmmul_zaamo_zalrsc_zca
-mabi=ilp32 -misa-spec=20191213 -o mwe.o mwe.s
GNU assembler version 2.47 (riscv64-elf) using BFD version (GNU Binutils)
2.47.20260726
COMPILER_PATH=/usr/lib/gcc/riscv64-elf/16.2.0/:/usr/lib/gcc/riscv64-elf/16.2.0/:/usr/lib/gcc/riscv64-elf/:/usr/lib/gcc/riscv64-elf/16.2.0/:/usr/lib/gcc/riscv64-elf/:/usr/lib/gcc/riscv64-elf/16.2.0/../../../../riscv64-elf/bin/
LIBRARY_PATH=/usr/lib/gcc/riscv64-elf/16.2.0/rv32imac/ilp32/:/usr/lib/gcc/riscv64-elf/16.2.0/../../../../riscv64-elf/lib/rv32imac/ilp32/:/usr/riscv64-elf/lib/rv32imac/ilp32/:/usr/lib/gcc/riscv64-elf/16.2.0/:/usr/lib/gcc/riscv64-elf/16.2.0/../../../../riscv64-elf/lib/:/usr/riscv64-elf/lib/
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-Wextra' '-march=rv32imac'
'-mabi=ilp32' '-O2' '-o' 'mwe' '-misa-spec=20191213'
'-march=rv32imac_zmmul_zaamo_zalrsc_zca' '-dumpdir' 'mwe.'
 /usr/lib/gcc/riscv64-elf/16.2.0/collect2 -plugin
/usr/lib/gcc/riscv64-elf/16.2.0/liblto_plugin.so
-plugin-opt=/usr/lib/gcc/riscv64-elf/16.2.0/lto-wrapper
-plugin-opt=-fresolution=mwe.res -plugin-opt=-pass-through=-lgcc
-plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgloss
-plugin-opt=-pass-through=-lgcc --sysroot=/usr/riscv64-elf -melf32lriscv -X -o
mwe
/usr/lib/gcc/riscv64-elf/16.2.0/../../../../riscv64-elf/lib/rv32imac/ilp32/crt0.o
/usr/lib/gcc/riscv64-elf/16.2.0/rv32imac/ilp32/crtbegin.o
-L/usr/lib/gcc/riscv64-elf/16.2.0/rv32imac/ilp32
-L/usr/lib/gcc/riscv64-elf/16.2.0/../../../../riscv64-elf/lib/rv32imac/ilp32
-L/usr/riscv64-elf/lib/rv32imac/ilp32 -L/usr/lib/gcc/riscv64-elf/16.2.0
-L/usr/lib/gcc/riscv64-elf/16.2.0/../../../../riscv64-elf/lib
-L/usr/riscv64-elf/lib mwe.o -lgcc --start-group -lc -lgloss --end-group -lgcc
/usr/lib/gcc/riscv64-elf/16.2.0/rv32imac/ilp32/crtend.o
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-Wextra' '-march=rv32imac'
'-mabi=ilp32' '-O2' '-o' 'mwe' '-misa-spec=20191213'
'-march=rv32imac_zmmul_zaamo_zalrsc_zca' '-dumpdir' 'mwe.'
---------------------------------------

Running with qemu-riscv32, I would expect return code 143. What I get is return
code 200 and checking with GDB, u actually computes to 9345992 (& 0xff = exit
code 200) instead of the expected 143. If I omit "-O2" from the command line, I
get the expected result.

Looking at the generated assembly, extract_field appears to be generated
correctly:
extract_field:
        lui     a5,%hi(data)
        lw      a0,%lo(data)(a5)
        srli    a0,a0,8
        andi    a0,a0,0xff
        ret

A right shift by 8 and a subsequent andi 0xff extract the value of "target"
correctly. However, what gets inlined into main is not correct:
main:
        lui     a5,%hi(data)
        lw      a1,%lo(data)(a5)
        li      a2,29999104
        addi    sp,sp,-16
        srli    a1,a1,8
        addi    a2,a2,896
        li      a3,0
        li      a0,0
        slli    a1,a1,1
        sw      ra,12(sp)
        call    __udivdi3
        lw      ra,12(sp)
        srli    a0,a0,1
        slli    a1,a1,31
        add     a0,a1,a0
        addi    sp,sp,16
        jr      ra

Here we can see the right-shift again, but the andi 0xff is missing.

Reply via email to