Ppr.hs 31.6 KB
Newer Older
Sylvain Henry's avatar
Sylvain Henry committed
1 2
{-# LANGUAGE LambdaCase #-}

3 4 5 6 7 8 9 10
-----------------------------------------------------------------------------
--
-- Pretty-printing assembly language
--
-- (c) The University of Glasgow 1993-2005
--
-----------------------------------------------------------------------------

11 12 13 14 15
module GHC.CmmToAsm.PPC.Ppr
   ( pprNatCmmDecl
   , pprInstr
   )
where
16

17
import GHC.Prelude
18

Sylvain Henry's avatar
Sylvain Henry committed
19 20 21 22 23 24 25 26
import GHC.CmmToAsm.PPC.Regs
import GHC.CmmToAsm.PPC.Instr
import GHC.CmmToAsm.PPC.Cond
import GHC.CmmToAsm.Ppr
import GHC.CmmToAsm.Format
import GHC.Platform.Reg
import GHC.Platform.Reg.Class
import GHC.CmmToAsm.Reg.Target
27
import GHC.CmmToAsm.Config
28 29
import GHC.CmmToAsm.Types
import GHC.CmmToAsm.Utils
30

31 32 33
import GHC.Cmm hiding (topInfoTable)
import GHC.Cmm.Dataflow.Collections
import GHC.Cmm.Dataflow.Label
34

35 36 37
import GHC.Cmm.BlockId
import GHC.Cmm.CLabel
import GHC.Cmm.Ppr.Expr () -- For Outputable instances
38

Sylvain Henry's avatar
Sylvain Henry committed
39
import GHC.Types.Unique ( pprUniqueAlways, getUnique )
John Ericson's avatar
John Ericson committed
40
import GHC.Platform
41 42
import GHC.Data.FastString
import GHC.Utils.Outputable
43
import GHC.Utils.Panic
44

45
import Data.Word
46
import Data.Int
47 48
import Data.Bits

49 50 51
-- -----------------------------------------------------------------------------
-- Printing this stuff out

52 53 54 55
pprNatCmmDecl :: NCGConfig -> NatCmmDecl RawCmmStatics Instr -> SDoc
pprNatCmmDecl config (CmmData section dats) =
  pprSectionAlign config section
  $$ pprDatas (ncgPlatform config) dats
56

57 58
pprNatCmmDecl config proc@(CmmProc top_info lbl _ (ListGraph blocks)) =
  let platform = ncgPlatform config in
59 60
  case topInfoTable proc of
    Nothing ->
Ben Gamari's avatar
Ben Gamari committed
61
         -- special case for code without info table:
62
         pprSectionAlign config (Section Text lbl) $$
Ben Gamari's avatar
Ben Gamari committed
63
         (case platformArch platform of
Sylvain Henry's avatar
Sylvain Henry committed
64 65
            ArchPPC_64 ELF_V1 -> pprFunctionDescriptor platform lbl
            ArchPPC_64 ELF_V2 -> pprFunctionPrologue platform lbl
66 67
            _ -> pprLabel platform lbl) $$ -- blocks guaranteed not null,
                                           -- so label needed
68
         vcat (map (pprBasicBlock config top_info) blocks) $$
69 70 71
         ppWhen (ncgDwarfEnabled config) (pdoc platform (mkAsmTempEndLabel lbl)
                                          <> char ':' $$
                                          pprProcEndLabel platform lbl) $$
72
         pprSizeDecl platform lbl
73

Sylvain Henry's avatar
Sylvain Henry committed
74
    Just (CmmStaticsRaw info_lbl _) ->
75
      pprSectionAlign config (Section Text info_lbl) $$
76
      (if platformHasSubsectionsViaSymbols platform
Sylvain Henry's avatar
Sylvain Henry committed
77
          then pdoc platform (mkDeadStripPreventer info_lbl) <> char ':'
78
          else empty) $$
79
      vcat (map (pprBasicBlock config top_info) blocks) $$
80 81 82 83
      -- above: Even the first block gets a label, because with branch-chain
      -- elimination, it might be the target of a goto.
      (if platformHasSubsectionsViaSymbols platform
       then
84
       -- See Note [Subsections Via Symbols] in X86/Ppr.hs
85
                text "\t.long "
Sylvain Henry's avatar
Sylvain Henry committed
86
            <+> pdoc platform info_lbl
87
            <+> char '-'
Sylvain Henry's avatar
Sylvain Henry committed
88
            <+> pdoc platform (mkDeadStripPreventer info_lbl)
89 90 91 92 93 94 95
       else empty) $$
      pprSizeDecl platform info_lbl

-- | Output the ELF .size directive.
pprSizeDecl :: Platform -> CLabel -> SDoc
pprSizeDecl platform lbl
 = if osElfTarget (platformOS platform)
96
   then text "\t.size" <+> prettyLbl <> text ", .-" <> codeLbl
97
   else empty
98
  where
Sylvain Henry's avatar
Sylvain Henry committed
99
    prettyLbl = pdoc platform lbl
100 101 102
    codeLbl
      | platformArch platform == ArchPPC_64 ELF_V1 = char '.' <> prettyLbl
      | otherwise                                  = prettyLbl
103

Sylvain Henry's avatar
Sylvain Henry committed
104 105
pprFunctionDescriptor :: Platform -> CLabel -> SDoc
pprFunctionDescriptor platform lab = pprGloblDecl platform lab
106 107
                        $$  text "\t.section \".opd\", \"aw\""
                        $$  text "\t.align 3"
Sylvain Henry's avatar
Sylvain Henry committed
108
                        $$  pdoc platform lab <> char ':'
109
                        $$  text "\t.quad ."
Sylvain Henry's avatar
Sylvain Henry committed
110
                        <>  pdoc platform lab
111 112 113
                        <>  text ",.TOC.@tocbase,0"
                        $$  text "\t.previous"
                        $$  text "\t.type"
Sylvain Henry's avatar
Sylvain Henry committed
114
                        <+> pdoc platform lab
115
                        <>  text ", @function"
Sylvain Henry's avatar
Sylvain Henry committed
116
                        $$  char '.' <> pdoc platform lab <> char ':'
117

Sylvain Henry's avatar
Sylvain Henry committed
118 119
pprFunctionPrologue :: Platform -> CLabel ->SDoc
pprFunctionPrologue platform lab =  pprGloblDecl platform lab
120
                        $$  text ".type "
Sylvain Henry's avatar
Sylvain Henry committed
121
                        <> pdoc platform lab
122
                        <> text ", @function"
Sylvain Henry's avatar
Sylvain Henry committed
123
                        $$ pdoc platform lab <> char ':'
124 125 126 127
                        $$ text "0:\taddis\t" <> pprReg toc
                        <> text ",12,.TOC.-0b@ha"
                        $$ text "\taddi\t" <> pprReg toc
                        <> char ',' <> pprReg toc <> text ",.TOC.-0b@l"
Sylvain Henry's avatar
Sylvain Henry committed
128 129
                        $$ text "\t.localentry\t" <> pdoc platform lab
                        <> text ",.-" <> pdoc platform lab
130

131 132 133 134 135
pprProcEndLabel :: Platform -> CLabel -- ^ Procedure name
                -> SDoc
pprProcEndLabel platform lbl =
    pdoc platform (mkAsmTempProcEndLabel lbl) <> char ':'

136 137 138
pprBasicBlock :: NCGConfig -> LabelMap RawCmmStatics -> NatBasicBlock Instr
              -> SDoc
pprBasicBlock config info_env (BasicBlock blockid instrs)
139
  = maybe_infotable $$
140 141
    pprLabel platform asmLbl $$
    vcat (map (pprInstr platform) instrs) $$
142 143 144
    ppWhen (ncgDwarfEnabled config) (
      pdoc platform (mkAsmTempEndLabel asmLbl) <> char ':'
      <> pprProcEndLabel platform asmLbl
145
    )
146
  where
147 148
    asmLbl = blockLbl blockid
    platform = ncgPlatform config
149 150
    maybe_infotable = case mapLookup blockid info_env of
       Nothing   -> empty
Sylvain Henry's avatar
Sylvain Henry committed
151
       Just (CmmStaticsRaw info_lbl info) ->
152 153 154
           pprAlignForSection platform Text $$
           vcat (map (pprData platform) info) $$
           pprLabel platform info_lbl
155 156


157

158
pprDatas :: Platform -> RawCmmStatics -> SDoc
159
-- See note [emit-time elimination of static indirections] in "GHC.Cmm.CLabel".
Sylvain Henry's avatar
Sylvain Henry committed
160
pprDatas platform (CmmStaticsRaw alias [CmmStaticLit (CmmLabel lbl), CmmStaticLit ind, _, _])
161 162 163 164 165 166
  | lbl == mkIndStaticInfoLabel
  , let labelInd (CmmLabelOff l _) = Just l
        labelInd (CmmLabel l) = Just l
        labelInd _ = Nothing
  , Just ind' <- labelInd ind
  , alias `mayRedirectTo` ind'
Sylvain Henry's avatar
Sylvain Henry committed
167 168
  = pprGloblDecl platform alias
    $$ text ".equiv" <+> pdoc platform alias <> comma <> pdoc platform (CmmLabel ind')
Sylvain Henry's avatar
Sylvain Henry committed
169
pprDatas platform (CmmStaticsRaw lbl dats) = vcat (pprLabel platform lbl : map (pprData platform) dats)
170

171 172
pprData :: Platform -> CmmStatic -> SDoc
pprData platform d = case d of
173 174
   CmmString str          -> pprString str
   CmmFileEmbed path      -> pprFileEmbed path
175 176
   CmmUninitialised bytes -> text ".space " <> int bytes
   CmmStaticLit lit       -> pprDataItem platform lit
177

Sylvain Henry's avatar
Sylvain Henry committed
178 179
pprGloblDecl :: Platform -> CLabel -> SDoc
pprGloblDecl platform lbl
180
  | not (externallyVisibleCLabel lbl) = empty
Sylvain Henry's avatar
Sylvain Henry committed
181
  | otherwise = text ".globl " <> pdoc platform lbl
182

183 184 185
pprTypeAndSizeDecl :: Platform -> CLabel -> SDoc
pprTypeAndSizeDecl platform lbl
  = if platformOS platform == OSLinux && externallyVisibleCLabel lbl
186
    then text ".type " <>
Sylvain Henry's avatar
Sylvain Henry committed
187
         pdoc platform lbl <> text ", @object"
188
    else empty
189

190 191
pprLabel :: Platform -> CLabel -> SDoc
pprLabel platform lbl =
Sylvain Henry's avatar
Sylvain Henry committed
192
   pprGloblDecl platform lbl
193
   $$ pprTypeAndSizeDecl platform lbl
Sylvain Henry's avatar
Sylvain Henry committed
194
   $$ (pdoc platform lbl <> char ':')
195 196 197 198

-- -----------------------------------------------------------------------------
-- pprInstr: print an 'Instr'

199
pprReg :: Reg -> SDoc
200

201
pprReg r
202
  = case r of
203 204
      RegReal    (RealRegSingle i) -> ppr_reg_no i
      RegReal    (RealRegPair{})   -> panic "PPC.pprReg: no reg pairs on this arch"
205 206 207 208
      RegVirtual (VirtualRegI  u)  -> text "%vI_"   <> pprUniqueAlways u
      RegVirtual (VirtualRegHi u)  -> text "%vHi_"  <> pprUniqueAlways u
      RegVirtual (VirtualRegF  u)  -> text "%vF_"   <> pprUniqueAlways u
      RegVirtual (VirtualRegD  u)  -> text "%vD_"   <> pprUniqueAlways u
209

210
  where
211
    ppr_reg_no :: Int -> SDoc
212 213 214 215
    ppr_reg_no i
         | i <= 31   = int i      -- GPRs
         | i <= 63   = int (i-32) -- FPRs
         | otherwise = text "very naughty powerpc register"
216 217 218



219 220
pprFormat :: Format -> SDoc
pprFormat x
221
 = ptext (case x of
222 223 224 225 226
                II8  -> sLit "b"
                II16 -> sLit "h"
                II32 -> sLit "w"
                II64 -> sLit "d"
                FF32 -> sLit "fs"
227
                FF64 -> sLit "fd")
228 229


230
pprCond :: Cond -> SDoc
231
pprCond c
232
 = ptext (case c of {
Erik de Castro Lopo's avatar
Erik de Castro Lopo committed
233
                ALWAYS  -> sLit "";
234
                EQQ     -> sLit "eq";  NE    -> sLit "ne";
Erik de Castro Lopo's avatar
Erik de Castro Lopo committed
235 236 237 238
                LTT     -> sLit "lt";  GE    -> sLit "ge";
                GTT     -> sLit "gt";  LE    -> sLit "le";
                LU      -> sLit "lt";  GEU   -> sLit "ge";
                GU      -> sLit "gt";  LEU   -> sLit "le"; })
239 240


Sylvain Henry's avatar
Sylvain Henry committed
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
pprImm :: Platform -> Imm -> SDoc
pprImm platform = \case
   ImmInt i       -> int i
   ImmInteger i   -> integer i
   ImmCLbl l      -> pdoc platform l
   ImmIndex l i   -> pdoc platform l <> char '+' <> int i
   ImmLit s       -> s
   ImmFloat f     -> float $ fromRational f
   ImmDouble d    -> double $ fromRational d
   ImmConstantSum a b   -> pprImm platform a <> char '+' <> pprImm platform b
   ImmConstantDiff a b  -> pprImm platform a <> char '-' <> lparen <> pprImm platform b <> rparen
   LO (ImmInt i)        -> pprImm platform (LO (ImmInteger (toInteger i)))
   LO (ImmInteger i)    -> pprImm platform (ImmInteger (toInteger lo16))
        where
          lo16 = fromInteger (i .&. 0xffff) :: Int16

   LO i              -> pprImm platform i <> text "@l"
   HI i              -> pprImm platform i <> text "@h"
   HA (ImmInt i)     -> pprImm platform (HA (ImmInteger (toInteger i)))
   HA (ImmInteger i) -> pprImm platform (ImmInteger ha16)
        where
          ha16 = if lo16 >= 0x8000 then hi16+1 else hi16
          hi16 = (i `shiftR` 16)
          lo16 = i .&. 0xffff

   HA i        -> pprImm platform i <> text "@ha"
   HIGHERA i   -> pprImm platform i <> text "@highera"
   HIGHESTA i  -> pprImm platform i <> text "@highesta"


pprAddr :: Platform -> AddrMode -> SDoc
pprAddr platform = \case
   AddrRegReg r1 r2             -> pprReg r1 <> char ',' <+> pprReg r2
   AddrRegImm r1 (ImmInt i)     -> hcat [ int i, char '(', pprReg r1, char ')' ]
   AddrRegImm r1 (ImmInteger i) -> hcat [ integer i, char '(', pprReg r1, char ')' ]
   AddrRegImm r1 imm            -> hcat [ pprImm platform imm, char '(', pprReg r1, char ')' ]
277 278


279 280 281 282
pprSectionAlign :: NCGConfig -> Section -> SDoc
pprSectionAlign config sec@(Section seg _) =
   pprSectionHeader config sec $$
   pprAlignForSection (ncgPlatform config) seg
283 284

-- | Print appropriate alignment for the given section type.
285 286
pprAlignForSection :: Platform -> SectionType -> SDoc
pprAlignForSection platform seg =
287
 let ppc64    = not $ target32Bit platform
288
 in ptext $ case seg of
289 290 291 292 293 294 295 296 297 298 299 300 301
       Text              -> sLit ".align 2"
       Data
        | ppc64          -> sLit ".align 3"
        | otherwise      -> sLit ".align 2"
       ReadOnlyData
        | ppc64          -> sLit ".align 3"
        | otherwise      -> sLit ".align 2"
       RelocatableReadOnlyData
        | ppc64          -> sLit ".align 3"
        | otherwise      -> sLit ".align 2"
       UninitialisedData
        | ppc64          -> sLit ".align 3"
        | otherwise      -> sLit ".align 2"
302
       ReadOnlyData16    -> sLit ".align 4"
303 304 305 306 307
       -- TODO: This is copied from the ReadOnlyData case, but it can likely be
       -- made more efficient.
       CString
        | ppc64          -> sLit ".align 3"
        | otherwise      -> sLit ".align 2"
308
       OtherSection _    -> panic "PprMach.pprSectionAlign: unknown section"
309

310 311
pprDataItem :: Platform -> CmmLit -> SDoc
pprDataItem platform lit
312
  = vcat (ppr_item (cmmTypeFormat $ cmmLitType platform lit) lit)
313
    where
Erik de Castro Lopo's avatar
Erik de Castro Lopo committed
314
        imm = litToImm lit
315
        archPPC_64 = not $ target32Bit platform
316

Sylvain Henry's avatar
Sylvain Henry committed
317 318 319
        ppr_item II8  _ = [text "\t.byte\t"  <> pprImm platform imm]
        ppr_item II16 _ = [text "\t.short\t" <> pprImm platform imm]
        ppr_item II32 _ = [text "\t.long\t"  <> pprImm platform imm]
320
        ppr_item II64 _
Sylvain Henry's avatar
Sylvain Henry committed
321
           | archPPC_64 = [text "\t.quad\t"  <> pprImm platform imm]
322

323 324 325 326 327 328 329
        ppr_item II64 (CmmInt x _)
           | not archPPC_64 =
                [text "\t.long\t"
                    <> int (fromIntegral
                        (fromIntegral (x `shiftR` 32) :: Word32)),
                 text "\t.long\t"
                    <> int (fromIntegral (fromIntegral x :: Word32))]
330 331


Sylvain Henry's avatar
Sylvain Henry committed
332 333
        ppr_item FF32 _ = [text "\t.float\t" <> pprImm platform imm]
        ppr_item FF64 _ = [text "\t.double\t" <> pprImm platform imm]
334

335 336
        ppr_item _ _
                = panic "PPC.Ppr.pprDataItem: no match"
337 338


339 340
pprInstr :: Platform -> Instr -> SDoc
pprInstr platform instr = case instr of
341

342 343
   COMMENT _
      -> empty -- nuke 'em
344

345 346 347 348
   -- COMMENT s
   --    -> if platformOS platform == OSLinux
   --          then text "# " <> ftext s
   --          else text "; " <> ftext s
349

350 351 352
   LOCATION file line col _name
      -> text "\t.loc" <+> ppr file <+> ppr line <+> ppr col

353 354
   DELTA d
      -> pprInstr platform (COMMENT (mkFastString ("\tdelta = " ++ show d)))
355

356 357
   NEWBLOCK _
      -> panic "PprMach.pprInstr: NEWBLOCK"
358

359 360
   LDATA _ _
      -> panic "PprMach.pprInstr: LDATA"
361

362
{-
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
   SPILL reg slot
      -> hcat [
              text "\tSPILL",
           char '\t',
           pprReg reg,
           comma,
           text "SLOT" <> parens (int slot)]

   RELOAD slot reg
      -> hcat [
              text "\tRELOAD",
           char '\t',
           text "SLOT" <> parens (int slot),
           comma,
           pprReg reg]
378
-}
379

380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
   LD fmt reg addr
      -> hcat [
           char '\t',
           text "l",
           ptext (case fmt of
               II8  -> sLit "bz"
               II16 -> sLit "hz"
               II32 -> sLit "wz"
               II64 -> sLit "d"
               FF32 -> sLit "fs"
               FF64 -> sLit "fd"
               ),
           case addr of AddrRegImm _ _ -> empty
                        AddrRegReg _ _ -> char 'x',
           char '\t',
           pprReg reg,
           text ", ",
Sylvain Henry's avatar
Sylvain Henry committed
397
           pprAddr platform addr
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
       ]

   LDFAR fmt reg (AddrRegImm source off)
      -> vcat
            [ pprInstr platform (ADDIS (tmpReg platform) source (HA off))
            , pprInstr platform (LD fmt reg (AddrRegImm (tmpReg platform) (LO off)))
            ]

   LDFAR _ _ _
      -> panic "PPC.Ppr.pprInstr LDFAR: no match"

   LDR fmt reg1 addr
      -> hcat [
           text "\tl",
           case fmt of
             II32 -> char 'w'
             II64 -> char 'd'
             _    -> panic "PPC.Ppr.Instr LDR: no match",
           text "arx\t",
           pprReg reg1,
           text ", ",
Sylvain Henry's avatar
Sylvain Henry committed
419
           pprAddr platform addr
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
           ]

   LA fmt reg addr
      -> hcat [
           char '\t',
           text "l",
           ptext (case fmt of
               II8  -> sLit "ba"
               II16 -> sLit "ha"
               II32 -> sLit "wa"
               II64 -> sLit "d"
               FF32 -> sLit "fs"
               FF64 -> sLit "fd"
               ),
           case addr of AddrRegImm _ _ -> empty
                        AddrRegReg _ _ -> char 'x',
           char '\t',
           pprReg reg,
           text ", ",
Sylvain Henry's avatar
Sylvain Henry committed
439
           pprAddr platform addr
440 441 442 443 444 445 446 447 448 449 450 451
           ]

   ST fmt reg addr
      -> hcat [
           char '\t',
           text "st",
           pprFormat fmt,
           case addr of AddrRegImm _ _ -> empty
                        AddrRegReg _ _ -> char 'x',
           char '\t',
           pprReg reg,
           text ", ",
Sylvain Henry's avatar
Sylvain Henry committed
452
           pprAddr platform addr
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
           ]

   STFAR fmt reg (AddrRegImm source off)
      -> vcat [ pprInstr platform (ADDIS (tmpReg platform) source (HA off))
              , pprInstr platform (ST fmt reg (AddrRegImm (tmpReg platform) (LO off)))
              ]

   STFAR _ _ _
      -> panic "PPC.Ppr.pprInstr STFAR: no match"

   STU fmt reg addr
      -> hcat [
           char '\t',
           text "st",
           pprFormat fmt,
           char 'u',
           case addr of AddrRegImm _ _ -> empty
                        AddrRegReg _ _ -> char 'x',
           char '\t',
           pprReg reg,
           text ", ",
Sylvain Henry's avatar
Sylvain Henry committed
474
           pprAddr platform addr
475 476 477 478 479 480 481 482 483 484 485 486
           ]

   STC fmt reg1 addr
      -> hcat [
           text "\tst",
           case fmt of
             II32 -> char 'w'
             II64 -> char 'd'
             _    -> panic "PPC.Ppr.Instr STC: no match",
           text "cx.\t",
           pprReg reg1,
           text ", ",
Sylvain Henry's avatar
Sylvain Henry committed
487
           pprAddr platform addr
488 489 490 491 492 493 494 495 496
           ]

   LIS reg imm
      -> hcat [
           char '\t',
           text "lis",
           char '\t',
           pprReg reg,
           text ", ",
Sylvain Henry's avatar
Sylvain Henry committed
497
           pprImm platform imm
498 499 500 501 502 503 504 505 506
           ]

   LI reg imm
      -> hcat [
           char '\t',
           text "li",
           char '\t',
           pprReg reg,
           text ", ",
Sylvain Henry's avatar
Sylvain Henry committed
507
           pprImm platform imm
508 509 510 511 512
           ]

   MR reg1 reg2
    | reg1 == reg2 -> empty
    | otherwise    -> hcat [
Erik de Castro Lopo's avatar
Erik de Castro Lopo committed
513 514
        char '\t',
        case targetClassOfReg platform reg1 of
515 516
            RcInteger -> text "mr"
            _ -> text "fmr",
Erik de Castro Lopo's avatar
Erik de Castro Lopo committed
517
        char '\t',
518
        pprReg reg1,
519
        text ", ",
520
        pprReg reg2
521 522
        ]

523 524 525 526 527 528 529
   CMP fmt reg ri
      -> hcat [
           char '\t',
           op,
           char '\t',
           pprReg reg,
           text ", ",
Sylvain Henry's avatar
Sylvain Henry committed
530
           pprRI platform ri
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
           ]
         where
           op = hcat [
                   text "cmp",
                   pprFormat fmt,
                   case ri of
                       RIReg _ -> empty
                       RIImm _ -> char 'i'
               ]

   CMPL fmt reg ri
      -> hcat [
           char '\t',
           op,
           char '\t',
           pprReg reg,
           text ", ",
Sylvain Henry's avatar
Sylvain Henry committed
548
           pprRI platform ri
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
           ]
          where
              op = hcat [
                      text "cmpl",
                      pprFormat fmt,
                      case ri of
                          RIReg _ -> empty
                          RIImm _ -> char 'i'
                  ]

   BCC cond blockid prediction
      -> hcat [
           char '\t',
           text "b",
           pprCond cond,
           pprPrediction prediction,
           char '\t',
Sylvain Henry's avatar
Sylvain Henry committed
566
           pdoc platform lbl
567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
           ]
         where lbl = mkLocalBlockLabel (getUnique blockid)
               pprPrediction p = case p of
                 Nothing    -> empty
                 Just True  -> char '+'
                 Just False -> char '-'

   BCCFAR cond blockid prediction
      -> vcat [
           hcat [
               text "\tb",
               pprCond (condNegate cond),
               neg_prediction,
               text "\t$+8"
           ],
           hcat [
               text "\tb\t",
Sylvain Henry's avatar
Sylvain Henry committed
584
               pdoc platform lbl
585
           ]
586
          ]
587 588 589 590 591 592 593 594 595 596 597 598 599 600
          where lbl = mkLocalBlockLabel (getUnique blockid)
                neg_prediction = case prediction of
                  Nothing    -> empty
                  Just True  -> char '-'
                  Just False -> char '+'

   JMP lbl _
     -- We never jump to ForeignLabels; if we ever do, c.f. handling for "BL"
     | isForeignLabel lbl -> panic "PPC.Ppr.pprInstr: JMP to ForeignLabel"
     | otherwise ->
       hcat [ -- an alias for b that takes a CLabel
           char '\t',
           text "b",
           char '\t',
Sylvain Henry's avatar
Sylvain Henry committed
601
           pdoc platform lbl
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
       ]

   MTCTR reg
      -> hcat [
           char '\t',
           text "mtctr",
           char '\t',
           pprReg reg
        ]

   BCTR _ _ _
      -> hcat [
           char '\t',
           text "bctr"
         ]

   BL lbl _
      -> case platformOS platform of
           OSAIX ->
             -- On AIX, "printf" denotes a function-descriptor (for use
             -- by function pointers), whereas the actual entry-code
             -- address is denoted by the dot-prefixed ".printf" label.
             -- Moreover, the PPC NCG only ever emits a BL instruction
             -- for calling C ABI functions. Most of the time these calls
             -- originate from FFI imports and have a 'ForeignLabel',
             -- but when profiling the codegen inserts calls via
             -- 'emitRtsCallGen' which are 'CmmLabel's even though
             -- they'd technically be more like 'ForeignLabel's.
             hcat [
               text "\tbl\t.",
Sylvain Henry's avatar
Sylvain Henry committed
632
               pdoc platform lbl
633 634 635 636
             ]
           _ ->
             hcat [
               text "\tbl\t",
Sylvain Henry's avatar
Sylvain Henry committed
637
               pdoc platform lbl
638 639 640 641 642 643 644 645 646
             ]

   BCTRL _
      -> hcat [
             char '\t',
             text "bctrl"
         ]

   ADD reg1 reg2 ri
Sylvain Henry's avatar
Sylvain Henry committed
647
      -> pprLogic platform (sLit "add") reg1 reg2 ri
648 649 650 651 652 653 654 655 656 657

   ADDIS reg1 reg2 imm
      -> hcat [
           char '\t',
           text "addis",
           char '\t',
           pprReg reg1,
           text ", ",
           pprReg reg2,
           text ", ",
Sylvain Henry's avatar
Sylvain Henry committed
658
           pprImm platform imm
659 660 661
           ]

   ADDO reg1 reg2 reg3
Sylvain Henry's avatar
Sylvain Henry committed
662
      -> pprLogic platform (sLit "addo") reg1 reg2 (RIReg reg3)
663 664

   ADDC reg1 reg2 reg3
Sylvain Henry's avatar
Sylvain Henry committed
665
      -> pprLogic platform (sLit "addc") reg1 reg2 (RIReg reg3)
666 667

   ADDE reg1 reg2 reg3
Sylvain Henry's avatar
Sylvain Henry committed
668
      -> pprLogic platform (sLit "adde") reg1 reg2 (RIReg reg3)
669 670 671 672 673

   ADDZE reg1 reg2
      -> pprUnary (sLit "addze") reg1 reg2

   SUBF reg1 reg2 reg3
Sylvain Henry's avatar
Sylvain Henry committed
674
      -> pprLogic platform (sLit "subf") reg1 reg2 (RIReg reg3)
675 676

   SUBFO reg1 reg2 reg3
Sylvain Henry's avatar
Sylvain Henry committed
677
      -> pprLogic platform (sLit "subfo") reg1 reg2 (RIReg reg3)
678 679 680 681 682 683 684 685 686 687 688 689 690

   SUBFC reg1 reg2 ri
      -> hcat [
           char '\t',
           text "subf",
           case ri of
               RIReg _ -> empty
               RIImm _ -> char 'i',
           text "c\t",
           pprReg reg1,
           text ", ",
           pprReg reg2,
           text ", ",
Sylvain Henry's avatar
Sylvain Henry committed
691
           pprRI platform ri
692 693 694
           ]

   SUBFE reg1 reg2 reg3
Sylvain Henry's avatar
Sylvain Henry committed
695
      -> pprLogic platform (sLit "subfe") reg1 reg2 (RIReg reg3)
696 697

   MULL fmt reg1 reg2 ri
Sylvain Henry's avatar
Sylvain Henry committed
698
      -> pprMul platform fmt reg1 reg2 ri
699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744

   MULLO fmt reg1 reg2 reg3
      -> hcat [
             char '\t',
             text "mull",
             case fmt of
               II32 -> char 'w'
               II64 -> char 'd'
               _    -> panic "PPC: illegal format",
             text "o\t",
             pprReg reg1,
             text ", ",
             pprReg reg2,
             text ", ",
             pprReg reg3
         ]

   MFOV fmt reg
      -> vcat [
           hcat [
               char '\t',
               text "mfxer",
               char '\t',
               pprReg reg
               ],
           hcat [
               char '\t',
               text "extr",
               case fmt of
                 II32 -> char 'w'
                 II64 -> char 'd'
                 _    -> panic "PPC: illegal format",
               text "i\t",
               pprReg reg,
               text ", ",
               pprReg reg,
               text ", 1, ",
               case fmt of
                 II32 -> text "1"
                 II64 -> text "33"
                 _    -> panic "PPC: illegal format"
               ]
           ]

   MULHU fmt reg1 reg2 reg3
      -> hcat [
745
            char '\t',
746
            text "mulh",
747 748 749 750
            case fmt of
              II32 -> char 'w'
              II64 -> char 'd'
              _    -> panic "PPC: illegal format",
751 752
            text "u\t",
            pprReg reg1,
753
            text ", ",
754 755 756
            pprReg reg2,
            text ", ",
            pprReg reg3
757 758
        ]

759 760
   DIV fmt sgn reg1 reg2 reg3
      -> pprDiv fmt sgn reg1 reg2 reg3
761

762
        -- for some reason, "andi" doesn't exist.
Erik de Castro Lopo's avatar
Erik de Castro Lopo committed
763
        -- we'll use "andi." instead.
764 765 766 767 768 769 770 771 772
   AND reg1 reg2 (RIImm imm)
      -> hcat [
            char '\t',
            text "andi.",
            char '\t',
            pprReg reg1,
            text ", ",
            pprReg reg2,
            text ", ",
Sylvain Henry's avatar
Sylvain Henry committed
773
            pprImm platform imm
774
        ]
775

776
   AND reg1 reg2 ri
Sylvain Henry's avatar
Sylvain Henry committed
777
      -> pprLogic platform (sLit "and") reg1 reg2 ri
778

779
   ANDC reg1 reg2 reg3
Sylvain Henry's avatar
Sylvain Henry committed
780
      -> pprLogic platform (sLit "andc") reg1 reg2 (RIReg reg3)
781

782
   NAND reg1 reg2 reg3
Sylvain Henry's avatar
Sylvain Henry committed
783
      -> pprLogic platform (sLit "nand") reg1 reg2 (RIReg reg3)
784

785
   OR reg1 reg2 ri
Sylvain Henry's avatar
Sylvain Henry committed
786
      -> pprLogic platform (sLit "or") reg1 reg2 ri
787

788
   XOR reg1 reg2 ri
Sylvain Henry's avatar
Sylvain Henry committed
789
      -> pprLogic platform (sLit "xor") reg1 reg2 ri
790

791 792 793 794 795 796 797 798 799
   ORIS reg1 reg2 imm
      -> hcat [
            char '\t',
            text "oris",
            char '\t',
            pprReg reg1,
            text ", ",
            pprReg reg2,
            text ", ",
Sylvain Henry's avatar
Sylvain Henry committed
800
            pprImm platform imm
801 802 803 804 805 806 807 808 809 810 811
        ]

   XORIS reg1 reg2 imm
      -> hcat [
            char '\t',
            text "xoris",
            char '\t',
            pprReg reg1,
            text ", ",
            pprReg reg2,
            text ", ",
Sylvain Henry's avatar
Sylvain Henry committed
812
            pprImm platform imm
813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
        ]

   EXTS fmt reg1 reg2
      -> hcat [
           char '\t',
           text "exts",
           pprFormat fmt,
           char '\t',
           pprReg reg1,
           text ", ",
           pprReg reg2
         ]

   CNTLZ fmt reg1 reg2
      -> hcat [
           char '\t',
           text "cntlz",
           case fmt of
             II32 -> char 'w'
             II64 -> char 'd'
             _    -> panic "PPC: illegal format",
           char '\t',
           pprReg reg1,
           text ", ",
           pprReg reg2
         ]

   NEG reg1 reg2
      -> pprUnary (sLit "neg") reg1 reg2

   NOT reg1 reg2
      -> pprUnary (sLit "not") reg1 reg2

   SR II32 reg1 reg2 (RIImm (ImmInt i))
847 848 849
    -- Handle the case where we are asked to shift a 32 bit register by
    -- less than zero or more than 31 bits. We convert this into a clear
    -- of the destination register.
850
    -- Fixes ticket https://gitlab.haskell.org/ghc/ghc/issues/5900
851
      | i < 0  || i > 31 -> pprInstr platform (XOR reg1 reg2 (RIReg reg2))
852

853
   SL II32 reg1 reg2 (RIImm (ImmInt i))
854
    -- As above for SR, but for left shifts.
855
    -- Fixes ticket https://gitlab.haskell.org/ghc/ghc/issues/10870
856
      | i < 0  || i > 31 -> pprInstr platform (XOR reg1 reg2 (RIReg reg2))
857

858
   SRA II32 reg1 reg2 (RIImm (ImmInt i))
859 860 861 862 863
    -- PT: I don't know what to do for negative shift amounts:
    -- For now just panic.
    --
    -- For shift amounts greater than 31 set all bit to the
    -- value of the sign bit, this also what sraw does.
864
      | i > 31 -> pprInstr platform (SRA II32 reg1 reg2 (RIImm (ImmInt 31)))
865

866 867
   SL fmt reg1 reg2 ri
      -> let op = case fmt of
868 869 870
                       II32 -> "slw"
                       II64 -> "sld"
                       _    -> panic "PPC.Ppr.pprInstr: shift illegal size"
Sylvain Henry's avatar
Sylvain Henry committed
871
         in pprLogic platform (sLit op) reg1 reg2 (limitShiftRI fmt ri)
872

873 874
   SR fmt reg1 reg2 ri
      -> let op = case fmt of
875 876 877
                       II32 -> "srw"
                       II64 -> "srd"
                       _    -> panic "PPC.Ppr.pprInstr: shift illegal size"
Sylvain Henry's avatar
Sylvain Henry committed
878
         in pprLogic platform (sLit op) reg1 reg2 (limitShiftRI fmt ri)
879

880 881
   SRA fmt reg1 reg2 ri
      -> let op = case fmt of
882 883 884
                       II32 -> "sraw"
                       II64 -> "srad"
                       _    -> panic "PPC.Ppr.pprInstr: shift illegal size"
Sylvain Henry's avatar
Sylvain Henry committed
885
         in pprLogic platform (sLit op) reg1 reg2 (limitShiftRI fmt ri)
886

887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911
   RLWINM reg1 reg2 sh mb me
      -> hcat [
             text "\trlwinm\t",
             pprReg reg1,
             text ", ",
             pprReg reg2,
             text ", ",
             int sh,
             text ", ",
             int mb,
             text ", ",
             int me
         ]

   CLRLI fmt reg1 reg2 n
      -> hcat [
            text "\tclrl",
            pprFormat fmt,
            text "i ",
            pprReg reg1,
            text ", ",
            pprReg reg2,
            text ", ",
            int n
        ]
912

913 914 915 916 917 918 919 920 921 922 923
   CLRRI fmt reg1 reg2 n
      -> hcat [
            text "\tclrr",
            pprFormat fmt,
            text "i ",
            pprReg reg1,
            text ", ",
            pprReg reg2,
            text ", ",
            int n
        ]
924

925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
   FADD fmt reg1 reg2 reg3
      -> pprBinaryF (sLit "fadd") fmt reg1 reg2 reg3

   FSUB fmt reg1 reg2 reg3
      -> pprBinaryF (sLit "fsub") fmt reg1 reg2 reg3

   FMUL fmt reg1 reg2 reg3
      -> pprBinaryF (sLit "fmul") fmt reg1 reg2 reg3

   FDIV fmt reg1 reg2 reg3
      -> pprBinaryF (sLit "fdiv") fmt reg1 reg2 reg3

   FABS reg1 reg2
      -> pprUnary (sLit "fabs") reg1 reg2

   FNEG reg1 reg2
      -> pprUnary (sLit "fneg") reg1 reg2

   FCMP reg1 reg2
      -> hcat [
           char '\t',
           text "fcmpu\t0, ",
               -- Note: we're using fcmpu, not fcmpo
               -- The difference is with fcmpo, compare with NaN is an invalid operation.
               -- We don't handle invalid fp ops, so we don't care.
               -- Moreover, we use `fcmpu 0, ...` rather than `fcmpu cr0, ...` for
               -- better portability since some non-GNU assembler (such as
               -- IBM's `as`) tend not to support the symbolic register name cr0.
               -- This matches the syntax that GCC seems to emit for PPC targets.
           pprReg reg1,
           text ", ",
           pprReg reg2
         ]

   FCTIWZ reg1 reg2
      -> pprUnary (sLit "fctiwz") reg1 reg2

   FCTIDZ reg1 reg2
      -> pprUnary (sLit "fctidz") reg1 reg2

   FCFID reg1 reg2
      -> pprUnary (sLit "fcfid") reg1 reg2

   FRSP reg1 reg2
      -> pprUnary (sLit "frsp") reg1 reg2

   CRNOR dst src1 src2
      -> hcat [
           text "\tcrnor\t",
           int dst,
           text ", ",
           int src1,
           text ", ",
           int src2
         ]

   MFCR reg
      -> hcat [
             char '\t',
             text "mfcr",
             char '\t',
             pprReg reg
         ]

   MFLR reg
      -> hcat [
           char '\t',
           text "mflr",
           char '\t',
           pprReg reg
         ]

   FETCHPC reg
      -> vcat [
             text "\tbcl\t20,31,1f",
             hcat [ text "1:\tmflr\t", pprReg reg ]
         ]

   HWSYNC
      -> text "\tsync"

   ISYNC
      -> text "\tisync"

   LWSYNC
      -> text "\tlwsync"

   NOP
      -> text "\tnop"
1014

Sylvain Henry's avatar
Sylvain Henry committed
1015 1016
pprLogic :: Platform -> PtrString -> Reg -> Reg -> RI -> SDoc
pprLogic platform op reg1 reg2 ri = hcat [
Erik de Castro Lopo's avatar
Erik de Castro Lopo committed
1017 1018 1019 1020 1021 1022
        char '\t',
        ptext op,
        case ri of
            RIReg _ -> empty
            RIImm _ -> char 'i',
        char '\t',
1023
        pprReg reg1,
1024
        text ", ",
1025
        pprReg reg2,
1026
        text ", ",
Sylvain Henry's avatar
Sylvain Henry committed
1027
        pprRI platform ri
1028 1029 1030
    ]


Sylvain Henry's avatar
Sylvain Henry committed
1031 1032
pprMul :: Platform -> Format -> Reg -> Reg -> RI -> SDoc
pprMul platform fmt reg1 reg2 ri = hcat [
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
        char '\t',
        text "mull",
        case ri of
            RIReg _ -> case fmt of
              II32 -> char 'w'
              II64 -> char 'd'
              _    -> panic "PPC: illegal format"
            RIImm _ -> char 'i',
        char '\t',
        pprReg reg1,
        text ", ",
        pprReg reg2,
        text ", ",
Sylvain Henry's avatar
Sylvain Henry committed
1046
        pprRI platform ri
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
    ]


pprDiv :: Format -> Bool -> Reg -> Reg -> Reg -> SDoc
pprDiv fmt sgn reg1 reg2 reg3 = hcat [
        char '\t',
        text "div",
        case fmt of
          II32 -> char 'w'
          II64 -> char 'd'
          _    -> panic "PPC: illegal format",
        if sgn then empty else char 'u',
        char '\t',
        pprReg reg1,
        text ", ",
        pprReg reg2,
        text ", ",
        pprReg reg3
    ]


Sylvain Henry's avatar
Sylvain Henry committed
1068
pprUnary :: PtrString -> Reg -> Reg -> SDoc
1069
pprUnary op reg1 reg2 = hcat [
Erik de Castro Lopo's avatar
Erik de Castro Lopo committed
1070 1071 1072
        char '\t',
        ptext op,
        char '\t',
1073
        pprReg reg1,
1074
        text ", ",
1075
        pprReg reg2
1076
    ]
1077 1078


Sylvain Henry's avatar
Sylvain Henry committed
1079
pprBinaryF :: PtrString -> Format -> Reg -> Reg -> Reg -> SDoc
1080
pprBinaryF op fmt reg1 reg2 reg3 = hcat [
Erik de Castro Lopo's avatar