FMA, which is short for fused multiply–add, use lots by math in Go compiler and standard library.

I found that Go 1.20 did some riscv64 support for FMA, however, when I'm trying to add test cases for FNMA ` x * y - z`

or FNMS ` -x * y + z`

.

The binary output always different with my expectation and test cases in math always failed.

At first, I thought that is floating point error since floating point number follows IEEE-754, 2008 edition which allows minor errors within 1e-16 i.e. "veryclose" in math test cases.

However, when I implement the same algorithm for 32 bits FP, there is far more error than it should be.

After my carefully search on SSA code generator, I found that FMA SSA for riscv64 will invert FMA into FNMX if multiplier or adder is negative.

`(F(MADD|NMADD|MSUB|NMSUB)D neg:(FNEGD x) y z) && neg.Uses == 1 => (F(NMADD|MADD|NMSUB|MSUB)D x y z)`

This SSA will convert `FMADDD`

into `FNMADD`

, unfortunately according to RISCV manual, this is wrong.

In the manual

`FMADD`

means

x * y + z

`FNMADD`

means

- x * y - z

instead of original CL thought `FNMADD`

should be implemented as

x * y - z

Then I commit a CL that fix this issue for good with some test cases.

https://go-review.googlesource.com/c/go/+/506575