copilot-{bluespec,theorem}: Special floating-point values are translated incorrectly
#675
Replies: 6 comments 1 reply
-
|
In addition to the In Expr.hs the following changes work locally for at least the bluespec generation, I haven't yet tackled the theorem proving section yet. -- | Translate a Copilot floating-point literal into a Bluespec expression.
constFP :: Type ty -> Double -> BS.CExpr
constFP ty d
-- Bluespec intentionally does not support negative literal syntax (e.g.,
-- -42.5), so we must create negative floating-point literals using the
-- `negate` function.
| isInfinite d = BS.CApply
(BS.CVar $ BS.mkId BS.NoPos "infinity")
[if d < 0 then BS.CCon BS.idTrue [] else BS.CCon BS.idFalse []]
| isNaN d = BS.CApply
(BS.CVar $ BS.mkId BS.NoPos "qnan") []
| d == 0 = BS.CApply
(BS.CVar $ BS.mkId BS.NoPos "zero")
[if isNegativeZero d then BS.CCon BS.idTrue [] else BS.CCon BS.idFalse []]
| d > 0 = withTypeAnnotation ty $ cLit $ BS.LReal d
| otherwise = withTypeAnnotation ty $
BS.CApply
(BS.CVar $ BS.idNegateAt BS.NoPos)
[cLit $ BS.LReal $ negate d]These changes can be seen in a branch on the galois fork that also has an accompanying example matching the one previously posted. The following BS code is synthesized s0_0 :: Prelude.Reg Float <- mkReg (qnan);
let { s0 :: Vector.Vector 1 (Prelude.Reg Float);
s0 = update newVector 0 s0_0; };
s1_0 :: Prelude.Reg Float <- mkReg (infinity Prelude.False);
s1_1 :: Prelude.Reg Float <- mkReg (infinity Prelude.True);
let { s1 :: Vector.Vector 2 (Prelude.Reg Float);
s1 = update (update newVector 0 s1_0) 1 s1_1; };
s2_0 :: Prelude.Reg Float <- mkReg (zero Prelude.False);
s2_1 :: Prelude.Reg Float <- mkReg (zero Prelude.True);and while the floating point print formatting doesn't seem to function correctly for these special cases, looking at the bit-representations ( |
Beta Was this translation helpful? Give feedback.
-
|
Good catch! I don't think that Notably, the test case involving |
Beta Was this translation helpful? Give feedback.
-
|
It looks like this issue requires some discussion before it can be addressed. Do we need to turn it into a discussion? |
Beta Was this translation helpful? Give feedback.
-
|
Up to you, but I think there's a consensus on what the implementation should be. (@tkann-galois, please speak up if you feel differently.) |
Beta Was this translation helpful? Give feedback.
-
|
Bluespec does expose both a quiet NaN and a signaling NaN. I assumed if someone put it in a stream it's intended and therefore should be a quiet nan ( |
Beta Was this translation helpful? Give feedback.
-
|
This is a good observation, and it's a corner case that I've ran into separately in copilot/copilot-bluespec/tests/Test/Copilot/Compile/Bluespec.hs Lines 1254 to 1267 in 21cb3b1 For the sake of being bit-for-bit compatible, I opted for the approach of calling |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Description
The following functions use
realToFracin their implementations to translateFloatvalues.copilot-bluespec:Copilot.Compile.Bluespec.constTycopilot-theorem:Copilot.Theorem.What4.valFromExprAs noted in haskell/core-libraries-committee#338, the
realToFracfunction can miscompile special floating-point values, such as negative zero, infinity, andNaN. This can causecopilot-bluespecto generate unexpected Bluespec code, and it can causecopilot-theoremto produce incorrect counterexamples.Type
Additional context
Requester
Method to check presence of bug
The following search finds mentions of
realToFracin the implementation:At a minimum, these should be removed.
Sometimes, it is also possible to test for the presence of incorrect results as a result of
realToFrac, although the presence or absence of these effects can depend on GHC versions and optimization levels, so they may not be as reliable of a metric. The following test case has been observed to demonstrate incorrect generated code fromcopilot-bluespec:Compare the results of the Copilot interpreter (which handles special
Floatvalues correctly):To the generated Bluespec code, where
NaNis mistranslated to5.104235503814077e38, both positive and negative infinity are mistranslated to3.402823669209385e38, and negative zero is mistranslated to zero:In addition,
copilot-theoremwill generate an incorrect counterexample for the following program if you compile the Copilot libraries without optimizations:That last line should read
floats: NaN, notreads: Infinity.Expected result
The string returned by
grep ...(as shown above) should be empty.Desired result
The string returned by
grep ...(as shown above) should be empty. At least one test for each of thecopilot-bluespecandcopilot-theorempackages should be added that exercise correct results involvingFloatvalues.Proposed solution
Removing the function from the module
Copilot.Theorem.Misc.SExpr.parseSExpr, as well as any auxiliary functions or imports exclusively needed by that function, if any.Further notes
None.
Beta Was this translation helpful? Give feedback.
All reactions