[GHC] #15686: Different results depending on if the code was compiled with or without optimizations

GHC ghc-devs at haskell.org
Fri Sep 28 14:59:59 UTC 2018


#15686: Different results depending on if the code was compiled with or without
optimizations
-------------------------------------+-------------------------------------
           Reporter:  Darwin226      |             Owner:  (none)
               Type:  bug            |            Status:  new
           Priority:  normal         |         Milestone:  8.6.1
          Component:  Compiler       |           Version:  8.2.2
           Keywords:                 |  Operating System:  Windows
       Architecture:  x86_64         |   Type of failure:  Incorrect result
  (amd64)                            |  at runtime
          Test Case:                 |        Blocked By:
           Blocking:                 |   Related Tickets:
Differential Rev(s):                 |         Wiki Page:
-------------------------------------+-------------------------------------
 The test case consists of three files:

 Main.hs
 {{{#!hs
 {-# LANGUAGE OverloadedLists, BangPatterns #-}
 {-# OPTIONS_GHC -ddump-simpl -dsuppress-all -ddump-to-file #-}
 module Main where

 import Mesh
 import Vec
 import Control.Exception

 main :: IO ()
 main = do
     !_ <- evaluate $ toBondForce (Particle {_position = Vec {_vecX = 0.0,
 _vecY = -20.0}, _mass = 10.0, _velocity = Vec {_vecX = 0.0, _vecY = 3.0}})
 (Particle {_position = Vec {_vecX = 20.0, _vecY = -20.0}, _mass = 10.0,
 _velocity = Vec {_vecX = 0.0, _vecY = 0.0}}) (FixedDistanceBond {_distance
 = 20.0, _strength = 0.5})
     return ()
 }}}

 Vec.hs
 {{{#!hs
 {-# LANGUAGE TemplateHaskell #-}
 {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts,
 FunctionalDependencies #-}
 module Vec where

 data Vec = Vec { _vecX :: {-# UNPACK #-}!Double, _vecY :: {-# UNPACK
 #-}!Double }
     deriving (Eq, Ord, Read, Show)

 liftVec :: (Double -> Double -> Double) -> Vec -> Vec -> Vec
 liftVec f (Vec x y) (Vec z w) = Vec (f x z) (f y w)
 {-# INLINE liftVec #-}

 instance Num Vec where
     fromInteger i = Vec (fromInteger i) (fromInteger i)
     (+) a b = liftVec (+) a b
     {-# INLINE (+) #-}
     (*) a b = liftVec (*) a b
     {-# INLINE (*) #-}
     (-) a b = liftVec (-) a b
     {-# INLINE (-) #-}
     signum (Vec x y) = Vec (signum x) (signum y)
     abs (Vec x y) = Vec (abs x) (abs y)
 instance Fractional Vec where
     fromRational r = Vec (fromRational r) (fromRational r)
     (/) = liftVec (/)
     {-# INLINE (/) #-}

 fromDouble :: Double -> Vec
 fromDouble x = Vec x x
 {-# INLINE fromDouble #-}

 class Vector2D v where
     norm :: v -> Double
     normalize :: v -> v
     distance :: v -> v -> Double
     dot :: v -> v -> Double
     project :: v -> v -> v

 instance Vector2D Vec where
     norm (Vec x y) = sqrt (x ** 2 + y ** 2)
     {-# INLINE norm #-}

     normalize v@(Vec x y) = Vec (x / n) (y / n)
         where
         n = norm v
     {-# INLINE normalize #-}

     distance v1 v2 = norm (v2 - v1)
     {-# INLINE distance #-}

     dot (Vec x y) (Vec z w) = x * z + y * w
     {-# INLINE dot #-}

     project tgt v = normTgt * realToFrac (dot normTgt v)
         where normTgt = normalize tgt
     {-# INLINE project #-}

 }}}

 Mesh.hs
 {{{#!hs
 {-# LANGUAGE Strict, RecordWildCards, TemplateHaskell, BangPatterns #-}
 {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts,
 FunctionalDependencies #-}
 {-# OPTIONS_GHC -ddump-simpl -dsuppress-all -ddump-to-file #-}
 module Mesh where

 import Vec
 import Debug.Trace

 data Particle = Particle
     { _position :: {-# UNPACK #-}!Vec
     , _mass :: {-# UNPACK #-}!Double
     , _velocity :: {-# UNPACK #-}!Vec }
     deriving (Eq, Ord, Read, Show)

 data Bond = FixedDistanceBond
     { _distance :: {-# UNPACK #-}!Double
     , _strength :: {-# UNPACK #-}!Double }
     deriving (Eq, Ord, Read, Show)

 toBondForce :: Particle -> Particle -> Bond -> Vec
 toBondForce Particle{..} !p2 FixedDistanceBond{..} =
     traceShow (show (Mesh._position p2, dir)) $ dir * fromDouble
 (actualDist - _distance) * fromDouble _strength - project dir velDiff *
 0.1
     where
     posDiff = Mesh._position p2 - _position
     dir = normalize posDiff
     actualDist = norm posDiff
     velDiff = _velocity - Mesh._velocity p2

 }}}

 Compiling Main.hs with optimizations (-O2) and running the program
 produces the output "(Vec {_vecX = 20.0, _vecY = 0.0},Vec {_vecX = 1.0,
 _vecY = 0.0})" while compiling without optimizations produces "(Vec {_vecX
 = 20.0, _vecY = -20.0},Vec {_vecX = 1.0, _vecY = 0.0})" which is correct.

 Further observations:
 Changing `traceShow (show (Mesh._position p2, dir))` to `traceShow (show
 (Mesh._position p2))` makes the code perform correctly even with
 optimizations.
 The core output looks correct to me even with optimizations.

 I can't test with other GHC versions on Windows, but I know I can't
 reproduce this with GHC 8.4 on Linux and I think it also doesn't reproduce
 with 8.2 on Linux.

-- 
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15686>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list