summaryrefslogtreecommitdiff
path: root/compiler/utils
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/utils')
-rw-r--r--compiler/utils/Bag.lhs2
-rw-r--r--compiler/utils/Binary.hs198
-rw-r--r--compiler/utils/BooleanFormula.hs211
-rw-r--r--compiler/utils/BufWrite.hs2
-rw-r--r--compiler/utils/Digraph.lhs32
-rw-r--r--compiler/utils/Encoding.hs3
-rw-r--r--compiler/utils/ExtsCompat46.hs293
-rw-r--r--compiler/utils/FastMutInt.lhs16
-rw-r--r--compiler/utils/FastString.lhs285
-rw-r--r--compiler/utils/FastTypes.lhs12
-rw-r--r--compiler/utils/Fingerprint.hsc45
-rw-r--r--compiler/utils/FiniteMap.lhs4
-rw-r--r--compiler/utils/GraphBase.hs2
-rw-r--r--compiler/utils/GraphPpr.hs2
-rw-r--r--compiler/utils/IOEnv.hs11
-rw-r--r--compiler/utils/Maybes.lhs66
-rw-r--r--compiler/utils/OrdList.lhs9
-rw-r--r--compiler/utils/Outputable.lhs95
-rw-r--r--compiler/utils/Platform.hs15
-rw-r--r--compiler/utils/Pretty.lhs54
-rw-r--r--compiler/utils/Stream.hs13
-rw-r--r--compiler/utils/UnVarGraph.hs136
-rw-r--r--compiler/utils/UniqFM.lhs51
-rw-r--r--compiler/utils/UniqSet.lhs15
-rw-r--r--compiler/utils/Util.lhs31
25 files changed, 1269 insertions, 334 deletions
diff --git a/compiler/utils/Bag.lhs b/compiler/utils/Bag.lhs
index a83397898e..2d823e46bb 100644
--- a/compiler/utils/Bag.lhs
+++ b/compiler/utils/Bag.lhs
@@ -21,8 +21,6 @@ module Bag (
mapAndUnzipBagM, mapAccumBagLM
) where
-#include "Typeable.h"
-
import Outputable
import Util
diff --git a/compiler/utils/Binary.hs b/compiler/utils/Binary.hs
index e07577776a..332bfc8e0c 100644
--- a/compiler/utils/Binary.hs
+++ b/compiler/utils/Binary.hs
@@ -20,7 +20,6 @@ module Binary
{-type-} BinHandle,
SymbolTable, Dictionary,
- openBinIO, openBinIO_,
openBinMem,
-- closeBin,
@@ -87,7 +86,7 @@ import System.IO as IO
import System.IO.Unsafe ( unsafeInterleaveIO )
import System.IO.Error ( mkIOError, eofErrorType )
import GHC.Real ( Ratio(..) )
-import GHC.Exts
+import ExtsCompat46
import GHC.Word ( Word8(..) )
import GHC.IO ( IO(..) )
@@ -108,15 +107,6 @@ data BinHandle
-- XXX: should really store a "high water mark" for dumping out
-- the binary data to a file.
- | BinIO { -- binary data stored in a file
- bh_usr :: UserData,
- _off_r :: !FastMutInt, -- the current offset (cached)
- _hdl :: !IO.Handle -- the file handle (must be seekable)
- }
- -- cache the file ptr in BinIO; using hTell is too expensive
- -- to call repeatedly. If anyone else is modifying this Handle
- -- at the same time, we'll be screwed.
-
getUserData :: BinHandle -> UserData
getUserData bh = bh_usr bh
@@ -155,15 +145,6 @@ putAt bh p x = do seekBin bh p; put_ bh x; return ()
getAt :: Binary a => BinHandle -> Bin a -> IO a
getAt bh p = do seekBin bh p; get bh
-openBinIO_ :: IO.Handle -> IO BinHandle
-openBinIO_ h = openBinIO h
-
-openBinIO :: IO.Handle -> IO BinHandle
-openBinIO h = do
- r <- newFastMutInt
- writeFastMutInt r 0
- return (BinIO noUserData r h)
-
openBinMem :: Int -> IO BinHandle
openBinMem size
| size <= 0 = error "Data.Binary.openBinMem: size must be >= 0"
@@ -177,13 +158,9 @@ openBinMem size
return (BinMem noUserData ix_r sz_r arr_r)
tellBin :: BinHandle -> IO (Bin a)
-tellBin (BinIO _ r _) = do ix <- readFastMutInt r; return (BinPtr ix)
tellBin (BinMem _ r _ _) = do ix <- readFastMutInt r; return (BinPtr ix)
seekBin :: BinHandle -> Bin a -> IO ()
-seekBin (BinIO _ ix_r h) (BinPtr p) = do
- writeFastMutInt ix_r p
- hSeek h AbsoluteSeek (fromIntegral p)
seekBin h@(BinMem _ ix_r sz_r _) (BinPtr p) = do
sz <- readFastMutInt sz_r
if (p >= sz)
@@ -191,11 +168,6 @@ seekBin h@(BinMem _ ix_r sz_r _) (BinPtr p) = do
else writeFastMutInt ix_r p
seekBy :: BinHandle -> Int -> IO ()
-seekBy (BinIO _ ix_r h) off = do
- ix <- readFastMutInt ix_r
- let ix' = ix + off
- writeFastMutInt ix_r ix'
- hSeek h AbsoluteSeek (fromIntegral ix')
seekBy h@(BinMem _ ix_r sz_r _) off = do
sz <- readFastMutInt sz_r
ix <- readFastMutInt ix_r
@@ -209,10 +181,8 @@ isEOFBin (BinMem _ ix_r sz_r _) = do
ix <- readFastMutInt ix_r
sz <- readFastMutInt sz_r
return (ix >= sz)
-isEOFBin (BinIO _ _ h) = hIsEOF h
writeBinMem :: BinHandle -> FilePath -> IO ()
-writeBinMem (BinIO _ _ _) _ = error "Data.Binary.writeBinMem: not a memory handle"
writeBinMem (BinMem _ ix_r _ arr_r) fn = do
h <- openBinaryFile fn WriteMode
arr <- readIORef arr_r
@@ -239,7 +209,6 @@ readBinMem filename = do
return (BinMem noUserData ix_r sz_r arr_r)
fingerprintBinMem :: BinHandle -> IO Fingerprint
-fingerprintBinMem (BinIO _ _ _) = error "Binary.md5BinMem: not a memory handle"
fingerprintBinMem (BinMem _ ix_r _ arr_r) = do
arr <- readIORef arr_r
ix <- readFastMutInt ix_r
@@ -265,11 +234,9 @@ expandBin (BinMem _ _ sz_r arr_r) off = do
arr' <- mallocForeignPtrBytes sz'
withForeignPtr arr $ \old ->
withForeignPtr arr' $ \new ->
- copyBytes new old sz
+ copyBytes new old sz
writeFastMutInt sz_r sz'
writeIORef arr_r arr'
-expandBin (BinIO _ _ _) _ = return ()
--- no need to expand a file, we'll assume they expand by themselves.
-- -----------------------------------------------------------------------------
-- Low-level reading/writing of bytes
@@ -286,11 +253,6 @@ putWord8 h@(BinMem _ ix_r sz_r arr_r) w = do
withForeignPtr arr $ \p -> pokeByteOff p ix w
writeFastMutInt ix_r (ix+1)
return ()
-putWord8 (BinIO _ ix_r h) w = do
- ix <- readFastMutInt ix_r
- hPutChar h (chr (fromIntegral w)) -- XXX not really correct
- writeFastMutInt ix_r (ix+1)
- return ()
getWord8 :: BinHandle -> IO Word8
getWord8 (BinMem _ ix_r sz_r arr_r) = do
@@ -302,11 +264,6 @@ getWord8 (BinMem _ ix_r sz_r arr_r) = do
w <- withForeignPtr arr $ \p -> peekByteOff p ix
writeFastMutInt ix_r (ix+1)
return w
-getWord8 (BinIO _ ix_r h) = do
- ix <- readFastMutInt ix_r
- c <- hGetChar h
- writeFastMutInt ix_r (ix+1)
- return $! (fromIntegral (ord c)) -- XXX not really correct
putByte :: BinHandle -> Word8 -> IO ()
putByte bh w = put_ bh w
@@ -639,7 +596,11 @@ lazyGet :: Binary a => BinHandle -> IO a
lazyGet bh = do
p <- get bh -- a BinPtr
p_a <- tellBin bh
- a <- unsafeInterleaveIO (getAt bh p_a)
+ a <- unsafeInterleaveIO $ do
+ -- NB: Use a fresh off_r variable in the child thread, for thread
+ -- safety.
+ off_r <- newFastMutInt
+ getAt bh { _off_r = off_r } p_a
seekBin bh p -- skip over the object for now
return a
@@ -667,8 +628,8 @@ newReadState get_name get_fs
ud_put_name = undef "put_name",
ud_put_fs = undef "put_fs"
}
-
-newWriteState :: (BinHandle -> Name -> IO ())
+
+newWriteState :: (BinHandle -> Name -> IO ())
-> (BinHandle -> FastString -> IO ())
-> UserData
newWriteState put_name put_fs
@@ -784,3 +745,144 @@ instance Binary FunctionOrData where
1 -> return IsData
_ -> panic "Binary FunctionOrData"
+instance Binary TupleSort where
+ put_ bh BoxedTuple = putByte bh 0
+ put_ bh UnboxedTuple = putByte bh 1
+ put_ bh ConstraintTuple = putByte bh 2
+ get bh = do
+ h <- getByte bh
+ case h of
+ 0 -> do return BoxedTuple
+ 1 -> do return UnboxedTuple
+ _ -> do return ConstraintTuple
+
+instance Binary Activation where
+ put_ bh NeverActive = do
+ putByte bh 0
+ put_ bh AlwaysActive = do
+ putByte bh 1
+ put_ bh (ActiveBefore aa) = do
+ putByte bh 2
+ put_ bh aa
+ put_ bh (ActiveAfter ab) = do
+ putByte bh 3
+ put_ bh ab
+ get bh = do
+ h <- getByte bh
+ case h of
+ 0 -> do return NeverActive
+ 1 -> do return AlwaysActive
+ 2 -> do aa <- get bh
+ return (ActiveBefore aa)
+ _ -> do ab <- get bh
+ return (ActiveAfter ab)
+
+instance Binary InlinePragma where
+ put_ bh (InlinePragma a b c d) = do
+ put_ bh a
+ put_ bh b
+ put_ bh c
+ put_ bh d
+
+ get bh = do
+ a <- get bh
+ b <- get bh
+ c <- get bh
+ d <- get bh
+ return (InlinePragma a b c d)
+
+instance Binary RuleMatchInfo where
+ put_ bh FunLike = putByte bh 0
+ put_ bh ConLike = putByte bh 1
+ get bh = do
+ h <- getByte bh
+ if h == 1 then return ConLike
+ else return FunLike
+
+instance Binary InlineSpec where
+ put_ bh EmptyInlineSpec = putByte bh 0
+ put_ bh Inline = putByte bh 1
+ put_ bh Inlinable = putByte bh 2
+ put_ bh NoInline = putByte bh 3
+
+ get bh = do h <- getByte bh
+ case h of
+ 0 -> return EmptyInlineSpec
+ 1 -> return Inline
+ 2 -> return Inlinable
+ _ -> return NoInline
+
+instance Binary DefMethSpec where
+ put_ bh NoDM = putByte bh 0
+ put_ bh VanillaDM = putByte bh 1
+ put_ bh GenericDM = putByte bh 2
+ get bh = do
+ h <- getByte bh
+ case h of
+ 0 -> return NoDM
+ 1 -> return VanillaDM
+ _ -> return GenericDM
+
+instance Binary RecFlag where
+ put_ bh Recursive = do
+ putByte bh 0
+ put_ bh NonRecursive = do
+ putByte bh 1
+ get bh = do
+ h <- getByte bh
+ case h of
+ 0 -> do return Recursive
+ _ -> do return NonRecursive
+
+instance Binary OverlapFlag where
+ put_ bh (NoOverlap b) = putByte bh 0 >> put_ bh b
+ put_ bh (OverlapOk b) = putByte bh 1 >> put_ bh b
+ put_ bh (Incoherent b) = putByte bh 2 >> put_ bh b
+ get bh = do
+ h <- getByte bh
+ b <- get bh
+ case h of
+ 0 -> return $ NoOverlap b
+ 1 -> return $ OverlapOk b
+ 2 -> return $ Incoherent b
+ _ -> panic ("get OverlapFlag " ++ show h)
+
+instance Binary FixityDirection where
+ put_ bh InfixL = do
+ putByte bh 0
+ put_ bh InfixR = do
+ putByte bh 1
+ put_ bh InfixN = do
+ putByte bh 2
+ get bh = do
+ h <- getByte bh
+ case h of
+ 0 -> do return InfixL
+ 1 -> do return InfixR
+ _ -> do return InfixN
+
+instance Binary Fixity where
+ put_ bh (Fixity aa ab) = do
+ put_ bh aa
+ put_ bh ab
+ get bh = do
+ aa <- get bh
+ ab <- get bh
+ return (Fixity aa ab)
+
+instance Binary WarningTxt where
+ put_ bh (WarningTxt w) = do
+ putByte bh 0
+ put_ bh w
+ put_ bh (DeprecatedTxt d) = do
+ putByte bh 1
+ put_ bh d
+
+ get bh = do
+ h <- getByte bh
+ case h of
+ 0 -> do w <- get bh
+ return (WarningTxt w)
+ _ -> do d <- get bh
+ return (DeprecatedTxt d)
+
diff --git a/compiler/utils/BooleanFormula.hs b/compiler/utils/BooleanFormula.hs
new file mode 100644
index 0000000000..8620ef555d
--- /dev/null
+++ b/compiler/utils/BooleanFormula.hs
@@ -0,0 +1,211 @@
+--------------------------------------------------------------------------------
+-- | Boolean formulas without quantifiers and without negation.
+-- Such a formula consists of variables, conjunctions (and), and disjunctions (or).
+--
+-- This module is used to represent minimal complete definitions for classes.
+--
+{-# LANGUAGE DeriveDataTypeable, DeriveFunctor, DeriveFoldable,
+ DeriveTraversable #-}
+
+module BooleanFormula (
+ BooleanFormula(..),
+ mkFalse, mkTrue, mkAnd, mkOr, mkVar,
+ isFalse, isTrue,
+ eval, simplify, isUnsatisfied,
+ implies, impliesAtom,
+ pprBooleanFormula, pprBooleanFormulaNice
+ ) where
+
+import Data.List ( nub, intersperse )
+import Data.Data
+import Data.Foldable ( Foldable )
+import Data.Traversable ( Traversable )
+
+import MonadUtils
+import Outputable
+import Binary
+
+----------------------------------------------------------------------
+-- Boolean formula type and smart constructors
+----------------------------------------------------------------------
+
+data BooleanFormula a = Var a | And [BooleanFormula a] | Or [BooleanFormula a]
+ deriving (Eq, Data, Typeable, Functor, Foldable, Traversable)
+
+mkVar :: a -> BooleanFormula a
+mkVar = Var
+
+mkFalse, mkTrue :: BooleanFormula a
+mkFalse = Or []
+mkTrue = And []
+
+-- Convert a Bool to a BooleanFormula
+mkBool :: Bool -> BooleanFormula a
+mkBool False = mkFalse
+mkBool True = mkTrue
+
+-- Make a conjunction, and try to simplify
+mkAnd :: Eq a => [BooleanFormula a] -> BooleanFormula a
+mkAnd = maybe mkFalse (mkAnd' . nub) . concatMapM fromAnd
+ where
+ -- See Note [Simplification of BooleanFormulas]
+ fromAnd :: BooleanFormula a -> Maybe [BooleanFormula a]
+ fromAnd (And xs) = Just xs
+ -- assume that xs are already simplified
+ -- otherwise we would need: fromAnd (And xs) = concat <$> traverse fromAnd xs
+ fromAnd (Or []) = Nothing -- in case of False we bail out, And [..,mkFalse,..] == mkFalse
+ fromAnd x = Just [x]
+ mkAnd' [x] = x
+ mkAnd' xs = And xs
+
+mkOr :: Eq a => [BooleanFormula a] -> BooleanFormula a
+mkOr = maybe mkTrue (mkOr' . nub) . concatMapM fromOr
+ where
+ -- See Note [Simplification of BooleanFormulas]
+ fromOr (Or xs) = Just xs
+ fromOr (And []) = Nothing
+ fromOr x = Just [x]
+ mkOr' [x] = x
+ mkOr' xs = Or xs
+
+
+{-
+Note [Simplification of BooleanFormulas]
+~~~~~~~~~~~~~~~~~~~~~~
+The smart constructors (`mkAnd` and `mkOr`) do some attempt to simplify expressions. In particular,
+ 1. Collapsing nested ands and ors, so
+ `(mkAnd [x, And [y,z]]`
+ is represented as
+ `And [x,y,z]`
+ Implemented by `fromAnd`/`fromOr`
+ 2. Collapsing trivial ands and ors, so
+ `mkAnd [x]` becomes just `x`.
+ Implemented by mkAnd' / mkOr'
+ 3. Conjunction with false, disjunction with true is simplified, i.e.
+ `mkAnd [mkFalse,x]` becomes `mkFalse`.
+ 4. Common subexpresion elimination:
+ `mkAnd [x,x,y]` is reduced to just `mkAnd [x,y]`.
+
+This simplification is not exhaustive, in the sense that it will not produce
+the smallest possible equivalent expression. For example,
+`Or [And [x,y], And [x]]` could be simplified to `And [x]`, but it currently
+is not. A general simplifier would need to use something like BDDs.
+
+The reason behind the (crude) simplifier is to make for more user friendly
+error messages. E.g. for the code
+ > class Foo a where
+ > {-# MINIMAL bar, (foo, baq | foo, quux) #-}
+ > instance Foo Int where
+ > bar = ...
+ > baz = ...
+ > quux = ...
+We don't show a ridiculous error message like
+ Implement () and (either (`foo' and ()) or (`foo' and ()))
+-}
+
+----------------------------------------------------------------------
+-- Evaluation and simplification
+----------------------------------------------------------------------
+
+isFalse :: BooleanFormula a -> Bool
+isFalse (Or []) = True
+isFalse _ = False
+
+isTrue :: BooleanFormula a -> Bool
+isTrue (And []) = True
+isTrue _ = False
+
+eval :: (a -> Bool) -> BooleanFormula a -> Bool
+eval f (Var x) = f x
+eval f (And xs) = all (eval f) xs
+eval f (Or xs) = any (eval f) xs
+
+-- Simplify a boolean formula.
+-- The argument function should give the truth of the atoms, or Nothing if undecided.
+simplify :: Eq a => (a -> Maybe Bool) -> BooleanFormula a -> BooleanFormula a
+simplify f (Var a) = case f a of
+ Nothing -> Var a
+ Just b -> mkBool b
+simplify f (And xs) = mkAnd (map (simplify f) xs)
+simplify f (Or xs) = mkOr (map (simplify f) xs)
+
+-- Test if a boolean formula is satisfied when the given values are assigned to the atoms
+-- if it is, returns Nothing
+-- if it is not, return (Just remainder)
+isUnsatisfied :: Eq a => (a -> Bool) -> BooleanFormula a -> Maybe (BooleanFormula a)
+isUnsatisfied f bf
+ | isTrue bf' = Nothing
+ | otherwise = Just bf'
+ where
+ f' x = if f x then Just True else Nothing
+ bf' = simplify f' bf
+
+-- prop_simplify:
+-- eval f x == True <==> isTrue (simplify (Just . f) x)
+-- eval f x == False <==> isFalse (simplify (Just . f) x)
+
+-- If the boolean formula holds, does that mean that the given atom is always true?
+impliesAtom :: Eq a => BooleanFormula a -> a -> Bool
+Var x `impliesAtom` y = x == y
+And xs `impliesAtom` y = any (`impliesAtom` y) xs -- we have all of xs, so one of them implying y is enough
+Or xs `impliesAtom` y = all (`impliesAtom` y) xs
+
+implies :: Eq a => BooleanFormula a -> BooleanFormula a -> Bool
+x `implies` Var y = x `impliesAtom` y
+x `implies` And ys = all (x `implies`) ys
+x `implies` Or ys = any (x `implies`) ys
+
+----------------------------------------------------------------------
+-- Pretty printing
+----------------------------------------------------------------------
+
+-- Pretty print a BooleanFormula,
+-- using the arguments as pretty printers for Var, And and Or respectively
+pprBooleanFormula' :: (Rational -> a -> SDoc)
+ -> (Rational -> [SDoc] -> SDoc)
+ -> (Rational -> [SDoc] -> SDoc)
+ -> Rational -> BooleanFormula a -> SDoc
+pprBooleanFormula' pprVar pprAnd pprOr = go
+ where
+ go p (Var x) = pprVar p x
+ go p (And []) = cparen (p > 0) $ empty
+ go p (And xs) = pprAnd p (map (go 3) xs)
+ go _ (Or []) = keyword $ text "FALSE"
+ go p (Or xs) = pprOr p (map (go 2) xs)
+
+-- Pretty print in source syntax, "a | b | c,d,e"
+pprBooleanFormula :: (Rational -> a -> SDoc) -> Rational -> BooleanFormula a -> SDoc
+pprBooleanFormula pprVar = pprBooleanFormula' pprVar pprAnd pprOr
+ where
+ pprAnd p = cparen (p > 3) . fsep . punctuate comma
+ pprOr p = cparen (p > 2) . fsep . intersperse (text "|")
+
+-- Pretty print human in readable format, "either `a' or `b' or (`c', `d' and `e')"?
+pprBooleanFormulaNice :: Outputable a => BooleanFormula a -> SDoc
+pprBooleanFormulaNice = pprBooleanFormula' pprVar pprAnd pprOr 0
+ where
+ pprVar _ = quotes . ppr
+ pprAnd p = cparen (p > 1) . pprAnd'
+ pprAnd' [] = empty
+ pprAnd' [x,y] = x <+> text "and" <+> y
+ pprAnd' xs@(_:_) = fsep (punctuate comma (init xs)) <> text ", and" <+> last xs
+ pprOr p xs = cparen (p > 1) $ text "either" <+> sep (intersperse (text "or") xs)
+
+instance Outputable a => Outputable (BooleanFormula a) where
+ pprPrec = pprBooleanFormula pprPrec
+
+----------------------------------------------------------------------
+-- Binary
+----------------------------------------------------------------------
+
+instance Binary a => Binary (BooleanFormula a) where
+ put_ bh (Var x) = putByte bh 0 >> put_ bh x
+ put_ bh (And xs) = putByte bh 1 >> put_ bh xs
+ put_ bh (Or xs) = putByte bh 2 >> put_ bh xs
+
+ get bh = do
+ h <- getByte bh
+ case h of
+ 0 -> Var <$> get bh
+ 1 -> And <$> get bh
+ _ -> Or <$> get bh
diff --git a/compiler/utils/BufWrite.hs b/compiler/utils/BufWrite.hs
index c0dda03bbb..f85ea8e792 100644
--- a/compiler/utils/BufWrite.hs
+++ b/compiler/utils/BufWrite.hs
@@ -14,7 +14,7 @@
-- The above warning supression flag is a temporary kludge.
-- While working on this module you are encouraged to remove it and
-- detab the module (please do the detabbing in a separate patch). See
--- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces
+-- http://ghc.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces
-- for details
module BufWrite (
diff --git a/compiler/utils/Digraph.lhs b/compiler/utils/Digraph.lhs
index 9ae84a7897..cc684303b6 100644
--- a/compiler/utils/Digraph.lhs
+++ b/compiler/utils/Digraph.lhs
@@ -7,7 +7,7 @@
-- The above warning supression flag is a temporary kludge.
-- While working on this module you are encouraged to remove it and
-- detab the module (please do the detabbing in a separate patch). See
--- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces
+-- http://ghc.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces
-- for details
{-# LANGUAGE ScopedTypeVariables #-}
@@ -15,7 +15,8 @@ module Digraph(
Graph, graphFromVerticesAndAdjacency, graphFromEdgedVertices,
SCC(..), Node, flattenSCC, flattenSCCs,
- stronglyConnCompG, topologicalSortG, dfsTopSortG,
+ stronglyConnCompG, stronglyConnCompFromG,
+ topologicalSortG, dfsTopSortG,
verticesG, edgesG, hasVertexG,
reachableG, transposeG,
outdegreeG, indegreeG,
@@ -254,9 +255,21 @@ edges going from them to earlier ones.
\begin{code}
stronglyConnCompG :: Graph node -> [SCC node]
-stronglyConnCompG (Graph { gr_int_graph = graph, gr_vertex_to_node = vertex_fn }) = map decode forest
+stronglyConnCompG graph = decodeSccs graph forest
+ where forest = {-# SCC "Digraph.scc" #-} scc (gr_int_graph graph)
+
+-- Find the set of strongly connected components starting from the
+-- given roots. This is a good way to discard unreachable nodes at
+-- the same time as computing SCCs.
+stronglyConnCompFromG :: Graph node -> [node] -> [SCC node]
+stronglyConnCompFromG graph roots = decodeSccs graph forest
+ where forest = {-# SCC "Digraph.scc" #-} sccFrom (gr_int_graph graph) vs
+ vs = [ v | Just v <- map (gr_node_to_vertex graph) roots ]
+
+decodeSccs :: Graph node -> Forest Vertex -> [SCC node]
+decodeSccs Graph { gr_int_graph = graph, gr_vertex_to_node = vertex_fn } forest
+ = map decode forest
where
- forest = {-# SCC "Digraph.scc" #-} scc graph
decode (Node v []) | mentions_itself v = CyclicSCC [vertex_fn v]
| otherwise = AcyclicSCC (vertex_fn v)
decode other = CyclicSCC (dec other [])
@@ -269,11 +282,12 @@ stronglyConnCompFromEdgedVertices
:: Ord key
=> [Node key payload]
-> [SCC payload]
-stronglyConnCompFromEdgedVertices = map (fmap get_node) . stronglyConnCompFromEdgedVerticesR
+stronglyConnCompFromEdgedVertices
+ = map (fmap get_node) . stronglyConnCompFromEdgedVerticesR
where get_node (n, _, _) = n
-- The "R" interface is used when you expect to apply SCC to
--- the (some of) the result of SCC, so you dont want to lose the dependency info
+-- (some of) the result of SCC, so you dont want to lose the dependency info
stronglyConnCompFromEdgedVerticesR
:: Ord key
=> [Node key payload]
@@ -534,6 +548,9 @@ postorderF ts = foldr (.) id $ map postorder ts
postOrd :: IntGraph -> [Vertex]
postOrd g = postorderF (dff g) []
+postOrdFrom :: IntGraph -> [Vertex] -> [Vertex]
+postOrdFrom g vs = postorderF (dfs g vs) []
+
topSort :: IntGraph -> [Vertex]
topSort = reverse . postOrd
\end{code}
@@ -557,6 +574,9 @@ undirected g = buildG (bounds g) (edges g ++ reverseE g)
\begin{code}
scc :: IntGraph -> Forest Vertex
scc g = dfs g (reverse (postOrd (transpose g)))
+
+sccFrom :: IntGraph -> [Vertex] -> Forest Vertex
+sccFrom g vs = reverse (dfs (transpose g) (reverse (postOrdFrom g vs)))
\end{code}
------------------------------------------------------------
diff --git a/compiler/utils/Encoding.hs b/compiler/utils/Encoding.hs
index 6467377a1a..c4a669c134 100644
--- a/compiler/utils/Encoding.hs
+++ b/compiler/utils/Encoding.hs
@@ -32,8 +32,7 @@ module Encoding (
import Foreign
import Data.Char
import Numeric
-import GHC.Ptr ( Ptr(..) )
-import GHC.Base
+import ExtsCompat46
-- -----------------------------------------------------------------------------
-- UTF-8
diff --git a/compiler/utils/ExtsCompat46.hs b/compiler/utils/ExtsCompat46.hs
new file mode 100644
index 0000000000..da0e67ab93
--- /dev/null
+++ b/compiler/utils/ExtsCompat46.hs
@@ -0,0 +1,293 @@
+{-# LANGUAGE BangPatterns, CPP #-}
+
+-----------------------------------------------------------------------------
+-- |
+-- Module : ExtsCompat46
+-- Copyright : (c) Lodz University of Technology 2013
+-- License : see LICENSE
+--
+-- Maintainer : ghc-devs@haskell.org
+-- Stability : internal
+-- Portability : non-portable (GHC internal)
+--
+-- Compatibility module to encapsulate primops API change between GHC 7.6
+-- GHC 7.8.
+--
+-- In GHC we use comparison primops in a couple of modules, but that primops
+-- have different type signature in GHC 7.6 (where they return Bool) than
+-- in GHC 7.8 (where they return Int#). As long as we allow bootstrapping
+-- with GHC 7.6 or earlier we need to have this compatibility module, so that
+-- we can compile stage1 compiler using the old API and then continue with
+-- stage2 using the new API. When we set GHC 7.8 as the minimum version
+-- required for bootstrapping, we should remove this module.
+--
+-----------------------------------------------------------------------------
+
+module ExtsCompat46 (
+ module GHC.Exts,
+
+ gtChar#, geChar#, eqChar#,
+ neChar#, ltChar#, leChar#,
+
+ (>#), (>=#), (==#), (/=#), (<#), (<=#),
+
+ gtWord#, geWord#, eqWord#,
+ neWord#, ltWord#, leWord#,
+
+ (>##), (>=##), (==##), (/=##), (<##), (<=##),
+
+ gtFloat#, geFloat#, eqFloat#,
+ neFloat#, ltFloat#, leFloat#,
+
+ gtAddr#, geAddr#, eqAddr#,
+ neAddr#, ltAddr#, leAddr#,
+
+ sameMutableArray#, sameMutableByteArray#, sameMutableArrayArray#,
+ sameMutVar#, sameTVar#, sameMVar#
+
+ ) where
+
+import GHC.Exts hiding (
+ gtChar#, geChar#, eqChar#,
+ neChar#, ltChar#, leChar#,
+
+ (>#), (>=#), (==#), (/=#), (<#), (<=#),
+
+ gtWord#, geWord#, eqWord#,
+ neWord#, ltWord#, leWord#,
+
+ (>##), (>=##), (==##), (/=##), (<##), (<=##),
+
+ gtFloat#, geFloat#, eqFloat#,
+ neFloat#, ltFloat#, leFloat#,
+
+ gtAddr#, geAddr#, eqAddr#,
+ neAddr#, ltAddr#, leAddr#,
+
+ sameMutableArray#, sameMutableByteArray#, sameMutableArrayArray#,
+ sameMutVar#, sameTVar#, sameMVar#
+ )
+
+import qualified GHC.Exts as E (
+ gtChar#, geChar#, eqChar#,
+ neChar#, ltChar#, leChar#,
+
+ (>#), (>=#), (==#), (/=#), (<#), (<=#),
+
+ gtWord#, geWord#, eqWord#,
+ neWord#, ltWord#, leWord#,
+
+ (>##), (>=##), (==##), (/=##), (<##), (<=##),
+
+ gtFloat#, geFloat#, eqFloat#,
+ neFloat#, ltFloat#, leFloat#,
+
+ gtAddr#, geAddr#, eqAddr#,
+ neAddr#, ltAddr#, leAddr#,
+
+ sameMutableArray#, sameMutableByteArray#, sameMutableArrayArray#,
+ sameMutVar#, sameTVar#, sameMVar#
+ )
+
+-- See #8330
+#if __GLASGOW_HASKELL__ > 710
+#error What is minimal version of GHC required for bootstraping? If it's GHC 7.8 we should remove this module and use GHC.Exts instead.
+#endif
+
+#if __GLASGOW_HASKELL__ > 706
+
+gtChar# :: Char# -> Char# -> Bool
+gtChar# a b = isTrue# (a `E.gtChar#` b)
+geChar# :: Char# -> Char# -> Bool
+geChar# a b = isTrue# (a `E.geChar#` b)
+eqChar# :: Char# -> Char# -> Bool
+eqChar# a b = isTrue# (a `E.eqChar#` b)
+neChar# :: Char# -> Char# -> Bool
+neChar# a b = isTrue# (a `E.neChar#` b)
+ltChar# :: Char# -> Char# -> Bool
+ltChar# a b = isTrue# (a `E.ltChar#` b)
+leChar# :: Char# -> Char# -> Bool
+leChar# a b = isTrue# (a `E.leChar#` b)
+
+infix 4 >#, >=#, ==#, /=#, <#, <=#
+
+(>#) :: Int# -> Int# -> Bool
+(>#) a b = isTrue# (a E.># b)
+(>=#) :: Int# -> Int# -> Bool
+(>=#) a b = isTrue# (a E.>=# b)
+(==#) :: Int# -> Int# -> Bool
+(==#) a b = isTrue# (a E.==# b)
+(/=#) :: Int# -> Int# -> Bool
+(/=#) a b = isTrue# (a E./=# b)
+(<#) :: Int# -> Int# -> Bool
+(<#) a b = isTrue# (a E.<# b)
+(<=#) :: Int# -> Int# -> Bool
+(<=#) a b = isTrue# (a E.<=# b)
+
+gtWord# :: Word# -> Word# -> Bool
+gtWord# a b = isTrue# (a `E.gtWord#` b)
+geWord# :: Word# -> Word# -> Bool
+geWord# a b = isTrue# (a `E.geWord#` b)
+eqWord# :: Word# -> Word# -> Bool
+eqWord# a b = isTrue# (a `E.eqWord#` b)
+neWord# :: Word# -> Word# -> Bool
+neWord# a b = isTrue# (a `E.neWord#` b)
+ltWord# :: Word# -> Word# -> Bool
+ltWord# a b = isTrue# (a `E.ltWord#` b)
+leWord# :: Word# -> Word# -> Bool
+leWord# a b = isTrue# (a `E.leWord#` b)
+
+infix 4 >##, >=##, ==##, /=##, <##, <=##
+
+(>##) :: Double# -> Double# -> Bool
+(>##) a b = isTrue# (a E.>## b)
+(>=##) :: Double# -> Double# -> Bool
+(>=##) a b = isTrue# (a E.>=## b)
+(==##) :: Double# -> Double# -> Bool
+(==##) a b = isTrue# (a E.==## b)
+(/=##) :: Double# -> Double# -> Bool
+(/=##) a b = isTrue# (a E./=## b)
+(<##) :: Double# -> Double# -> Bool
+(<##) a b = isTrue# (a E.<## b)
+(<=##) :: Double# -> Double# -> Bool
+(<=##) a b = isTrue# (a E.<=## b)
+
+gtFloat# :: Float# -> Float# -> Bool
+gtFloat# a b = isTrue# (a `E.gtFloat#` b)
+geFloat# :: Float# -> Float# -> Bool
+geFloat# a b = isTrue# (a `E.geFloat#` b)
+eqFloat# :: Float# -> Float# -> Bool
+eqFloat# a b = isTrue# (a `E.eqFloat#` b)
+neFloat# :: Float# -> Float# -> Bool
+neFloat# a b = isTrue# (a `E.neFloat#` b)
+ltFloat# :: Float# -> Float# -> Bool
+ltFloat# a b = isTrue# (a `E.ltFloat#` b)
+leFloat# :: Float# -> Float# -> Bool
+leFloat# a b = isTrue# (a `E.leFloat#` b)
+
+gtAddr# :: Addr# -> Addr# -> Bool
+gtAddr# a b = isTrue# (a `E.gtAddr#` b)
+geAddr# :: Addr# -> Addr# -> Bool
+geAddr# a b = isTrue# (a `E.geAddr#` b)
+eqAddr# :: Addr# -> Addr# -> Bool
+eqAddr# a b = isTrue# (a `E.eqAddr#` b)
+neAddr# :: Addr# -> Addr# -> Bool
+neAddr# a b = isTrue# (a `E.neAddr#` b)
+ltAddr# :: Addr# -> Addr# -> Bool
+ltAddr# a b = isTrue# (a `E.ltAddr#` b)
+leAddr# :: Addr# -> Addr# -> Bool
+leAddr# a b = isTrue# (a `E.leAddr#` b)
+
+sameMutableArray# :: MutableArray# s a -> MutableArray# s a -> Bool
+sameMutableArray# a b = isTrue# (E.sameMutableArray# a b)
+sameMutableByteArray# :: MutableByteArray# s -> MutableByteArray# s -> Bool
+sameMutableByteArray# a b = isTrue# (E.sameMutableByteArray# a b)
+sameMutableArrayArray# :: MutableArrayArray# s -> MutableArrayArray# s -> Bool
+sameMutableArrayArray# a b = isTrue# (E.sameMutableArrayArray# a b)
+
+sameMutVar# :: MutVar# s a -> MutVar# s a -> Bool
+sameMutVar# a b = isTrue# (E.sameMutVar# a b)
+sameTVar# :: TVar# s a -> TVar# s a -> Bool
+sameTVar# a b = isTrue# (E.sameTVar# a b)
+sameMVar# :: MVar# s a -> MVar# s a -> Bool
+sameMVar# a b = isTrue# (E.sameMVar# a b)
+
+#else
+
+gtChar# :: Char# -> Char# -> Bool
+gtChar# a b = a `E.gtChar#` b
+geChar# :: Char# -> Char# -> Bool
+geChar# a b = a `E.geChar#` b
+eqChar# :: Char# -> Char# -> Bool
+eqChar# a b = a `E.eqChar#` b
+neChar# :: Char# -> Char# -> Bool
+neChar# a b = a `E.neChar#` b
+ltChar# :: Char# -> Char# -> Bool
+ltChar# a b = a `E.ltChar#` b
+leChar# :: Char# -> Char# -> Bool
+leChar# a b = a `E.leChar#` b
+
+infix 4 >#, >=#, ==#, /=#, <#, <=#
+
+(>#) :: Int# -> Int# -> Bool
+(>#) a b = a E.># b
+(>=#) :: Int# -> Int# -> Bool
+(>=#) a b = a E.>=# b
+(==#) :: Int# -> Int# -> Bool
+(==#) a b = a E.==# b
+(/=#) :: Int# -> Int# -> Bool
+(/=#) a b = a E./=# b
+(<#) :: Int# -> Int# -> Bool
+(<#) a b = a E.<# b
+(<=#) :: Int# -> Int# -> Bool
+(<=#) a b = a E.<=# b
+
+gtWord# :: Word# -> Word# -> Bool
+gtWord# a b = a `E.gtWord#` b
+geWord# :: Word# -> Word# -> Bool
+geWord# a b = a `E.geWord#` b
+eqWord# :: Word# -> Word# -> Bool
+eqWord# a b = a `E.eqWord#` b
+neWord# :: Word# -> Word# -> Bool
+neWord# a b = a `E.neWord#` b
+ltWord# :: Word# -> Word# -> Bool
+ltWord# a b = a `E.ltWord#` b
+leWord# :: Word# -> Word# -> Bool
+leWord# a b = a `E.leWord#` b
+
+infix 4 >##, >=##, ==##, /=##, <##, <=##
+
+(>##) :: Double# -> Double# -> Bool
+(>##) a b = a E.>## b
+(>=##) :: Double# -> Double# -> Bool
+(>=##) a b = a E.>=## b
+(==##) :: Double# -> Double# -> Bool
+(==##) a b = a E.==## b
+(/=##) :: Double# -> Double# -> Bool
+(/=##) a b = a E./=## b
+(<##) :: Double# -> Double# -> Bool
+(<##) a b = a E.<## b
+(<=##) :: Double# -> Double# -> Bool
+(<=##) a b = a E.<=## b
+
+gtFloat# :: Float# -> Float# -> Bool
+gtFloat# a b = a `E.gtFloat#` b
+geFloat# :: Float# -> Float# -> Bool
+geFloat# a b = a `E.geFloat#` b
+eqFloat# :: Float# -> Float# -> Bool
+eqFloat# a b = a `E.eqFloat#` b
+neFloat# :: Float# -> Float# -> Bool
+neFloat# a b = a `E.neFloat#` b
+ltFloat# :: Float# -> Float# -> Bool
+ltFloat# a b = a `E.ltFloat#` b
+leFloat# :: Float# -> Float# -> Bool
+leFloat# a b = a `E.leFloat#` b
+
+gtAddr# :: Addr# -> Addr# -> Bool
+gtAddr# a b = a `E.gtAddr#` b
+geAddr# :: Addr# -> Addr# -> Bool
+geAddr# a b = a `E.geAddr#` b
+eqAddr# :: Addr# -> Addr# -> Bool
+eqAddr# a b = a `E.eqAddr#` b
+neAddr# :: Addr# -> Addr# -> Bool
+neAddr# a b = a `E.neAddr#` b
+ltAddr# :: Addr# -> Addr# -> Bool
+ltAddr# a b = a `E.ltAddr#` b
+leAddr# :: Addr# -> Addr# -> Bool
+leAddr# a b = a `E.leAddr#` b
+
+sameMutableArray# :: MutableArray# s a -> MutableArray# s a -> Bool
+sameMutableArray# a b = E.sameMutableArray# a b
+sameMutableByteArray# :: MutableByteArray# s -> MutableByteArray# s -> Bool
+sameMutableByteArray# a b = E.sameMutableByteArray# a b
+sameMutableArrayArray# :: MutableArrayArray# s -> MutableArrayArray# s -> Bool
+sameMutableArrayArray# a b = E.sameMutableArrayArray# a b
+
+sameMutVar# :: MutVar# s a -> MutVar# s a -> Bool
+sameMutVar# a b = E.sameMutVar# a b
+sameTVar# :: TVar# s a -> TVar# s a -> Bool
+sameTVar# a b = E.sameTVar# a b
+sameMVar# :: MVar# s a -> MVar# s a -> Bool
+sameMVar# a b = E.sameMVar# a b
+
+#endif \ No newline at end of file
diff --git a/compiler/utils/FastMutInt.lhs b/compiler/utils/FastMutInt.lhs
index d29bb9136c..7156cdc9fb 100644
--- a/compiler/utils/FastMutInt.lhs
+++ b/compiler/utils/FastMutInt.lhs
@@ -1,28 +1,20 @@
\begin{code}
-{-# OPTIONS -fno-warn-tabs #-}
--- The above warning supression flag is a temporary kludge.
--- While working on this module you are encouraged to remove it and
--- detab the module (please do the detabbing in a separate patch). See
--- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces
--- for details
-
{-# LANGUAGE BangPatterns #-}
{-# OPTIONS -cpp #-}
{-# OPTIONS_GHC -O #-}
-- We always optimise this, otherwise performance of a non-optimised
-- compiler is severely affected
-
--
-- (c) The University of Glasgow 2002-2006
--
-- Unboxed mutable Ints
module FastMutInt(
- FastMutInt, newFastMutInt,
- readFastMutInt, writeFastMutInt,
+ FastMutInt, newFastMutInt,
+ readFastMutInt, writeFastMutInt,
- FastMutPtr, newFastMutPtr,
- readFastMutPtr, writeFastMutPtr
+ FastMutPtr, newFastMutPtr,
+ readFastMutPtr, writeFastMutPtr
) where
#ifdef __GLASGOW_HASKELL__
diff --git a/compiler/utils/FastString.lhs b/compiler/utils/FastString.lhs
index 1eeab0f561..5a78c0b59b 100644
--- a/compiler/utils/FastString.lhs
+++ b/compiler/utils/FastString.lhs
@@ -10,18 +10,20 @@
-- |
-- There are two principal string types used internally by GHC:
--
--- 'FastString':
--- * A compact, hash-consed, representation of character strings.
--- * Comparison is O(1), and you can get a 'Unique.Unique' from them.
--- * Generated by 'fsLit'.
--- * Turn into 'Outputable.SDoc' with 'Outputable.ftext'.
+-- ['FastString']
--
--- 'LitString':
--- * Just a wrapper for the @Addr#@ of a C string (@Ptr CChar@).
--- * Practically no operations.
--- * Outputing them is fast.
--- * Generated by 'sLit'.
--- * Turn into 'Outputable.SDoc' with 'Outputable.ptext'
+-- * A compact, hash-consed, representation of character strings.
+-- * Comparison is O(1), and you can get a 'Unique.Unique' from them.
+-- * Generated by 'fsLit'.
+-- * Turn into 'Outputable.SDoc' with 'Outputable.ftext'.
+--
+-- ['LitString']
+--
+-- * Just a wrapper for the @Addr#@ of a C string (@Ptr CChar@).
+-- * Practically no operations.
+-- * Outputing them is fast.
+-- * Generated by 'sLit'.
+-- * Turn into 'Outputable.SDoc' with 'Outputable.ptext'
--
-- Use 'LitString' unless you want the facilities of 'FastString'.
module FastString
@@ -79,17 +81,17 @@ module FastString
-- * LitStrings
LitString,
-
+
-- ** Construction
sLit,
#if defined(__GLASGOW_HASKELL__)
mkLitString#,
#endif
mkLitString,
-
+
-- ** Deconstruction
unpackLitString,
-
+
-- ** Operations
lengthLS
) where
@@ -102,24 +104,30 @@ import FastFunctions
import Panic
import Util
+import Control.Monad
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as BSC
import qualified Data.ByteString.Internal as BS
import qualified Data.ByteString.Unsafe as BS
import Foreign.C
-import GHC.Exts
+import ExtsCompat46
import System.IO
import System.IO.Unsafe ( unsafePerformIO )
import Data.Data
-import Data.IORef ( IORef, newIORef, readIORef, writeIORef )
+import Data.IORef ( IORef, newIORef, readIORef, atomicModifyIORef )
import Data.Maybe ( isJust )
import Data.Char
+import Data.List ( elemIndex )
-import GHC.IO ( IO(..) )
+import GHC.IO ( IO(..), unsafeDupablePerformIO )
import Foreign.Safe
+#if STAGE >= 2
+import GHC.Conc.Sync (sharedCAF)
+#endif
+
#if defined(__GLASGOW_HASKELL__)
import GHC.Base ( unpackCString# )
#endif
@@ -207,116 +215,175 @@ cmpFS f1@(FastString u1 _ _ _) f2@(FastString u2 _ _ _) =
if u1 == u2 then EQ else
compare (fastStringToByteString f1) (fastStringToByteString f2)
-#ifndef __HADDOCK__
foreign import ccall unsafe "ghc_memcmp"
memcmp :: Ptr a -> Ptr b -> Int -> IO Int
-#endif
-- -----------------------------------------------------------------------------
-- Construction
{-
-Internally, the compiler will maintain a fast string symbol
-table, providing sharing and fast comparison. Creation of
-new @FastString@s then covertly does a lookup, re-using the
-@FastString@ if there was a hit.
--}
+Internally, the compiler will maintain a fast string symbol table, providing
+sharing and fast comparison. Creation of new @FastString@s then covertly does a
+lookup, re-using the @FastString@ if there was a hit.
+
+The design of the FastString hash table allows for lockless concurrent reads
+and updates to multiple buckets with low synchronization overhead.
+See Note [Updating the FastString table] on how it's updated.
+-}
data FastStringTable =
FastStringTable
- {-# UNPACK #-} !Int
- (MutableArray# RealWorld [FastString])
+ {-# UNPACK #-} !(IORef Int) -- the unique ID counter shared with all buckets
+ (MutableArray# RealWorld (IORef [FastString])) -- the array of mutable buckets
+string_table :: FastStringTable
{-# NOINLINE string_table #-}
-string_table :: IORef FastStringTable
-string_table =
- unsafePerformIO $ do
- tab <- IO $ \s1# -> case newArray# hASH_TBL_SIZE_UNBOXED [] s1# of
- (# s2#, arr# #) ->
- (# s2#, FastStringTable 0 arr# #)
- newIORef tab
-
-lookupTbl :: FastStringTable -> Int -> IO [FastString]
+string_table = unsafePerformIO $ do
+ uid <- newIORef 0
+ tab <- IO $ \s1# -> case newArray# hASH_TBL_SIZE_UNBOXED (panic "string_table") s1# of
+ (# s2#, arr# #) ->
+ (# s2#, FastStringTable uid arr# #)
+ forM_ [0.. hASH_TBL_SIZE-1] $ \i -> do
+ bucket <- newIORef []
+ updTbl tab i bucket
+
+ -- use the support wired into the RTS to share this CAF among all images of
+ -- libHSghc
+#if STAGE < 2
+ return tab
+#else
+ sharedCAF tab getOrSetLibHSghcFastStringTable
+
+-- from the RTS; thus we cannot use this mechanism when STAGE<2; the previous
+-- RTS might not have this symbol
+foreign import ccall unsafe "getOrSetLibHSghcFastStringTable"
+ getOrSetLibHSghcFastStringTable :: Ptr a -> IO (Ptr a)
+#endif
+
+{-
+
+We include the FastString table in the `sharedCAF` mechanism because we'd like
+FastStrings created by a Core plugin to have the same uniques as corresponding
+strings created by the host compiler itself. For example, this allows plugins
+to lookup known names (eg `mkTcOcc "MySpecialType"`) in the GlobalRdrEnv or
+even re-invoke the parser.
+
+In particular, the following little sanity test was failing in a plugin
+prototyping safe newtype-coercions: GHC.NT.Type.NT was imported, but could not
+be looked up /by the plugin/.
+
+ let rdrName = mkModuleName "GHC.NT.Type" `mkRdrQual` mkTcOcc "NT"
+ putMsgS $ showSDoc dflags $ ppr $ lookupGRE_RdrName rdrName $ mg_rdr_env guts
+
+`mkTcOcc` involves the lookup (or creation) of a FastString. Since the
+plugin's FastString.string_table is empty, constructing the RdrName also
+allocates new uniques for the FastStrings "GHC.NT.Type" and "NT". These
+uniques are almost certainly unequal to the ones that the host compiler
+originally assigned to those FastStrings. Thus the lookup fails since the
+domain of the GlobalRdrEnv is affected by the RdrName's OccName's FastString's
+unique.
+
+The old `reinitializeGlobals` mechanism is enough to provide the plugin with
+read-access to the table, but it insufficient in the general case where the
+plugin may allocate FastStrings. This mutates the supply for the FastStrings'
+unique, and that needs to be propagated back to the compiler's instance of the
+global variable. Such propagation is beyond the `reinitializeGlobals`
+mechanism.
+
+Maintaining synchronization of the two instances of this global is rather
+difficult because of the uses of `unsafePerformIO` in this module. Not
+synchronizing them risks breaking the rather major invariant that two
+FastStrings with the same unique have the same string. Thus we use the
+lower-level `sharedCAF` mechanism that relies on Globals.c.
+
+-}
+
+lookupTbl :: FastStringTable -> Int -> IO (IORef [FastString])
lookupTbl (FastStringTable _ arr#) (I# i#) =
IO $ \ s# -> readArray# arr# i# s#
-updTbl :: IORef FastStringTable -> FastStringTable -> Int -> [FastString] -> IO ()
-updTbl fs_table_var (FastStringTable uid arr#) (I# i#) ls = do
+updTbl :: FastStringTable -> Int -> IORef [FastString] -> IO ()
+updTbl (FastStringTable _uid arr#) (I# i#) ls = do
(IO $ \ s# -> case writeArray# arr# i# ls s# of { s2# -> (# s2#, () #) })
- writeIORef fs_table_var (FastStringTable (uid+1) arr#)
mkFastString# :: Addr# -> FastString
mkFastString# a# = mkFastStringBytes ptr (ptrStrLength ptr)
where ptr = Ptr a#
+{- Note [Updating the FastString table]
+
+The procedure goes like this:
+
+1. Read the relevant bucket and perform a look up of the string.
+2. If it exists, return it.
+3. Otherwise grab a unique ID, create a new FastString and atomically attempt
+ to update the relevant bucket with this FastString:
+
+ * Double check that the string is not in the bucket. Another thread may have
+ inserted it while we were creating our string.
+ * Return the existing FastString if it exists. The one we preemptively
+ created will get GCed.
+ * Otherwise, insert and return the string we created.
+-}
+
+{- Note [Double-checking the bucket]
+
+It is not necessary to check the entire bucket the second time. We only have to
+check the strings that are new to the bucket since the last time we read it.
+-}
+
+mkFastStringWith :: (Int -> IO FastString) -> Ptr Word8 -> Int -> IO FastString
+mkFastStringWith mk_fs !ptr !len = do
+ let hash = hashStr ptr len
+ bucket <- lookupTbl string_table hash
+ ls1 <- readIORef bucket
+ res <- bucket_match ls1 len ptr
+ case res of
+ Just v -> return v
+ Nothing -> do
+ n <- get_uid
+ new_fs <- mk_fs n
+
+ atomicModifyIORef bucket $ \ls2 ->
+ -- Note [Double-checking the bucket]
+ let delta_ls = case ls1 of
+ [] -> ls2
+ l:_ -> case l `elemIndex` ls2 of
+ Nothing -> panic "mkFastStringWith"
+ Just idx -> take idx ls2
+
+ -- NB: Might as well use inlinePerformIO, since the call to
+ -- bucket_match doesn't perform any IO that could be floated
+ -- out of this closure or erroneously duplicated.
+ in case inlinePerformIO (bucket_match delta_ls len ptr) of
+ Nothing -> (new_fs:ls2, new_fs)
+ Just fs -> (ls2,fs)
+ where
+ !(FastStringTable uid _arr) = string_table
+
+ get_uid = atomicModifyIORef uid $ \n -> (n+1,n)
+
mkFastStringBytes :: Ptr Word8 -> Int -> FastString
-mkFastStringBytes ptr len = unsafePerformIO $ do
- ft@(FastStringTable uid _) <- readIORef string_table
- let
- h = hashStr ptr len
- add_it ls = do
- fs <- copyNewFastString uid ptr len
- updTbl string_table ft h (fs:ls)
- {- _trace ("new: " ++ show f_str) $ -}
- return fs
- --
- lookup_result <- lookupTbl ft h
- case lookup_result of
- [] -> add_it []
- ls -> do
- b <- bucket_match ls len ptr
- case b of
- Nothing -> add_it ls
- Just v -> {- _trace ("re-use: "++show v) $ -} return v
+mkFastStringBytes !ptr !len =
+ -- NB: Might as well use unsafeDupablePerformIO, since mkFastStringWith is
+ -- idempotent.
+ unsafeDupablePerformIO $
+ mkFastStringWith (copyNewFastString ptr len) ptr len
-- | Create a 'FastString' from an existing 'ForeignPtr'; the difference
-- between this and 'mkFastStringBytes' is that we don't have to copy
-- the bytes if the string is new to the table.
mkFastStringForeignPtr :: Ptr Word8 -> ForeignPtr Word8 -> Int -> IO FastString
-mkFastStringForeignPtr ptr fp len = do
- ft@(FastStringTable uid _) <- readIORef string_table
--- _trace ("hashed: "++show (I# h)) $
- let
- h = hashStr ptr len
- add_it ls = do
- fs <- mkNewFastString uid ptr fp len
- updTbl string_table ft h (fs:ls)
- {- _trace ("new: " ++ show f_str) $ -}
- return fs
- --
- lookup_result <- lookupTbl ft h
- case lookup_result of
- [] -> add_it []
- ls -> do
- b <- bucket_match ls len ptr
- case b of
- Nothing -> add_it ls
- Just v -> {- _trace ("re-use: "++show v) $ -} return v
+mkFastStringForeignPtr ptr !fp len
+ = mkFastStringWith (mkNewFastString fp ptr len) ptr len
-- | Create a 'FastString' from an existing 'ForeignPtr'; the difference
-- between this and 'mkFastStringBytes' is that we don't have to copy
-- the bytes if the string is new to the table.
mkFastStringByteString :: ByteString -> IO FastString
mkFastStringByteString bs = BS.unsafeUseAsCStringLen bs $ \(ptr, len) -> do
- ft@(FastStringTable uid _) <- readIORef string_table
--- _trace ("hashed: "++show (I# h)) $
- let
- ptr' = castPtr ptr
- h = hashStr ptr' len
- add_it ls = do
- fs <- mkNewFastStringByteString uid ptr' len bs
- updTbl string_table ft h (fs:ls)
- {- _trace ("new: " ++ show f_str) $ -}
- return fs
- --
- lookup_result <- lookupTbl ft h
- case lookup_result of
- [] -> add_it []
- ls -> do
- b <- bucket_match ls len ptr'
- case b of
- Nothing -> add_it ls
- Just v -> {- _trace ("re-use: "++show v) $ -} return v
+ let ptr' = castPtr ptr
+ mkFastStringWith (mkNewFastStringByteString bs ptr' len) ptr' len
-- | Creates a UTF-8 encoded 'FastString' from a 'String'
mkFastString :: String -> FastString
@@ -353,22 +420,22 @@ bucket_match (v@(FastString _ _ bs _):ls) len ptr
| otherwise =
bucket_match ls len ptr
-mkNewFastString :: Int -> Ptr Word8 -> ForeignPtr Word8 -> Int
+mkNewFastString :: ForeignPtr Word8 -> Ptr Word8 -> Int -> Int
-> IO FastString
-mkNewFastString uid ptr fp len = do
+mkNewFastString fp ptr len uid = do
ref <- newIORef Nothing
n_chars <- countUTF8Chars ptr len
return (FastString uid n_chars (BS.fromForeignPtr fp 0 len) ref)
-mkNewFastStringByteString :: Int -> Ptr Word8 -> Int -> ByteString
+mkNewFastStringByteString :: ByteString -> Ptr Word8 -> Int -> Int
-> IO FastString
-mkNewFastStringByteString uid ptr len bs = do
+mkNewFastStringByteString bs ptr len uid = do
ref <- newIORef Nothing
n_chars <- countUTF8Chars ptr len
return (FastString uid n_chars bs ref)
-copyNewFastString :: Int -> Ptr Word8 -> Int -> IO FastString
-copyNewFastString uid ptr len = do
+copyNewFastString :: Ptr Word8 -> Int -> Int -> IO FastString
+copyNewFastString ptr len uid = do
fp <- copyBytesToForeignPtr ptr len
ref <- newIORef Nothing
n_chars <- countUTF8Chars ptr len
@@ -390,10 +457,10 @@ hashStr :: Ptr Word8 -> Int -> Int
-- use the Addr to produce a hash value between 0 & m (inclusive)
hashStr (Ptr a#) (I# len#) = loop 0# 0#
where
- loop h n | n GHC.Exts.==# len# = I# h
- | otherwise = loop h2 (n GHC.Exts.+# 1#)
+ loop h n | n ExtsCompat46.==# len# = I# h
+ | otherwise = loop h2 (n ExtsCompat46.+# 1#)
where !c = ord# (indexCharOffAddr# a# n)
- !h2 = (c GHC.Exts.+# (h GHC.Exts.*# 128#)) `remInt#`
+ !h2 = (c ExtsCompat46.+# (h ExtsCompat46.*# 128#)) `remInt#`
hASH_TBL_SIZE#
-- -----------------------------------------------------------------------------
@@ -437,9 +504,10 @@ zEncodeFS fs@(FastString _ _ _ ref) =
case m of
Just zfs -> return zfs
Nothing -> do
- let zfs = mkZFastString (zEncodeString (unpackFS fs))
- writeIORef ref (Just zfs)
- return zfs
+ atomicModifyIORef ref $ \m' -> case m' of
+ Nothing -> let zfs = mkZFastString (zEncodeString (unpackFS fs))
+ in (Just zfs, zfs)
+ Just zfs -> (m', zfs)
appendFS :: FastString -> FastString -> FastString
appendFS fs1 fs2 = inlinePerformIO
@@ -478,8 +546,9 @@ nilFS = mkFastString ""
getFastStringTable :: IO [[FastString]]
getFastStringTable = do
- tbl <- readIORef string_table
- buckets <- mapM (lookupTbl tbl) [0 .. hASH_TBL_SIZE]
+ buckets <- forM [0.. hASH_TBL_SIZE-1] $ \idx -> do
+ bucket <- lookupTbl string_table idx
+ readIORef bucket
return buckets
-- -----------------------------------------------------------------------------
diff --git a/compiler/utils/FastTypes.lhs b/compiler/utils/FastTypes.lhs
index ace46e6e1b..0ef10ade56 100644
--- a/compiler/utils/FastTypes.lhs
+++ b/compiler/utils/FastTypes.lhs
@@ -14,10 +14,10 @@
module FastTypes (
-- * FastInt
FastInt,
-
+
-- ** Getting in and out of FastInt
_ILIT, iBox, iUnbox,
-
+
-- ** Arithmetic on FastInt
(+#), (-#), (*#), quotFastInt, negateFastInt,
--quotRemFastInt is difficult because unboxed values can't
@@ -51,11 +51,11 @@ module FastTypes (
--character values above the range of Unicode
-- * FastPtr
- FastPtr,
-
+ FastPtr,
+
-- ** Getting in and out of FastPtr
pBox, pUnbox,
-
+
-- ** Casting FastPtrs
castFastPtr
) where
@@ -65,7 +65,7 @@ module FastTypes (
#if defined(__GLASGOW_HASKELL__)
-- Import the beggars
-import GHC.Exts
+import ExtsCompat46
type FastInt = Int#
diff --git a/compiler/utils/Fingerprint.hsc b/compiler/utils/Fingerprint.hsc
index 95f31c08bb..9a55e385b3 100644
--- a/compiler/utils/Fingerprint.hsc
+++ b/compiler/utils/Fingerprint.hsc
@@ -1,25 +1,33 @@
-- ----------------------------------------------------------------------------
---
+--
-- (c) The University of Glasgow 2006
--
-- Fingerprints for recompilation checking and ABI versioning.
--
--- http://hackage.haskell.org/trac/ghc/wiki/Commentary/Compiler/RecompilationAvoidance
+-- http://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/RecompilationAvoidance
--
-- ----------------------------------------------------------------------------
-{-# OPTIONS_GHC -fno-warn-orphans #-}
module Fingerprint (
Fingerprint(..), fingerprint0,
readHexFingerprint,
fingerprintData,
- fingerprintString
+ fingerprintString,
+ -- Re-exported from GHC.Fingerprint for GHC >= 7.7, local otherwise
+ getFileHash
) where
#include "md5.h"
##include "HsVersions.h"
import Numeric ( readHex )
+#if __GLASGOW_HASKELL__ < 707
+-- Only needed for getFileHash below.
+import Foreign
+import Panic
+import System.IO
+import Control.Monad ( when )
+#endif
import GHC.Fingerprint
@@ -30,3 +38,32 @@ readHexFingerprint s = Fingerprint w1 w2
[(w1,"")] = readHex s1
[(w2,"")] = readHex (take 16 s2)
+
+#if __GLASGOW_HASKELL__ < 707
+-- Only use this if we're smaller than GHC 7.7, otherwise
+-- GHC.Fingerprint exports a better version of this function.
+
+-- | Computes the hash of a given file.
+-- It loads the full file into memory an does not work with files bigger than
+-- MAXINT.
+getFileHash :: FilePath -> IO Fingerprint
+getFileHash path = withBinaryFile path ReadMode $ \h -> do
+
+ fileSize <- toIntFileSize `fmap` hFileSize h
+
+ allocaBytes fileSize $ \bufPtr -> do
+ n <- hGetBuf h bufPtr fileSize
+ when (n /= fileSize) readFailedError
+ fingerprintData bufPtr fileSize
+
+ where
+ toIntFileSize :: Integer -> Int
+ toIntFileSize size
+ | size > fromIntegral (maxBound :: Int) = throwGhcException $
+ Sorry $ "Fingerprint.getFileHash: Tried to calculate hash of file "
+ ++ path ++ " with size > maxBound :: Int. This is not supported."
+ | otherwise = fromIntegral size
+
+ readFailedError = throwGhcException $
+ Panic $ "Fingerprint.getFileHash: hGetBuf failed on interface file"
+#endif
diff --git a/compiler/utils/FiniteMap.lhs b/compiler/utils/FiniteMap.lhs
index 94d1eef94e..b52f28c324 100644
--- a/compiler/utils/FiniteMap.lhs
+++ b/compiler/utils/FiniteMap.lhs
@@ -27,10 +27,6 @@ deleteList ks m = foldl (flip Map.delete) m ks
foldRight :: (elt -> a -> a) -> a -> Map key elt -> a
foldRight = Map.fold
foldRightWithKey :: (key -> elt -> a -> a) -> a -> Map key elt -> a
-#if (MIN_VERSION_containers(0,4,0))
foldRightWithKey = Map.foldrWithKey
-#else
-foldRightWithKey = Map.foldWithKey
-#endif
\end{code}
diff --git a/compiler/utils/GraphBase.hs b/compiler/utils/GraphBase.hs
index c070df4762..8cb3acee71 100644
--- a/compiler/utils/GraphBase.hs
+++ b/compiler/utils/GraphBase.hs
@@ -5,7 +5,7 @@
-- The above warning supression flag is a temporary kludge.
-- While working on this module you are encouraged to remove it and
-- detab the module (please do the detabbing in a separate patch). See
--- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces
+-- http://ghc.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces
-- for details
module GraphBase (
diff --git a/compiler/utils/GraphPpr.hs b/compiler/utils/GraphPpr.hs
index 5ea5fdfb75..a896bbbf63 100644
--- a/compiler/utils/GraphPpr.hs
+++ b/compiler/utils/GraphPpr.hs
@@ -5,7 +5,7 @@
-- The above warning supression flag is a temporary kludge.
-- While working on this module you are encouraged to remove it and
-- detab the module (please do the detabbing in a separate patch). See
--- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces
+-- http://ghc.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces
-- for details
module GraphPpr (
diff --git a/compiler/utils/IOEnv.hs b/compiler/utils/IOEnv.hs
index 583e875903..6885bbd127 100644
--- a/compiler/utils/IOEnv.hs
+++ b/compiler/utils/IOEnv.hs
@@ -22,7 +22,7 @@ module IOEnv (
-- Getting at the environment
getEnv, setEnv, updEnv,
- runIOEnv, unsafeInterleaveM,
+ runIOEnv, unsafeInterleaveM, uninterruptibleMaskM_,
tryM, tryAllM, tryMostM, fixM,
-- I/O operations
@@ -42,6 +42,7 @@ import System.IO.Unsafe ( unsafeInterleaveIO )
import System.IO ( fixIO )
import Control.Monad
import MonadUtils
+import Control.Applicative (Alternative(..))
----------------------------------------------------------------------
-- Defining the monad type
@@ -148,11 +149,17 @@ tryMostM (IOEnv thing) = IOEnv (\ env -> tryMost (thing env))
unsafeInterleaveM :: IOEnv env a -> IOEnv env a
unsafeInterleaveM (IOEnv m) = IOEnv (\ env -> unsafeInterleaveIO (m env))
+uninterruptibleMaskM_ :: IOEnv env a -> IOEnv env a
+uninterruptibleMaskM_ (IOEnv m) = IOEnv (\ env -> uninterruptibleMask_ (m env))
----------------------------------------------------------------------
--- MonadPlus
+-- Alternative/MonadPlus
----------------------------------------------------------------------
+instance MonadPlus IO => Alternative (IOEnv env) where
+ empty = mzero
+ (<|>) = mplus
+
-- For use if the user has imported Control.Monad.Error from MTL
-- Requires UndecidableInstances
instance MonadPlus IO => MonadPlus (IOEnv env) where
diff --git a/compiler/utils/Maybes.lhs b/compiler/utils/Maybes.lhs
index 210a7b9f02..d9e1762a2f 100644
--- a/compiler/utils/Maybes.lhs
+++ b/compiler/utils/Maybes.lhs
@@ -4,13 +4,6 @@
%
\begin{code}
-{-# OPTIONS -fno-warn-tabs #-}
--- The above warning supression flag is a temporary kludge.
--- While working on this module you are encouraged to remove it and
--- detab the module (please do the detabbing in a separate patch). See
--- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces
--- for details
-
module Maybes (
module Data.Maybe,
@@ -18,15 +11,14 @@ module Maybes (
failME, isSuccess,
orElse,
- mapCatMaybes,
- allMaybes,
firstJust, firstJusts,
+ whenIsJust,
expectJust,
- maybeToBool,
MaybeT(..)
) where
-
+import Control.Applicative
+import Control.Monad
import Data.Maybe
infixr 4 `orElse`
@@ -39,55 +31,32 @@ infixr 4 `orElse`
%************************************************************************
\begin{code}
-maybeToBool :: Maybe a -> Bool
-maybeToBool Nothing = False
-maybeToBool (Just _) = True
-
--- | Collects a list of @Justs@ into a single @Just@, returning @Nothing@ if
--- there are any @Nothings@.
-allMaybes :: [Maybe a] -> Maybe [a]
-allMaybes [] = Just []
-allMaybes (Nothing : _) = Nothing
-allMaybes (Just x : ms) = case allMaybes ms of
- Nothing -> Nothing
- Just xs -> Just (x:xs)
-
firstJust :: Maybe a -> Maybe a -> Maybe a
-firstJust (Just a) _ = Just a
-firstJust Nothing b = b
+firstJust a b = firstJusts [a, b]
-- | Takes a list of @Maybes@ and returns the first @Just@ if there is one, or
-- @Nothing@ otherwise.
firstJusts :: [Maybe a] -> Maybe a
-firstJusts = foldr firstJust Nothing
-\end{code}
+firstJusts = msum
-\begin{code}
expectJust :: String -> Maybe a -> a
{-# INLINE expectJust #-}
expectJust _ (Just x) = x
expectJust err Nothing = error ("expectJust " ++ err)
-\end{code}
-\begin{code}
-mapCatMaybes :: (a -> Maybe b) -> [a] -> [b]
-mapCatMaybes _ [] = []
-mapCatMaybes f (x:xs) = case f x of
- Just y -> y : mapCatMaybes f xs
- Nothing -> mapCatMaybes f xs
-\end{code}
+whenIsJust :: Monad m => Maybe a -> (a -> m ()) -> m ()
+whenIsJust (Just x) f = f x
+whenIsJust Nothing _ = return ()
-\begin{code}
--- | flipped version of @fromMaybe@.
+-- | Flipped version of @fromMaybe@, useful for chaining.
orElse :: Maybe a -> a -> a
-(Just x) `orElse` _ = x
-Nothing `orElse` y = y
+orElse = flip fromMaybe
\end{code}
%************************************************************************
-%* *
+%* *
\subsection[MaybeT type]{The @MaybeT@ monad transformer}
-%* *
+%* *
%************************************************************************
\begin{code}
@@ -97,6 +66,10 @@ newtype MaybeT m a = MaybeT {runMaybeT :: m (Maybe a)}
instance Functor m => Functor (MaybeT m) where
fmap f x = MaybeT $ fmap (fmap f) $ runMaybeT x
+instance (Monad m, Functor m) => Applicative (MaybeT m) where
+ pure = return
+ (<*>) = ap
+
instance Monad m => Monad (MaybeT m) where
return = MaybeT . return . Just
x >>= f = MaybeT $ runMaybeT x >>= maybe (return Nothing) (runMaybeT . f)
@@ -114,6 +87,13 @@ instance Monad m => Monad (MaybeT m) where
\begin{code}
data MaybeErr err val = Succeeded val | Failed err
+instance Functor (MaybeErr err) where
+ fmap = liftM
+
+instance Applicative (MaybeErr err) where
+ pure = return
+ (<*>) = ap
+
instance Monad (MaybeErr err) where
return v = Succeeded v
Succeeded v >>= k = k v
diff --git a/compiler/utils/OrdList.lhs b/compiler/utils/OrdList.lhs
index 7e3b24a5da..d1d8708dd3 100644
--- a/compiler/utils/OrdList.lhs
+++ b/compiler/utils/OrdList.lhs
@@ -9,15 +9,8 @@ Provide trees (of instructions), so that lists of instructions
can be appended in linear time.
\begin{code}
-{-# OPTIONS -fno-warn-tabs #-}
--- The above warning supression flag is a temporary kludge.
--- While working on this module you are encouraged to remove it and
--- detab the module (please do the detabbing in a separate patch). See
--- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces
--- for details
-
module OrdList (
- OrdList,
+ OrdList,
nilOL, isNilOL, unitOL, appOL, consOL, snocOL, concatOL,
mapOL, fromOL, toOL, foldrOL, foldlOL
) where
diff --git a/compiler/utils/Outputable.lhs b/compiler/utils/Outputable.lhs
index bd2a955469..e8d9347767 100644
--- a/compiler/utils/Outputable.lhs
+++ b/compiler/utils/Outputable.lhs
@@ -32,7 +32,7 @@ module Outputable (
sep, cat,
fsep, fcat,
hang, punctuate, ppWhen, ppUnless,
- speakNth, speakNTimes, speakN, speakNOf, plural,
+ speakNth, speakNTimes, speakN, speakNOf, plural, isOrAre,
coloured, PprColour, colType, colCoerc, colDataCon,
colBinder, bold, keyword,
@@ -42,8 +42,7 @@ module Outputable (
pprCode, mkCodeStyle,
showSDoc, showSDocOneLine,
showSDocForUser, showSDocDebug, showSDocDump, showSDocDumpOneLine,
- showPpr,
- showSDocUnqual,
+ showSDocUnqual, showPpr,
renderWithStyle,
pprInfixVar, pprPrefixVar,
@@ -53,7 +52,9 @@ module Outputable (
-- * Controlling the style in which output is printed
BindingSite(..),
- PprStyle, CodeStyle(..), PrintUnqualified, alwaysQualify, neverQualify,
+ PprStyle, CodeStyle(..), PrintUnqualified,
+ alwaysQualify, alwaysQualifyNames, alwaysQualifyModules,
+ neverQualify, neverQualifyNames, neverQualifyModules,
QualifyName(..),
sdocWithDynFlags, sdocWithPlatform,
getPprStyle, withPprStyle, withPprStyleDoc,
@@ -75,7 +76,7 @@ import {-# SOURCE #-} DynFlags( DynFlags,
useUnicodeQuotes,
unsafeGlobalDynFlags )
import {-# SOURCE #-} Module( Module, ModuleName, moduleName )
-import {-# SOURCE #-} Name( Name, nameModule )
+import {-# SOURCE #-} OccName( OccName )
import {-# SOURCE #-} StaticFlags( opt_PprStyle_Debug, opt_NoDebugOutput )
import FastString
@@ -90,6 +91,7 @@ import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import Data.Char
import qualified Data.Map as M
+import Data.Int
import qualified Data.IntMap as IM
import Data.Set (Set)
import qualified Data.Set as Set
@@ -144,13 +146,20 @@ data Depth = AllTheWay
-- purpose of the pair of functions that gets passed around
-- when rendering 'SDoc'.
+type PrintUnqualified = (QueryQualifyName, QueryQualifyModule)
+
-- | given an /original/ name, this function tells you which module
-- name it should be qualified with when printing for the user, if
-- any. For example, given @Control.Exception.catch@, which is in scope
-- as @Exception.catch@, this fuction will return @Just "Exception"@.
-- Note that the return value is a ModuleName, not a Module, because
-- in source code, names are qualified by ModuleNames.
-type QueryQualifyName = Name -> QualifyName
+type QueryQualifyName = Module -> OccName -> QualifyName
+
+-- | For a given module, we need to know whether to print it with
+-- a package name to disambiguate it.
+type QueryQualifyModule = Module -> Bool
+
-- See Note [Printing original names] in HscTypes
data QualifyName -- given P:M.T
@@ -163,18 +172,11 @@ data QualifyName -- given P:M.T
-- it is not in scope at all, and M.T is already bound in the
-- current scope, so we must refer to it as "P:M.T"
-
--- | For a given module, we need to know whether to print it with
--- a package name to disambiguate it.
-type QueryQualifyModule = Module -> Bool
-
-type PrintUnqualified = (QueryQualifyName, QueryQualifyModule)
-
alwaysQualifyNames :: QueryQualifyName
-alwaysQualifyNames n = NameQual (moduleName (nameModule n))
+alwaysQualifyNames m _ = NameQual (moduleName m)
neverQualifyNames :: QueryQualifyName
-neverQualifyNames _ = NameUnqual
+neverQualifyNames _ _ = NameUnqual
alwaysQualifyModules :: QueryQualifyModule
alwaysQualifyModules _ = True
@@ -295,8 +297,8 @@ sdocWithPlatform f = sdocWithDynFlags (f . targetPlatform)
\begin{code}
qualName :: PprStyle -> QueryQualifyName
-qualName (PprUser (qual_name,_) _) n = qual_name n
-qualName _other n = NameQual (moduleName (nameModule n))
+qualName (PprUser (qual_name,_) _) mod occ = qual_name mod occ
+qualName _other mod _ = NameQual (moduleName mod)
qualModule :: PprStyle -> QueryQualifyModule
qualModule (PprUser (_,qual_mod) _) m = qual_mod m
@@ -363,44 +365,47 @@ mkCodeStyle = PprCode
-- However, Doc *is* an instance of Show
-- showSDoc just blasts it out as a string
showSDoc :: DynFlags -> SDoc -> String
-showSDoc dflags d =
- Pretty.showDocWith PageMode
- (runSDoc d (initSDocContext dflags defaultUserStyle))
+showSDoc dflags sdoc = renderWithStyle dflags sdoc defaultUserStyle
renderWithStyle :: DynFlags -> SDoc -> PprStyle -> String
-renderWithStyle dflags sdoc sty =
- Pretty.render (runSDoc sdoc (initSDocContext dflags sty))
+renderWithStyle dflags sdoc sty
+ = Pretty.showDoc PageMode (pprCols dflags) $
+ runSDoc sdoc (initSDocContext dflags sty)
-- This shows an SDoc, but on one line only. It's cheaper than a full
-- showSDoc, designed for when we're getting results like "Foo.bar"
-- and "foo{uniq strictness}" so we don't want fancy layout anyway.
showSDocOneLine :: DynFlags -> SDoc -> String
showSDocOneLine dflags d
- = Pretty.showDocWith PageMode
- (runSDoc d (initSDocContext dflags defaultUserStyle))
+ = Pretty.showDoc OneLineMode (pprCols dflags) $
+ runSDoc d (initSDocContext dflags defaultUserStyle)
showSDocForUser :: DynFlags -> PrintUnqualified -> SDoc -> String
showSDocForUser dflags unqual doc
- = show (runSDoc doc (initSDocContext dflags (mkUserStyle unqual AllTheWay)))
+ = renderWithStyle dflags doc (mkUserStyle unqual AllTheWay)
showSDocUnqual :: DynFlags -> SDoc -> String
--- Only used in the gruesome isOperator
-showSDocUnqual dflags d
- = show (runSDoc d (initSDocContext dflags (mkUserStyle neverQualify AllTheWay)))
+-- Only used by Haddock
+showSDocUnqual dflags doc
+ = renderWithStyle dflags doc (mkUserStyle neverQualify AllTheWay)
showSDocDump :: DynFlags -> SDoc -> String
-showSDocDump dflags d
- = Pretty.showDocWith PageMode (runSDoc d (initSDocContext dflags defaultDumpStyle))
+showSDocDump dflags d = renderWithStyle dflags d defaultDumpStyle
+
+showSDocDebug :: DynFlags -> SDoc -> String
+showSDocDebug dflags d = renderWithStyle dflags d PprDebug
showSDocDumpOneLine :: DynFlags -> SDoc -> String
showSDocDumpOneLine dflags d
- = Pretty.showDocWith OneLineMode (runSDoc d (initSDocContext dflags PprDump))
-
-showSDocDebug :: DynFlags -> SDoc -> String
-showSDocDebug dflags d = show (runSDoc d (initSDocContext dflags PprDebug))
+ = Pretty.showDoc OneLineMode irrelevantNCols $
+ runSDoc d (initSDocContext dflags PprDump)
showPpr :: Outputable a => DynFlags -> a -> String
-showPpr dflags = showSDoc dflags . ppr
+showPpr dflags thing = showSDoc dflags (ppr thing)
+
+irrelevantNCols :: Int
+-- Used for OneLineMode and LeftMode when number of cols isn't used
+irrelevantNCols = 1
\end{code}
\begin{code}
@@ -421,7 +426,10 @@ rational :: Rational -> SDoc
empty = docToSDoc $ Pretty.empty
char c = docToSDoc $ Pretty.char c
+
text s = docToSDoc $ Pretty.text s
+{-# INLINE text #-} -- Inline so that the RULE Pretty.text will fire
+
ftext s = docToSDoc $ Pretty.ftext s
ptext s = docToSDoc $ Pretty.ptext s
ztext s = docToSDoc $ Pretty.ztext s
@@ -452,7 +460,7 @@ cparen b d = SDoc $ Pretty.cparen b . runSDoc d
quotes d =
sdocWithDynFlags $ \dflags ->
if useUnicodeQuotes dflags
- then char '‛' <> d <> char '’'
+ then char '‘' <> d <> char '’'
else SDoc $ \sty ->
let pp_d = runSDoc d sty
str = show pp_d
@@ -616,6 +624,12 @@ instance Outputable Bool where
ppr True = ptext (sLit "True")
ppr False = ptext (sLit "False")
+instance Outputable Int32 where
+ ppr n = integer $ fromIntegral n
+
+instance Outputable Int64 where
+ ppr n = integer $ fromIntegral n
+
instance Outputable Int where
ppr n = int n
@@ -898,6 +912,15 @@ speakNTimes t | t == 1 = ptext (sLit "once")
plural :: [a] -> SDoc
plural [_] = empty -- a bit frightening, but there you are
plural _ = char 's'
+
+-- | Determines the form of to be appropriate for the length of a list:
+--
+-- > isOrAre [] = ptext (sLit "are")
+-- > isOrAre ["Hello"] = ptext (sLit "is")
+-- > isOrAre ["Hello", "World"] = ptext (sLit "are")
+isOrAre :: [a] -> SDoc
+isOrAre [_] = ptext (sLit "is")
+isOrAre _ = ptext (sLit "are")
\end{code}
diff --git a/compiler/utils/Platform.hs b/compiler/utils/Platform.hs
index 213a63e0c8..ea1a3e5e93 100644
--- a/compiler/utils/Platform.hs
+++ b/compiler/utils/Platform.hs
@@ -12,7 +12,9 @@ module Platform (
target32Bit,
isARM,
osElfTarget,
+ osMachOTarget,
platformUsesFrameworks,
+ platformBinariesAreStaticLibs,
)
where
@@ -53,6 +55,7 @@ data Arch
| ArchAlpha
| ArchMipseb
| ArchMipsel
+ | ArchJavaScript
deriving (Read, Show, Eq)
isARM :: Arch -> Bool
@@ -127,6 +130,11 @@ osElfTarget OSUnknown = False
-- portability, otherwise we have to answer this question for every
-- new platform we compile on (even unreg).
+-- | This predicate tells us whether the OS support Mach-O shared libraries.
+osMachOTarget :: OS -> Bool
+osMachOTarget OSDarwin = True
+osMachOTarget _ = False
+
osUsesFrameworks :: OS -> Bool
osUsesFrameworks OSDarwin = True
osUsesFrameworks OSiOS = True
@@ -135,3 +143,10 @@ osUsesFrameworks _ = False
platformUsesFrameworks :: Platform -> Bool
platformUsesFrameworks = osUsesFrameworks . platformOS
+osBinariesAreStaticLibs :: OS -> Bool
+osBinariesAreStaticLibs OSiOS = True
+osBinariesAreStaticLibs _ = False
+
+platformBinariesAreStaticLibs :: Platform -> Bool
+platformBinariesAreStaticLibs = osBinariesAreStaticLibs . platformOS
+
diff --git a/compiler/utils/Pretty.lhs b/compiler/utils/Pretty.lhs
index e4f748a05d..fb7fe2b7fb 100644
--- a/compiler/utils/Pretty.lhs
+++ b/compiler/utils/Pretty.lhs
@@ -71,7 +71,7 @@ Version 2.0 24 April 1997
nest k empty = empty
which wasn't true before.
- * Fixed an obscure bug in sep that occassionally gave very wierd behaviour
+ * Fixed an obscure bug in sep that occasionally gave very weird behaviour
* Added $+$
@@ -173,8 +173,7 @@ module Pretty (
hang, punctuate,
--- renderStyle, -- Haskell 1.3 only
- render, fullRender, printDoc, showDocWith,
+ fullRender, printDoc, printDoc_, showDoc,
bufLeftRender -- performance hack
) where
@@ -270,9 +269,8 @@ Displaying @Doc@ values.
\begin{code}
instance Show Doc where
- showsPrec _ doc cont = showDoc doc cont
+ showsPrec _ doc cont = showDocPlus PageMode 100 doc cont
-render :: Doc -> String -- Uses default style
fullRender :: Mode
-> Int -- Line length
-> Float -- Ribbons per line
@@ -281,21 +279,10 @@ fullRender :: Mode
-> Doc
-> a -- Result
-{- When we start using 1.3
-renderStyle :: Style -> Doc -> String
-data Style = Style { lineLength :: Int, -- In chars
- ribbonsPerLine :: Float, -- Ratio of ribbon length to line length
- mode :: Mode
- }
-style :: Style -- The default style
-style = Style { lineLength = 100, ribbonsPerLine = 2.5, mode = PageMode }
--}
-
data Mode = PageMode -- Normal
| ZigZagMode -- With zig-zag cuts
| LeftMode -- No indentation, infinitely long lines
| OneLineMode -- All on one line
-
\end{code}
@@ -557,7 +544,9 @@ isEmpty _ = False
char c = textBeside_ (Chr c) (_ILIT(1)) Empty
text s = case iUnbox (length s) of {sl -> textBeside_ (Str s) sl Empty}
-{-# NOINLINE [1] text #-} -- Give the RULE a chance to fire
+{-# NOINLINE [0] text #-} -- Give the RULE a chance to fire
+ -- It must wait till after phase 1 when
+ -- the unpackCString first is manifested
ftext :: FastString -> Doc
ftext s = case iUnbox (lengthFS s) of {sl -> textBeside_ (PStr s) sl Empty}
@@ -888,21 +877,11 @@ oneLiner _ = panic "oneLiner: Unhandled case"
\begin{code}
-{-
-renderStyle Style{mode, lineLength, ribbonsPerLine} doc
- = fullRender mode lineLength ribbonsPerLine doc ""
--}
-
-render doc = showDocWith PageMode doc
-
-showDoc :: Doc -> String -> String
-showDoc doc rest = showDocWithAppend PageMode doc rest
-
-showDocWithAppend :: Mode -> Doc -> String -> String
-showDocWithAppend mode doc rest = fullRender mode 100 1.5 string_txt rest doc
+showDocPlus :: Mode -> Int -> Doc -> String -> String
+showDocPlus mode cols doc rest = fullRender mode cols 1.5 string_txt rest doc
-showDocWith :: Mode -> Doc -> String
-showDocWith mode doc = showDocWithAppend mode doc ""
+showDoc :: Mode -> Int -> Doc -> String
+showDoc mode cols doc = showDocPlus mode cols doc ""
string_txt :: TextDetails -> String -> String
string_txt (Chr c) s = c:s
@@ -1006,9 +985,16 @@ spaces n | n <=# _ILIT(0) = ""
\begin{code}
printDoc :: Mode -> Int -> Handle -> Doc -> IO ()
-printDoc LeftMode _ hdl doc
+-- printDoc adds a newline to the end
+printDoc mode cols hdl doc = printDoc_ mode cols hdl (doc $$ text "")
+
+printDoc_ :: Mode -> Int -> Handle -> Doc -> IO ()
+-- printDoc_ does not add a newline at the end, so that
+-- successive calls can output stuff on the same line
+-- Rather like putStr vs putStrLn
+printDoc_ LeftMode _ hdl doc
= do { printLeftRender hdl doc; hFlush hdl }
-printDoc mode pprCols hdl doc
+printDoc_ mode pprCols hdl doc
= do { fullRender mode pprCols 1.5 put done doc ;
hFlush hdl }
where
@@ -1020,7 +1006,7 @@ printDoc mode pprCols hdl doc
put (ZStr s) next = hPutFZS hdl s >> next
put (LStr s l) next = hPutLitString hdl s l >> next
- done = hPutChar hdl '\n'
+ done = return () -- hPutChar hdl '\n'
-- some versions of hPutBuf will barf if the length is zero
hPutLitString :: Handle -> Ptr a -> Int# -> IO ()
diff --git a/compiler/utils/Stream.hs b/compiler/utils/Stream.hs
index 2fa76d2345..47cdee0789 100644
--- a/compiler/utils/Stream.hs
+++ b/compiler/utils/Stream.hs
@@ -11,6 +11,8 @@ module Stream (
collect, fromList,
Stream.map, Stream.mapM, Stream.mapAccumL
) where
+import Control.Monad
+import Control.Applicative
-- |
-- @Stream m a b@ is a computation in some Monad @m@ that delivers a sequence
@@ -37,6 +39,13 @@ module Stream (
--
newtype Stream m a b = Stream { runStream :: m (Either b (a, Stream m a b)) }
+instance Monad f => Functor (Stream f a) where
+ fmap = liftM
+
+instance Monad m => Applicative (Stream m a) where
+ pure = return
+ (<*>) = ap
+
instance Monad m => Monad (Stream m a) where
return a = Stream (return (Left a))
@@ -66,7 +75,7 @@ collect str = go str []
fromList :: Monad m => [a] -> Stream m a ()
fromList = mapM_ yield
--- | Apply a function to each element of a 'Stream', lazilly
+-- | Apply a function to each element of a 'Stream', lazily
map :: Monad m => (a -> b) -> Stream m a x -> Stream m b x
map f str = Stream $ do
r <- runStream str
@@ -74,7 +83,7 @@ map f str = Stream $ do
Left x -> return (Left x)
Right (a, str') -> return (Right (f a, Stream.map f str'))
--- | Apply a monadic operation to each element of a 'Stream', lazilly
+-- | Apply a monadic operation to each element of a 'Stream', lazily
mapM :: Monad m => (a -> m b) -> Stream m a x -> Stream m b x
mapM f str = Stream $ do
r <- runStream str
diff --git a/compiler/utils/UnVarGraph.hs b/compiler/utils/UnVarGraph.hs
new file mode 100644
index 0000000000..228f3b5220
--- /dev/null
+++ b/compiler/utils/UnVarGraph.hs
@@ -0,0 +1,136 @@
+{-
+
+Copyright (c) 2014 Joachim Breitner
+
+A data structure for undirected graphs of variables
+(or in plain terms: Sets of unordered pairs of numbers)
+
+
+This is very specifically tailored for the use in CallArity. In particular it
+stores the graph as a union of complete and complete bipartite graph, which
+would be very expensive to store as sets of edges or as adjanceny lists.
+
+It does not normalize the graphs. This means that g `unionUnVarGraph` g is
+equal to g, but twice as expensive and large.
+
+-}
+module UnVarGraph
+ ( UnVarSet
+ , emptyUnVarSet, mkUnVarSet, varEnvDom, unionUnVarSet, unionUnVarSets
+ , delUnVarSet
+ , elemUnVarSet, isEmptyUnVarSet
+ , UnVarGraph
+ , emptyUnVarGraph
+ , unionUnVarGraph, unionUnVarGraphs
+ , completeGraph, completeBipartiteGraph
+ , neighbors
+ , delNode
+ ) where
+
+import Id
+import VarEnv
+import UniqFM
+import Outputable
+import Data.List
+import Bag
+import Unique
+
+import qualified Data.IntSet as S
+
+-- We need a type for sets of variables (UnVarSet).
+-- We do not use VarSet, because for that we need to have the actual variable
+-- at hand, and we do not have that when we turn the domain of a VarEnv into a UnVarSet.
+-- Therefore, use a IntSet directly (which is likely also a bit more efficient).
+
+-- Set of uniques, i.e. for adjancet nodes
+newtype UnVarSet = UnVarSet (S.IntSet)
+ deriving Eq
+
+k :: Var -> Int
+k v = getKey (getUnique v)
+
+emptyUnVarSet :: UnVarSet
+emptyUnVarSet = UnVarSet S.empty
+
+elemUnVarSet :: Var -> UnVarSet -> Bool
+elemUnVarSet v (UnVarSet s) = k v `S.member` s
+
+
+isEmptyUnVarSet :: UnVarSet -> Bool
+isEmptyUnVarSet (UnVarSet s) = S.null s
+
+delUnVarSet :: UnVarSet -> Var -> UnVarSet
+delUnVarSet (UnVarSet s) v = UnVarSet $ k v `S.delete` s
+
+mkUnVarSet :: [Var] -> UnVarSet
+mkUnVarSet vs = UnVarSet $ S.fromList $ map k vs
+
+varEnvDom :: VarEnv a -> UnVarSet
+varEnvDom ae = UnVarSet $ ufmToSet_Directly ae
+
+unionUnVarSet :: UnVarSet -> UnVarSet -> UnVarSet
+unionUnVarSet (UnVarSet set1) (UnVarSet set2) = UnVarSet (set1 `S.union` set2)
+
+unionUnVarSets :: [UnVarSet] -> UnVarSet
+unionUnVarSets = foldr unionUnVarSet emptyUnVarSet
+
+instance Outputable UnVarSet where
+ ppr (UnVarSet s) = braces $
+ hcat $ punctuate comma [ ppr (getUnique i) | i <- S.toList s]
+
+
+-- The graph type. A list of complete bipartite graphs
+data Gen = CBPG UnVarSet UnVarSet -- complete bipartite
+ | CG UnVarSet -- complete
+newtype UnVarGraph = UnVarGraph (Bag Gen)
+
+emptyUnVarGraph :: UnVarGraph
+emptyUnVarGraph = UnVarGraph emptyBag
+
+unionUnVarGraph :: UnVarGraph -> UnVarGraph -> UnVarGraph
+{-
+Premature optimisation, it seems.
+unionUnVarGraph (UnVarGraph [CBPG s1 s2]) (UnVarGraph [CG s3, CG s4])
+ | s1 == s3 && s2 == s4
+ = pprTrace "unionUnVarGraph fired" empty $
+ completeGraph (s1 `unionUnVarSet` s2)
+unionUnVarGraph (UnVarGraph [CBPG s1 s2]) (UnVarGraph [CG s3, CG s4])
+ | s2 == s3 && s1 == s4
+ = pprTrace "unionUnVarGraph fired2" empty $
+ completeGraph (s1 `unionUnVarSet` s2)
+-}
+unionUnVarGraph (UnVarGraph g1) (UnVarGraph g2)
+ = -- pprTrace "unionUnVarGraph" (ppr (length g1, length g2)) $
+ UnVarGraph (g1 `unionBags` g2)
+
+unionUnVarGraphs :: [UnVarGraph] -> UnVarGraph
+unionUnVarGraphs = foldl' unionUnVarGraph emptyUnVarGraph
+
+-- completeBipartiteGraph A B = { {a,b} | a ∈ A, b ∈ B }
+completeBipartiteGraph :: UnVarSet -> UnVarSet -> UnVarGraph
+completeBipartiteGraph s1 s2 = prune $ UnVarGraph $ unitBag $ CBPG s1 s2
+
+completeGraph :: UnVarSet -> UnVarGraph
+completeGraph s = prune $ UnVarGraph $ unitBag $ CG s
+
+neighbors :: UnVarGraph -> Var -> UnVarSet
+neighbors (UnVarGraph g) v = unionUnVarSets $ concatMap go $ bagToList g
+ where go (CG s) = (if v `elemUnVarSet` s then [s] else [])
+ go (CBPG s1 s2) = (if v `elemUnVarSet` s1 then [s2] else []) ++
+ (if v `elemUnVarSet` s2 then [s1] else [])
+
+delNode :: UnVarGraph -> Var -> UnVarGraph
+delNode (UnVarGraph g) v = prune $ UnVarGraph $ mapBag go g
+ where go (CG s) = CG (s `delUnVarSet` v)
+ go (CBPG s1 s2) = CBPG (s1 `delUnVarSet` v) (s2 `delUnVarSet` v)
+
+prune :: UnVarGraph -> UnVarGraph
+prune (UnVarGraph g) = UnVarGraph $ filterBag go g
+ where go (CG s) = not (isEmptyUnVarSet s)
+ go (CBPG s1 s2) = not (isEmptyUnVarSet s1) && not (isEmptyUnVarSet s2)
+
+instance Outputable Gen where
+ ppr (CG s) = ppr s <> char '²'
+ ppr (CBPG s1 s2) = ppr s1 <+> char 'x' <+> ppr s2
+instance Outputable UnVarGraph where
+ ppr (UnVarGraph g) = ppr g
diff --git a/compiler/utils/UniqFM.lhs b/compiler/utils/UniqFM.lhs
index ab39bc87f5..0836e12e28 100644
--- a/compiler/utils/UniqFM.lhs
+++ b/compiler/utils/UniqFM.lhs
@@ -20,7 +20,7 @@ and ``addToUFM\_C'' and ``Data.IntMap.insertWith'' differ in the order
of arguments of combining function.
\begin{code}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE DeriveTraversable, GeneralizedNewtypeDeriving #-}
{-# OPTIONS -Wall #-}
module UniqFM (
@@ -45,6 +45,7 @@ module UniqFM (
delListFromUFM,
plusUFM,
plusUFM_C,
+ plusUFM_CD,
minusUFM,
intersectUFM,
intersectUFM_C,
@@ -58,6 +59,7 @@ module UniqFM (
lookupUFM, lookupUFM_Directly,
lookupWithDefaultUFM, lookupWithDefaultUFM_Directly,
eltsUFM, keysUFM, splitUFM,
+ ufmToSet_Directly,
ufmToList,
joinUFM
) where
@@ -69,10 +71,12 @@ import Compiler.Hoopl hiding (Unique)
import Data.Function (on)
import qualified Data.IntMap as M
+import qualified Data.IntSet as S
import qualified Data.Foldable as Foldable
import qualified Data.Traversable as Traversable
import Data.Typeable
import Data.Data
+import Data.Monoid
\end{code}
%************************************************************************
@@ -135,6 +139,20 @@ plusUFM :: UniqFM elt -> UniqFM elt -> UniqFM elt
plusUFM_C :: (elt -> elt -> elt)
-> UniqFM elt -> UniqFM elt -> UniqFM elt
+-- | `plusUFM_CD f m1 d1 m2 d2` merges the maps using `f` as the
+-- combinding function and `d1` resp. `d2` as the default value if
+-- there is no entry in `m1` reps. `m2`. The domain is the union of
+-- the domains of `m1` and `m2`.
+--
+-- Representative example:
+--
+-- @
+-- plusUFM_CD f {A: 1, B: 2} 23 {B: 3, C: 4} 42
+-- == {A: f 1 42, B: f 2 3, C: f 23 4 }
+-- @
+plusUFM_CD :: (elt -> elt -> elt)
+ -> UniqFM elt -> elt -> UniqFM elt -> elt -> UniqFM elt
+
minusUFM :: UniqFM elt1 -> UniqFM elt2 -> UniqFM elt1
intersectUFM :: UniqFM elt -> UniqFM elt -> UniqFM elt
@@ -166,12 +184,25 @@ lookupWithDefaultUFM_Directly
:: UniqFM elt -> elt -> Unique -> elt
keysUFM :: UniqFM elt -> [Unique] -- Get the keys
eltsUFM :: UniqFM elt -> [elt]
+ufmToSet_Directly :: UniqFM elt -> S.IntSet
ufmToList :: UniqFM elt -> [(Unique, elt)]
\end{code}
%************************************************************************
%* *
+\subsection{Monoid interface}
+%* *
+%************************************************************************
+
+\begin{code}
+instance Monoid (UniqFM a) where
+ mempty = emptyUFM
+ mappend = plusUFM
+\end{code}
+
+%************************************************************************
+%* *
\subsection{Implementation using ``Data.IntMap''}
%* *
%************************************************************************
@@ -224,7 +255,24 @@ delFromUFM_Directly (UFM m) u = UFM (M.delete (getKey u) m)
-- M.union is left-biased, plusUFM should be right-biased.
plusUFM (UFM x) (UFM y) = UFM (M.union y x)
+ -- Note (M.union y x), with arguments flipped
+ -- M.union is left-biased, plusUFM should be right-biased.
+
plusUFM_C f (UFM x) (UFM y) = UFM (M.unionWith f x y)
+
+plusUFM_CD f (UFM xm) dx (UFM ym) dy
+{-
+The following implementation should be used as soon as we can expect
+containers-0.5; presumably from GHC 7.9 on:
+ = UFM $ M.mergeWithKey
+ (\_ x y -> Just (x `f` y))
+ (M.map (\x -> x `f` dy))
+ (M.map (\y -> dx `f` y))
+ xm ym
+-}
+ = UFM $ M.intersectionWith f xm ym
+ `M.union` M.map (\x -> x `f` dy) xm
+ `M.union` M.map (\y -> dx `f` y) ym
minusUFM (UFM x) (UFM y) = UFM (M.difference x y)
intersectUFM (UFM x) (UFM y) = UFM (M.intersection x y)
intersectUFM_C f (UFM x) (UFM y) = UFM (M.intersectionWith f x y)
@@ -251,6 +299,7 @@ lookupWithDefaultUFM (UFM m) v k = M.findWithDefault v (getKey $ getUnique k) m
lookupWithDefaultUFM_Directly (UFM m) v u = M.findWithDefault v (getKey u) m
keysUFM (UFM m) = map getUnique $ M.keys m
eltsUFM (UFM m) = M.elems m
+ufmToSet_Directly (UFM m) = M.keysSet m
ufmToList (UFM m) = map (\(k, v) -> (getUnique k, v)) $ M.toList m
-- Hoopl
diff --git a/compiler/utils/UniqSet.lhs b/compiler/utils/UniqSet.lhs
index f8e7d9039f..fae5ddabb6 100644
--- a/compiler/utils/UniqSet.lhs
+++ b/compiler/utils/UniqSet.lhs
@@ -9,13 +9,6 @@ Based on @UniqFMs@ (as you would expect).
Basically, the things need to be in class @Uniquable@.
\begin{code}
-{-# OPTIONS -fno-warn-tabs #-}
--- The above warning supression flag is a temporary kludge.
--- While working on this module you are encouraged to remove it and
--- detab the module (please do the detabbing in a separate patch). See
--- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces
--- for details
-
module UniqSet (
-- * Unique set type
UniqSet, -- type synonym for UniqFM a
@@ -38,6 +31,7 @@ module UniqSet (
isEmptyUniqSet,
lookupUniqSet,
uniqSetToList,
+ partitionUniqSet
) where
import UniqFM
@@ -46,9 +40,9 @@ import Unique
\end{code}
%************************************************************************
-%* *
+%* *
\subsection{The signature of the module}
-%* *
+%* *
%************************************************************************
\begin{code}
@@ -74,12 +68,14 @@ mapUniqSet :: (a -> b) -> UniqSet a -> UniqSet b
elementOfUniqSet :: Uniquable a => a -> UniqSet a -> Bool
elemUniqSet_Directly :: Unique -> UniqSet a -> Bool
filterUniqSet :: (a -> Bool) -> UniqSet a -> UniqSet a
+partitionUniqSet :: (a -> Bool) -> UniqSet a -> (UniqSet a, UniqSet a)
sizeUniqSet :: UniqSet a -> Int
isEmptyUniqSet :: UniqSet a -> Bool
lookupUniqSet :: Uniquable a => UniqSet a -> a -> Maybe a
uniqSetToList :: UniqSet a -> [a]
\end{code}
+
%************************************************************************
%* *
\subsection{Implementation using ``UniqFM''}
@@ -113,6 +109,7 @@ mapUniqSet = mapUFM
elementOfUniqSet = elemUFM
elemUniqSet_Directly = elemUFM_Directly
filterUniqSet = filterUFM
+partitionUniqSet = partitionUFM
sizeUniqSet = sizeUFM
isEmptyUniqSet = isNullUFM
diff --git a/compiler/utils/Util.lhs b/compiler/utils/Util.lhs
index 90a2077c71..5c82c757aa 100644
--- a/compiler/utils/Util.lhs
+++ b/compiler/utils/Util.lhs
@@ -14,11 +14,11 @@ module Util (
-- * General list processing
zipEqual, zipWithEqual, zipWith3Equal, zipWith4Equal,
- zipLazy, stretchZipWith,
+ zipLazy, stretchZipWith, zipWithAndUnzip,
unzipWith,
- mapFst, mapSnd,
+ mapFst, mapSnd, chkAppend,
mapAndUnzip, mapAndUnzip3, mapAccumL2,
nOfThem, filterOut, partitionWith, splitEithers,
@@ -259,6 +259,13 @@ splitEithers (e : es) = case e of
Left x -> (x:xs, ys)
Right y -> (xs, y:ys)
where (xs,ys) = splitEithers es
+
+chkAppend :: [a] -> [a] -> [a]
+-- Checks for the second arguemnt being empty
+-- Used in situations where that situation is common
+chkAppend xs ys
+ | null ys = xs
+ | otherwise = xs ++ ys
\end{code}
A paranoid @zip@ (and some @zipWith@ friends) that checks the lists
@@ -344,6 +351,14 @@ mapAndUnzip3 f (x:xs)
in
(r1:rs1, r2:rs2, r3:rs3)
+zipWithAndUnzip :: (a -> b -> (c,d)) -> [a] -> [b] -> ([c],[d])
+zipWithAndUnzip f (a:as) (b:bs)
+ = let (r1, r2) = f a b
+ (rs1, rs2) = zipWithAndUnzip f as bs
+ in
+ (r1:rs1, r2:rs2)
+zipWithAndUnzip _ _ _ = ([],[])
+
mapAccumL2 :: (s1 -> s2 -> a -> (s1, s2, b)) -> s1 -> s2 -> [a] -> (s1, s2, [b])
mapAccumL2 f s1 s2 xs = (s1', s2', ys)
where ((s1', s2'), ys) = mapAccumL (\(s1, s2) x -> case f s1 s2 x of
@@ -559,7 +574,15 @@ splitAtList (_:xs) (y:ys) = (y:ys', ys'')
-- drop from the end of a list
dropTail :: Int -> [a] -> [a]
-dropTail n = reverse . drop n . reverse
+-- Specification: dropTail n = reverse . drop n . reverse
+-- Better implemention due to Joachim Breitner
+-- http://www.joachim-breitner.de/blog/archives/600-On-taking-the-last-n-elements-of-a-list.html
+dropTail n xs
+ = go (drop n xs) xs
+ where
+ go (_:ys) (x:xs) = x : go ys xs
+ go _ _ = [] -- Stop when ys runs out
+ -- It'll always run out before xs does
snocView :: [a] -> Maybe ([a],a)
-- Split off the last element
@@ -1088,7 +1111,7 @@ charToC w =
hashString :: String -> Int32
hashString = foldl' f golden
where f m c = fromIntegral (ord c) * magic + hashInt32 m
- magic = 0xdeadbeef
+ magic = fromIntegral (0xdeadbeef :: Word32)
golden :: Int32
golden = 1013904242 -- = round ((sqrt 5 - 1) * 2^32) :: Int32