diff options
author | Thomas Miedema <thomasmiedema@gmail.com> | 2015-08-03 20:16:58 +0200 |
---|---|---|
committer | Thomas Miedema <thomasmiedema@gmail.com> | 2015-08-05 10:10:33 +0200 |
commit | 926e4288c5aabb75addcdc4cbdc106e74c11162d (patch) | |
tree | 898f838e1e89996abe999bc90db949b0f06ac18b /compiler/utils | |
parent | 6f6d082124b24bd8437f95d99a8fd8844a0f6cd8 (diff) | |
download | haskell-926e4288c5aabb75addcdc4cbdc106e74c11162d.tar.gz |
Pretty: use BangPatterns instead of manual unboxing Ints (#10735)
Follow same style as libraries/pretty, although some of it is pretty
archaic, and could be improved with BangPatterns:
* `get w _ | w == 0 && False = undefined`
* `mkNest k _ | k `seq` False = undefined`
Diffstat (limited to 'compiler/utils')
-rw-r--r-- | compiler/utils/BufWrite.hs | 8 | ||||
-rw-r--r-- | compiler/utils/Pretty.hs | 168 |
2 files changed, 91 insertions, 85 deletions
diff --git a/compiler/utils/BufWrite.hs b/compiler/utils/BufWrite.hs index 40b9759a7b..48a2c4c940 100644 --- a/compiler/utils/BufWrite.hs +++ b/compiler/utils/BufWrite.hs @@ -24,7 +24,6 @@ module BufWrite ( ) where import FastString -import FastTypes import FastMutInt import Control.Monad ( when ) @@ -97,16 +96,15 @@ bPutCStringLen b@(BufHandle buf r hdl) cstr@(ptr, len) = do copyBytes (buf `plusPtr` i) ptr len writeFastMutInt r (i + len) -bPutLitString :: BufHandle -> LitString -> FastInt -> IO () -bPutLitString b@(BufHandle buf r hdl) a len_ = a `seq` do - let len = iBox len_ +bPutLitString :: BufHandle -> LitString -> Int -> IO () +bPutLitString b@(BufHandle buf r hdl) a len = a `seq` do i <- readFastMutInt r if (i+len) >= buf_size then do hPutBuf hdl buf i writeFastMutInt r 0 if (len >= buf_size) then hPutBuf hdl a len - else bPutLitString b a len_ + else bPutLitString b a len else do copyBytes (buf `plusPtr` i) a len writeFastMutInt r (i+len) diff --git a/compiler/utils/Pretty.hs b/compiler/utils/Pretty.hs index 12a8a531fb..9a85cc002e 100644 --- a/compiler/utils/Pretty.hs +++ b/compiler/utils/Pretty.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE BangPatterns #-} {- ********************************************************************************* * * @@ -200,7 +201,6 @@ module Pretty ( import BufWrite import FastString -import FastTypes import Panic import Numeric (fromRat) import System.IO @@ -208,7 +208,6 @@ import Prelude hiding (error) --for a RULES import GHC.Base ( unpackCString# ) -import GHC.Exts ( Int# ) import GHC.Ptr ( Ptr(..) ) -- Don't import Util( assertPanic ) because it makes a loop in the module structure @@ -306,8 +305,8 @@ infixl 5 $$, $+$ data Doc = Empty -- empty | NilAbove Doc -- text "" $$ x - | TextBeside !TextDetails FastInt Doc -- text s <> x - | Nest FastInt Doc -- nest k x + | TextBeside !TextDetails {-# UNPACK #-} !Int Doc -- text s <> x + | Nest {-# UNPACK #-} !Int Doc -- nest k x | Union Doc Doc -- ul `union` ur | NoDoc -- The empty set of documents | Beside Doc Bool Doc -- True <=> space between @@ -358,8 +357,8 @@ data TextDetails = Chr {-# UNPACK #-} !Char -- ^ A single Char fragment | Str String -- ^ A whole String fragment | PStr FastString -- a hashed string | ZStr FastZString -- a z-encoded string - | LStr {-#UNPACK#-}!LitString FastInt -- a '\0'-terminated - -- array of bytes + | LStr {-# UNPACK #-} !LitString {-#UNPACK #-} !Int + -- a '\0'-terminated array of bytes instance Show Doc where showsPrec _ doc cont = showDocPlus PageMode 100 doc cont @@ -375,7 +374,7 @@ showDocPlus mode cols doc rest = fullRender mode cols 1.5 txtPrinter rest doc -- | A document of height and width 1, containing a literal character. char :: Char -> Doc -char c = textBeside_ (Chr c) (_ILIT(1)) Empty +char c = textBeside_ (Chr c) 1 Empty -- | A document of height 1 containing a literal string. -- 'text' satisfies the following laws: @@ -387,7 +386,7 @@ char c = textBeside_ (Chr c) (_ILIT(1)) Empty -- The side condition on the last law is necessary because @'text' \"\"@ -- has height 1, while 'empty' has no height. text :: String -> Doc -text s = case iUnbox (length s) of {sl -> textBeside_ (Str s) sl Empty} +text s = case length s of {sl -> textBeside_ (Str s) sl Empty} {-# NOINLINE [0] text #-} -- Give the RULE a chance to fire -- It must wait till after phase 1 when -- the unpackCString first is manifested @@ -399,18 +398,18 @@ text s = case iUnbox (length s) of {sl -> textBeside_ (Str s) sl Empty} #-} ftext :: FastString -> Doc -ftext s = case iUnbox (lengthFS s) of {sl -> textBeside_ (PStr s) sl Empty} +ftext s = case lengthFS s of {sl -> textBeside_ (PStr s) sl Empty} ptext :: LitString -> Doc -ptext s = case iUnbox (lengthLS s) of {sl -> textBeside_ (LStr s sl) sl Empty} +ptext s = case lengthLS s of {sl -> textBeside_ (LStr s sl) sl Empty} ztext :: FastZString -> Doc -ztext s = case iUnbox (lengthFZS s) of {sl -> textBeside_ (ZStr s) sl Empty} +ztext s = case lengthFZS s of {sl -> textBeside_ (ZStr s) sl Empty} -- | Some text, but without any width. Use for non-printing text -- such as a HTML or Latex tags zeroWidthText :: String -> Doc -zeroWidthText s = textBeside_ (Str s) (_ILIT(0)) Empty +zeroWidthText s = textBeside_ (Str s) 0 Empty -- | The empty document, with no height and no width. -- 'empty' is the identity for '<>', '<+>', '$$' and '$+$', and anywhere @@ -426,9 +425,9 @@ isEmpty _ = False -- | Produce spacing for indenting the amount specified. -- -- an old version inserted tabs being 8 columns apart in the output. -spaces :: Int# -> String -spaces n | n <=# _ILIT(0) = "" - | otherwise = ' ' : spaces (n -# _ILIT(1)) +spaces :: Int -> String +spaces !n | n <= 0 = "" + | otherwise = ' ' : spaces (n - 1) {- Q: What is the reason for negative indentation (i.e. argument to indent @@ -557,7 +556,7 @@ vcat = foldr ($$) empty -- The side condition on the last law is needed because -- 'empty' is a left identity for '<>'. nest :: Int -> Doc -> Doc -nest k p = mkNest (iUnbox k) (reduceDoc p) +nest k p = mkNest k (reduceDoc p) -- | @hang d1 n d2 = sep [d1, nest n d2]@ hang :: Doc -> Int -> Doc -> Doc @@ -571,11 +570,12 @@ punctuate p (x:xs) = go x xs go y (z:zs) = (y <> p) : go z zs -- mkNest checks for Nest's invariant that it doesn't have an Empty inside it -mkNest :: Int# -> Doc -> Doc -mkNest k (Nest k1 p) = mkNest (k +# k1) p +mkNest :: Int -> Doc -> Doc +mkNest k _ | k `seq` False = undefined +mkNest k (Nest k1 p) = mkNest (k + k1) p mkNest _ NoDoc = NoDoc mkNest _ Empty = Empty -mkNest k p | k ==# _ILIT(0) = p -- Worth a try! +mkNest 0 p = p mkNest k p = nest_ k p -- mkUnion checks for an empty document @@ -587,10 +587,10 @@ nilAbove_ :: RDoc -> RDoc nilAbove_ = NilAbove -- Arg of a TextBeside is always an RDoc -textBeside_ :: TextDetails -> FastInt -> RDoc -> RDoc +textBeside_ :: TextDetails -> Int -> RDoc -> RDoc textBeside_ = TextBeside -nest_ :: FastInt -> RDoc -> RDoc +nest_ :: Int -> RDoc -> RDoc nest_ = Nest union_ :: RDoc -> RDoc -> RDoc @@ -629,23 +629,24 @@ p $+$ q = Above p True q above :: Doc -> Bool -> RDoc -> RDoc above (Above p g1 q1) g2 q2 = above p g1 (above q1 g2 q2) -above p@(Beside{}) g q = aboveNest (reduceDoc p) g (_ILIT(0)) (reduceDoc q) -above p g q = aboveNest p g (_ILIT(0)) (reduceDoc q) +above p@(Beside{}) g q = aboveNest (reduceDoc p) g 0 (reduceDoc q) +above p g q = aboveNest p g 0 (reduceDoc q) -- Specfication: aboveNest p g k q = p $g$ (nest k q) -aboveNest :: RDoc -> Bool -> FastInt -> RDoc -> RDoc +aboveNest :: RDoc -> Bool -> Int -> RDoc -> RDoc +aboveNest _ _ k _ | k `seq` False = undefined aboveNest NoDoc _ _ _ = NoDoc aboveNest (p1 `Union` p2) g k q = aboveNest p1 g k q `union_` aboveNest p2 g k q aboveNest Empty _ k q = mkNest k q -aboveNest (Nest k1 p) g k q = nest_ k1 (aboveNest p g (k -# k1) q) +aboveNest (Nest k1 p) g k q = nest_ k1 (aboveNest p g (k - k1) q) -- p can't be Empty, so no need for mkNest aboveNest (NilAbove p) g k q = nilAbove_ (aboveNest p g k q) aboveNest (TextBeside s sl p) g k q = textBeside_ s sl rest where - !k1 = k -# sl + !k1 = k - sl rest = case p of Empty -> nilAboveNest g k1 q _ -> aboveNest p g k1 q @@ -654,11 +655,12 @@ aboveNest (Beside {}) _ _ _ = error "aboveNest Beside" -- Specification: text s <> nilaboveNest g k q -- = text s <> (text "" $g$ nest k q) -nilAboveNest :: Bool -> FastInt -> RDoc -> RDoc +nilAboveNest :: Bool -> Int -> RDoc -> RDoc +nilAboveNest _ k _ | k `seq` False = undefined nilAboveNest _ _ Empty = Empty -- Here's why the "text s <>" is in the spec! -nilAboveNest g k (Nest k1 q) = nilAboveNest g (k +# k1) q -nilAboveNest g k q | not g && k ># _ILIT(0) -- No newline if no overlap +nilAboveNest g k (Nest k1 q) = nilAboveNest g (k + k1) q +nilAboveNest g k q | not g && k > 0 -- No newline if no overlap = textBeside_ (Str (spaces k)) k q | otherwise -- Put them really above = nilAbove_ (mkNest k q) @@ -690,7 +692,7 @@ beside (Nest k p) g q = nest_ k $! beside p g q beside p@(Beside p1 g1 q1) g2 q2 | g1 == g2 = beside p1 g1 $! beside q1 g2 q2 | otherwise = beside (reduceDoc p) g2 q2 -beside p@(Above{}) g q = let d = reduceDoc p in d `seq` beside d g q +beside p@(Above{}) g q = let !d = reduceDoc p in beside d g q beside (NilAbove p) g q = nilAbove_ $! beside p g q beside (TextBeside s sl p) g q = textBeside_ s sl $! rest where @@ -703,7 +705,7 @@ beside (TextBeside s sl p) g q = textBeside_ s sl $! rest nilBeside :: Bool -> RDoc -> RDoc nilBeside _ Empty = Empty -- Hence the text "" in the spec nilBeside g (Nest _ p) = nilBeside g p -nilBeside g p | g = textBeside_ spaceText (_ILIT(1)) p +nilBeside g p | g = textBeside_ spaceText 1 p | otherwise = p @@ -724,30 +726,31 @@ cat = sepX False -- Don't sepX :: Bool -> [Doc] -> Doc sepX _ [] = empty -sepX x (p:ps) = sep1 x (reduceDoc p) (_ILIT(0)) ps +sepX x (p:ps) = sep1 x (reduceDoc p) 0 ps -- Specification: sep1 g k ys = sep (x : map (nest k) ys) -- = oneLiner (x <g> nest k (hsep ys)) -- `union` x $$ nest k (vcat ys) -sep1 :: Bool -> RDoc -> FastInt -> [Doc] -> RDoc +sep1 :: Bool -> RDoc -> Int -> [Doc] -> RDoc +sep1 _ _ k _ | k `seq` False = undefined sep1 _ NoDoc _ _ = NoDoc sep1 g (p `Union` q) k ys = sep1 g p k ys `union_` aboveNest q False k (reduceDoc (vcat ys)) sep1 g Empty k ys = mkNest k (sepX g ys) -sep1 g (Nest n p) k ys = nest_ n (sep1 g p (k -# n) ys) +sep1 g (Nest n p) k ys = nest_ n (sep1 g p (k - n) ys) sep1 _ (NilAbove p) k ys = nilAbove_ (aboveNest p False k (reduceDoc (vcat ys))) -sep1 g (TextBeside s sl p) k ys = textBeside_ s sl (sepNB g p (k -# sl) ys) +sep1 g (TextBeside s sl p) k ys = textBeside_ s sl (sepNB g p (k - sl) ys) sep1 _ (Above {}) _ _ = error "sep1 Above" sep1 _ (Beside {}) _ _ = error "sep1 Beside" -- Specification: sepNB p k ys = sep1 (text "" <> p) k ys -- Called when we have already found some text in the first item -- We have to eat up nests -sepNB :: Bool -> Doc -> FastInt -> [Doc] -> Doc +sepNB :: Bool -> Doc -> Int -> [Doc] -> Doc sepNB g (Nest _ p) k ys = sepNB g p k ys -- Never triggered, because of invariant (2) sepNB g Empty k ys @@ -790,20 +793,22 @@ fsep = fill True fill :: Bool -> [Doc] -> RDoc fill _ [] = empty -fill g (p:ps) = fill1 g (reduceDoc p) (_ILIT(0)) ps +fill g (p:ps) = fill1 g (reduceDoc p) 0 ps -fill1 :: Bool -> RDoc -> FastInt -> [Doc] -> Doc +fill1 :: Bool -> RDoc -> Int -> [Doc] -> Doc +fill1 _ _ k _ | k `seq` False = undefined fill1 _ NoDoc _ _ = NoDoc fill1 g (p `Union` q) k ys = fill1 g p k ys `union_` aboveNest q False k (fill g ys) fill1 g Empty k ys = mkNest k (fill g ys) -fill1 g (Nest n p) k ys = nest_ n (fill1 g p (k -# n) ys) +fill1 g (Nest n p) k ys = nest_ n (fill1 g p (k - n) ys) fill1 g (NilAbove p) k ys = nilAbove_ (aboveNest p False k (fill g ys)) -fill1 g (TextBeside s sl p) k ys = textBeside_ s sl (fillNB g p (k -# sl) ys) +fill1 g (TextBeside s sl p) k ys = textBeside_ s sl (fillNB g p (k - sl) ys) fill1 _ (Above {}) _ _ = error "fill1 Above" fill1 _ (Beside {}) _ _ = error "fill1 Beside" -fillNB :: Bool -> Doc -> Int# -> [Doc] -> Doc +fillNB :: Bool -> Doc -> Int -> [Doc] -> Doc +fillNB _ _ k _ | k `seq` False = undefined fillNB g (Nest _ p) k ys = fillNB g p k ys -- Never triggered, because of invariant (2) fillNB _ Empty _ [] = Empty @@ -811,8 +816,8 @@ fillNB g Empty k (y:ys) = nilBeside g (fill1 g (oneLiner (reduceDoc y)) k' y `mkUnion` nilAboveNest False k (fill g (y:ys)) where - !k' | g = k -# _ILIT(1) - | otherwise = k + k' | g = k - 1 + | otherwise = k fillNB g p k ys = fill1 g p k ys @@ -824,51 +829,51 @@ best :: Int -- Line length -> Int -- Ribbon length -> RDoc -> RDoc -- No unions in here! -best w_ r_ p - = get (iUnbox w_) p +best w0 r = get w0 where - !r = iUnbox r_ - get :: FastInt -- (Remaining) width of line + get :: Int -- (Remaining) width of line -> Doc -> Doc + get w _ | w == 0 && False = undefined get _ Empty = Empty get _ NoDoc = NoDoc get w (NilAbove p) = nilAbove_ (get w p) get w (TextBeside s sl p) = textBeside_ s sl (get1 w sl p) - get w (Nest k p) = nest_ k (get (w -# k) p) + get w (Nest k p) = nest_ k (get (w - k) p) get w (p `Union` q) = nicest w r (get w p) (get w q) get _ (Above {}) = error "best get Above" get _ (Beside {}) = error "best get Beside" - get1 :: FastInt -- (Remaining) width of line - -> FastInt -- Amount of first line already eaten up + get1 :: Int -- (Remaining) width of line + -> Int -- Amount of first line already eaten up -> Doc -- This is an argument to TextBeside => eat Nests -> Doc -- No unions in here! + get1 w _ _ | w == 0 && False = undefined get1 _ _ Empty = Empty get1 _ _ NoDoc = NoDoc - get1 w sl (NilAbove p) = nilAbove_ (get (w -# sl) p) - get1 w sl (TextBeside t tl p) = textBeside_ t tl (get1 w (sl +# tl) p) + get1 w sl (NilAbove p) = nilAbove_ (get (w - sl) p) + get1 w sl (TextBeside t tl p) = textBeside_ t tl (get1 w (sl + tl) p) get1 w sl (Nest _ p) = get1 w sl p get1 w sl (p `Union` q) = nicest1 w r sl (get1 w sl p) (get1 w sl q) get1 _ _ (Above {}) = error "best get1 Above" get1 _ _ (Beside {}) = error "best get1 Beside" -nicest :: FastInt -> FastInt -> Doc -> Doc -> Doc -nicest w r p q = nicest1 w r (_ILIT(0)) p q +nicest :: Int -> Int -> Doc -> Doc -> Doc +nicest !w !r = nicest1 w r 0 -nicest1 :: FastInt -> FastInt -> Int# -> Doc -> Doc -> Doc -nicest1 w r sl p q | fits ((w `minFastInt` r) -# sl) p = p - | otherwise = q +nicest1 :: Int -> Int -> Int -> Doc -> Doc -> Doc +nicest1 !w !r !sl p q | fits ((w `min` r) - sl) p = p + | otherwise = q -fits :: FastInt -- Space available +fits :: Int -- Space available -> Doc -> Bool -- True if *first line* of Doc fits in space available -fits n _ | n <# _ILIT(0) = False +fits n _ | n < 0 = False fits _ NoDoc = False fits _ Empty = True fits _ (NilAbove _) = True -fits n (TextBeside _ sl p) = fits (n -# sl) p +fits n (TextBeside _ sl p) = fits (n - sl) p fits _ (Above {}) = error "fits Above" fits _ (Beside {}) = error "fits Beside" fits _ (Union {}) = error "fits Union" @@ -962,26 +967,27 @@ fullRender m lineLen ribbons txt rest doc _ -> lineLen display :: Mode -> Int -> Int -> (TextDetails -> a -> a) -> a -> Doc -> a -display m page_width ribbon_width txt end doc - = case (iUnbox page_width) -# (iUnbox ribbon_width) of { gap_width -> - case gap_width `quotFastInt` _ILIT(2) of { shift -> +display m !page_width !ribbon_width txt end doc + = case page_width - ribbon_width of { gap_width -> + case gap_width `quot` 2 of { shift -> let - lay k (Nest k1 p) = lay (k +# k1) p + lay k _ | k `seq` False = undefined + lay k (Nest k1 p) = lay (k + k1) p lay _ Empty = end lay k (NilAbove p) = nlText `txt` lay k p lay k (TextBeside s sl p) = case m of - ZigZagMode | k >=# gap_width + ZigZagMode | k >= gap_width -> nlText `txt` ( Str (multi_ch shift '/') `txt` ( nlText `txt` - lay1 (k -# shift) s sl p )) + lay1 (k - shift) s sl p )) - | k <# _ILIT(0) + | k < 0 -> nlText `txt` ( Str (multi_ch shift '\\') `txt` ( nlText `txt` - lay1 (k +# shift) s sl p )) + lay1 (k + shift) s sl p )) _ -> lay1 k s sl p lay _ (Above {}) = error "display lay Above" @@ -989,10 +995,12 @@ display m page_width ribbon_width txt end doc lay _ NoDoc = error "display lay NoDoc" lay _ (Union {}) = error "display lay Union" - lay1 k s sl p = indent k (s `txt` lay2 (k +# sl) p) + lay1 !k s !sl p = let !r = k + sl + in indent k (s `txt` lay2 r p) + lay2 k _ | k `seq` False = undefined lay2 k (NilAbove p) = nlText `txt` lay k p - lay2 k (TextBeside s sl p) = s `txt` lay2 (k +# sl) p + lay2 k (TextBeside s sl p) = s `txt` lay2 (k + sl) p lay2 k (Nest _ p) = lay2 k p lay2 _ Empty = end lay2 _ (Above {}) = error "display lay2 Above" @@ -1001,19 +1009,19 @@ display m page_width ribbon_width txt end doc lay2 _ (Union {}) = error "display lay2 Union" -- optimise long indentations using LitString chunks of 8 spaces - indent n r | n >=# _ILIT(8) = LStr (sLit " ") (_ILIT(8)) `txt` - indent (n -# _ILIT(8)) r - | otherwise = Str (spaces n) `txt` r + indent !n r | n >= 8 = LStr (sLit " ") 8 `txt` + indent (n - 8) r + | otherwise = Str (spaces n) `txt` r in - lay (_ILIT(0)) doc + lay 0 doc }} cant_fail :: a cant_fail = error "easy_display: NoDoc" -multi_ch :: Int# -> Char -> String -multi_ch n ch | n <=# _ILIT(0) = "" - | otherwise = ch : multi_ch (n -# _ILIT(1)) ch +multi_ch :: Int -> Char -> String +multi_ch !n ch | n <= 0 = "" + | otherwise = ch : multi_ch (n - 1) ch printDoc :: Mode -> Int -> Handle -> Doc -> IO () -- printDoc adds a newline to the end @@ -1040,10 +1048,10 @@ printDoc_ mode pprCols hdl doc done = return () -- hPutChar hdl '\n' -- some versions of hPutBuf will barf if the length is zero -hPutLitString :: Handle -> Ptr a -> Int# -> IO () -hPutLitString handle a l = if l ==# _ILIT(0) +hPutLitString :: Handle -> Ptr a -> Int -> IO () +hPutLitString handle a l = if l == 0 then return () - else hPutBuf handle a (iBox l) + else hPutBuf handle a l -- Printing output in LeftMode is performance critical: it's used when -- dumping C and assembly output, so we allow ourselves a few dirty |