Different results depending on if the code was compiled with or without optimizations
The test case consists of three files:
Main.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
{-# 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
{-# 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.
Trac metadata
Trac field | Value |
---|---|
Version | 8.2.2 |
Type | Bug |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | Compiler |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | |
Architecture |