4

Z3 returns a satisfying model for this benchmark: http://rise4fun.com/Z3/Bnv5m

However, the query is essentially asserting that a*b+0 is equivalent to a*b using the FMA instruction, which I believe holds for IEEE floating point numbers. Note that the benchmark explicitly makes sure that neither a nor b is NaN.

Is there a problem in my encoding of the FMA?

Mysticial
  • 464,885
  • 45
  • 335
  • 332
alias
  • 28,120
  • 2
  • 23
  • 40

2 Answers2

3

It looks like their (fusedMA <mode> foo bar baz) returns foo*bar/2 + baz. Something weird, either in the theorem prover or in real fused multiply-adds, seems to happen when either the arguments or the result is subnormal.

I ran this to see what it thought the offending product and FMA were:

(set-logic QF_FPA)
; s7 is equivalent to single-precision +0
(define-fun s7 () (_ FP  8 24) ((_ asFloat 8 24) roundNearestTiesToEven (/ 0 1)))
(declare-fun s0 () (_ FP  8 24))
(declare-fun s1 () (_ FP  8 24))
(declare-fun prod () (_ FP  8 24))
(declare-fun fma () (_ FP  8 24))
(assert
   (let ((s2 (== s0 s0)))     ; make sure s0 is not NaN
   (let ((s3 (== s1 s1)))     ; make sure s1 is not NaN
   (let ((s4 (and s2 s3)))
   (let ((s5 (not s4)))       ; s5 is True when either argument is NaN
   (let ((s6 (* roundNearestTiesToEven s0 s1)))            ; s6 = s0*s1
   (let ((s8 (fusedMA roundNearestTiesToEven s0 s1 s7)))   ; s8 = s0*s1 + s7 = s0*s1 since s7 is 0
   (let ((s9 (== s6 s8)))     ; s9 should always be true provided arguments are not NaN  
   (let ((s10 (or s5 s9)))    ; thus; s10 is true always
   (and (== fma s8) (== prod s6) (not s10)))))))))))         ; hence, the whole expression is unsatisfiable
(check-sat)
(get-model)

and got this:

sat
(model
  (define-fun prod () (_ FP 8 24) (as -1.0572719573974609375p-9 (_ FP 8 24)))
  (define-fun fma () (_ FP 8 24) (as -1.0572719573974609375p-10 (_ FP 8 24)))
  (define-fun s1 () (_ FP 8 24) (as +1.62525212764739990234375p118 (_ FP 8 24)))
  (define-fun s0 () (_ FP 8 24) (as -0.0101644992828369140625p-126 (_ FP 8 24)))
)

Neither the product nor the FMA really line up with something that's about -2-14, which is...irksome.

If you bound prod and fma below by 2-125, you can get something like this:

sat
(model
  (define-fun prod () (_ FP 8 24) (as +1.52807605266571044921875p-3 (_ FP 8 24))) 
  (define-fun fma () (_ FP 8 24) (as +1.528076171875p-3 (_ FP 8 24)))
  (define-fun s1 () (_ FP 8 24) (as -0.0002593994140625p-126 (_ FP 8 24)))
  (define-fun s0 () (_ FP 8 24) (as -1.4381892681121826171875p125 (_ FP 8 24)))
)

If you also bound s0 and s1 below by 2-125, it returns unsat.

tmyklebu
  • 13,915
  • 3
  • 28
  • 57
3

Yes, FMA is currently buggy. I've committed a few fixes for the other instructions last Friday, but haven't gotten around to fixing FMA yet. Thanks for the report and especially the test case, especially in the case of FMA this is invaluable help!

Christoph Wintersteiger
  • 8,234
  • 1
  • 16
  • 30