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

            Bug ID: 126932
           Summary: GCC's RISC-V auto-vectorizer emits FMA instructions
                    with -ffp-contract=off
           Product: gcc
           Version: 16.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: grezindanil at gmail dot com
  Target Milestone: ---

Created attachment 65362
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65362&action=edit
Preprocessed file that triggers -ffp-contract=off auto-vectorizer bug

-ffp-contract=off should stop GCC from fusing mul and add into a single FMA
instruction. Scalar code generator obeys this rule, but GCC's RISC-V
auto-vectorizer doesn't. It generates FMA vector instructions regardless of the
fp-contract setting.


gcc -v output:

```
Using built-in specs.
COLLECT_GCC=/home/danil/x-tools/riscv64-unknown-linux-gnu/bin/riscv64-unknown-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/home/danil/x-tools/riscv64-unknown-linux-gnu/libexec/gcc/riscv64-unknown-linux-gnu/16.1.0/lto-wrapper
Target: riscv64-unknown-linux-gnu
Configured with:
/home/danil/Proj/crosstool-ng/.build/riscv64-unknown-linux-gnu/src/gcc/configure
--build=x86_64-build_pc-linux-gnu --host=x86_64-build_pc-linux-gnu
--target=riscv64-unknown-linux-gnu
--prefix=/home/danil/x-tools/riscv64-unknown-linux-gnu
--exec_prefix=/home/danil/x-tools/riscv64-unknown-linux-gnu
--with-sysroot=/home/danil/x-tools/riscv64-unknown-linux-gnu/riscv64-unknown-linux-gnu/sysroot
--enable-languages=c,c++
--with-arch=rv64imafdcv_zicbom_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zfhmin_zca_zcd_zba_zbb_zbc_zbs_zkt_zve32f_zve32x_zve64d_zve64f_zve64x_zvfh_zvfhmin_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt
--with-pkgversion='crosstool-NG 1.28.0.58_27cd838' --enable-__cxa_atexit
--disable-libmudflap --disable-libgomp --disable-libssp --disable-libquadmath
--disable-libquadmath-support --disable-libmpx
--with-gmp=/home/danil/Proj/crosstool-ng/.build/riscv64-unknown-linux-gnu/buildtools
--with-mpfr=/home/danil/Proj/crosstool-ng/.build/riscv64-unknown-linux-gnu/buildtools
--with-mpc=/home/danil/Proj/crosstool-ng/.build/riscv64-unknown-linux-gnu/buildtools
--with-isl=/home/danil/Proj/crosstool-ng/.build/riscv64-unknown-linux-gnu/buildtools
--enable-lto --enable-threads=posix --enable-target-optspace --disable-plugin
--disable-nls --disable-multilib
--with-local-prefix=/home/danil/x-tools/riscv64-unknown-linux-gnu/riscv64-unknown-linux-gnu/sysroot
--enable-long-long
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 16.1.0 (crosstool-NG 1.28.0.58_27cd838)
```


## Source code

```
typedef struct { 
    float x, y, z, w; 
} vec4;

vec4 mul_add(vec4 a, vec4 b, vec4 c) {
    vec4 v;
    v.x = a.x + b.x * c.x;
    v.y = a.y + b.y * c.y;
    v.z = a.z + b.z * c.z;
    v.w = a.w + b.w * c.w;
    return v;
}

vec4 neg_mul_add(vec4 a, vec4 b, vec4 c) {
    vec4 v;
    v.x = c.x - a.x * b.x;
    v.y = c.y - a.y * b.y;
    v.z = c.z - a.z * b.z;
    v.w = c.w - a.w * b.w;
    return v;
}

vec4 mul_sub(vec4 a, vec4 b, vec4 c) {
    vec4 v;
    v.x = a.x * b.x - c.x;
    v.y = a.y * b.y - c.y;
    v.z = a.z * b.z - c.z;
    v.w = a.w * b.w - c.w;
    return v;
}

vec4 neg_mul_sub(vec4 a, vec4 b, vec4 c) {
    vec4 v;
    v.x = -(a.x * b.x) - c.x;
    v.y = -(a.y * b.y) - c.y;
    v.z = -(a.z * b.z) - c.z;
    v.w = -(a.w * b.w) - c.w;
    return v;
}

int main(void) { 
    return 0; 
}
```

Compiled it with:
* -march=rv64gcv -O3 -ffp-contract=off. Auto-vectorizer is ON and vector FMA is
present. Not OK.
* -march=rv64gcv -O3 -ffp-contract=off -fno-tree-vectorize. Auto-vectorizer is
OFF and no scalar FMA. OK.

`mul_add` version with auto-vectorizer ON:

```
vle32.v v1,0(a5)
...
vle32.v v2,0(a5)
vle32.v v3,0(sp)
...
vfmadd.vv v1,v3,v2
```

`mul_add` version with auto-vectorizer OFF:

```
fmul.s  fa2,fa5,fa4 
...
fadd.s  fa2,fa2,fa1 
```

The same pattern appears in neg_mul_add, mul_sub and neg_mul_sub. Full
comparison: https://godbolt.org/z/aqT6M9hzq

Expected: no FMA fusion in either compilation since -ffp-contract=off was
passed.
Actual: compilation with the auto-vectorizer ignores the flag, compilation
without the auto-vectorizer respects it correctly.


Command line that triggers the bug:

```
riscv64-unknown-linux-gnu-gcc -ffp-contract=off -O3 -march=rv64gcv test.c -o
test
```

Preprocessed file is in attach.


Related Box2D issue:
https://github.com/erincatto/box2d/issues/1086#issuecomment-5143830277

Reply via email to