[Git][ghc/ghc][master] Allow LLVM backend to use HDoc for faster file generation.

Marge Bot (@marge-bot) gitlab at gitlab.haskell.org
Tue Mar 21 22:11:46 UTC 2023



Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC


Commits:
e8b4aac4 by Alex Mason at 2023-03-21T18:11:04-04:00
Allow LLVM backend to use HDoc for faster file generation.

Also remove the MetaStmt constructor from LlvmStatement and places the annotations into the Store statement.

Includes “Implement a workaround for -no-asm-shortcutting bug“ (https://gitlab.haskell.org/ghc/ghc/-/commit/2fda9e0df886cc551e2cd6b9c2a384192bdc3045)

- - - - -


8 changed files:

- compiler/GHC/CmmToLlvm.hs
- compiler/GHC/CmmToLlvm/Base.hs
- compiler/GHC/CmmToLlvm/CodeGen.hs
- compiler/GHC/CmmToLlvm/Ppr.hs
- compiler/GHC/Llvm/MetaData.hs
- compiler/GHC/Llvm/Ppr.hs
- compiler/GHC/Llvm/Syntax.hs
- compiler/GHC/Llvm/Types.hs


Changes:

=====================================
compiler/GHC/CmmToLlvm.hs
=====================================
@@ -91,7 +91,7 @@ llvmCodeGen logger cfg h cmm_stream
 llvmCodeGen' :: LlvmCgConfig -> Stream.Stream IO RawCmmGroup a -> LlvmM a
 llvmCodeGen' cfg cmm_stream
   = do  -- Preamble
-        renderLlvm header
+        renderLlvm (llvmHeader cfg) (llvmHeader cfg)
         ghcInternalFunctions
         cmmMetaLlvmPrelude
 
@@ -99,20 +99,23 @@ llvmCodeGen' cfg cmm_stream
         a <- Stream.consume cmm_stream liftIO llvmGroupLlvmGens
 
         -- Declare aliases for forward references
-        renderLlvm . pprLlvmData cfg =<< generateExternDecls
+        decls <- generateExternDecls
+        renderLlvm (pprLlvmData cfg decls)
+                   (pprLlvmData cfg decls)
 
         -- Postamble
         cmmUsedLlvmGens
 
         return a
-  where
-    header :: SDoc
-    header =
-      let target  = llvmCgLlvmTarget cfg
-          llvmCfg = llvmCgLlvmConfig cfg
-      in     (text "target datalayout = \"" <> text (getDataLayout llvmCfg target) <> text "\"")
-         $+$ (text "target triple = \"" <> text target <> text "\"")
 
+llvmHeader :: IsDoc doc => LlvmCgConfig -> doc
+llvmHeader cfg =
+  let target  = llvmCgLlvmTarget cfg
+      llvmCfg = llvmCgLlvmConfig cfg
+  in lines_
+      [ text "target datalayout = \"" <> text (getDataLayout llvmCfg target) <> text "\""
+      , text "target triple = \"" <> text target <> text "\"" ]
+  where
     getDataLayout :: LlvmConfig -> String -> String
     getDataLayout config target =
       case lookup target (llvmTargets config) of
@@ -121,6 +124,8 @@ llvmCodeGen' cfg cmm_stream
                    text "Target:" <+> text target $$
                    hang (text "Available targets:") 4
                         (vcat $ map (text . fst) $ llvmTargets config)
+{-# SPECIALIZE llvmHeader :: LlvmCgConfig -> SDoc #-}
+{-# SPECIALIZE llvmHeader :: LlvmCgConfig -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 llvmGroupLlvmGens :: RawCmmGroup -> LlvmM ()
 llvmGroupLlvmGens cmm = do
@@ -156,10 +161,11 @@ cmmDataLlvmGens statics
                         = funInsert l ty
            regGlobal _  = pure ()
        mapM_ regGlobal gs
-       gss' <- mapM aliasify $ gs
+       gss' <- mapM aliasify gs
 
        cfg <- getConfig
-       renderLlvm $ pprLlvmData cfg (concat gss', concat tss)
+       renderLlvm (pprLlvmData cfg (concat gss', concat tss))
+                  (pprLlvmData cfg (concat gss', concat tss))
 
 -- | Complete LLVM code generation phase for a single top-level chunk of Cmm.
 cmmLlvmGen ::RawCmmDecl -> LlvmM ()
@@ -175,12 +181,12 @@ cmmLlvmGen cmm at CmmProc{} = do
     -- generate llvm code from cmm
     llvmBC <- withClearVars $ genLlvmProc fixed_cmm
 
-    -- pretty print
-    (docs, ivars) <- fmap unzip $ mapM pprLlvmCmmDecl llvmBC
-
-    -- Output, note down used variables
-    renderLlvm (vcat docs)
-    mapM_ markUsedVar $ concat ivars
+    -- pretty print - print as we go, since we produce HDocs, we know
+    -- no nesting state needs to be maintained for the SDocs.
+    forM_ llvmBC (\decl -> do
+        (hdoc, sdoc) <- pprLlvmCmmDecl decl
+        renderLlvm (hdoc $$ empty) (sdoc $$ empty)
+      )
 
 cmmLlvmGen _ = return ()
 
@@ -204,7 +210,8 @@ cmmMetaLlvmPrelude = do
               -- name.
               Nothing -> [ MetaStr name ]
   cfg <- getConfig
-  renderLlvm $ ppLlvmMetas cfg metas
+  renderLlvm (ppLlvmMetas cfg metas)
+             (ppLlvmMetas cfg metas)
 
 -- -----------------------------------------------------------------------------
 -- | Marks variables as used where necessary
@@ -229,4 +236,7 @@ cmmUsedLlvmGens = do
       lmUsed    = LMGlobal lmUsedVar (Just usedArray)
   if null ivars
      then return ()
-     else getConfig >>= renderLlvm . flip pprLlvmData ([lmUsed], [])
+     else do
+      cfg <- getConfig
+      renderLlvm (pprLlvmData cfg ([lmUsed], []))
+                 (pprLlvmData cfg ([lmUsed], []))


=====================================
compiler/GHC/CmmToLlvm/Base.hs
=====================================
@@ -371,13 +371,13 @@ dumpIfSetLlvm flag hdr fmt doc = do
   liftIO $ putDumpFileMaybe logger flag hdr fmt doc
 
 -- | Prints the given contents to the output handle
-renderLlvm :: Outp.SDoc -> LlvmM ()
-renderLlvm sdoc = do
+renderLlvm :: Outp.HDoc -> Outp.SDoc -> LlvmM ()
+renderLlvm hdoc sdoc = do
 
     -- Write to output
     ctx <- llvmCgContext <$> getConfig
     out <- getEnv envOutput
-    liftIO $ Outp.bufLeftRenderSDoc ctx out sdoc
+    liftIO $ Outp.bPutHDoc out ctx hdoc
 
     -- Dump, if requested
     dumpIfSetLlvm Opt_D_dump_llvm "LLVM Code" FormatLLVM sdoc
@@ -428,7 +428,7 @@ ghcInternalFunctions = do
       let n' = fsLit n
           decl = LlvmFunctionDecl n' ExternallyVisible CC_Ccc ret
                                  FixedArgs (tysToParams args) Nothing
-      renderLlvm $ ppLlvmFunctionDecl decl
+      renderLlvm (ppLlvmFunctionDecl decl) (ppLlvmFunctionDecl decl)
       funInsert n' (LMFunction decl)
 
 -- ----------------------------------------------------------------------------


=====================================
compiler/GHC/CmmToLlvm/CodeGen.hs
=====================================
@@ -207,7 +207,7 @@ genCall (PrimTarget (MO_UF_Conv w)) [dst] [e] = runStmtsDecls $ do
     castV <- lift $ mkLocalVar ty
     ve <- exprToVarW e
     statement $ Assignment castV $ Cast LM_Uitofp ve width
-    statement $ Store castV dstV Nothing
+    statement $ Store castV dstV Nothing []
 
 genCall (PrimTarget (MO_UF_Conv _)) [_] args =
     panic $ "genCall: Too many arguments to MO_UF_Conv. " ++
@@ -263,12 +263,12 @@ genCall (PrimTarget (MO_AtomicRMW width amop)) [dst] [addr, n] = runStmtsDecls $
                AMO_Or   -> LAO_Or
                AMO_Xor  -> LAO_Xor
     retVar <- doExprW targetTy $ AtomicRMW op ptrVar nVar SyncSeqCst
-    statement $ Store retVar dstVar Nothing
+    statement $ Store retVar dstVar Nothing []
 
 genCall (PrimTarget (MO_AtomicRead _ mem_ord)) [dst] [addr] = runStmtsDecls $ do
     dstV <- getCmmRegW (CmmLocal dst)
     v1 <- genLoadW (Just mem_ord) addr (localRegType dst) NaturallyAligned
-    statement $ Store v1 dstV Nothing
+    statement $ Store v1 dstV Nothing []
 
 genCall (PrimTarget (MO_Cmpxchg _width))
         [dst] [addr, old, new] = runStmtsDecls $ do
@@ -282,7 +282,7 @@ genCall (PrimTarget (MO_Cmpxchg _width))
     retVar <- doExprW (LMStructU [targetTy,i1])
               $ CmpXChg ptrVar oldVar newVar SyncSeqCst SyncSeqCst
     retVar' <- doExprW targetTy $ ExtractV retVar 0
-    statement $ Store retVar' dstVar Nothing
+    statement $ Store retVar' dstVar Nothing []
 
 genCall (PrimTarget (MO_Xchg _width)) [dst] [addr, val] = runStmtsDecls $ do
     dstV <- getCmmRegW (CmmLocal dst) :: WriterT LlvmAccum LlvmM LlvmVar
@@ -292,7 +292,7 @@ genCall (PrimTarget (MO_Xchg _width)) [dst] [addr, val] = runStmtsDecls $ do
         ptrExpr = Cast LM_Inttoptr addrVar ptrTy
     ptrVar <- doExprW ptrTy ptrExpr
     resVar <- doExprW (getVarType valVar) (AtomicRMW LAO_Xchg ptrVar valVar SyncSeqCst)
-    statement $ Store resVar dstV Nothing
+    statement $ Store resVar dstV Nothing []
 
 genCall (PrimTarget (MO_AtomicWrite _width mem_ord)) [] [addr, val] = runStmtsDecls $ do
     addrVar <- exprToVarW addr
@@ -353,8 +353,8 @@ genCall (PrimTarget (MO_U_Mul2 w)) [dstH, dstL] [lhs, rhs] = runStmtsDecls $ do
     retH <- doExprW width $ Cast LM_Trunc retShifted width
     dstRegL <- getCmmRegW (CmmLocal dstL)
     dstRegH <- getCmmRegW (CmmLocal dstH)
-    statement $ Store retL dstRegL Nothing
-    statement $ Store retH dstRegH Nothing
+    statement $ Store retL dstRegL Nothing []
+    statement $ Store retH dstRegH Nothing []
 
 genCall (PrimTarget (MO_S_Mul2 w)) [dstC, dstH, dstL] [lhs, rhs] = runStmtsDecls $ do
     let width = widthToLlvmInt w
@@ -385,9 +385,9 @@ genCall (PrimTarget (MO_S_Mul2 w)) [dstC, dstH, dstL] [lhs, rhs] = runStmtsDecls
     dstRegL <- getCmmRegW (CmmLocal dstL)
     dstRegH <- getCmmRegW (CmmLocal dstH)
     dstRegC <- getCmmRegW (CmmLocal dstC)
-    statement $ Store retL dstRegL Nothing
-    statement $ Store retH dstRegH Nothing
-    statement $ Store retC dstRegC Nothing
+    statement $ Store retL dstRegL Nothing []
+    statement $ Store retH dstRegH Nothing []
+    statement $ Store retC dstRegC Nothing []
 
 -- MO_U_QuotRem2 is another case we handle by widening the registers to double
 -- the width and use normal LLVM instructions (similarly to the MO_U_Mul2). The
@@ -421,8 +421,8 @@ genCall (PrimTarget (MO_U_QuotRem2 w))
     retRem <- narrow retExtRem
     dstRegQ <- lift $ getCmmReg (CmmLocal dstQ)
     dstRegR <- lift $ getCmmReg (CmmLocal dstR)
-    statement $ Store retDiv dstRegQ Nothing
-    statement $ Store retRem dstRegR Nothing
+    statement $ Store retDiv dstRegQ Nothing []
+    statement $ Store retRem dstRegR Nothing []
 
 -- Handle the MO_{Add,Sub}IntC separately. LLVM versions return a record from
 -- which we need to extract the actual values.
@@ -529,7 +529,7 @@ genCall target res args = do
             vreg <- getCmmRegW (CmmLocal creg)
             if retTy == pLower (getVarType vreg)
                 then do
-                    statement $ Store v1 vreg Nothing
+                    statement $ Store v1 vreg Nothing []
                     doReturn
                 else do
                     let ty = pLower $ getVarType vreg
@@ -541,7 +541,7 @@ genCall target res args = do
                                         ++ " returned type!"
 
                     v2 <- doExprW ty $ Cast op v1 ty
-                    statement $ Store v2 vreg Nothing
+                    statement $ Store v2 vreg Nothing []
                     doReturn
 
 -- | Generate a call to an LLVM intrinsic that performs arithmetic operation
@@ -570,8 +570,8 @@ genCallWithOverflow t@(PrimTarget op) w [dstV, dstO] [lhs, rhs] = do
     (overflow, zext) <- doExpr width $ Cast LM_Zext overflowBit width
     dstRegV <- getCmmReg (CmmLocal dstV)
     dstRegO <- getCmmReg (CmmLocal dstO)
-    let storeV = Store value dstRegV Nothing
-        storeO = Store overflow dstRegO Nothing
+    let storeV = Store value dstRegV Nothing []
+        storeO = Store overflow dstRegO Nothing []
     return (stmts `snocOL` zext `snocOL` storeV `snocOL` storeO, top)
 genCallWithOverflow _ _ _ _ =
     panic "genCallExtract: wrong ForeignTarget or number of arguments"
@@ -636,7 +636,7 @@ genCallSimpleCast w t@(PrimTarget op) [dst] args = do
     (retV, s1)                  <- doExpr width $ Call StdCall fptr argsV' []
     (retVs', stmts5)            <- castVars (cmmPrimOpRetValSignage op) [(retV,dstTy)]
     let retV'                    = singletonPanic "genCallSimpleCast" retVs'
-    let s2                       = Store retV' dstV Nothing
+    let s2                       = Store retV' dstV Nothing []
 
     let stmts = stmts2 `appOL` stmts4 `snocOL`
                 s1 `appOL` stmts5 `snocOL` s2
@@ -668,7 +668,7 @@ genCallSimpleCast2 w t@(PrimTarget op) [dst] args = do
     (retV, s1)                  <- doExpr width $ Call StdCall fptr argsV' []
     (retVs', stmts5)             <- castVars (cmmPrimOpRetValSignage op) [(retV,dstTy)]
     let retV'                    = singletonPanic "genCallSimpleCast2" retVs'
-    let s2                       = Store retV' dstV Nothing
+    let s2                       = Store retV' dstV Nothing []
 
     let stmts = stmts2 `appOL` stmts4 `snocOL`
                 s1 `appOL` stmts5 `snocOL` s2
@@ -1098,16 +1098,16 @@ genAssign reg val = do
       -- Some registers are pointer types, so need to cast value to pointer
       LMPointer _ | getVarType vval == llvmWord platform -> do
           (v, s1) <- doExpr ty $ Cast LM_Inttoptr vval ty
-          let s2 = Store v vreg Nothing
+          let s2 = Store v vreg Nothing []
           return (stmts `snocOL` s1 `snocOL` s2, top2)
 
       LMVector _ _ -> do
           (v, s1) <- doExpr ty $ Cast LM_Bitcast vval ty
-          let s2 = mkStore v vreg NaturallyAligned
+          let s2 = mkStore v vreg NaturallyAligned []
           return (stmts `snocOL` s1 `snocOL` s2, top2)
 
       _ -> do
-          let s1 = Store vval vreg Nothing
+          let s1 = Store vval vreg Nothing []
           return (stmts `snocOL` s1, top2)
 
 
@@ -1158,7 +1158,7 @@ genStore_fast addr r n val alignment
                 case pLower grt == getVarType vval of
                      -- were fine
                      True  -> do
-                         let s3 = MetaStmt meta $ mkStore vval ptr alignment
+                         let s3 = mkStore vval ptr alignment meta
                          return (stmts `appOL` s1 `snocOL` s2
                                  `snocOL` s3, top)
 
@@ -1166,7 +1166,7 @@ genStore_fast addr r n val alignment
                      False -> do
                          let ty = (pLift . getVarType) vval
                          (ptr', s3) <- doExpr ty $ Cast LM_Bitcast ptr ty
-                         let s4 = MetaStmt meta $ mkStore vval ptr' alignment
+                         let s4 = mkStore vval ptr' alignment meta
                          return (stmts `appOL` s1 `snocOL` s2
                                  `snocOL` s3 `snocOL` s4, top)
 
@@ -1189,17 +1189,17 @@ genStore_slow addr val alignment meta = do
         -- sometimes we need to cast an int to a pointer before storing
         LMPointer ty@(LMPointer _) | getVarType vval == llvmWord platform -> do
             (v, s1) <- doExpr ty $ Cast LM_Inttoptr vval ty
-            let s2 = MetaStmt meta $ mkStore v vaddr alignment
+            let s2 = mkStore v vaddr alignment meta
             return (stmts `snocOL` s1 `snocOL` s2, top1 ++ top2)
 
         LMPointer _ -> do
-            let s1 = MetaStmt meta $ mkStore vval vaddr alignment
+            let s1 = mkStore vval vaddr alignment meta
             return (stmts `snocOL` s1, top1 ++ top2)
 
         i@(LMInt _) | i == llvmWord platform -> do
             let vty = pLift $ getVarType vval
             (vptr, s1) <- doExpr vty $ Cast LM_Inttoptr vaddr vty
-            let s2 = MetaStmt meta $ mkStore vval vptr alignment
+            let s2 = mkStore vval vptr alignment meta
             return (stmts `snocOL` s1 `snocOL` s2, top1 ++ top2)
 
         other ->
@@ -1209,9 +1209,9 @@ genStore_slow addr val alignment meta = do
                      text "Size of var:" <+> ppr (llvmWidthInBits platform other) $$
                      text "Var:"         <+> ppVar cfg vaddr)
 
-mkStore :: LlvmVar -> LlvmVar -> AlignmentSpec -> LlvmStatement
-mkStore vval vptr alignment =
-    Store vval vptr align
+mkStore :: LlvmVar -> LlvmVar -> AlignmentSpec -> [MetaAnnot] -> LlvmStatement
+mkStore vval vptr alignment metas =
+    Store vval vptr align metas
   where
     ty = pLower (getVarType vptr)
     align = case alignment of
@@ -2072,7 +2072,7 @@ funPrologue live cmmBlocks = do
             rval  = if isLive r then arg else trash
             alloc = Assignment reg $ Alloca (pLower $ getVarType reg) 1
         markStackReg r
-        return $ toOL [alloc, Store rval reg Nothing]
+        return $ toOL [alloc, Store rval reg Nothing []]
 
   return (concatOL stmtss `snocOL` jumpToEntry, [])
   where


=====================================
compiler/GHC/CmmToLlvm/Ppr.hs
=====================================
@@ -26,22 +26,28 @@ import GHC.Types.Unique
 --
 
 -- | Pretty print LLVM data code
-pprLlvmData :: LlvmCgConfig -> LlvmData -> SDoc
+pprLlvmData :: IsDoc doc => LlvmCgConfig -> LlvmData -> doc
 pprLlvmData cfg (globals, types) =
-    let ppLlvmTys (LMAlias    a) = ppLlvmAlias a
+    let ppLlvmTys (LMAlias    a) = line $ ppLlvmAlias a
         ppLlvmTys (LMFunction f) = ppLlvmFunctionDecl f
         ppLlvmTys _other         = empty
 
         types'   = vcat $ map ppLlvmTys types
         globals' = ppLlvmGlobals cfg globals
-    in types' $+$ globals'
+    in types' $$ globals'
+{-# SPECIALIZE pprLlvmData :: LlvmCgConfig -> LlvmData -> SDoc #-}
+{-# SPECIALIZE pprLlvmData :: LlvmCgConfig -> LlvmData -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
 -- | Pretty print LLVM code
-pprLlvmCmmDecl :: LlvmCmmDecl -> LlvmM (SDoc, [LlvmVar])
+-- The HDoc we return is used to produce the final LLVM file, with the
+-- SDoc being returned alongside for use when @Opt_D_dump_llvm@ is set
+-- as we can't (currently) dump HDocs.
+pprLlvmCmmDecl :: LlvmCmmDecl -> LlvmM (HDoc, SDoc)
 pprLlvmCmmDecl (CmmData _ lmdata) = do
   opts <- getConfig
-  return (vcat $ map (pprLlvmData opts) lmdata, [])
+  return ( vcat $ map (pprLlvmData opts) lmdata
+         , vcat $ map (pprLlvmData opts) lmdata)
 
 pprLlvmCmmDecl (CmmProc mb_info entry_lbl live (ListGraph blks))
   = do let lbl = case mb_info of
@@ -92,7 +98,8 @@ pprLlvmCmmDecl (CmmProc mb_info entry_lbl live (ListGraph blks))
                             (Just $ LMBitc (LMStaticPointer defVar)
                                            i8Ptr)
 
-       return (ppLlvmGlobal cfg alias $+$ ppLlvmFunction cfg fun', [])
+       return ( vcat [line $ ppLlvmGlobal cfg alias, ppLlvmFunction cfg fun']
+              , vcat [line $ ppLlvmGlobal cfg alias, ppLlvmFunction cfg fun'])
 
 
 -- | The section we are putting info tables and their entry code into, should


=====================================
compiler/GHC/Llvm/MetaData.hs
=====================================
@@ -64,7 +64,12 @@ newtype MetaId = MetaId Int
                deriving (Eq, Ord, Enum)
 
 instance Outputable MetaId where
-    ppr (MetaId n) = char '!' <> int n
+    ppr = ppMetaId
+
+ppMetaId :: IsLine doc => MetaId -> doc
+ppMetaId (MetaId n) = char '!' <> int n
+{-# SPECIALIZE ppMetaId :: MetaId -> SDoc #-}
+{-# SPECIALIZE ppMetaId :: MetaId -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 -- | LLVM metadata expressions
 data MetaExpr = MetaStr !LMString


=====================================
compiler/GHC/Llvm/Ppr.hs
=====================================
@@ -1,5 +1,6 @@
 
 {-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE TypeApplications #-}
 
 --------------------------------------------------------------------------------
 -- | Pretty print LLVM IR Code.
@@ -36,7 +37,6 @@ import GHC.Llvm.Syntax
 import GHC.Llvm.MetaData
 import GHC.Llvm.Types
 
-import Data.Int
 import Data.List ( intersperse )
 import GHC.Utils.Outputable
 
@@ -49,30 +49,39 @@ import GHC.Types.Unique
 --------------------------------------------------------------------------------
 
 -- | Print out a whole LLVM module.
-ppLlvmModule :: LlvmCgConfig -> LlvmModule -> SDoc
+ppLlvmModule :: IsDoc doc => LlvmCgConfig -> LlvmModule -> doc
 ppLlvmModule opts (LlvmModule comments aliases meta globals decls funcs)
-  = ppLlvmComments comments $+$ newLine
-    $+$ ppLlvmAliases aliases $+$ newLine
-    $+$ ppLlvmMetas opts meta $+$ newLine
-    $+$ ppLlvmGlobals opts globals $+$ newLine
-    $+$ ppLlvmFunctionDecls decls $+$ newLine
-    $+$ ppLlvmFunctions opts funcs
+  = ppLlvmComments comments $$ newLine
+    $$ ppLlvmAliases aliases $$ newLine
+    $$ ppLlvmMetas opts meta $$ newLine
+    $$ ppLlvmGlobals opts globals $$ newLine
+    $$ ppLlvmFunctionDecls decls $$ newLine
+    $$ ppLlvmFunctions opts funcs
+{-# SPECIALIZE ppLlvmModule :: LlvmCgConfig -> LlvmModule -> SDoc #-}
+{-# SPECIALIZE ppLlvmModule :: LlvmCgConfig -> LlvmModule -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
+
 
 -- | Print out a multi-line comment, can be inside a function or on its own
-ppLlvmComments :: [LMString] -> SDoc
-ppLlvmComments comments = vcat $ map ppLlvmComment comments
+ppLlvmComments :: IsDoc doc => [LMString] -> doc
+ppLlvmComments comments = lines_ $ map ppLlvmComment comments
+{-# SPECIALIZE ppLlvmComments :: [LMString] -> SDoc #-}
+{-# SPECIALIZE ppLlvmComments :: [LMString] -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 -- | Print out a comment, can be inside a function or on its own
-ppLlvmComment :: LMString -> SDoc
+ppLlvmComment :: IsLine doc => LMString -> doc
 ppLlvmComment com = semi <+> ftext com
+{-# SPECIALIZE ppLlvmComment :: LMString -> SDoc #-}
+{-# SPECIALIZE ppLlvmComment :: LMString -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
 -- | Print out a list of global mutable variable definitions
-ppLlvmGlobals :: LlvmCgConfig -> [LMGlobal] -> SDoc
-ppLlvmGlobals opts ls = vcat $ map (ppLlvmGlobal opts) ls
+ppLlvmGlobals :: IsDoc doc => LlvmCgConfig -> [LMGlobal] -> doc
+ppLlvmGlobals opts ls = lines_ $ map (ppLlvmGlobal opts) ls
+{-# SPECIALIZE ppLlvmGlobals :: LlvmCgConfig -> [LMGlobal] -> SDoc #-}
+{-# SPECIALIZE ppLlvmGlobals :: LlvmCgConfig -> [LMGlobal] -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 -- | Print out a global mutable variable definition
-ppLlvmGlobal :: LlvmCgConfig -> LMGlobal -> SDoc
+ppLlvmGlobal :: IsLine doc => LlvmCgConfig -> LMGlobal -> doc
 ppLlvmGlobal opts (LMGlobal var@(LMGlobalVar _ _ link x a c) dat) =
     let sect = case x of
             Just x' -> text ", section" <+> doubleQuotes (ftext x')
@@ -84,7 +93,7 @@ ppLlvmGlobal opts (LMGlobal var@(LMGlobalVar _ _ link x a c) dat) =
 
         rhs = case dat of
             Just stat -> pprSpecialStatic opts stat
-            Nothing   -> ppr (pLower $ getVarType var)
+            Nothing   -> ppLlvmType (pLower $ getVarType var)
 
         -- Position of linkage is different for aliases.
         const = case c of
@@ -92,105 +101,130 @@ ppLlvmGlobal opts (LMGlobal var@(LMGlobalVar _ _ link x a c) dat) =
           Constant -> "constant"
           Alias    -> "alias"
 
-    in ppAssignment opts var $ ppr link <+> text const <+> rhs <> sect <> align
-       $+$ newLine
+    in ppAssignment opts var $ ppLlvmLinkageType link <+> text const <+> rhs <> sect <> align
 
 ppLlvmGlobal opts (LMGlobal var val) = pprPanic "ppLlvmGlobal" $
-  text "Non Global var ppr as global! " <> ppVar opts var <> text "=" <> ppr (fmap (ppStatic opts) val)
+  text "Non Global var ppr as global! " <> ppVar opts var <> text "=" <> ppr (fmap (ppStatic @SDoc opts) val)
+{-# SPECIALIZE ppLlvmGlobal :: LlvmCgConfig -> LMGlobal -> SDoc #-}
+{-# SPECIALIZE ppLlvmGlobal :: LlvmCgConfig -> LMGlobal -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
 -- | Print out a list of LLVM type aliases.
-ppLlvmAliases :: [LlvmAlias] -> SDoc
-ppLlvmAliases tys = vcat $ map ppLlvmAlias tys
+ppLlvmAliases :: IsDoc doc => [LlvmAlias] -> doc
+ppLlvmAliases tys = lines_ $ map ppLlvmAlias tys
+{-# SPECIALIZE ppLlvmAliases :: [LlvmAlias] -> SDoc #-}
+{-# SPECIALIZE ppLlvmAliases :: [LlvmAlias] -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 -- | Print out an LLVM type alias.
-ppLlvmAlias :: LlvmAlias -> SDoc
+ppLlvmAlias :: IsLine doc => LlvmAlias -> doc
 ppLlvmAlias (name, ty)
-  = char '%' <> ftext name <+> equals <+> text "type" <+> ppr ty
+  = char '%' <> ftext name <+> equals <+> text "type" <+> ppLlvmType ty
+{-# SPECIALIZE ppLlvmAlias :: LlvmAlias -> SDoc #-}
+{-# SPECIALIZE ppLlvmAlias :: LlvmAlias -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
 -- | Print out a list of LLVM metadata.
-ppLlvmMetas :: LlvmCgConfig -> [MetaDecl] -> SDoc
-ppLlvmMetas opts metas = vcat $ map (ppLlvmMeta opts) metas
+ppLlvmMetas :: IsDoc doc => LlvmCgConfig -> [MetaDecl] -> doc
+ppLlvmMetas opts metas = lines_ $ map (ppLlvmMeta opts) metas
+{-# SPECIALIZE ppLlvmMetas :: LlvmCgConfig -> [MetaDecl] -> SDoc #-}
+{-# SPECIALIZE ppLlvmMetas :: LlvmCgConfig -> [MetaDecl] -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 -- | Print out an LLVM metadata definition.
-ppLlvmMeta :: LlvmCgConfig -> MetaDecl -> SDoc
+ppLlvmMeta :: IsLine doc => LlvmCgConfig -> MetaDecl -> doc
 ppLlvmMeta opts (MetaUnnamed n m)
-  = ppr n <+> equals <+> ppMetaExpr opts m
+  = ppMetaId n <+> equals <+> ppMetaExpr opts m
 
 ppLlvmMeta _opts (MetaNamed n m)
   = exclamation <> ftext n <+> equals <+> exclamation <> braces nodes
   where
-    nodes = hcat $ intersperse comma $ map ppr m
+    nodes = hcat $ intersperse comma $ map ppMetaId m
+{-# SPECIALIZE ppLlvmMeta :: LlvmCgConfig -> MetaDecl -> SDoc #-}
+{-# SPECIALIZE ppLlvmMeta :: LlvmCgConfig -> MetaDecl -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
 -- | Print out a list of function definitions.
-ppLlvmFunctions :: LlvmCgConfig -> LlvmFunctions -> SDoc
+ppLlvmFunctions :: IsDoc doc => LlvmCgConfig -> LlvmFunctions -> doc
 ppLlvmFunctions opts funcs = vcat $ map (ppLlvmFunction opts) funcs
+{-# SPECIALIZE ppLlvmFunctions :: LlvmCgConfig -> LlvmFunctions -> SDoc #-}
+{-# SPECIALIZE ppLlvmFunctions :: LlvmCgConfig -> LlvmFunctions -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 -- | Print out a function definition.
-ppLlvmFunction :: LlvmCgConfig -> LlvmFunction -> SDoc
+ppLlvmFunction :: IsDoc doc => LlvmCgConfig -> LlvmFunction -> doc
 ppLlvmFunction opts fun =
-    let attrDoc = ppSpaceJoin (funcAttrs fun)
+    let attrDoc = ppSpaceJoin ppLlvmFuncAttr (funcAttrs fun)
         secDoc = case funcSect fun of
                       Just s' -> text "section" <+> (doubleQuotes $ ftext s')
                       Nothing -> empty
         prefixDoc = case funcPrefix fun of
                         Just v  -> text "prefix" <+> ppStatic opts v
                         Nothing -> empty
-    in text "define" <+> ppLlvmFunctionHeader (funcDecl fun) (funcArgs fun)
-        <+> attrDoc <+> secDoc <+> prefixDoc
-        $+$ lbrace
-        $+$ ppLlvmBlocks opts (funcBody fun)
-        $+$ rbrace
-        $+$ newLine
-        $+$ newLine
+    in vcat
+        [line $ text "define" <+> ppLlvmFunctionHeader (funcDecl fun) (funcArgs fun)
+              <+> attrDoc <+> secDoc <+> prefixDoc
+        , line lbrace
+        , ppLlvmBlocks opts (funcBody fun)
+        , line rbrace
+        , newLine
+        , newLine]
+{-# SPECIALIZE ppLlvmFunction :: LlvmCgConfig -> LlvmFunction -> SDoc #-}
+{-# SPECIALIZE ppLlvmFunction :: LlvmCgConfig -> LlvmFunction -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 -- | Print out a function definition header.
-ppLlvmFunctionHeader :: LlvmFunctionDecl -> [LMString] -> SDoc
+ppLlvmFunctionHeader :: IsLine doc => LlvmFunctionDecl -> [LMString] -> doc
 ppLlvmFunctionHeader (LlvmFunctionDecl n l c r varg p a) args
   = let varg' = case varg of
                       VarArgs | null p    -> text "..."
                               | otherwise -> text ", ..."
                       _otherwise          -> text ""
         align = case a of
-                     Just a' -> text " align " <> ppr a'
+                     Just a' -> text " align " <> int a'
                      Nothing -> empty
-        args' = map (\((ty,p),n) -> ppr ty <+> ppSpaceJoin p <+> char '%'
+        args' = zipWith (\(ty,p) n -> ppLlvmType ty <+> ppSpaceJoin ppLlvmParamAttr p <+> char '%'
                                     <> ftext n)
-                    (zip p args)
-    in ppr l <+> ppr c <+> ppr r <+> char '@' <> ftext n <> lparen <>
-        (hsep $ punctuate comma args') <> varg' <> rparen <> align
+                   p
+                   args
+    in ppLlvmLinkageType l <+> ppLlvmCallConvention c <+> ppLlvmType r <+> char '@' <> ftext n <> lparen <>
+        hsep (punctuate comma args') <> varg' <> rparen <> align
+{-# SPECIALIZE ppLlvmFunctionHeader :: LlvmFunctionDecl -> [LMString] -> SDoc #-}
+{-# SPECIALIZE ppLlvmFunctionHeader :: LlvmFunctionDecl -> [LMString] -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 -- | Print out a list of function declaration.
-ppLlvmFunctionDecls :: LlvmFunctionDecls -> SDoc
+ppLlvmFunctionDecls :: IsDoc doc => LlvmFunctionDecls -> doc
 ppLlvmFunctionDecls decs = vcat $ map ppLlvmFunctionDecl decs
+{-# SPECIALIZE ppLlvmFunctionDecls :: LlvmFunctionDecls -> SDoc #-}
+{-# SPECIALIZE ppLlvmFunctionDecls :: LlvmFunctionDecls -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 -- | Print out a function declaration.
 -- Declarations define the function type but don't define the actual body of
 -- the function.
-ppLlvmFunctionDecl :: LlvmFunctionDecl -> SDoc
+ppLlvmFunctionDecl :: IsDoc doc => LlvmFunctionDecl -> doc
 ppLlvmFunctionDecl (LlvmFunctionDecl n l c r varg p a)
   = let varg' = case varg of
                       VarArgs | null p    -> text "..."
                               | otherwise -> text ", ..."
                       _otherwise          -> text ""
         align = case a of
-                     Just a' -> text " align" <+> ppr a'
+                     Just a' -> text " align" <+> int a'
                      Nothing -> empty
         args = hcat $ intersperse (comma <> space) $
-                  map (\(t,a) -> ppr t <+> ppSpaceJoin a) p
-    in text "declare" <+> ppr l <+> ppr c <+> ppr r <+> char '@' <>
-        ftext n <> lparen <> args <> varg' <> rparen <> align $+$ newLine
+                  map (\(t,a) -> ppLlvmType t <+> ppSpaceJoin ppLlvmParamAttr a) p
+    in lines_
+        [ text "declare" <+> ppLlvmLinkageType l <+> ppLlvmCallConvention c
+          <+> ppLlvmType r <+> char '@' <> ftext n <> lparen <> args <> varg' <> rparen <> align
+        , empty]
+{-# SPECIALIZE ppLlvmFunctionDecl :: LlvmFunctionDecl -> SDoc #-}
+{-# SPECIALIZE ppLlvmFunctionDecl :: LlvmFunctionDecl -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
 -- | Print out a list of LLVM blocks.
-ppLlvmBlocks :: LlvmCgConfig -> LlvmBlocks -> SDoc
+ppLlvmBlocks :: IsDoc doc => LlvmCgConfig -> LlvmBlocks -> doc
 ppLlvmBlocks opts blocks = vcat $ map (ppLlvmBlock opts) blocks
+{-# SPECIALIZE ppLlvmBlocks :: LlvmCgConfig -> LlvmBlocks -> SDoc #-}
+{-# SPECIALIZE ppLlvmBlocks :: LlvmCgConfig -> LlvmBlocks -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 -- | Print out an LLVM block.
 -- It must be part of a function definition.
-ppLlvmBlock :: LlvmCgConfig -> LlvmBlock -> SDoc
+ppLlvmBlock :: IsDoc doc => LlvmCgConfig -> LlvmBlock -> doc
 ppLlvmBlock opts (LlvmBlock blockId stmts) =
   let isLabel (MkLabel _) = True
       isLabel _           = False
@@ -198,39 +232,44 @@ ppLlvmBlock opts (LlvmBlock blockId stmts) =
       ppRest = case rest of
         MkLabel id:xs -> ppLlvmBlock opts (LlvmBlock id xs)
         _             -> empty
-  in ppLlvmBlockLabel blockId
-           $+$ (vcat $ map (ppLlvmStatement opts) block)
-           $+$ newLine
-           $+$ ppRest
+  in vcat $
+      line (ppLlvmBlockLabel blockId)
+      : map (ppLlvmStatement opts) block
+      ++ [ empty , ppRest ]
+{-# SPECIALIZE ppLlvmBlock :: LlvmCgConfig -> LlvmBlock -> SDoc #-}
+{-# SPECIALIZE ppLlvmBlock :: LlvmCgConfig -> LlvmBlock -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 -- | Print out an LLVM block label.
-ppLlvmBlockLabel :: LlvmBlockId -> SDoc
+ppLlvmBlockLabel :: IsLine doc => LlvmBlockId -> doc
 ppLlvmBlockLabel id = pprUniqueAlways id <> colon
+{-# SPECIALIZE ppLlvmBlockLabel :: LlvmBlockId -> SDoc #-}
+{-# SPECIALIZE ppLlvmBlockLabel :: LlvmBlockId -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
--- | Print out an LLVM statement.
-ppLlvmStatement :: LlvmCgConfig -> LlvmStatement -> SDoc
+-- | Print out an LLVM statement, with any metadata to append to the statement.
+ppLlvmStatement :: IsDoc doc => LlvmCgConfig -> LlvmStatement -> doc
 ppLlvmStatement opts stmt =
-  let ind = (text "  " <>)
+  let ind = line . (text "  " <>)
   in case stmt of
         Assignment  dst expr      -> ind $ ppAssignment opts dst (ppLlvmExpression opts expr)
         Fence       st ord        -> ind $ ppFence st ord
         Branch      target        -> ind $ ppBranch opts target
         BranchIf    cond ifT ifF  -> ind $ ppBranchIf opts cond ifT ifF
-        Comment     comments      -> ind $ ppLlvmComments comments
-        MkLabel     label         -> ppLlvmBlockLabel label
-        Store       value ptr align
-                                  -> ind $ ppStore opts value ptr align
-        Switch      scrut def tgs -> ind $ ppSwitch opts scrut def tgs
+        Comment     comments      -> ppLlvmComments comments
+        MkLabel     label         -> line $ ppLlvmBlockLabel label
+        Store       value ptr align metas
+                                  -> ind $ ppStore opts value ptr align metas
+        Switch      scrut def tgs -> ppSwitch opts scrut def tgs
         Return      result        -> ind $ ppReturn opts result
         Expr        expr          -> ind $ ppLlvmExpression opts expr
         Unreachable               -> ind $ text "unreachable"
-        Nop                       -> empty
-        MetaStmt    meta s        -> ppMetaStatement opts meta s
+        Nop                       -> line empty
 
+{-# SPECIALIZE ppLlvmStatement :: LlvmCgConfig -> LlvmStatement -> SDoc #-}
+{-# SPECIALIZE ppLlvmStatement :: LlvmCgConfig -> LlvmStatement -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 -- | Print out an LLVM expression.
-ppLlvmExpression :: LlvmCgConfig -> LlvmExpression -> SDoc
+ppLlvmExpression :: IsLine doc => LlvmCgConfig -> LlvmExpression -> doc
 ppLlvmExpression opts expr
   = case expr of
         Alloca     tp amount        -> ppAlloca opts tp amount
@@ -251,14 +290,18 @@ ppLlvmExpression opts expr
         Phi        tp predecessors  -> ppPhi opts tp predecessors
         Asm        asm c ty v se sk -> ppAsm opts asm c ty v se sk
         MExpr      meta expr        -> ppMetaAnnotExpr opts meta expr
+{-# SPECIALIZE ppLlvmExpression :: LlvmCgConfig -> LlvmExpression -> SDoc #-}
+{-# SPECIALIZE ppLlvmExpression :: LlvmCgConfig -> LlvmExpression -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-ppMetaExpr :: LlvmCgConfig -> MetaExpr -> SDoc
+ppMetaExpr :: IsLine doc => LlvmCgConfig -> MetaExpr -> doc
 ppMetaExpr opts = \case
   MetaVar (LMLitVar (LMNullLit _)) -> text "null"
   MetaStr    s                     -> char '!' <> doubleQuotes (ftext s)
-  MetaNode   n                     -> ppr n
+  MetaNode   n                     -> ppMetaId n
   MetaVar    v                     -> ppVar opts v
-  MetaStruct es                    -> char '!' <> braces (ppCommaJoin (map (ppMetaExpr opts) es))
+  MetaStruct es                    -> char '!' <> braces (ppCommaJoin (ppMetaExpr opts) es)
+{-# SPECIALIZE ppMetaExpr :: LlvmCgConfig -> MetaExpr -> SDoc #-}
+{-# SPECIALIZE ppMetaExpr :: LlvmCgConfig -> MetaExpr -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
 --------------------------------------------------------------------------------
@@ -267,7 +310,8 @@ ppMetaExpr opts = \case
 
 -- | Should always be a function pointer. So a global var of function type
 -- (since globals are always pointers) or a local var of pointer function type.
-ppCall :: LlvmCgConfig -> LlvmCallType -> LlvmVar -> [MetaExpr] -> [LlvmFuncAttr] -> SDoc
+ppCall :: forall doc. IsLine doc => LlvmCgConfig -> LlvmCallType -> LlvmVar -> [MetaExpr]
+       -> [LlvmFuncAttr] -> doc
 ppCall opts ct fptr args attrs = case fptr of
                            --
     -- if local var function pointer, unwrap
@@ -285,32 +329,36 @@ ppCall opts ct fptr args attrs = case fptr of
         ppCall' (LlvmFunctionDecl _ _ cc ret argTy params _) =
             let tc = if ct == TailCall then text "tail " else empty
                 ppValues = ppCallParams opts (map snd params) args
-                ppArgTy  = (ppCommaJoin $ map (ppr . fst) params) <>
+                ppArgTy  = ppCommaJoin (ppLlvmType . fst) params <>
                            (case argTy of
                                VarArgs   -> text ", ..."
                                FixedArgs -> empty)
                 fnty = space <> lparen <> ppArgTy <> rparen
-                attrDoc = ppSpaceJoin attrs
-            in  tc <> text "call" <+> ppr cc <+> ppr ret
+                attrDoc = ppSpaceJoin ppLlvmFuncAttr attrs
+            in  tc <> text "call" <+> ppLlvmCallConvention cc <+> ppLlvmType ret
                     <> fnty <+> ppName opts fptr <> lparen <+> ppValues
                     <+> rparen <+> attrDoc
 
-        ppCallParams :: LlvmCgConfig -> [[LlvmParamAttr]] -> [MetaExpr] -> SDoc
+        ppCallParams :: LlvmCgConfig -> [[LlvmParamAttr]] -> [MetaExpr] -> doc
         ppCallParams opts attrs args = hsep $ punctuate comma $ zipWith ppCallMetaExpr attrs args
          where
           -- Metadata needs to be marked as having the `metadata` type when used
           -- in a call argument
           ppCallMetaExpr attrs (MetaVar v) = ppVar' attrs opts v
           ppCallMetaExpr _ v             = text "metadata" <+> ppMetaExpr opts v
+{-# SPECIALIZE ppCall :: LlvmCgConfig -> LlvmCallType -> LlvmVar -> [MetaExpr] -> [LlvmFuncAttr] -> SDoc #-}
+{-# SPECIALIZE ppCall :: LlvmCgConfig -> LlvmCallType -> LlvmVar -> [MetaExpr] -> [LlvmFuncAttr] -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
-ppMachOp :: LlvmCgConfig -> LlvmMachOp -> LlvmVar -> LlvmVar -> SDoc
+ppMachOp :: IsLine doc => LlvmCgConfig -> LlvmMachOp -> LlvmVar -> LlvmVar -> doc
 ppMachOp opts op left right =
-  (ppr op) <+> (ppr (getVarType left)) <+> ppName opts left
+  ppLlvmMachOp op <+> ppLlvmType (getVarType left) <+> ppName opts left
         <> comma <+> ppName opts right
+{-# SPECIALIZE ppMachOp :: LlvmCgConfig -> LlvmMachOp -> LlvmVar -> LlvmVar -> SDoc #-}
+{-# SPECIALIZE ppMachOp :: LlvmCgConfig -> LlvmMachOp -> LlvmVar -> LlvmVar -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
-ppCmpOp :: LlvmCgConfig -> LlvmCmpOp -> LlvmVar -> LlvmVar -> SDoc
+ppCmpOp :: IsLine doc => LlvmCgConfig -> LlvmCmpOp -> LlvmVar -> LlvmVar -> doc
 ppCmpOp opts op left right =
   let cmpOp
         | isInt (getVarType left) && isInt (getVarType right) = text "icmp"
@@ -321,28 +369,36 @@ ppCmpOp opts op left right =
                 ++ (show $ getVarType left) ++ ", right = "
                 ++ (show $ getVarType right))
         -}
-  in cmpOp <+> ppr op <+> ppr (getVarType left)
+  in cmpOp <+> ppLlvmCmpOp op <+> ppLlvmType (getVarType left)
         <+> ppName opts left <> comma <+> ppName opts right
+{-# SPECIALIZE ppCmpOp :: LlvmCgConfig -> LlvmCmpOp -> LlvmVar -> LlvmVar -> SDoc #-}
+{-# SPECIALIZE ppCmpOp :: LlvmCgConfig -> LlvmCmpOp -> LlvmVar -> LlvmVar -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
-ppAssignment :: LlvmCgConfig -> LlvmVar -> SDoc -> SDoc
+ppAssignment :: IsLine doc => LlvmCgConfig -> LlvmVar -> doc -> doc
 ppAssignment opts var expr = ppName opts var <+> equals <+> expr
+{-# SPECIALIZE ppAssignment :: LlvmCgConfig -> LlvmVar -> SDoc -> SDoc #-}
+{-# SPECIALIZE ppAssignment :: LlvmCgConfig -> LlvmVar -> HLine -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-ppFence :: Bool -> LlvmSyncOrdering -> SDoc
+ppFence :: IsLine doc => Bool -> LlvmSyncOrdering -> doc
 ppFence st ord =
   let singleThread = case st of True  -> text "singlethread"
                                 False -> empty
   in text "fence" <+> singleThread <+> ppSyncOrdering ord
+{-# SPECIALIZE ppFence :: Bool -> LlvmSyncOrdering -> SDoc #-}
+{-# SPECIALIZE ppFence :: Bool -> LlvmSyncOrdering -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-ppSyncOrdering :: LlvmSyncOrdering -> SDoc
+ppSyncOrdering :: IsLine doc => LlvmSyncOrdering -> doc
 ppSyncOrdering SyncUnord     = text "unordered"
 ppSyncOrdering SyncMonotonic = text "monotonic"
 ppSyncOrdering SyncAcquire   = text "acquire"
 ppSyncOrdering SyncRelease   = text "release"
 ppSyncOrdering SyncAcqRel    = text "acq_rel"
 ppSyncOrdering SyncSeqCst    = text "seq_cst"
+{-# SPECIALIZE ppSyncOrdering :: LlvmSyncOrdering -> SDoc #-}
+{-# SPECIALIZE ppSyncOrdering :: LlvmSyncOrdering -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-ppAtomicOp :: LlvmAtomicOp -> SDoc
+ppAtomicOp :: IsLine doc => LlvmAtomicOp -> doc
 ppAtomicOp LAO_Xchg = text "xchg"
 ppAtomicOp LAO_Add  = text "add"
 ppAtomicOp LAO_Sub  = text "sub"
@@ -354,184 +410,222 @@ ppAtomicOp LAO_Max  = text "max"
 ppAtomicOp LAO_Min  = text "min"
 ppAtomicOp LAO_Umax = text "umax"
 ppAtomicOp LAO_Umin = text "umin"
+{-# SPECIALIZE ppAtomicOp :: LlvmAtomicOp -> SDoc #-}
+{-# SPECIALIZE ppAtomicOp :: LlvmAtomicOp -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-ppAtomicRMW :: LlvmCgConfig -> LlvmAtomicOp -> LlvmVar -> LlvmVar -> LlvmSyncOrdering -> SDoc
+ppAtomicRMW :: IsLine doc => LlvmCgConfig -> LlvmAtomicOp -> LlvmVar -> LlvmVar -> LlvmSyncOrdering -> doc
 ppAtomicRMW opts aop tgt src ordering =
   text "atomicrmw" <+> ppAtomicOp aop <+> ppVar opts tgt <> comma
   <+> ppVar opts src <+> ppSyncOrdering ordering
+{-# SPECIALIZE ppAtomicRMW :: LlvmCgConfig -> LlvmAtomicOp -> LlvmVar -> LlvmVar -> LlvmSyncOrdering -> SDoc #-}
+{-# SPECIALIZE ppAtomicRMW :: LlvmCgConfig -> LlvmAtomicOp -> LlvmVar -> LlvmVar -> LlvmSyncOrdering -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-ppCmpXChg :: LlvmCgConfig -> LlvmVar -> LlvmVar -> LlvmVar
-          -> LlvmSyncOrdering -> LlvmSyncOrdering -> SDoc
+ppCmpXChg :: IsLine doc => LlvmCgConfig -> LlvmVar -> LlvmVar -> LlvmVar
+          -> LlvmSyncOrdering -> LlvmSyncOrdering -> doc
 ppCmpXChg opts addr old new s_ord f_ord =
   text "cmpxchg" <+> ppVar opts addr <> comma <+> ppVar opts old <> comma <+> ppVar opts new
   <+> ppSyncOrdering s_ord <+> ppSyncOrdering f_ord
+{-# SPECIALIZE ppCmpXChg :: LlvmCgConfig -> LlvmVar -> LlvmVar -> LlvmVar -> LlvmSyncOrdering -> LlvmSyncOrdering -> SDoc #-}
+{-# SPECIALIZE ppCmpXChg :: LlvmCgConfig -> LlvmVar -> LlvmVar -> LlvmVar -> LlvmSyncOrdering -> LlvmSyncOrdering -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
-ppLoad :: LlvmCgConfig -> LlvmVar -> LMAlign -> SDoc
+ppLoad :: IsLine doc => LlvmCgConfig -> LlvmVar -> LMAlign -> doc
 ppLoad opts var alignment =
-  text "load" <+> ppr derefType <> comma <+> ppVar opts var <> align
+  text "load" <+> ppLlvmType derefType <> comma <+> ppVar opts var <> align
   where
     derefType = pLower $ getVarType var
     align =
       case alignment of
-        Just n  -> text ", align" <+> ppr n
+        Just n  -> text ", align" <+> int n
         Nothing -> empty
+{-# SPECIALIZE ppLoad :: LlvmCgConfig -> LlvmVar -> LMAlign -> SDoc #-}
+{-# SPECIALIZE ppLoad :: LlvmCgConfig -> LlvmVar -> LMAlign -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-ppALoad :: LlvmCgConfig -> LlvmSyncOrdering -> SingleThreaded -> LlvmVar -> SDoc
+ppALoad :: IsLine doc => LlvmCgConfig -> LlvmSyncOrdering -> SingleThreaded -> LlvmVar -> doc
 ppALoad opts ord st var =
   let alignment = llvmWidthInBits (llvmCgPlatform opts) (getVarType var) `quot` 8
-      align     = text ", align" <+> ppr alignment
+      align     = text ", align" <+> int alignment
       sThreaded | st        = text " singlethread"
                 | otherwise = empty
       derefType = pLower $ getVarType var
-  in text "load atomic" <+> ppr derefType <> comma <+> ppVar opts var <> sThreaded
+  in text "load atomic" <+> ppLlvmType derefType <> comma <+> ppVar opts var <> sThreaded
             <+> ppSyncOrdering ord <> align
+{-# SPECIALIZE ppALoad :: LlvmCgConfig -> LlvmSyncOrdering -> SingleThreaded -> LlvmVar -> SDoc #-}
+{-# SPECIALIZE ppALoad :: LlvmCgConfig -> LlvmSyncOrdering -> SingleThreaded -> LlvmVar -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-ppStore :: LlvmCgConfig -> LlvmVar -> LlvmVar -> LMAlign -> SDoc
-ppStore opts val dst alignment =
-    text "store" <+> ppVar opts val <> comma <+> ppVar opts dst <> align
+ppStore :: IsLine doc => LlvmCgConfig -> LlvmVar -> LlvmVar -> LMAlign -> [MetaAnnot] -> doc
+ppStore opts val dst alignment metas =
+    text "store" <+> ppVar opts val <> comma <+> ppVar opts dst <> align <+> ppMetaAnnots opts metas
   where
     align =
       case alignment of
-        Just n  -> text ", align" <+> ppr n
+        Just n  -> text ", align" <+> int n
         Nothing -> empty
+{-# SPECIALIZE ppStore :: LlvmCgConfig -> LlvmVar -> LlvmVar -> LMAlign -> [MetaAnnot] -> SDoc #-}
+{-# SPECIALIZE ppStore :: LlvmCgConfig -> LlvmVar -> LlvmVar -> LMAlign -> [MetaAnnot] -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
-ppCast :: LlvmCgConfig -> LlvmCastOp -> LlvmVar -> LlvmType -> SDoc
+ppCast :: IsLine doc => LlvmCgConfig -> LlvmCastOp -> LlvmVar -> LlvmType -> doc
 ppCast opts op from to
-    =   ppr op
-    <+> ppr (getVarType from) <+> ppName opts from
+    =   ppLlvmCastOp op
+    <+> ppLlvmType (getVarType from) <+> ppName opts from
     <+> text "to"
-    <+> ppr to
+    <+> ppLlvmType to
+{-# SPECIALIZE ppCast :: LlvmCgConfig -> LlvmCastOp -> LlvmVar -> LlvmType -> SDoc #-}
+{-# SPECIALIZE ppCast :: LlvmCgConfig -> LlvmCastOp -> LlvmVar -> LlvmType -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
-ppMalloc :: LlvmCgConfig -> LlvmType -> Int -> SDoc
+ppMalloc :: IsLine doc => LlvmCgConfig -> LlvmType -> Int -> doc
 ppMalloc opts tp amount =
   let amount' = LMLitVar $ LMIntLit (toInteger amount) i32
-  in text "malloc" <+> ppr tp <> comma <+> ppVar opts amount'
-
+  in text "malloc" <+> ppLlvmType tp <> comma <+> ppVar opts amount'
+{-# SPECIALIZE ppMalloc :: LlvmCgConfig -> LlvmType -> Int -> SDoc #-}
+{-# SPECIALIZE ppMalloc :: LlvmCgConfig -> LlvmType -> Int -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-ppAlloca :: LlvmCgConfig -> LlvmType -> Int -> SDoc
+ppAlloca :: IsLine doc => LlvmCgConfig -> LlvmType -> Int -> doc
 ppAlloca opts tp amount =
   let amount' = LMLitVar $ LMIntLit (toInteger amount) i32
-  in text "alloca" <+> ppr tp <> comma <+> ppVar opts amount'
-
+  in text "alloca" <+> ppLlvmType tp <> comma <+> ppVar opts amount'
+{-# SPECIALIZE ppAlloca :: LlvmCgConfig -> LlvmType -> Int -> SDoc #-}
+{-# SPECIALIZE ppAlloca :: LlvmCgConfig -> LlvmType -> Int -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-ppGetElementPtr :: LlvmCgConfig -> Bool -> LlvmVar -> [LlvmVar] -> SDoc
+ppGetElementPtr :: IsLine doc => LlvmCgConfig -> Bool -> LlvmVar -> [LlvmVar] -> doc
 ppGetElementPtr opts inb ptr idx =
-  let indexes = comma <+> ppCommaJoin (map (ppVar opts) idx)
+  let indexes = comma <+> ppCommaJoin (ppVar opts) idx
       inbound = if inb then text "inbounds" else empty
       derefType = pLower $ getVarType ptr
-  in text "getelementptr" <+> inbound <+> ppr derefType <> comma <+> ppVar opts ptr
+  in text "getelementptr" <+> inbound <+> ppLlvmType derefType <> comma <+> ppVar opts ptr
                             <> indexes
+{-# SPECIALIZE ppGetElementPtr :: LlvmCgConfig -> Bool -> LlvmVar -> [LlvmVar] -> SDoc #-}
+{-# SPECIALIZE ppGetElementPtr :: LlvmCgConfig -> Bool -> LlvmVar -> [LlvmVar] -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
-ppReturn :: LlvmCgConfig -> Maybe LlvmVar -> SDoc
+ppReturn :: IsLine doc => LlvmCgConfig -> Maybe LlvmVar -> doc
 ppReturn opts (Just var) = text "ret" <+> ppVar opts var
-ppReturn _    Nothing    = text "ret" <+> ppr LMVoid
+ppReturn _    Nothing    = text "ret" <+> ppLlvmType LMVoid
+{-# SPECIALIZE ppReturn :: LlvmCgConfig -> Maybe LlvmVar -> SDoc #-}
+{-# SPECIALIZE ppReturn :: LlvmCgConfig -> Maybe LlvmVar -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-
-ppBranch :: LlvmCgConfig -> LlvmVar -> SDoc
+ppBranch :: IsLine doc => LlvmCgConfig -> LlvmVar -> doc
 ppBranch opts var = text "br" <+> ppVar opts var
+{-# SPECIALIZE ppBranch :: LlvmCgConfig -> LlvmVar -> SDoc #-}
+{-# SPECIALIZE ppBranch :: LlvmCgConfig -> LlvmVar -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
-ppBranchIf :: LlvmCgConfig -> LlvmVar -> LlvmVar -> LlvmVar -> SDoc
+ppBranchIf :: IsLine doc => LlvmCgConfig -> LlvmVar -> LlvmVar -> LlvmVar -> doc
 ppBranchIf opts cond trueT falseT
   = text "br" <+> ppVar opts cond <> comma <+> ppVar opts trueT <> comma <+> ppVar opts falseT
+{-# SPECIALIZE ppBranchIf :: LlvmCgConfig -> LlvmVar -> LlvmVar -> LlvmVar -> SDoc #-}
+{-# SPECIALIZE ppBranchIf :: LlvmCgConfig -> LlvmVar -> LlvmVar -> LlvmVar -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
-ppPhi :: LlvmCgConfig -> LlvmType -> [(LlvmVar,LlvmVar)] -> SDoc
+ppPhi :: IsLine doc => LlvmCgConfig -> LlvmType -> [(LlvmVar,LlvmVar)] -> doc
 ppPhi opts tp preds =
   let ppPreds (val, label) = brackets $ ppName opts val <> comma <+> ppName opts label
-  in text "phi" <+> ppr tp <+> hsep (punctuate comma $ map ppPreds preds)
+  in text "phi" <+> ppLlvmType tp <+> hsep (punctuate comma $ map ppPreds preds)
+{-# SPECIALIZE ppPhi :: LlvmCgConfig -> LlvmType -> [(LlvmVar,LlvmVar)] -> SDoc #-}
+{-# SPECIALIZE ppPhi :: LlvmCgConfig -> LlvmType -> [(LlvmVar,LlvmVar)] -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
-ppSwitch :: LlvmCgConfig -> LlvmVar -> LlvmVar -> [(LlvmVar,LlvmVar)] -> SDoc
+ppSwitch :: IsDoc doc => LlvmCgConfig -> LlvmVar -> LlvmVar -> [(LlvmVar,LlvmVar)] -> doc
 ppSwitch opts scrut dflt targets =
-  let ppTarget  (val, lab) = ppVar opts val <> comma <+> ppVar opts lab
-      ppTargets  xs        = brackets $ vcat (map ppTarget xs)
-  in text "switch" <+> ppVar opts scrut <> comma <+> ppVar opts dflt
-        <+> ppTargets targets
+  let ppTarget  (val, lab) = text "  " <> ppVar opts val <> comma <+> ppVar opts lab
+  in lines_ $ concat
+      [ [text "switch" <+> ppVar opts scrut <> comma <+> ppVar opts dflt <+> char '[']
+      , map ppTarget targets
+      , [char ']']
+      ]
+{-# SPECIALIZE ppSwitch :: LlvmCgConfig -> LlvmVar -> LlvmVar -> [(LlvmVar,LlvmVar)] -> SDoc #-}
+{-# SPECIALIZE ppSwitch :: LlvmCgConfig -> LlvmVar -> LlvmVar -> [(LlvmVar,LlvmVar)] -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
-ppAsm :: LlvmCgConfig -> LMString -> LMString -> LlvmType -> [LlvmVar] -> Bool -> Bool -> SDoc
+ppAsm :: IsLine doc => LlvmCgConfig -> LMString -> LMString -> LlvmType -> [LlvmVar] -> Bool -> Bool -> doc
 ppAsm opts asm constraints rty vars sideeffect alignstack =
   let asm'  = doubleQuotes $ ftext asm
       cons  = doubleQuotes $ ftext constraints
-      rty'  = ppr rty
-      vars' = lparen <+> ppCommaJoin (map (ppVar opts) vars) <+> rparen
+      rty'  = ppLlvmType rty
+      vars' = lparen <+> ppCommaJoin (ppVar opts) vars <+> rparen
       side  = if sideeffect then text "sideeffect" else empty
       align = if alignstack then text "alignstack" else empty
   in text "call" <+> rty' <+> text "asm" <+> side <+> align <+> asm' <> comma
         <+> cons <> vars'
+{-# SPECIALIZE ppAsm :: LlvmCgConfig -> LMString -> LMString -> LlvmType -> [LlvmVar] -> Bool -> Bool -> SDoc #-}
+{-# SPECIALIZE ppAsm :: LlvmCgConfig -> LMString -> LMString -> LlvmType -> [LlvmVar] -> Bool -> Bool -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-ppExtract :: LlvmCgConfig -> LlvmVar -> LlvmVar -> SDoc
+ppExtract :: IsLine doc => LlvmCgConfig -> LlvmVar -> LlvmVar -> doc
 ppExtract opts vec idx =
     text "extractelement"
-    <+> ppr (getVarType vec) <+> ppName opts vec <> comma
+    <+> ppLlvmType (getVarType vec) <+> ppName opts vec <> comma
     <+> ppVar opts idx
+{-# SPECIALIZE ppExtract :: LlvmCgConfig -> LlvmVar -> LlvmVar -> SDoc #-}
+{-# SPECIALIZE ppExtract :: LlvmCgConfig -> LlvmVar -> LlvmVar -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-ppExtractV :: LlvmCgConfig -> LlvmVar -> Int -> SDoc
+ppExtractV :: IsLine doc => LlvmCgConfig -> LlvmVar -> Int -> doc
 ppExtractV opts struct idx =
     text "extractvalue"
-    <+> ppr (getVarType struct) <+> ppName opts struct <> comma
-    <+> ppr idx
+    <+> ppLlvmType (getVarType struct) <+> ppName opts struct <> comma
+    <+> int idx
+{-# SPECIALIZE ppExtractV :: LlvmCgConfig -> LlvmVar -> Int -> SDoc #-}
+{-# SPECIALIZE ppExtractV :: LlvmCgConfig -> LlvmVar -> Int -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-ppInsert :: LlvmCgConfig -> LlvmVar -> LlvmVar -> LlvmVar -> SDoc
+ppInsert :: IsLine doc => LlvmCgConfig -> LlvmVar -> LlvmVar -> LlvmVar -> doc
 ppInsert opts vec elt idx =
     text "insertelement"
-    <+> ppr (getVarType vec) <+> ppName opts vec <> comma
-    <+> ppr (getVarType elt) <+> ppName opts elt <> comma
+    <+> ppLlvmType (getVarType vec) <+> ppName opts vec <> comma
+    <+> ppLlvmType (getVarType elt) <+> ppName opts elt <> comma
     <+> ppVar opts idx
+{-# SPECIALIZE ppInsert :: LlvmCgConfig -> LlvmVar -> LlvmVar -> LlvmVar -> SDoc #-}
+{-# SPECIALIZE ppInsert :: LlvmCgConfig -> LlvmVar -> LlvmVar -> LlvmVar -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-
-ppMetaStatement :: LlvmCgConfig -> [MetaAnnot] -> LlvmStatement -> SDoc
-ppMetaStatement opts meta stmt =
-   ppLlvmStatement opts stmt <> ppMetaAnnots opts meta
-
-ppMetaAnnotExpr :: LlvmCgConfig -> [MetaAnnot] -> LlvmExpression -> SDoc
+ppMetaAnnotExpr :: IsLine doc => LlvmCgConfig -> [MetaAnnot] -> LlvmExpression -> doc
 ppMetaAnnotExpr opts meta expr =
    ppLlvmExpression opts expr <> ppMetaAnnots opts meta
+{-# SPECIALIZE ppMetaAnnotExpr :: LlvmCgConfig -> [MetaAnnot] -> LlvmExpression -> SDoc #-}
+{-# SPECIALIZE ppMetaAnnotExpr :: LlvmCgConfig -> [MetaAnnot] -> LlvmExpression -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-ppMetaAnnots :: LlvmCgConfig -> [MetaAnnot] -> SDoc
+ppMetaAnnots :: IsLine doc => LlvmCgConfig -> [MetaAnnot] -> doc
 ppMetaAnnots opts meta = hcat $ map ppMeta meta
   where
     ppMeta (MetaAnnot name e)
         = comma <+> exclamation <> ftext name <+>
           case e of
-            MetaNode n    -> ppr n
-            MetaStruct ms -> exclamation <> braces (ppCommaJoin (map (ppMetaExpr opts) ms))
+            MetaNode n    -> ppMetaId n
+            MetaStruct ms -> exclamation <> braces (ppCommaJoin (ppMetaExpr opts) ms)
             other         -> exclamation <> braces (ppMetaExpr opts other) -- possible?
+{-# SPECIALIZE ppMetaAnnots :: LlvmCgConfig -> [MetaAnnot] -> SDoc #-}
+{-# SPECIALIZE ppMetaAnnots :: LlvmCgConfig -> [MetaAnnot] -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 -- | Return the variable name or value of the 'LlvmVar'
 -- in Llvm IR textual representation (e.g. @\@x@, @%y@ or @42@).
-ppName :: LlvmCgConfig -> LlvmVar -> SDoc
+ppName :: IsLine doc => LlvmCgConfig -> LlvmVar -> doc
 ppName opts v = case v of
    LMGlobalVar {} -> char '@' <> ppPlainName opts v
    LMLocalVar  {} -> char '%' <> ppPlainName opts v
    LMNLocalVar {} -> char '%' <> ppPlainName opts v
    LMLitVar    {} ->             ppPlainName opts v
+{-# SPECIALIZE ppName :: LlvmCgConfig -> LlvmVar -> SDoc #-}
+{-# SPECIALIZE ppName :: LlvmCgConfig -> LlvmVar -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 -- | Return the variable name or value of the 'LlvmVar'
 -- in a plain textual representation (e.g. @x@, @y@ or @42@).
-ppPlainName :: LlvmCgConfig -> LlvmVar -> SDoc
+ppPlainName :: IsLine doc => LlvmCgConfig -> LlvmVar -> doc
 ppPlainName opts v = case v of
    (LMGlobalVar x _ _ _ _ _) -> ftext x
    (LMLocalVar  x LMLabel  ) -> pprUniqueAlways x
    (LMLocalVar  x _        ) -> char 'l' <> pprUniqueAlways x
    (LMNLocalVar x _        ) -> ftext x
    (LMLitVar    x          ) -> ppLit opts x
+{-# SPECIALIZE ppPlainName :: LlvmCgConfig -> LlvmVar -> SDoc #-}
+{-# SPECIALIZE ppPlainName :: LlvmCgConfig -> LlvmVar -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 -- | Print a literal value. No type.
-ppLit :: LlvmCgConfig -> LlvmLit -> SDoc
+ppLit :: IsLine doc => LlvmCgConfig -> LlvmLit -> doc
 ppLit opts l = case l of
-   (LMIntLit i (LMInt 32))  -> ppr (fromInteger i :: Int32)
-   (LMIntLit i (LMInt 64))  -> ppr (fromInteger i :: Int64)
-   (LMIntLit   i _       )  -> ppr ((fromInteger i)::Int)
+   (LMIntLit   i _       )  -> integer i
    (LMFloatLit r LMFloat )  -> ppFloat (llvmCgPlatform opts) $ narrowFp r
    (LMFloatLit r LMDouble)  -> ppDouble (llvmCgPlatform opts) r
    f@(LMFloatLit _ _)       -> pprPanic "ppLit" (text "Can't print this float literal: " <> ppTypeLit opts f)
-   (LMVectorLit ls  )       -> char '<' <+> ppCommaJoin (map (ppTypeLit opts) ls) <+> char '>'
+   (LMVectorLit ls  )       -> char '<' <+> ppCommaJoin (ppTypeLit opts) ls <+> char '>'
    (LMNullLit _     )       -> text "null"
    -- #11487 was an issue where we passed undef for some arguments
    -- that were actually live. By chance the registers holding those
@@ -544,61 +638,76 @@ ppLit opts l = case l of
       | llvmCgFillUndefWithGarbage opts
       , Just lit <- garbageLit t   -> ppLit opts lit
       | otherwise                  -> text "undef"
+{-# SPECIALIZE ppLit :: LlvmCgConfig -> LlvmLit -> SDoc #-}
+{-# SPECIALIZE ppLit :: LlvmCgConfig -> LlvmLit -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-ppVar :: LlvmCgConfig -> LlvmVar -> SDoc
+ppVar :: IsLine doc => LlvmCgConfig -> LlvmVar -> doc
 ppVar = ppVar' []
+{-# SPECIALIZE ppVar :: LlvmCgConfig -> LlvmVar -> SDoc #-}
+{-# SPECIALIZE ppVar :: LlvmCgConfig -> LlvmVar -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-ppVar' :: [LlvmParamAttr] -> LlvmCgConfig -> LlvmVar -> SDoc
+ppVar' :: IsLine doc => [LlvmParamAttr] -> LlvmCgConfig -> LlvmVar -> doc
 ppVar' attrs opts v = case v of
   LMLitVar x -> ppTypeLit' attrs opts x
-  x          -> ppr (getVarType x) <+> ppSpaceJoin attrs <+> ppName opts x
+  x          -> ppLlvmType (getVarType x) <+> ppSpaceJoin ppLlvmParamAttr attrs <+> ppName opts x
+{-# SPECIALIZE ppVar' :: [LlvmParamAttr] -> LlvmCgConfig -> LlvmVar -> SDoc #-}
+{-# SPECIALIZE ppVar' :: [LlvmParamAttr] -> LlvmCgConfig -> LlvmVar -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-ppTypeLit :: LlvmCgConfig -> LlvmLit -> SDoc
+ppTypeLit :: IsLine doc => LlvmCgConfig -> LlvmLit -> doc
 ppTypeLit = ppTypeLit' []
+{-# SPECIALIZE ppTypeLit :: LlvmCgConfig -> LlvmLit -> SDoc #-}
+{-# SPECIALIZE ppTypeLit :: LlvmCgConfig -> LlvmLit -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-ppTypeLit' :: [LlvmParamAttr] -> LlvmCgConfig -> LlvmLit -> SDoc
+ppTypeLit' :: IsLine doc => [LlvmParamAttr] -> LlvmCgConfig -> LlvmLit -> doc
 ppTypeLit' attrs opts l = case l of
   LMVectorLit {} -> ppLit opts l
-  _              -> ppr (getLitType l) <+> ppSpaceJoin attrs <+> ppLit opts l
+  _              -> ppLlvmType (getLitType l) <+> ppSpaceJoin ppLlvmParamAttr attrs <+> ppLit opts l
+{-# SPECIALIZE ppTypeLit' :: [LlvmParamAttr] -> LlvmCgConfig -> LlvmLit -> SDoc #-}
+{-# SPECIALIZE ppTypeLit' :: [LlvmParamAttr] -> LlvmCgConfig -> LlvmLit -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-ppStatic :: LlvmCgConfig -> LlvmStatic -> SDoc
+ppStatic :: IsLine doc => LlvmCgConfig -> LlvmStatic -> doc
 ppStatic opts st = case st of
   LMComment       s -> text "; " <> ftext s
   LMStaticLit   l   -> ppTypeLit opts l
-  LMUninitType    t -> ppr t <> text " undef"
-  LMStaticStr   s t -> ppr t <> text " c\"" <> ftext s <> text "\\00\""
-  LMStaticArray d t -> ppr t <> text " [" <> ppCommaJoin (map (ppStatic opts) d) <> char ']'
-  LMStaticStruc d t -> ppr t <> text "<{" <> ppCommaJoin (map (ppStatic opts) d) <> text "}>"
-  LMStaticStrucU d t -> ppr t <> text "{" <> ppCommaJoin (map (ppStatic opts) d) <> text "}"
+  LMUninitType    t -> ppLlvmType t <> text " undef"
+  LMStaticStr   s t -> ppLlvmType t <> text " c\"" <> ftext s <> text "\\00\""
+  LMStaticArray d t -> ppLlvmType t <> text " [" <> ppCommaJoin (ppStatic opts) d <> char ']'
+  LMStaticStruc d t -> ppLlvmType t <> text "<{" <> ppCommaJoin (ppStatic opts) d <> text "}>"
+  LMStaticStrucU d t -> ppLlvmType t <> text "{" <> ppCommaJoin (ppStatic opts) d <> text "}"
   LMStaticPointer v -> ppVar opts v
-  LMTrunc v t       -> ppr t <> text " trunc (" <> ppStatic opts v <> text " to " <> ppr t <> char ')'
-  LMBitc v t        -> ppr t <> text " bitcast (" <> ppStatic opts v <> text " to " <> ppr t <> char ')'
-  LMPtoI v t        -> ppr t <> text " ptrtoint (" <> ppStatic opts v <> text " to " <> ppr t <> char ')'
+  LMTrunc v t       -> ppLlvmType t <> text " trunc (" <> ppStatic opts v <> text " to " <> ppLlvmType t <> char ')'
+  LMBitc v t        -> ppLlvmType t <> text " bitcast (" <> ppStatic opts v <> text " to " <> ppLlvmType t <> char ')'
+  LMPtoI v t        -> ppLlvmType t <> text " ptrtoint (" <> ppStatic opts v <> text " to " <> ppLlvmType t <> char ')'
   LMAdd s1 s2       -> pprStaticArith opts s1 s2 (text "add") (text "fadd") (text "LMAdd")
   LMSub s1 s2       -> pprStaticArith opts s1 s2 (text "sub") (text "fsub") (text "LMSub")
+{-# SPECIALIZE ppStatic :: LlvmCgConfig -> LlvmStatic -> SDoc #-}
+{-# SPECIALIZE ppStatic :: LlvmCgConfig -> LlvmStatic -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
-pprSpecialStatic :: LlvmCgConfig -> LlvmStatic -> SDoc
+pprSpecialStatic :: IsLine doc => LlvmCgConfig -> LlvmStatic -> doc
 pprSpecialStatic opts stat = case stat of
-   LMBitc v t        -> ppr (pLower t)
+   LMBitc v t        -> ppLlvmType (pLower t)
                         <> text ", bitcast ("
-                        <> ppStatic opts v <> text " to " <> ppr t
+                        <> ppStatic opts v <> text " to " <> ppLlvmType t
                         <> char ')'
-   LMStaticPointer x -> ppr (pLower $ getVarType x)
+   LMStaticPointer x -> ppLlvmType (pLower $ getVarType x)
                         <> comma <+> ppStatic opts stat
    _                 -> ppStatic opts stat
+{-# SPECIALIZE pprSpecialStatic :: LlvmCgConfig -> LlvmStatic -> SDoc #-}
+{-# SPECIALIZE pprSpecialStatic :: LlvmCgConfig -> LlvmStatic -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
-pprStaticArith :: LlvmCgConfig -> LlvmStatic -> LlvmStatic -> SDoc -> SDoc
-                  -> SDoc -> SDoc
+pprStaticArith :: IsLine doc => LlvmCgConfig -> LlvmStatic -> LlvmStatic -> doc -> doc -> SDoc -> doc
 pprStaticArith opts s1 s2 int_op float_op op_name =
   let ty1 = getStatType s1
       op  = if isFloat ty1 then float_op else int_op
   in if ty1 == getStatType s2
-     then ppr ty1 <+> op <+> lparen <> ppStatic opts s1 <> comma <> ppStatic opts s2 <> rparen
+     then ppLlvmType ty1 <+> op <+> lparen <> ppStatic opts s1 <> comma <> ppStatic opts s2 <> rparen
      else pprPanic "pprStaticArith" $
                  op_name <> text " with different types! s1: " <> ppStatic opts s1
                          <> text", s2: " <> ppStatic opts s2
+{-# SPECIALIZE pprStaticArith :: LlvmCgConfig -> LlvmStatic -> LlvmStatic -> SDoc -> SDoc -> SDoc -> SDoc #-}
+{-# SPECIALIZE pprStaticArith :: LlvmCgConfig -> LlvmStatic -> LlvmStatic -> HLine -> HLine -> SDoc -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
 --------------------------------------------------------------------------------
@@ -606,9 +715,13 @@ pprStaticArith opts s1 s2 int_op float_op op_name =
 --------------------------------------------------------------------------------
 
 -- | Blank line.
-newLine :: SDoc
+newLine :: IsDoc doc => doc
 newLine = empty
+{-# SPECIALIZE newLine :: SDoc #-}
+{-# SPECIALIZE newLine :: HDoc #-}
 
 -- | Exclamation point.
-exclamation :: SDoc
+exclamation :: IsLine doc => doc
 exclamation = char '!'
+{-# SPECIALIZE exclamation :: SDoc #-}
+{-# SPECIALIZE exclamation :: HLine #-}


=====================================
compiler/GHC/Llvm/Syntax.hs
=====================================
@@ -150,7 +150,7 @@ data LlvmStatement
       * value: Variable/Constant to store.
       * ptr:   Location to store the value in
   -}
-  | Store LlvmVar LlvmVar LMAlign
+  | Store LlvmVar LlvmVar LMAlign [MetaAnnot]
 
   {- |
     Multiway branch
@@ -186,11 +186,6 @@ data LlvmStatement
   -}
   | Nop
 
-  {- |
-    A LLVM statement with metadata attached to it.
-  -}
-  | MetaStmt [MetaAnnot] LlvmStatement
-
   deriving (Eq)
 
 


=====================================
compiler/GHC/Llvm/Types.hs
=====================================
@@ -1,6 +1,13 @@
 
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE LambdaCase #-}
 
+-- Workaround for #21972. It can be removed once the minimal bootstrapping
+-- compiler has a fix for this bug.
+#if defined(darwin_HOST_OS)
+{-# OPTIONS_GHC -fno-asm-shortcutting #-}
+#endif
+
 --------------------------------------------------------------------------------
 -- | The LLVM Type System.
 --
@@ -61,28 +68,30 @@ data LlvmType
   deriving (Eq)
 
 instance Outputable LlvmType where
-  ppr = ppType
+  ppr = ppLlvmType
 
-ppType :: LlvmType -> SDoc
-ppType t = case t of
-  LMInt size     -> char 'i' <> ppr size
+ppLlvmType :: IsLine doc => LlvmType -> doc
+ppLlvmType t = case t of
+  LMInt size     -> char 'i' <> int size
   LMFloat        -> text "float"
   LMDouble       -> text "double"
   LMFloat80      -> text "x86_fp80"
   LMFloat128     -> text "fp128"
-  LMPointer x    -> ppr x <> char '*'
-  LMArray nr tp  -> char '[' <> ppr nr <> text " x " <> ppr tp <> char ']'
-  LMVector nr tp -> char '<' <> ppr nr <> text " x " <> ppr tp <> char '>'
+  LMPointer x    -> ppLlvmType x <> char '*'
+  LMArray nr tp  -> char '[' <> int nr <> text " x " <> ppLlvmType tp <> char ']'
+  LMVector nr tp -> char '<' <> int nr <> text " x " <> ppLlvmType tp <> char '>'
   LMLabel        -> text "label"
   LMVoid         -> text "void"
-  LMStruct tys   -> text "<{" <> ppCommaJoin tys <> text "}>"
-  LMStructU tys  -> text "{" <> ppCommaJoin tys <> text "}"
+  LMStruct tys   -> text "<{" <> ppCommaJoin ppLlvmType tys <> text "}>"
+  LMStructU tys  -> text "{" <> ppCommaJoin ppLlvmType tys <> text "}"
   LMMetadata     -> text "metadata"
   LMAlias (s,_)  -> char '%' <> ftext s
   LMFunction (LlvmFunctionDecl _ _ _ r varg p _)
-    -> ppr r <+> lparen <> ppParams varg p <> rparen
+    -> ppLlvmType r <+> lparen <> ppParams varg p <> rparen
+{-# SPECIALIZE ppLlvmType :: LlvmType -> SDoc #-}
+{-# SPECIALIZE ppLlvmType :: LlvmType -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-ppParams :: LlvmParameterListType -> [LlvmParameter] -> SDoc
+ppParams :: IsLine doc => LlvmParameterListType -> [LlvmParameter] -> doc
 ppParams varg p
   = let varg' = case varg of
           VarArgs | null args -> text "..."
@@ -90,7 +99,9 @@ ppParams varg p
           _otherwise          -> text ""
         -- by default we don't print param attributes
         args = map fst p
-    in ppCommaJoin args <> varg'
+    in ppCommaJoin ppLlvmType args <> varg'
+{-# SPECIALIZE ppParams :: LlvmParameterListType -> [LlvmParameter] -> SDoc #-}
+{-# SPECIALIZE ppParams :: LlvmParameterListType -> [LlvmParameter] -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 -- | An LLVM section definition. If Nothing then let LLVM decide the section
 type LMSection = Maybe LMString
@@ -337,14 +348,6 @@ data LlvmFunctionDecl = LlvmFunctionDecl {
   }
   deriving (Eq)
 
-instance Outputable LlvmFunctionDecl where
-  ppr (LlvmFunctionDecl n l c r varg p a)
-    = let align = case a of
-                       Just a' -> text " align " <> ppr a'
-                       Nothing -> empty
-      in ppr l <+> ppr c <+> ppr r <+> char '@' <> ftext n <>
-             lparen <> ppParams varg p <> rparen <> align
-
 type LlvmFunctionDecls = [LlvmFunctionDecl]
 
 type LlvmParameter = (LlvmType, [LlvmParamAttr])
@@ -385,14 +388,19 @@ data LlvmParamAttr
   deriving (Eq)
 
 instance Outputable LlvmParamAttr where
-  ppr ZeroExt   = text "zeroext"
-  ppr SignExt   = text "signext"
-  ppr InReg     = text "inreg"
-  ppr ByVal     = text "byval"
-  ppr SRet      = text "sret"
-  ppr NoAlias   = text "noalias"
-  ppr NoCapture = text "nocapture"
-  ppr Nest      = text "nest"
+  ppr = ppLlvmParamAttr
+
+ppLlvmParamAttr :: IsLine doc => LlvmParamAttr -> doc
+ppLlvmParamAttr ZeroExt   = text "zeroext"
+ppLlvmParamAttr SignExt   = text "signext"
+ppLlvmParamAttr InReg     = text "inreg"
+ppLlvmParamAttr ByVal     = text "byval"
+ppLlvmParamAttr SRet      = text "sret"
+ppLlvmParamAttr NoAlias   = text "noalias"
+ppLlvmParamAttr NoCapture = text "nocapture"
+ppLlvmParamAttr Nest      = text "nest"
+{-# SPECIALIZE ppLlvmParamAttr :: LlvmParamAttr -> SDoc #-}
+{-# SPECIALIZE ppLlvmParamAttr :: LlvmParamAttr -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 -- | Llvm Function Attributes.
 --
@@ -473,19 +481,24 @@ data LlvmFuncAttr
   deriving (Eq)
 
 instance Outputable LlvmFuncAttr where
-  ppr AlwaysInline       = text "alwaysinline"
-  ppr InlineHint         = text "inlinehint"
-  ppr NoInline           = text "noinline"
-  ppr OptSize            = text "optsize"
-  ppr NoReturn           = text "noreturn"
-  ppr NoUnwind           = text "nounwind"
-  ppr ReadNone           = text "readnone"
-  ppr ReadOnly           = text "readonly"
-  ppr Ssp                = text "ssp"
-  ppr SspReq             = text "ssqreq"
-  ppr NoRedZone          = text "noredzone"
-  ppr NoImplicitFloat    = text "noimplicitfloat"
-  ppr Naked              = text "naked"
+  ppr = ppLlvmFuncAttr
+
+ppLlvmFuncAttr :: IsLine doc => LlvmFuncAttr -> doc
+ppLlvmFuncAttr AlwaysInline       = text "alwaysinline"
+ppLlvmFuncAttr InlineHint         = text "inlinehint"
+ppLlvmFuncAttr NoInline           = text "noinline"
+ppLlvmFuncAttr OptSize            = text "optsize"
+ppLlvmFuncAttr NoReturn           = text "noreturn"
+ppLlvmFuncAttr NoUnwind           = text "nounwind"
+ppLlvmFuncAttr ReadNone           = text "readnone"
+ppLlvmFuncAttr ReadOnly           = text "readonly"
+ppLlvmFuncAttr Ssp                = text "ssp"
+ppLlvmFuncAttr SspReq             = text "ssqreq"
+ppLlvmFuncAttr NoRedZone          = text "noredzone"
+ppLlvmFuncAttr NoImplicitFloat    = text "noimplicitfloat"
+ppLlvmFuncAttr Naked              = text "naked"
+{-# SPECIALIZE ppLlvmFuncAttr :: LlvmFuncAttr -> SDoc #-}
+{-# SPECIALIZE ppLlvmFuncAttr :: LlvmFuncAttr -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
 -- | Different types to call a function.
@@ -533,12 +546,17 @@ data LlvmCallConvention
   deriving (Eq)
 
 instance Outputable LlvmCallConvention where
-  ppr CC_Ccc       = text "ccc"
-  ppr CC_Fastcc    = text "fastcc"
-  ppr CC_Coldcc    = text "coldcc"
-  ppr CC_Ghc       = text "ghccc"
-  ppr (CC_Ncc i)   = text "cc " <> ppr i
-  ppr CC_X86_Stdcc = text "x86_stdcallcc"
+  ppr = ppLlvmCallConvention
+
+ppLlvmCallConvention :: IsLine doc => LlvmCallConvention -> doc
+ppLlvmCallConvention CC_Ccc       = text "ccc"
+ppLlvmCallConvention CC_Fastcc    = text "fastcc"
+ppLlvmCallConvention CC_Coldcc    = text "coldcc"
+ppLlvmCallConvention CC_Ghc       = text "ghccc"
+ppLlvmCallConvention (CC_Ncc i)   = text "cc " <> int i
+ppLlvmCallConvention CC_X86_Stdcc = text "x86_stdcallcc"
+{-# SPECIALIZE ppLlvmCallConvention :: LlvmCallConvention -> SDoc #-}
+{-# SPECIALIZE ppLlvmCallConvention :: LlvmCallConvention -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
 -- | Functions can have a fixed amount of parameters, or a variable amount.
@@ -597,17 +615,22 @@ data LlvmLinkageType
   deriving (Eq)
 
 instance Outputable LlvmLinkageType where
-  ppr Internal          = text "internal"
-  ppr LinkOnce          = text "linkonce"
-  ppr Weak              = text "weak"
-  ppr Appending         = text "appending"
-  ppr ExternWeak        = text "extern_weak"
-  -- ExternallyVisible does not have a textual representation, it is
-  -- the linkage type a function resolves to if no other is specified
-  -- in Llvm.
-  ppr ExternallyVisible = empty
-  ppr External          = text "external"
-  ppr Private           = text "private"
+  ppr = ppLlvmLinkageType
+
+ppLlvmLinkageType :: IsLine doc => LlvmLinkageType -> doc
+ppLlvmLinkageType Internal          = text "internal"
+ppLlvmLinkageType LinkOnce          = text "linkonce"
+ppLlvmLinkageType Weak              = text "weak"
+ppLlvmLinkageType Appending         = text "appending"
+ppLlvmLinkageType ExternWeak        = text "extern_weak"
+-- ExternallyVisible does not have a textual representation, it is
+-- the linkage type a function resolves to if no other is specified
+-- in Llvm.
+ppLlvmLinkageType ExternallyVisible = empty
+ppLlvmLinkageType External          = text "external"
+ppLlvmLinkageType Private           = text "private"
+{-# SPECIALIZE ppLlvmLinkageType :: LlvmLinkageType -> SDoc #-}
+{-# SPECIALIZE ppLlvmLinkageType :: LlvmLinkageType -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 -- -----------------------------------------------------------------------------
 -- * LLVM Operations
@@ -645,24 +668,29 @@ data LlvmMachOp
   deriving (Eq)
 
 instance Outputable LlvmMachOp where
-  ppr LM_MO_Add  = text "add"
-  ppr LM_MO_Sub  = text "sub"
-  ppr LM_MO_Mul  = text "mul"
-  ppr LM_MO_UDiv = text "udiv"
-  ppr LM_MO_SDiv = text "sdiv"
-  ppr LM_MO_URem = text "urem"
-  ppr LM_MO_SRem = text "srem"
-  ppr LM_MO_FAdd = text "fadd"
-  ppr LM_MO_FSub = text "fsub"
-  ppr LM_MO_FMul = text "fmul"
-  ppr LM_MO_FDiv = text "fdiv"
-  ppr LM_MO_FRem = text "frem"
-  ppr LM_MO_Shl  = text "shl"
-  ppr LM_MO_LShr = text "lshr"
-  ppr LM_MO_AShr = text "ashr"
-  ppr LM_MO_And  = text "and"
-  ppr LM_MO_Or   = text "or"
-  ppr LM_MO_Xor  = text "xor"
+  ppr = ppLlvmMachOp
+
+ppLlvmMachOp :: IsLine doc => LlvmMachOp -> doc
+ppLlvmMachOp LM_MO_Add  = text "add"
+ppLlvmMachOp LM_MO_Sub  = text "sub"
+ppLlvmMachOp LM_MO_Mul  = text "mul"
+ppLlvmMachOp LM_MO_UDiv = text "udiv"
+ppLlvmMachOp LM_MO_SDiv = text "sdiv"
+ppLlvmMachOp LM_MO_URem = text "urem"
+ppLlvmMachOp LM_MO_SRem = text "srem"
+ppLlvmMachOp LM_MO_FAdd = text "fadd"
+ppLlvmMachOp LM_MO_FSub = text "fsub"
+ppLlvmMachOp LM_MO_FMul = text "fmul"
+ppLlvmMachOp LM_MO_FDiv = text "fdiv"
+ppLlvmMachOp LM_MO_FRem = text "frem"
+ppLlvmMachOp LM_MO_Shl  = text "shl"
+ppLlvmMachOp LM_MO_LShr = text "lshr"
+ppLlvmMachOp LM_MO_AShr = text "ashr"
+ppLlvmMachOp LM_MO_And  = text "and"
+ppLlvmMachOp LM_MO_Or   = text "or"
+ppLlvmMachOp LM_MO_Xor  = text "xor"
+{-# SPECIALIZE ppLlvmMachOp :: LlvmMachOp -> SDoc #-}
+{-# SPECIALIZE ppLlvmMachOp :: LlvmMachOp -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
 -- | Llvm compare operations.
@@ -689,22 +717,27 @@ data LlvmCmpOp
   deriving (Eq)
 
 instance Outputable LlvmCmpOp where
-  ppr LM_CMP_Eq  = text "eq"
-  ppr LM_CMP_Ne  = text "ne"
-  ppr LM_CMP_Ugt = text "ugt"
-  ppr LM_CMP_Uge = text "uge"
-  ppr LM_CMP_Ult = text "ult"
-  ppr LM_CMP_Ule = text "ule"
-  ppr LM_CMP_Sgt = text "sgt"
-  ppr LM_CMP_Sge = text "sge"
-  ppr LM_CMP_Slt = text "slt"
-  ppr LM_CMP_Sle = text "sle"
-  ppr LM_CMP_Feq = text "oeq"
-  ppr LM_CMP_Fne = text "une"
-  ppr LM_CMP_Fgt = text "ogt"
-  ppr LM_CMP_Fge = text "oge"
-  ppr LM_CMP_Flt = text "olt"
-  ppr LM_CMP_Fle = text "ole"
+  ppr = ppLlvmCmpOp
+
+ppLlvmCmpOp :: IsLine doc => LlvmCmpOp -> doc
+ppLlvmCmpOp LM_CMP_Eq  = text "eq"
+ppLlvmCmpOp LM_CMP_Ne  = text "ne"
+ppLlvmCmpOp LM_CMP_Ugt = text "ugt"
+ppLlvmCmpOp LM_CMP_Uge = text "uge"
+ppLlvmCmpOp LM_CMP_Ult = text "ult"
+ppLlvmCmpOp LM_CMP_Ule = text "ule"
+ppLlvmCmpOp LM_CMP_Sgt = text "sgt"
+ppLlvmCmpOp LM_CMP_Sge = text "sge"
+ppLlvmCmpOp LM_CMP_Slt = text "slt"
+ppLlvmCmpOp LM_CMP_Sle = text "sle"
+ppLlvmCmpOp LM_CMP_Feq = text "oeq"
+ppLlvmCmpOp LM_CMP_Fne = text "une"
+ppLlvmCmpOp LM_CMP_Fgt = text "ogt"
+ppLlvmCmpOp LM_CMP_Fge = text "oge"
+ppLlvmCmpOp LM_CMP_Flt = text "olt"
+ppLlvmCmpOp LM_CMP_Fle = text "ole"
+{-# SPECIALIZE ppLlvmCmpOp :: LlvmCmpOp -> SDoc #-}
+{-# SPECIALIZE ppLlvmCmpOp :: LlvmCmpOp -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
 -- | Llvm cast operations.
@@ -724,18 +757,23 @@ data LlvmCastOp
   deriving (Eq)
 
 instance Outputable LlvmCastOp where
-  ppr LM_Trunc    = text "trunc"
-  ppr LM_Zext     = text "zext"
-  ppr LM_Sext     = text "sext"
-  ppr LM_Fptrunc  = text "fptrunc"
-  ppr LM_Fpext    = text "fpext"
-  ppr LM_Fptoui   = text "fptoui"
-  ppr LM_Fptosi   = text "fptosi"
-  ppr LM_Uitofp   = text "uitofp"
-  ppr LM_Sitofp   = text "sitofp"
-  ppr LM_Ptrtoint = text "ptrtoint"
-  ppr LM_Inttoptr = text "inttoptr"
-  ppr LM_Bitcast  = text "bitcast"
+  ppr = ppLlvmCastOp
+
+ppLlvmCastOp :: IsLine doc => LlvmCastOp -> doc
+ppLlvmCastOp LM_Trunc    = text "trunc"
+ppLlvmCastOp LM_Zext     = text "zext"
+ppLlvmCastOp LM_Sext     = text "sext"
+ppLlvmCastOp LM_Fptrunc  = text "fptrunc"
+ppLlvmCastOp LM_Fpext    = text "fpext"
+ppLlvmCastOp LM_Fptoui   = text "fptoui"
+ppLlvmCastOp LM_Fptosi   = text "fptosi"
+ppLlvmCastOp LM_Uitofp   = text "uitofp"
+ppLlvmCastOp LM_Sitofp   = text "sitofp"
+ppLlvmCastOp LM_Ptrtoint = text "ptrtoint"
+ppLlvmCastOp LM_Inttoptr = text "inttoptr"
+ppLlvmCastOp LM_Bitcast  = text "bitcast"
+{-# SPECIALIZE ppLlvmCastOp :: LlvmCastOp -> SDoc #-}
+{-# SPECIALIZE ppLlvmCastOp :: LlvmCastOp -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
 -- -----------------------------------------------------------------------------
@@ -747,7 +785,7 @@ instance Outputable LlvmCastOp where
 -- regardless of underlying architecture.
 --
 -- See Note [LLVM Float Types].
-ppDouble :: Platform -> Double -> SDoc
+ppDouble :: IsLine doc => Platform -> Double -> doc
 ppDouble platform d
   = let bs     = doubleToBytes d
         hex d' = case showHex d' "" of
@@ -761,6 +799,8 @@ ppDouble platform d
             LittleEndian -> reverse
         str       = map toUpper $ concat $ fixEndian $ map hex bs
     in text "0x" <> text str
+{-# SPECIALIZE ppDouble :: Platform -> Double -> SDoc #-}
+{-# SPECIALIZE ppDouble :: Platform -> Double -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 -- Note [LLVM Float Types]
 -- ~~~~~~~~~~~~~~~~~~~~~~~
@@ -787,16 +827,22 @@ widenFp :: Float -> Double
 {-# NOINLINE widenFp #-}
 widenFp = float2Double
 
-ppFloat :: Platform -> Float -> SDoc
+ppFloat :: IsLine doc => Platform -> Float -> doc
 ppFloat platform = ppDouble platform . widenFp
+{-# SPECIALIZE ppFloat :: Platform -> Float -> SDoc #-}
+{-# SPECIALIZE ppFloat :: Platform -> Float -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
 
 --------------------------------------------------------------------------------
 -- * Misc functions
 --------------------------------------------------------------------------------
 
-ppCommaJoin :: (Outputable a) => [a] -> SDoc
-ppCommaJoin strs = hsep $ punctuate comma (map ppr strs)
+ppCommaJoin :: IsLine doc => (a -> doc) -> [a] -> doc
+ppCommaJoin ppr strs = hsep $ punctuate comma (map ppr strs)
+{-# SPECIALIZE ppCommaJoin :: (a -> SDoc) -> [a] -> SDoc #-}
+{-# SPECIALIZE ppCommaJoin :: (a -> HLine) -> [a] -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
 
-ppSpaceJoin :: (Outputable a) => [a] -> SDoc
-ppSpaceJoin strs = hsep (map ppr strs)
+ppSpaceJoin :: IsLine doc => (a -> doc) -> [a] -> doc
+ppSpaceJoin ppr strs = hsep (map ppr strs)
+{-# SPECIALIZE ppSpaceJoin :: (a -> SDoc) -> [a] -> SDoc #-}
+{-# SPECIALIZE ppSpaceJoin :: (a -> HLine) -> [a] -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/e8b4aac437b2620d93546a57eb5818f317a4549e

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/e8b4aac437b2620d93546a57eb5818f317a4549e
You're receiving this email because of your account on gitlab.haskell.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20230321/49446dbd/attachment-0001.html>


More information about the ghc-commits mailing list