{-# OPTIONS_GHC -fno-warn-orphans #-}

module GHC.CmmToAsm.RV64.Instr

where

import GHC.Prelude

import GHC.CmmToAsm.RV64.Cond
import GHC.CmmToAsm.RV64.Regs

import GHC.CmmToAsm.Instr (RegUsage(..))
import GHC.CmmToAsm.Format
import GHC.CmmToAsm.Types
import GHC.CmmToAsm.Utils
import GHC.CmmToAsm.Config
import GHC.Platform.Reg

import GHC.Platform.Regs
import GHC.Cmm.BlockId
import GHC.Cmm.Dataflow.Collections
import GHC.Cmm.Dataflow.Label
import GHC.Cmm
import GHC.Cmm.CLabel
import GHC.Utils.Outputable
import GHC.Platform
import GHC.Types.Unique.Supply

import GHC.Utils.Panic

import Data.Maybe

import GHC.Stack
import qualified Data.List.NonEmpty as NE
import Data.Foldable
import GHC.Cmm.Info (maxRetInfoTableSizeW)
import GHC.Types.Unique.FM (listToUFM, lookupUFM)

-- | Stack frame header size in bytes.
--
-- The stack frame header is made of the values that are always saved
-- (regardless of the context.) It consists of the saved return address and a
-- pointer to the previous frame. Thus, its size is two stack frame slots which
-- equals two addresses/words (2 * 8 byte).
stackFrameHeaderSize :: Int
stackFrameHeaderSize :: RegNo
stackFrameHeaderSize = RegNo
2 RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
* RegNo
spillSlotSize

-- | All registers are 8 byte wide.
spillSlotSize :: Int
spillSlotSize :: RegNo
spillSlotSize = RegNo
8

-- | The number of bytes that the stack pointer should be aligned
-- to.
stackAlign :: Int
stackAlign :: RegNo
stackAlign = RegNo
16

-- | The number of spill slots available without allocating more.
maxSpillSlots :: NCGConfig -> Int
maxSpillSlots :: NCGConfig -> RegNo
maxSpillSlots NCGConfig
config
    = ((NCGConfig -> RegNo
ncgSpillPreallocSize NCGConfig
config RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
- RegNo
stackFrameHeaderSize)
         RegNo -> RegNo -> RegNo
forall a. Integral a => a -> a -> a
`div` RegNo
spillSlotSize) RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
- RegNo
1

-- | Convert a spill slot number to a *byte* offset, with no sign.
spillSlotToOffset :: Int -> Int
spillSlotToOffset :: RegNo -> RegNo
spillSlotToOffset RegNo
slot
   = RegNo
stackFrameHeaderSize RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
+ RegNo
spillSlotSize RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
* RegNo
slot

-- | Get the registers that are being used by this instruction.
-- regUsage doesn't need to do any trickery for jumps and such.
-- Just state precisely the regs read and written by that insn.
-- The consequences of control flow transfers, as far as register
-- allocation goes, are taken care of by the register allocator.
--
-- RegUsage = RU [<read regs>] [<write regs>]

instance Outputable RegUsage where
    ppr :: RegUsage -> SDoc
ppr (RU [Reg]
reads [Reg]
writes) = String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"RegUsage(reads:" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> [Reg] -> SDoc
forall a. Outputable a => a -> SDoc
ppr [Reg]
reads SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> SDoc
forall doc. IsLine doc => doc
comma SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"writes:" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> [Reg] -> SDoc
forall a. Outputable a => a -> SDoc
ppr [Reg]
writes SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> Char -> SDoc
forall doc. IsLine doc => Char -> doc
char Char
')'

regUsageOfInstr :: Platform -> Instr -> RegUsage
regUsageOfInstr :: Platform -> Instr -> RegUsage
regUsageOfInstr Platform
platform Instr
instr = case Instr
instr of
  ANN SDoc
_ Instr
i                  -> Platform -> Instr -> RegUsage
regUsageOfInstr Platform
platform Instr
i
  COMMENT{}                -> ([Reg], [Reg]) -> RegUsage
usage ([], [])
  MULTILINE_COMMENT{}      -> ([Reg], [Reg]) -> RegUsage
usage ([], [])
  Instr
PUSH_STACK_FRAME         -> ([Reg], [Reg]) -> RegUsage
usage ([], [])
  Instr
POP_STACK_FRAME          -> ([Reg], [Reg]) -> RegUsage
usage ([], [])
  DELTA{}                  -> ([Reg], [Reg]) -> RegUsage
usage ([], [])

  -- 1. Arithmetic Instructions ------------------------------------------------
  ADD Operand
dst Operand
src1 Operand
src2        -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  -- CMN l r                  -> usage (regOp l ++ regOp r, [])
  -- CMP l r                  -> usage (regOp l ++ regOp r, [])
  MUL Operand
dst Operand
src1 Operand
src2        -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  NEG Operand
dst Operand
src              -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src, Operand -> [Reg]
regOp Operand
dst)
  SMULH Operand
dst Operand
src1 Operand
src2      -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  DIV Operand
dst Operand
src1 Operand
src2        -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  REM Operand
dst Operand
src1 Operand
src2        -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  REMU Operand
dst Operand
src1 Operand
src2       -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  SUB Operand
dst Operand
src1 Operand
src2        -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  DIVU Operand
dst Operand
src1 Operand
src2       -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)

  -- 2. Bit Manipulation Instructions ------------------------------------------
  SBFM Operand
dst Operand
src Operand
_ Operand
_         -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src, Operand -> [Reg]
regOp Operand
dst)
  UBFM Operand
dst Operand
src Operand
_ Operand
_         -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src, Operand -> [Reg]
regOp Operand
dst)
  UBFX Operand
dst Operand
src Operand
_ Operand
_         -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src, Operand -> [Reg]
regOp Operand
dst)
  -- 3. Logical and Move Instructions ------------------------------------------
  AND Operand
dst Operand
src1 Operand
src2        -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  OR Operand
dst Operand
src1 Operand
src2         -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  ASR Operand
dst Operand
src1 Operand
src2        -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  BIC Operand
dst Operand
src1 Operand
src2        -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  BICS Operand
dst Operand
src1 Operand
src2       -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  XOR Operand
dst Operand
src1 Operand
src2        -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  LSL Operand
dst Operand
src1 Operand
src2        -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  LSR Operand
dst Operand
src1 Operand
src2        -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  MOV Operand
dst Operand
src              -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src, Operand -> [Reg]
regOp Operand
dst)
  -- ORI's third operand is always an immediate
  ORI Operand
dst Operand
src1 Operand
_           -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1, Operand -> [Reg]
regOp Operand
dst)
  XORI Operand
dst Operand
src1 Operand
_          -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1, Operand -> [Reg]
regOp Operand
dst)
  -- 4. Branch Instructions ----------------------------------------------------
  J Target
t                      -> ([Reg], [Reg]) -> RegUsage
usage (Target -> [Reg]
regTarget Target
t, [])
  B Target
t                      -> ([Reg], [Reg]) -> RegUsage
usage (Target -> [Reg]
regTarget Target
t, [])
  B_FAR BlockId
_t                 -> ([Reg], [Reg]) -> RegUsage
usage ([], [])
  BCOND Cond
_ Operand
l Operand
r Target
t            -> ([Reg], [Reg]) -> RegUsage
usage (Target -> [Reg]
regTarget Target
t [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
l [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
r, [])
  BCOND_FAR Cond
_ Operand
l Operand
r Target
_ Target
t        -> ([Reg], [Reg]) -> RegUsage
usage (Target -> [Reg]
regTarget Target
t [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
l [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
r, [])
  BL Target
t [Reg]
ps [Reg]
_rs              -> ([Reg], [Reg]) -> RegUsage
usage (Target -> [Reg]
regTarget Target
t [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ [Reg]
ps, [Reg]
callerSavedRegisters)

  -- 5. Atomic Instructions ----------------------------------------------------
  -- 6. Conditional Instructions -----------------------------------------------
  CSET Operand
dst Operand
l Operand
r Cond
_           -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
l [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
r, Operand -> [Reg]
regOp Operand
dst)
  -- 7. Load and Store Instructions --------------------------------------------
  STR Format
_ Operand
src Operand
dst            -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
dst, [])
  -- STLR _ src dst      L     -> usage (regOp src ++ regOp dst, [])
  LDR Format
_ Operand
dst Operand
src            -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src, Operand -> [Reg]
regOp Operand
dst)
  LDRU Format
_ Operand
dst Operand
src           -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src, Operand -> [Reg]
regOp Operand
dst)
  -- LDAR _ dst src           -> usage (regOp src, regOp dst)
  -- TODO is this right? see STR, which I'm only partial about being right?
  -- STP _ src1 src2 dst      -> usage (regOp src1 ++ regOp src2 ++ regOp dst, [])
  -- LDP _ dst1 dst2 src      -> usage (regOp src, regOp dst1 ++ regOp dst2)

  -- 8. Synchronization Instructions -------------------------------------------
  DMBSY DmbType
_ DmbType
_                  -> ([Reg], [Reg]) -> RegUsage
usage ([], [])

  -- 9. Floating Point Instructions --------------------------------------------
  FCVT Operand
dst Operand
src             -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src, Operand -> [Reg]
regOp Operand
dst)
  SCVTF Operand
dst Operand
src            -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src, Operand -> [Reg]
regOp Operand
dst)
  FCVTZS Operand
dst Operand
src           -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src, Operand -> [Reg]
regOp Operand
dst)
  FABS Operand
dst Operand
src             -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src, Operand -> [Reg]
regOp Operand
dst)

  Instr
_ -> String -> RegUsage
forall a. HasCallStack => String -> a
panic (String -> RegUsage) -> String -> RegUsage
forall a b. (a -> b) -> a -> b
$ String
"regUsageOfInstr: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Instr -> String
instrCon Instr
instr

  where
        -- filtering the usage is necessary, otherwise the register
        -- allocator will try to allocate pre-defined fixed stg
        -- registers as well, as they show up.
        usage :: ([Reg], [Reg]) -> RegUsage
usage ([Reg]
src, [Reg]
dst) = [Reg] -> [Reg] -> RegUsage
RU ((Reg -> Bool) -> [Reg] -> [Reg]
forall a. (a -> Bool) -> [a] -> [a]
filter (Platform -> Reg -> Bool
interesting Platform
platform) [Reg]
src)
                              ((Reg -> Bool) -> [Reg] -> [Reg]
forall a. (a -> Bool) -> [a] -> [a]
filter (Platform -> Reg -> Bool
interesting Platform
platform) [Reg]
dst)

        regAddr :: AddrMode -> [Reg]
        regAddr :: AddrMode -> [Reg]
regAddr (AddrRegImm Reg
r1 Imm
_)  = [Reg
r1]
        regAddr (AddrReg Reg
r1)       = [Reg
r1]
        regOp :: Operand -> [Reg]
        regOp :: Operand -> [Reg]
regOp (OpReg Width
_ Reg
r1) = [Reg
r1]
        regOp (OpAddr AddrMode
a) = AddrMode -> [Reg]
regAddr AddrMode
a
        regOp (OpImm Imm
_) = []
        regTarget :: Target -> [Reg]
        regTarget :: Target -> [Reg]
regTarget (TBlock BlockId
_) = []
        regTarget (TLabel CLabel
_) = []
        regTarget (TReg Reg
r1)  = [Reg
r1]

        -- Is this register interesting for the register allocator?
        interesting :: Platform -> Reg -> Bool
        interesting :: Platform -> Reg -> Bool
interesting Platform
_        (RegVirtual VirtualReg
_)                 = Bool
True
        interesting Platform
_        (RegReal (RealRegSingle (-1))) = Bool
False
        interesting Platform
platform (RegReal (RealRegSingle RegNo
i))    = Platform -> RegNo -> Bool
freeReg Platform
platform RegNo
i

-- Save caller save registers
-- This is x0-x18
--
-- For SIMD/FP Registers:
-- Registers v8-v15 must be preserved by a callee across subroutine calls;
-- the remaining registers (v0-v7, v16-v31) do not need to be preserved (or
-- should be preserved by the caller). Additionally, only the bottom 64 bits
-- of each value stored in v8-v15 need to be preserved [7]; it is the
-- responsibility of the caller to preserve larger values.
--
-- .---------------------------------------------------------------------------------------------------------------------------------------------------------------.
-- |  0 |  1 |  2 |  3 |  4 |  5 |  6 |  7 |  8 |  9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
-- | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 42 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
-- |== General Purpose registers ==================================================================================================================================|
-- | ZR | RA | SP | GP | TP | <- tmp r. -> | FP | <- | <---- argument passing -------------> | -- callee saved ------------------------------> | <--- tmp regs --> |
-- | -- | -- | -- | -- | -- | <- free r. > | -- | BR | <---- free registers ---------------> | SP | HP | R1 | R2 | R3 | R4 | R5 | R6 | R7 | SL | <-- free regs --> |
-- |== SIMD/FP Registers ==========================================================================================================================================|
-- | <--- temporary registers -----------> | <------ | <---- argument passing -------------> | -- callee saved ------------------------------> | <--- tmp regs --> |
-- | <---------- free registers ---------> | F1 | F2 | <---- free registers ---------------> | F3 | F4 | F5 | F6 | D1 | D2 | D3 | D4 | D5 | D6 | -- | -- | -- | -- |
-- '---------------------------------------------------------------------------------------------------------------------------------------------------------------'
-- ZR: Zero, RA: Return Address, SP: Stack Pointer, GP: Global Pointer, TP: Thread Pointer, FP: Frame Pointer
-- BR: Base, SL: SpLim
callerSavedRegisters :: [Reg]
callerSavedRegisters :: [Reg]
callerSavedRegisters =
  (RegNo -> Reg) -> [RegNo] -> [Reg]
forall a b. (a -> b) -> [a] -> [b]
map RegNo -> Reg
regSingle [RegNo
t0RegNo .. RegNo
t2RegNo]
    [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ (RegNo -> Reg) -> [RegNo] -> [Reg]
forall a b. (a -> b) -> [a] -> [b]
map RegNo -> Reg
regSingle [RegNo
a0RegNo .. RegNo
a7RegNo]
    [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ (RegNo -> Reg) -> [RegNo] -> [Reg]
forall a b. (a -> b) -> [a] -> [b]
map RegNo -> Reg
regSingle [RegNo
t3RegNo .. RegNo
t6RegNo]
    [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ (RegNo -> Reg) -> [RegNo] -> [Reg]
forall a b. (a -> b) -> [a] -> [b]
map RegNo -> Reg
regSingle [RegNo
ft0RegNo .. RegNo
ft7RegNo]
    [Reg] -> [Reg] -> [Reg]
forall a. [a] -> [a] -> [a]
++ (RegNo -> Reg) -> [RegNo] -> [Reg]
forall a b. (a -> b) -> [a] -> [b]
map RegNo -> Reg
regSingle [RegNo
fa0RegNo .. RegNo
fa7RegNo]

-- | Apply a given mapping to all the register references in this
-- instruction.
patchRegsOfInstr :: Instr -> (Reg -> Reg) -> Instr
patchRegsOfInstr :: Instr -> (Reg -> Reg) -> Instr
patchRegsOfInstr Instr
instr Reg -> Reg
env = case Instr
instr of
    -- 0. Meta Instructions
    ANN SDoc
d Instr
i             -> SDoc -> Instr -> Instr
ANN SDoc
d (Instr -> (Reg -> Reg) -> Instr
patchRegsOfInstr Instr
i Reg -> Reg
env)
    COMMENT{}           -> Instr
instr
    MULTILINE_COMMENT{} -> Instr
instr
    Instr
PUSH_STACK_FRAME    -> Instr
instr
    Instr
POP_STACK_FRAME     -> Instr
instr
    DELTA{}             -> Instr
instr
    -- 1. Arithmetic Instructions ----------------------------------------------
    ADD Operand
o1 Operand
o2 Operand
o3   -> Operand -> Operand -> Operand -> Instr
ADD (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)
    -- CMN o1 o2      -> CMN (patchOp o1) (patchOp o2)
    -- CMP o1 o2      -> CMP (patchOp o1) (patchOp o2)
    MUL Operand
o1 Operand
o2 Operand
o3   -> Operand -> Operand -> Operand -> Instr
MUL (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)
    NEG Operand
o1 Operand
o2      -> Operand -> Operand -> Instr
NEG (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2)
    SMULH Operand
o1 Operand
o2 Operand
o3 -> Operand -> Operand -> Operand -> Instr
SMULH (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2)  (Operand -> Operand
patchOp Operand
o3)
    DIV Operand
o1 Operand
o2 Operand
o3   -> Operand -> Operand -> Operand -> Instr
DIV (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)
    REM Operand
o1 Operand
o2 Operand
o3   -> Operand -> Operand -> Operand -> Instr
REM (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)
    REMU Operand
o1 Operand
o2 Operand
o3  -> Operand -> Operand -> Operand -> Instr
REMU (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)
    SUB Operand
o1 Operand
o2 Operand
o3   -> Operand -> Operand -> Operand -> Instr
SUB  (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)
    DIVU Operand
o1 Operand
o2 Operand
o3  -> Operand -> Operand -> Operand -> Instr
DIVU (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)

    -- 2. Bit Manipulation Instructions ----------------------------------------
    SBFM Operand
o1 Operand
o2 Operand
o3 Operand
o4 -> Operand -> Operand -> Operand -> Operand -> Instr
SBFM (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3) (Operand -> Operand
patchOp Operand
o4)
    UBFM Operand
o1 Operand
o2 Operand
o3 Operand
o4 -> Operand -> Operand -> Operand -> Operand -> Instr
UBFM (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3) (Operand -> Operand
patchOp Operand
o4)
    UBFX Operand
o1 Operand
o2 Operand
o3 Operand
o4 -> Operand -> Operand -> Operand -> Operand -> Instr
UBFX (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3) (Operand -> Operand
patchOp Operand
o4)

    -- 3. Logical and Move Instructions ----------------------------------------
    AND Operand
o1 Operand
o2 Operand
o3   -> Operand -> Operand -> Operand -> Instr
AND  (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)
    OR Operand
o1 Operand
o2 Operand
o3    -> Operand -> Operand -> Operand -> Instr
OR   (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)
    -- ANDS o1 o2 o3  -> ANDS (patchOp o1) (patchOp o2) (patchOp o3)
    ASR Operand
o1 Operand
o2 Operand
o3   -> Operand -> Operand -> Operand -> Instr
ASR  (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)
    BIC Operand
o1 Operand
o2 Operand
o3   -> Operand -> Operand -> Operand -> Instr
BIC  (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)
    BICS Operand
o1 Operand
o2 Operand
o3  -> Operand -> Operand -> Operand -> Instr
BICS (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)
    XOR Operand
o1 Operand
o2 Operand
o3   -> Operand -> Operand -> Operand -> Instr
XOR  (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)
    LSL Operand
o1 Operand
o2 Operand
o3   -> Operand -> Operand -> Operand -> Instr
LSL  (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)
    LSR Operand
o1 Operand
o2 Operand
o3   -> Operand -> Operand -> Operand -> Instr
LSR  (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)
    MOV Operand
o1 Operand
o2      -> Operand -> Operand -> Instr
MOV  (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2)
    -- o3 cannot be a register for ORI (always an immediate)
    ORI Operand
o1 Operand
o2 Operand
o3   -> Operand -> Operand -> Operand -> Instr
ORI  (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)
    XORI Operand
o1 Operand
o2 Operand
o3  -> Operand -> Operand -> Operand -> Instr
XORI  (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)

    -- 4. Branch Instructions --------------------------------------------------
    J Target
t            -> Target -> Instr
J (Target -> Target
patchTarget Target
t)
    B Target
t            -> Target -> Instr
B (Target -> Target
patchTarget Target
t)
    B_FAR BlockId
t            -> BlockId -> Instr
B_FAR BlockId
t
    BL Target
t [Reg]
rs [Reg]
ts     -> Target -> [Reg] -> [Reg] -> Instr
BL (Target -> Target
patchTarget Target
t) [Reg]
rs [Reg]
ts
    BCOND Cond
c Operand
o1 Operand
o2 Target
t -> Cond -> Operand -> Operand -> Target -> Instr
BCOND Cond
c (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Target -> Target
patchTarget Target
t)
    BCOND_FAR Cond
c Operand
o1 Operand
o2 Target
b Target
t -> Cond -> Operand -> Operand -> Target -> Target -> Instr
BCOND_FAR Cond
c (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Target -> Target
patchTarget Target
b) (Target -> Target
patchTarget Target
t)

    -- 5. Atomic Instructions --------------------------------------------------
    -- 6. Conditional Instructions ---------------------------------------------
    CSET Operand
o Operand
l Operand
r Cond
c   -> Operand -> Operand -> Operand -> Cond -> Instr
CSET (Operand -> Operand
patchOp Operand
o) (Operand -> Operand
patchOp Operand
l) (Operand -> Operand
patchOp Operand
r) Cond
c
    -- 7. Load and Store Instructions ------------------------------------------
    STR Format
f Operand
o1 Operand
o2    -> Format -> Operand -> Operand -> Instr
STR Format
f (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2)
    -- STLR f o1 o2   -> STLR f (patchOp o1) (patchOp o2)
    LDR Format
f Operand
o1 Operand
o2    -> Format -> Operand -> Operand -> Instr
LDR Format
f (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2)
    LDRU Format
f Operand
o1 Operand
o2    -> Format -> Operand -> Operand -> Instr
LDRU Format
f (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2)
    -- LDAR f o1 o2   -> LDAR f (patchOp o1) (patchOp o2)
    -- STP f o1 o2 o3 -> STP f (patchOp o1) (patchOp o2) (patchOp o3)
    -- LDP f o1 o2 o3 -> LDP f (patchOp o1) (patchOp o2) (patchOp o3)

    -- 8. Synchronization Instructions -----------------------------------------
    DMBSY DmbType
o1 DmbType
o2    -> DmbType -> DmbType -> Instr
DMBSY DmbType
o1 DmbType
o2

    -- 9. Floating Point Instructions ------------------------------------------
    FCVT Operand
o1 Operand
o2     -> Operand -> Operand -> Instr
FCVT (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2)
    SCVTF Operand
o1 Operand
o2    -> Operand -> Operand -> Instr
SCVTF (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2)
    FCVTZS Operand
o1 Operand
o2   -> Operand -> Operand -> Instr
FCVTZS (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2)
    FABS Operand
o1 Operand
o2     -> Operand -> Operand -> Instr
FABS (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2)
    Instr
_              -> String -> Instr
forall a. HasCallStack => String -> a
panic (String -> Instr) -> String -> Instr
forall a b. (a -> b) -> a -> b
$ String
"patchRegsOfInstr: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Instr -> String
instrCon Instr
instr
    where
        patchOp :: Operand -> Operand
        patchOp :: Operand -> Operand
patchOp (OpReg Width
w Reg
r) = Width -> Reg -> Operand
OpReg Width
w (Reg -> Reg
env Reg
r)
        patchOp (OpAddr AddrMode
a) = AddrMode -> Operand
OpAddr (AddrMode -> AddrMode
patchAddr AddrMode
a)
        patchOp Operand
op = Operand
op
        patchTarget :: Target -> Target
        patchTarget :: Target -> Target
patchTarget (TReg Reg
r) = Reg -> Target
TReg (Reg -> Reg
env Reg
r)
        patchTarget Target
t = Target
t
        patchAddr :: AddrMode -> AddrMode
        patchAddr :: AddrMode -> AddrMode
patchAddr (AddrRegImm Reg
r1 Imm
i)  = Reg -> Imm -> AddrMode
AddrRegImm (Reg -> Reg
env Reg
r1) Imm
i
        patchAddr (AddrReg Reg
r) = Reg -> AddrMode
AddrReg (Reg -> Reg
env Reg
r)
--------------------------------------------------------------------------------

-- | Checks whether this instruction is a jump/branch instruction.
--
-- One that can change the flow of control in a way that the
-- register allocator needs to worry about.
isJumpishInstr :: Instr -> Bool
isJumpishInstr :: Instr -> Bool
isJumpishInstr Instr
instr = case Instr
instr of
  ANN SDoc
_ Instr
i -> Instr -> Bool
isJumpishInstr Instr
i
  J {} -> Bool
True
  B {} -> Bool
True
  B_FAR {} -> Bool
True
  BL {} -> Bool
True
  BCOND {} -> Bool
True
  BCOND_FAR {} -> Bool
True
  Instr
_ -> Bool
False

-- | Get the `BlockId`s of the jump destinations (if any)
jumpDestsOfInstr :: Instr -> [BlockId]
jumpDestsOfInstr :: Instr -> [BlockId]
jumpDestsOfInstr (ANN SDoc
_ Instr
i) = Instr -> [BlockId]
jumpDestsOfInstr Instr
i
jumpDestsOfInstr (J Target
t) = [BlockId
id | TBlock BlockId
id <- [Target
t]]
jumpDestsOfInstr (B Target
t) = [BlockId
id | TBlock BlockId
id <- [Target
t]]
jumpDestsOfInstr (B_FAR BlockId
t) = [BlockId
t]
jumpDestsOfInstr (BL Target
t [Reg]
_ [Reg]
_) = [BlockId
id | TBlock BlockId
id <- [Target
t]]
jumpDestsOfInstr (BCOND Cond
_ Operand
_ Operand
_ Target
t) = [BlockId
id | TBlock BlockId
id <- [Target
t]]
jumpDestsOfInstr (BCOND_FAR Cond
_ Operand
_ Operand
_ Target
_ Target
t) = [BlockId
id | TBlock BlockId
id <- [Target
t]]
jumpDestsOfInstr Instr
_ = []

-- | Change the destination of this (potential) jump instruction.
--
-- Used in the linear allocator when adding fixup blocks for join
-- points.
patchJumpInstr :: Instr -> (BlockId -> BlockId) -> Instr
patchJumpInstr :: Instr -> (BlockId -> BlockId) -> Instr
patchJumpInstr Instr
instr BlockId -> BlockId
patchF =
  case Instr
instr of
    ANN SDoc
d Instr
i -> SDoc -> Instr -> Instr
ANN SDoc
d (Instr -> (BlockId -> BlockId) -> Instr
patchJumpInstr Instr
i BlockId -> BlockId
patchF)
    J (TBlock BlockId
bid) -> Target -> Instr
J (BlockId -> Target
TBlock (BlockId -> BlockId
patchF BlockId
bid))
    B (TBlock BlockId
bid) -> Target -> Instr
B (BlockId -> Target
TBlock (BlockId -> BlockId
patchF BlockId
bid))
    B_FAR BlockId
bid -> BlockId -> Instr
B_FAR (BlockId -> BlockId
patchF BlockId
bid)
    BL (TBlock BlockId
bid) [Reg]
ps [Reg]
rs -> Target -> [Reg] -> [Reg] -> Instr
BL (BlockId -> Target
TBlock (BlockId -> BlockId
patchF BlockId
bid)) [Reg]
ps [Reg]
rs
    BCOND Cond
c Operand
o1 Operand
o2 (TBlock BlockId
bid) -> Cond -> Operand -> Operand -> Target -> Instr
BCOND Cond
c Operand
o1 Operand
o2 (BlockId -> Target
TBlock (BlockId -> BlockId
patchF BlockId
bid))
    BCOND_FAR Cond
c Operand
o1 Operand
o2 Target
b (TBlock BlockId
bid) -> Cond -> Operand -> Operand -> Target -> Target -> Instr
BCOND_FAR Cond
c Operand
o1 Operand
o2 Target
b (BlockId -> Target
TBlock (BlockId -> BlockId
patchF BlockId
bid))
    Instr
_ -> String -> Instr
forall a. HasCallStack => String -> a
panic (String -> Instr) -> String -> Instr
forall a b. (a -> b) -> a -> b
$ String
"patchJumpInstr: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Instr -> String
instrCon Instr
instr

-- -----------------------------------------------------------------------------
-- Note [Spills and Reloads]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~
-- We reserve @RESERVED_C_STACK_BYTES@ on the C stack for spilling and reloading
-- registers.  AArch64s maximum displacement for SP relative spills and reloads
-- is essentially [-256,255], or [0, 0xFFF]*8 = [0, 32760] for 64bits.
--
-- The @RESERVED_C_STACK_BYTES@ is 16k, so we can't address any location in a
-- single instruction.  The idea is to use the Inter Procedure 0 (ip) register
-- to perform the computations for larger offsets.
--
-- Using sp to compute the offset will violate assumptions about the stack pointer
-- pointing to the top of the stack during signal handling.  As we can't force
-- every signal to use its own stack, we have to ensure that the stack pointer
-- always points to the top of the stack, and we can't use it for computation.
--
-- | An instruction to spill a register into a spill slot.
mkSpillInstr ::
  HasCallStack =>
  NCGConfig ->
  Reg -> -- ^ register to spill
  Int -> -- ^ current stack delta
  Int -> -- ^ spill slot to use
  [Instr]
mkSpillInstr :: HasCallStack => NCGConfig -> Reg -> RegNo -> RegNo -> [Instr]
mkSpillInstr NCGConfig
_config Reg
reg RegNo
delta RegNo
slot =
  case RegNo
off RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
- RegNo
delta of
    RegNo
imm | RegNo -> Bool
forall a. (Num a, Ord a) => a -> Bool
fitsIn12bitImm RegNo
imm -> [RegNo -> Instr
mkStrSpImm RegNo
imm]
    RegNo
imm ->
      [ RegNo -> Instr
movImmToIp RegNo
imm,
        Instr
addSpToIp,
        Instr
mkStrIp
      ]
  where
    fmt :: Format
fmt = case Reg
reg of
      RegReal (RealRegSingle RegNo
n) | RegNo
n RegNo -> RegNo -> Bool
forall a. Ord a => a -> a -> Bool
< RegNo
d0RegNo -> Format
II64
      Reg
_ -> Format
FF64
    mkStrSpImm :: RegNo -> Instr
mkStrSpImm RegNo
imm = SDoc -> Instr -> Instr
ANN (String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Spill@" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> RegNo -> SDoc
forall doc. IsLine doc => RegNo -> doc
int (RegNo
off RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
- RegNo
delta)) (Instr -> Instr) -> Instr -> Instr
forall a b. (a -> b) -> a -> b
$ Format -> Operand -> Operand -> Instr
STR Format
fmt (Width -> Reg -> Operand
OpReg Width
W64 Reg
reg) (AddrMode -> Operand
OpAddr (Reg -> Imm -> AddrMode
AddrRegImm Reg
spMachReg (RegNo -> Imm
ImmInt RegNo
imm)))
    movImmToIp :: RegNo -> Instr
movImmToIp RegNo
imm = SDoc -> Instr -> Instr
ANN (String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Spill: IP <- " SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> RegNo -> SDoc
forall doc. IsLine doc => RegNo -> doc
int RegNo
imm) (Instr -> Instr) -> Instr -> Instr
forall a b. (a -> b) -> a -> b
$ Operand -> Operand -> Instr
MOV Operand
ip (Imm -> Operand
OpImm (RegNo -> Imm
ImmInt RegNo
imm))
    addSpToIp :: Instr
addSpToIp = SDoc -> Instr -> Instr
ANN (String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Spill: IP <- SP + IP ") (Instr -> Instr) -> Instr -> Instr
forall a b. (a -> b) -> a -> b
$ Operand -> Operand -> Operand -> Instr
ADD Operand
ip Operand
ip Operand
sp
    mkStrIp :: Instr
mkStrIp = SDoc -> Instr -> Instr
ANN (String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Spill@" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> RegNo -> SDoc
forall doc. IsLine doc => RegNo -> doc
int (RegNo
off RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
- RegNo
delta)) (Instr -> Instr) -> Instr -> Instr
forall a b. (a -> b) -> a -> b
$ Format -> Operand -> Operand -> Instr
STR Format
fmt (Width -> Reg -> Operand
OpReg Width
W64 Reg
reg) (AddrMode -> Operand
OpAddr (Reg -> AddrMode
AddrReg Reg
ipReg))

    off :: RegNo
off = RegNo -> RegNo
spillSlotToOffset RegNo
slot

mkLoadInstr
   :: NCGConfig
   -> Reg       -- ^ register to load
   -> Int       -- ^ current stack delta
   -> Int       -- ^ spill slot to use
   -> [Instr]

mkLoadInstr :: NCGConfig -> Reg -> RegNo -> RegNo -> [Instr]
mkLoadInstr NCGConfig
_config Reg
reg RegNo
delta RegNo
slot =
  case RegNo
off RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
- RegNo
delta of
    RegNo
imm | RegNo -> Bool
forall a. (Num a, Ord a) => a -> Bool
fitsIn12bitImm RegNo
imm -> [RegNo -> Instr
mkLdrSpImm RegNo
imm]
    RegNo
imm ->
      [ RegNo -> Instr
movImmToIp RegNo
imm,
        Instr
addSpToIp,
        Instr
mkLdrIp
      ]
  where
    fmt :: Format
fmt = case Reg
reg of
      RegReal (RealRegSingle RegNo
n) | RegNo
n RegNo -> RegNo -> Bool
forall a. Ord a => a -> a -> Bool
< RegNo
d0RegNo -> Format
II64
      Reg
_ -> Format
FF64
    mkLdrSpImm :: RegNo -> Instr
mkLdrSpImm RegNo
imm = SDoc -> Instr -> Instr
ANN (String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Reload@" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> RegNo -> SDoc
forall doc. IsLine doc => RegNo -> doc
int (RegNo
off RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
- RegNo
delta)) (Instr -> Instr) -> Instr -> Instr
forall a b. (a -> b) -> a -> b
$ Format -> Operand -> Operand -> Instr
LDR Format
fmt (Width -> Reg -> Operand
OpReg Width
W64 Reg
reg) (AddrMode -> Operand
OpAddr (Reg -> Imm -> AddrMode
AddrRegImm Reg
spMachReg (RegNo -> Imm
ImmInt RegNo
imm)))
    movImmToIp :: RegNo -> Instr
movImmToIp RegNo
imm = SDoc -> Instr -> Instr
ANN (String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Reload: IP <- " SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> RegNo -> SDoc
forall doc. IsLine doc => RegNo -> doc
int RegNo
imm) (Instr -> Instr) -> Instr -> Instr
forall a b. (a -> b) -> a -> b
$ Operand -> Operand -> Instr
MOV Operand
ip (Imm -> Operand
OpImm (RegNo -> Imm
ImmInt RegNo
imm))
    addSpToIp :: Instr
addSpToIp = SDoc -> Instr -> Instr
ANN (String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Reload: IP <- SP + IP ") (Instr -> Instr) -> Instr -> Instr
forall a b. (a -> b) -> a -> b
$ Operand -> Operand -> Operand -> Instr
ADD Operand
ip Operand
ip Operand
sp
    mkLdrIp :: Instr
mkLdrIp = SDoc -> Instr -> Instr
ANN (String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Reload@" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> RegNo -> SDoc
forall doc. IsLine doc => RegNo -> doc
int (RegNo
off RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
- RegNo
delta)) (Instr -> Instr) -> Instr -> Instr
forall a b. (a -> b) -> a -> b
$ Format -> Operand -> Operand -> Instr
LDR Format
fmt (Width -> Reg -> Operand
OpReg Width
W64 Reg
reg) (AddrMode -> Operand
OpAddr (Reg -> AddrMode
AddrReg Reg
ipReg))

    off :: RegNo
off = RegNo -> RegNo
spillSlotToOffset RegNo
slot

-- | See if this instruction is telling us the current C stack delta
takeDeltaInstr :: Instr -> Maybe Int
takeDeltaInstr :: Instr -> Maybe RegNo
takeDeltaInstr (ANN SDoc
_ Instr
i) = Instr -> Maybe RegNo
takeDeltaInstr Instr
i
takeDeltaInstr (DELTA RegNo
i) = RegNo -> Maybe RegNo
forall a. a -> Maybe a
Just RegNo
i
takeDeltaInstr Instr
_         = Maybe RegNo
forall a. Maybe a
Nothing

-- | Not real instructions.  Just meta data
isMetaInstr :: Instr -> Bool
isMetaInstr :: Instr -> Bool
isMetaInstr Instr
instr =
  case Instr
instr of
    ANN SDoc
_ Instr
i -> Instr -> Bool
isMetaInstr Instr
i
    COMMENT {} -> Bool
True
    MULTILINE_COMMENT {} -> Bool
True
    LOCATION {} -> Bool
True
    LDATA {} -> Bool
True
    NEWBLOCK {} -> Bool
True
    DELTA {} -> Bool
True
    Instr
PUSH_STACK_FRAME -> Bool
True
    Instr
POP_STACK_FRAME -> Bool
True
    Instr
_ -> Bool
False

-- | Copy the value in a register to another one.
--
-- Must work for all register classes.
mkRegRegMoveInstr :: Reg -> Reg -> Instr
mkRegRegMoveInstr :: Reg -> Reg -> Instr
mkRegRegMoveInstr Reg
src Reg
dst = SDoc -> Instr -> Instr
ANN SDoc
desc Instr
instr
  where
    desc :: SDoc
desc = String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Reg->Reg Move: " SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> Reg -> SDoc
forall a. Outputable a => a -> SDoc
ppr Reg
src SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> String -> SDoc
forall doc. IsLine doc => String -> doc
text String
" -> " SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> Reg -> SDoc
forall a. Outputable a => a -> SDoc
ppr Reg
dst
    instr :: Instr
instr = Operand -> Operand -> Instr
MOV (Reg -> Operand
operandFromReg Reg
dst) (Reg -> Operand
operandFromReg Reg
src)

-- | Take the source and destination from this (potential) reg -> reg move instruction
--
-- We have to be a bit careful here: A `MOV` can also mean an implicit
-- conversion. This case is filtered out.
takeRegRegMoveInstr :: Instr -> Maybe (Reg, Reg)
takeRegRegMoveInstr :: Instr -> Maybe (Reg, Reg)
takeRegRegMoveInstr (MOV (OpReg Width
width Reg
dst) (OpReg Width
width' Reg
src))
  | Width
width Width -> Width -> Bool
forall a. Eq a => a -> a -> Bool
== Width
width' Bool -> Bool -> Bool
&& (Reg -> Bool
isFloatReg Reg
dst Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Reg -> Bool
isFloatReg Reg
src) = (Reg, Reg) -> Maybe (Reg, Reg)
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Reg
src, Reg
dst)
takeRegRegMoveInstr Instr
_ = Maybe (Reg, Reg)
forall a. Maybe a
Nothing

-- | Make an unconditional jump instruction.
mkJumpInstr :: BlockId -> [Instr]
mkJumpInstr :: BlockId -> [Instr]
mkJumpInstr = Instr -> [Instr]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Instr -> [Instr]) -> (BlockId -> Instr) -> BlockId -> [Instr]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Target -> Instr
B (Target -> Instr) -> (BlockId -> Target) -> BlockId -> Instr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BlockId -> Target
TBlock

-- | Decrement @sp@ to allocate stack space.
--
-- The stack grows downwards, so we decrement the stack pointer by @n@ (bytes).
-- This is dual to `mkStackDeallocInstr`. @sp@ is the RISCV stack pointer, not
-- to be confused with the STG stack pointer.
mkStackAllocInstr :: Platform -> Int -> [Instr]
mkStackAllocInstr :: Platform -> RegNo -> [Instr]
mkStackAllocInstr Platform
_platform = RegNo -> [Instr]
moveSp (RegNo -> [Instr]) -> (RegNo -> RegNo) -> RegNo -> [Instr]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RegNo -> RegNo
forall a. Num a => a -> a
negate

-- | Increment SP to deallocate stack space.
--
-- The stack grows downwards, so we increment the stack pointer by @n@ (bytes).
-- This is dual to `mkStackAllocInstr`. @sp@ is the RISCV stack pointer, not to
-- be confused with the STG stack pointer.
mkStackDeallocInstr :: Platform -> Int -> [Instr]
mkStackDeallocInstr :: Platform -> RegNo -> [Instr]
mkStackDeallocInstr Platform
_platform = RegNo -> [Instr]
moveSp

moveSp :: Int -> [Instr]
moveSp :: RegNo -> [Instr]
moveSp RegNo
n
  | RegNo
n RegNo -> RegNo -> Bool
forall a. Eq a => a -> a -> Bool
== RegNo
0 = []
  | RegNo
n RegNo -> RegNo -> Bool
forall a. Eq a => a -> a -> Bool
/= RegNo
0 Bool -> Bool -> Bool
&& RegNo -> Bool
forall a. (Num a, Ord a) => a -> Bool
fitsIn12bitImm RegNo
n = Instr -> [Instr]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Instr -> [Instr]) -> (Instr -> Instr) -> Instr -> [Instr]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SDoc -> Instr -> Instr
ANN SDoc
desc (Instr -> [Instr]) -> Instr -> [Instr]
forall a b. (a -> b) -> a -> b
$ Operand -> Operand -> Operand -> Instr
ADD Operand
sp Operand
sp (Imm -> Operand
OpImm (RegNo -> Imm
ImmInt RegNo
n))
  | Bool
otherwise =
      -- This ends up in three effective instructions. We could get away with
      -- two for intMax12bit < n < 3 * intMax12bit by recursing once. However,
      -- this way is likely less surprising.
      [ SDoc -> Instr -> Instr
ANN SDoc
desc (Operand -> Operand -> Instr
MOV Operand
ip (Imm -> Operand
OpImm (RegNo -> Imm
ImmInt RegNo
n))),
        Operand -> Operand -> Operand -> Instr
ADD Operand
sp Operand
sp Operand
ip
      ]
  where
    desc :: SDoc
desc = String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Move SP:" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> RegNo -> SDoc
forall doc. IsLine doc => RegNo -> doc
int RegNo
n

--
-- See Note [extra spill slots] in X86/Instr.hs
--
allocMoreStack
  :: Platform
  -> Int
  -> NatCmmDecl statics GHC.CmmToAsm.RV64.Instr.Instr
  -> UniqSM (NatCmmDecl statics GHC.CmmToAsm.RV64.Instr.Instr, [(BlockId,BlockId)])

allocMoreStack :: forall statics.
Platform
-> RegNo
-> NatCmmDecl statics Instr
-> UniqSM (NatCmmDecl statics Instr, [(BlockId, BlockId)])
allocMoreStack Platform
_ RegNo
_ top :: NatCmmDecl statics Instr
top@(CmmData Section
_ statics
_) = (NatCmmDecl statics Instr, [(BlockId, BlockId)])
-> UniqSM (NatCmmDecl statics Instr, [(BlockId, BlockId)])
forall a. a -> UniqSM a
forall (m :: * -> *) a. Monad m => a -> m a
return (NatCmmDecl statics Instr
top,[])
allocMoreStack Platform
platform RegNo
slots proc :: NatCmmDecl statics Instr
proc@(CmmProc LabelMap RawCmmStatics
info CLabel
lbl [GlobalReg]
live (ListGraph [GenBasicBlock Instr]
code)) = do
    let entries :: [BlockId]
entries = NatCmmDecl statics Instr -> [BlockId]
forall a i b. GenCmmDecl a (LabelMap i) (ListGraph b) -> [BlockId]
entryBlocks NatCmmDecl statics Instr
proc

    [Unique]
uniqs <- UniqSM [Unique]
forall (m :: * -> *). MonadUnique m => m [Unique]
getUniquesM

    let
      delta :: RegNo
delta = ((RegNo
x RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
+ RegNo
stackAlign RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
- RegNo
1) RegNo -> RegNo -> RegNo
forall a. Integral a => a -> a -> a
`quot` RegNo
stackAlign) RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
* RegNo
stackAlign -- round up
        where x :: RegNo
x = RegNo
slots RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
* RegNo
spillSlotSize -- sp delta

      alloc :: [Instr]
alloc   = Platform -> RegNo -> [Instr]
mkStackAllocInstr   Platform
platform RegNo
delta
      dealloc :: [Instr]
dealloc = Platform -> RegNo -> [Instr]
mkStackDeallocInstr Platform
platform RegNo
delta

      retargetList :: [(BlockId, BlockId)]
retargetList = [BlockId] -> [BlockId] -> [(BlockId, BlockId)]
forall a b. [a] -> [b] -> [(a, b)]
zip [BlockId]
entries ((Unique -> BlockId) -> [Unique] -> [BlockId]
forall a b. (a -> b) -> [a] -> [b]
map Unique -> BlockId
mkBlockId [Unique]
uniqs)

      new_blockmap :: LabelMap BlockId
      new_blockmap :: LabelMap BlockId
new_blockmap = [(KeyOf LabelMap, BlockId)] -> LabelMap BlockId
forall a. [(KeyOf LabelMap, a)] -> LabelMap a
forall (map :: * -> *) a. IsMap map => [(KeyOf map, a)] -> map a
mapFromList [(KeyOf LabelMap, BlockId)]
[(BlockId, BlockId)]
retargetList

      insert_stack_insn :: GenBasicBlock Instr -> [GenBasicBlock Instr]
insert_stack_insn (BasicBlock BlockId
id [Instr]
insns)
        | Just BlockId
new_blockid <- KeyOf LabelMap -> LabelMap BlockId -> Maybe BlockId
forall a. KeyOf LabelMap -> LabelMap a -> Maybe a
forall (map :: * -> *) a.
IsMap map =>
KeyOf map -> map a -> Maybe a
mapLookup KeyOf LabelMap
BlockId
id LabelMap BlockId
new_blockmap
        = [ BlockId -> [Instr] -> GenBasicBlock Instr
forall i. BlockId -> [i] -> GenBasicBlock i
BasicBlock BlockId
id ([Instr] -> GenBasicBlock Instr) -> [Instr] -> GenBasicBlock Instr
forall a b. (a -> b) -> a -> b
$ [Instr]
alloc [Instr] -> [Instr] -> [Instr]
forall a. [a] -> [a] -> [a]
++ [ Target -> Instr
B (BlockId -> Target
TBlock BlockId
new_blockid) ]
          , BlockId -> [Instr] -> GenBasicBlock Instr
forall i. BlockId -> [i] -> GenBasicBlock i
BasicBlock BlockId
new_blockid [Instr]
block' ]
        | Bool
otherwise
        = [ BlockId -> [Instr] -> GenBasicBlock Instr
forall i. BlockId -> [i] -> GenBasicBlock i
BasicBlock BlockId
id [Instr]
block' ]
        where
          block' :: [Instr]
block' = (Instr -> [Instr] -> [Instr]) -> [Instr] -> [Instr] -> [Instr]
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr Instr -> [Instr] -> [Instr]
insert_dealloc [] [Instr]
insns

      insert_dealloc :: Instr -> [Instr] -> [Instr]
insert_dealloc Instr
insn [Instr]
r = case Instr
insn of
        J Target
_ -> [Instr]
dealloc [Instr] -> [Instr] -> [Instr]
forall a. [a] -> [a] -> [a]
++ (Instr
insn Instr -> [Instr] -> [Instr]
forall a. a -> [a] -> [a]
: [Instr]
r)
        ANN SDoc
_ (J Target
_) -> [Instr]
dealloc [Instr] -> [Instr] -> [Instr]
forall a. [a] -> [a] -> [a]
++ (Instr
insn Instr -> [Instr] -> [Instr]
forall a. a -> [a] -> [a]
: [Instr]
r)
        Instr
_other | Instr -> [BlockId]
jumpDestsOfInstr Instr
insn [BlockId] -> [BlockId] -> Bool
forall a. Eq a => a -> a -> Bool
/= []
            -> Instr -> (BlockId -> BlockId) -> Instr
patchJumpInstr Instr
insn BlockId -> BlockId
retarget Instr -> [Instr] -> [Instr]
forall a. a -> [a] -> [a]
: [Instr]
r
        Instr
_other -> Instr
insn Instr -> [Instr] -> [Instr]
forall a. a -> [a] -> [a]
: [Instr]
r

        where retarget :: BlockId -> BlockId
retarget BlockId
b = BlockId -> Maybe BlockId -> BlockId
forall a. a -> Maybe a -> a
fromMaybe BlockId
b (KeyOf LabelMap -> LabelMap BlockId -> Maybe BlockId
forall a. KeyOf LabelMap -> LabelMap a -> Maybe a
forall (map :: * -> *) a.
IsMap map =>
KeyOf map -> map a -> Maybe a
mapLookup KeyOf LabelMap
BlockId
b LabelMap BlockId
new_blockmap)

      new_code :: [GenBasicBlock Instr]
new_code = (GenBasicBlock Instr -> [GenBasicBlock Instr])
-> [GenBasicBlock Instr] -> [GenBasicBlock Instr]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap GenBasicBlock Instr -> [GenBasicBlock Instr]
insert_stack_insn [GenBasicBlock Instr]
code
    (NatCmmDecl statics Instr, [(BlockId, BlockId)])
-> UniqSM (NatCmmDecl statics Instr, [(BlockId, BlockId)])
forall a. a -> UniqSM a
forall (m :: * -> *) a. Monad m => a -> m a
return (LabelMap RawCmmStatics
-> CLabel
-> [GlobalReg]
-> ListGraph Instr
-> NatCmmDecl statics Instr
forall d h g. h -> CLabel -> [GlobalReg] -> g -> GenCmmDecl d h g
CmmProc LabelMap RawCmmStatics
info CLabel
lbl [GlobalReg]
live ([GenBasicBlock Instr] -> ListGraph Instr
forall i. [GenBasicBlock i] -> ListGraph i
ListGraph [GenBasicBlock Instr]
new_code), [(BlockId, BlockId)]
retargetList)

-- -----------------------------------------------------------------------------
-- Machine's assembly language

-- We have a few common "instructions" (nearly all the pseudo-ops) but
-- mostly all of 'Instr' is machine-specific.

-- Some additional (potential future) instructions are commented out. They are
-- not needed yet for the backend but could be used in the future.

-- RV64 reference card: https://cs61c.org/sp23/pdfs/resources/reference-card.pdf
-- RV64 pseudo instructions: https://github.com/riscv-non-isa/riscv-asm-manual/blob/master/riscv-asm.md#-a-listing-of-standard-risc-v-pseudoinstructions
-- We will target: RV64G(C). That is G = I+A+F+S+D
-- I: Integer Multiplication and Division
-- A: Atomic Instructions
-- F: Single Precision
-- D: Double Precision
-- C: Compressed (though we won't use that).

-- This most notably leaves out B. (Bit Manipulation) instructions.

data Instr
    -- comment pseudo-op
    = COMMENT SDoc
    | MULTILINE_COMMENT SDoc

    -- Annotated instruction. Should print <instr> # <doc>
    | ANN SDoc Instr

    -- location pseudo-op (file, line, col, name)
    | LOCATION Int Int Int String

    -- some static data spat out during code
    -- generation.  Will be extracted before
    -- pretty-printing.
    | LDATA   Section RawCmmStatics

    -- start a new basic block.  Useful during
    -- codegen, removed later.  Preceding
    -- instruction should be a jump, as per the
    -- invariants for a BasicBlock (see Cmm).
    | NEWBLOCK BlockId

    -- specify current stack offset for
    -- benefit of subsequent passes
    | DELTA   Int

    -- 0. Pseudo Instructions --------------------------------------------------
    -- | SXTW Operand Operand
    -- | SXTX Operand Operand
    | PUSH_STACK_FRAME
    | POP_STACK_FRAME

    -- == Base Instructions (I) ================================================
    -- 1. Arithmetic Instructions ----------------------------------------------
    -- all of these instructions can also take an immediate, in which case they
    -- hafe a suffix I (except for U suffix, where it's IU then. E.g. SLTIU).
    | ADD Operand Operand Operand -- rd = rs1 + rs2
    | SUB Operand Operand Operand -- rd = rs1 - rs2

    | AND Operand Operand Operand -- rd = rs1 & rs2
    | OR  Operand Operand Operand -- rd = rs1 | rs2
    -- | XOR Operand Operand Operand -- rd = rs1 ^ rs2
    | LSL {- SLL -} Operand Operand Operand -- rd = rs1 << rs2 (zero ext)
    | LSR {- SRL -} Operand Operand Operand -- rd = rs1 >> rs2 (zero ext)
    -- | ASL {- SLA -} Operand Operand Operand -- rd = rs1 << rs2 (sign ext)
    | ASR {- SRA -} Operand Operand Operand -- rd = rs1 >> rs2 (sign ext)
    -- | SLT Operand Operand Operand -- rd = rs1 < rs2 ? 1 : 0 (signed)
    -- | SLTU Operand Operand Operand -- rd = rs1 < rs2 ? 1 : 0 (unsigned)

    -- 2. Memory Load/Store Instructions ---------------------------------------
    -- Unlike arm, we don't have register shorthands for size.
    -- We do however have {L,S}{B,H,W,D}[U] instructions for Load/Store, Byte, Half, Word, Double, (Unsigned).
    -- Reusing the arm logic with the _format_ specifier will hopefully work.
    | STR Format Operand Operand -- str Xn, address-mode // Xn -> *addr
    | LDR Format Operand Operand -- ldr Xn, address-mode // Xn <- *addr (sign-extended)
    | LDRU Format Operand Operand -- ldr Xn, address-mode // Xn <- *addr (unsigned)

    -- 3. Control Flow ---------------------------------------------------------
    -- B{EQ,GE,GEU,LT,LTU}, these are effectively BCOND from AArch64;
    -- however, AArch64 desugars them into CMP + BCOND. So these are a bit more
    -- powerful.
    -- JAL / JARL are effectively the BL instruction from AArch64.


    -- | CMN Operand Operand -- rd + op2
    -- | CMP Operand Operand -- rd - op2

    | MUL Operand Operand Operand -- rd = rn × rm


    -- Pseudo/synthesized:
    -- NEG = SUB x, 0, y
    -- NOT = XOR -1, x
    | NEG Operand Operand -- rd = -op2

    | DIV Operand Operand Operand -- rd = rn ÷ rm
    | REM Operand Operand Operand -- rd = rn % rm (signed)
    | REMU Operand Operand Operand -- rd = rn % rm (unsigned)

    -- TODO: Rename: MULH
    | SMULH Operand Operand Operand
    | DIVU Operand Operand Operand -- rd = rn ÷ rm

    -- 2. Bit Manipulation Instructions ----------------------------------------
    | SBFM Operand Operand Operand Operand -- rd = rn[i,j]
    | UBFM Operand Operand Operand Operand -- rd = rn[i,j]
    -- Signed/Unsigned bitfield extract
    | UBFX Operand Operand Operand Operand -- rd = rn[i,j]

    -- 3. Logical and Move Instructions ----------------------------------------
    -- | AND Operand Operand Operand -- rd = rn & op2
    -- | ANDS Operand Operand Operand -- rd = rn & op2
    -- | ASR Operand Operand Operand -- rd = rn ≫ rm  or  rd = rn ≫ #i, i is 6 bits
    -- TODO: unused
    | BIC Operand Operand Operand -- rd = rn & ~op2
    -- TODO: unused
    | BICS Operand Operand Operand -- rd = rn & ~op2
    | XOR Operand Operand Operand -- rd = rn ⊕ op2
    -- | LSL Operand Operand Operand -- rd = rn ≪ rm  or rd = rn ≪ #i, i is 6 bits
    -- | LSR Operand Operand Operand -- rd = rn ≫ rm  or rd = rn ≫ #i, i is 6 bits
    | MOV Operand Operand -- rd = rn  or  rd = #i
    | ORI Operand Operand Operand -- rd = rn | op2
    | XORI Operand Operand Operand -- rd = rn `xor` imm
    -- Load and stores.
    -- TODO STR/LDR might want to change to STP/LDP with XZR for the second register.
    -- | STR Format Operand Operand -- str Xn, address-mode // Xn -> *addr
    -- | STLR Format Operand Operand -- stlr Xn, address-mode // Xn -> *addr
    -- | LDR Format Operand Operand -- ldr Xn, address-mode // Xn <- *addr
    -- | LDAR Format Operand Operand -- ldar Xn, address-mode // Xn <- *addr
    -- | STP Format Operand Operand Operand -- stp Xn, Xm, address-mode // Xn -> *addr, Xm -> *(addr + 8)
    -- | LDP Format Operand Operand Operand -- stp Xn, Xm, address-mode // Xn <- *addr, Xm <- *(addr + 8)

    -- Conditional instructions
    -- This is a synthetic operation.
    | CSET Operand Operand Operand Cond   -- if(o2 cond o3) op <- 1 else op <- 0

    -- Branching.
    -- TODO: Unused
    | J Target            -- like B, but only generated from genJump. Used to distinguish genJumps from others.
    | B Target            -- unconditional branching b/br. (To a blockid, label or register)
    -- | pseudo-op for far branch targets
    | B_FAR BlockId
    | BL Target [Reg] [Reg] -- branch and link (e.g. set x30 to next pc, and branch)
    | BCOND Cond Operand Operand Target   -- branch with condition. b.<cond>
    -- | pseudo-op for far branch targets
    | BCOND_FAR Cond Operand Operand Target Target

    -- 8. Synchronization Instructions -----------------------------------------
    | DMBSY DmbType DmbType
    -- 9. Floating Point Instructions
    -- Float ConVerT
    | FCVT Operand Operand
    -- Signed ConVerT Float
    | SCVTF Operand Operand
    -- Float ConVerT to Zero Signed
    | FCVTZS Operand Operand
    -- Float ABSolute value
    | FABS Operand Operand

data DmbType = DmbRead | DmbWrite | DmbReadWrite

instrCon :: Instr -> String
instrCon :: Instr -> String
instrCon Instr
i =
    case Instr
i of
      COMMENT{} -> String
"COMMENT"
      MULTILINE_COMMENT{} -> String
"COMMENT"
      ANN{} -> String
"ANN"
      LOCATION{} -> String
"LOCATION"
      LDATA{} -> String
"LDATA"
      NEWBLOCK{} -> String
"NEWBLOCK"
      DELTA{} -> String
"DELTA"
      PUSH_STACK_FRAME{} -> String
"PUSH_STACK_FRAME"
      POP_STACK_FRAME{} -> String
"POP_STACK_FRAME"
      ADD{} -> String
"ADD"
      OR{} -> String
"OR"
      MUL{} -> String
"MUL"
      NEG{} -> String
"NEG"
      DIV{} -> String
"DIV"
      REM{} -> String
"REM"
      REMU{} -> String
"REMU"
      SMULH{} -> String
"SMULH"
      SUB{} -> String
"SUB"
      DIVU{} -> String
"DIVU"
      SBFM{} -> String
"SBFM"
      UBFM{} -> String
"UBFM"
      UBFX{} -> String
"UBFX"
      AND{} -> String
"AND"
      ASR{} -> String
"ASR"
      BIC{} -> String
"BIC"
      BICS{} -> String
"BICS"
      XOR{} -> String
"XOR"
      LSL{} -> String
"LSL"
      LSR{} -> String
"LSR"
      MOV{} -> String
"MOV"
      ORI{} -> String
"ORI"
      XORI{} -> String
"ORI"
      STR{} -> String
"STR"
      LDR{} -> String
"LDR"
      LDRU{} -> String
"LDRU"
      CSET{} -> String
"CSET"
      J{} -> String
"J"
      B{} -> String
"B"
      B_FAR{} -> String
"B_FAR"
      BL{} -> String
"BL"
      BCOND{} -> String
"BCOND"
      BCOND_FAR{} -> String
"BCOND_FAR"
      DMBSY{} -> String
"DMBSY"
      FCVT{} -> String
"FCVT"
      SCVTF{} -> String
"SCVTF"
      FCVTZS{} -> String
"FCVTZS"
      FABS{} -> String
"FABS"

-- TODO: We don't need TLabel.
data Target
    = TBlock BlockId
    | TLabel CLabel
    | TReg   Reg

data Operand
        = OpReg Width Reg            -- register
        | OpImm Imm            -- immediate value
        | OpAddr AddrMode       -- memory reference
        deriving (Operand -> Operand -> Bool
(Operand -> Operand -> Bool)
-> (Operand -> Operand -> Bool) -> Eq Operand
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Operand -> Operand -> Bool
== :: Operand -> Operand -> Bool
$c/= :: Operand -> Operand -> Bool
/= :: Operand -> Operand -> Bool
Eq, RegNo -> Operand -> String -> String
[Operand] -> String -> String
Operand -> String
(RegNo -> Operand -> String -> String)
-> (Operand -> String)
-> ([Operand] -> String -> String)
-> Show Operand
forall a.
(RegNo -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: RegNo -> Operand -> String -> String
showsPrec :: RegNo -> Operand -> String -> String
$cshow :: Operand -> String
show :: Operand -> String
$cshowList :: [Operand] -> String -> String
showList :: [Operand] -> String -> String
Show)

operandFromReg :: Reg -> Operand
operandFromReg :: Reg -> Operand
operandFromReg = Width -> Reg -> Operand
OpReg Width
W64

operandFromRegNo :: RegNo -> Operand
operandFromRegNo :: RegNo -> Operand
operandFromRegNo = Reg -> Operand
operandFromReg (Reg -> Operand) -> (RegNo -> Reg) -> RegNo -> Operand
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RegNo -> Reg
regSingle

zero, ra, sp, gp, tp, fp, ip :: Operand
zero :: Operand
zero = Reg -> Operand
operandFromReg Reg
zeroReg
ra :: Operand
ra  = Reg -> Operand
operandFromReg Reg
raReg
sp :: Operand
sp  = Reg -> Operand
operandFromReg Reg
spMachReg
gp :: Operand
gp  = RegNo -> Operand
operandFromRegNo RegNo
3
tp :: Operand
tp  = RegNo -> Operand
operandFromRegNo RegNo
4
fp :: Operand
fp  = RegNo -> Operand
operandFromRegNo RegNo
8
ip :: Operand
ip = Reg -> Operand
operandFromReg Reg
ipReg

x0,  x1,  x2,  x3,  x4,  x5,  x6,  x7  :: Operand
x8,  x9,  x10, x11, x12, x13, x14, x15 :: Operand
x16, x17, x18, x19, x20, x21, x22, x23 :: Operand
x24, x25, x26, x27, x28, x29, x30, x31 :: Operand
x0 :: Operand
x0  = RegNo -> Operand
operandFromRegNo  RegNo
x0RegNo
x1 :: Operand
x1  = RegNo -> Operand
operandFromRegNo  RegNo
1
x2 :: Operand
x2  = RegNo -> Operand
operandFromRegNo  RegNo
2
x3 :: Operand
x3  = RegNo -> Operand
operandFromRegNo  RegNo
3
x4 :: Operand
x4  = RegNo -> Operand
operandFromRegNo  RegNo
4
x5 :: Operand
x5  = RegNo -> Operand
operandFromRegNo  RegNo
x5RegNo
x6 :: Operand
x6  = RegNo -> Operand
operandFromRegNo  RegNo
6
x7 :: Operand
x7  = RegNo -> Operand
operandFromRegNo  RegNo
x7RegNo
x8 :: Operand
x8  = RegNo -> Operand
operandFromRegNo  RegNo
8
x9 :: Operand
x9  = RegNo -> Operand
operandFromRegNo  RegNo
9
x10 :: Operand
x10 = RegNo -> Operand
operandFromRegNo RegNo
x10RegNo
x11 :: Operand
x11 = RegNo -> Operand
operandFromRegNo RegNo
11
x12 :: Operand
x12 = RegNo -> Operand
operandFromRegNo RegNo
12
x13 :: Operand
x13 = RegNo -> Operand
operandFromRegNo RegNo
13
x14 :: Operand
x14 = RegNo -> Operand
operandFromRegNo RegNo
14
x15 :: Operand
x15 = RegNo -> Operand
operandFromRegNo RegNo
15
x16 :: Operand
x16 = RegNo -> Operand
operandFromRegNo RegNo
16
x17 :: Operand
x17 = RegNo -> Operand
operandFromRegNo RegNo
x17RegNo
x18 :: Operand
x18 = RegNo -> Operand
operandFromRegNo RegNo
18
x19 :: Operand
x19 = RegNo -> Operand
operandFromRegNo RegNo
19
x20 :: Operand
x20 = RegNo -> Operand
operandFromRegNo RegNo
20
x21 :: Operand
x21 = RegNo -> Operand
operandFromRegNo RegNo
21
x22 :: Operand
x22 = RegNo -> Operand
operandFromRegNo RegNo
22
x23 :: Operand
x23 = RegNo -> Operand
operandFromRegNo RegNo
23
x24 :: Operand
x24 = RegNo -> Operand
operandFromRegNo RegNo
24
x25 :: Operand
x25 = RegNo -> Operand
operandFromRegNo RegNo
25
x26 :: Operand
x26 = RegNo -> Operand
operandFromRegNo RegNo
26
x27 :: Operand
x27 = RegNo -> Operand
operandFromRegNo RegNo
27
x28 :: Operand
x28 = RegNo -> Operand
operandFromRegNo RegNo
x28RegNo
x29 :: Operand
x29 = RegNo -> Operand
operandFromRegNo RegNo
29
x30 :: Operand
x30 = RegNo -> Operand
operandFromRegNo RegNo
30
x31 :: Operand
x31 = RegNo -> Operand
operandFromRegNo RegNo
x31RegNo

d0,  d1,  d2,  d3,  d4,  d5,  d6,  d7  :: Operand
d8,  d9,  d10, d11, d12, d13, d14, d15 :: Operand
d16, d17, d18, d19, d20, d21, d22, d23 :: Operand
d24, d25, d26, d27, d28, d29, d30, d31 :: Operand
d0 :: Operand
d0  = RegNo -> Operand
operandFromRegNo RegNo
d0RegNo
d1 :: Operand
d1  = RegNo -> Operand
operandFromRegNo RegNo
33
d2 :: Operand
d2  = RegNo -> Operand
operandFromRegNo RegNo
34
d3 :: Operand
d3  = RegNo -> Operand
operandFromRegNo RegNo
35
d4 :: Operand
d4  = RegNo -> Operand
operandFromRegNo RegNo
36
d5 :: Operand
d5  = RegNo -> Operand
operandFromRegNo RegNo
37
d6 :: Operand
d6  = RegNo -> Operand
operandFromRegNo RegNo
38
d7 :: Operand
d7  = RegNo -> Operand
operandFromRegNo RegNo
d7RegNo
d8 :: Operand
d8  = RegNo -> Operand
operandFromRegNo RegNo
40
d9 :: Operand
d9  = RegNo -> Operand
operandFromRegNo RegNo
41
d10 :: Operand
d10 = RegNo -> Operand
operandFromRegNo RegNo
d10RegNo
d11 :: Operand
d11 = RegNo -> Operand
operandFromRegNo RegNo
43
d12 :: Operand
d12 = RegNo -> Operand
operandFromRegNo RegNo
44
d13 :: Operand
d13 = RegNo -> Operand
operandFromRegNo RegNo
45
d14 :: Operand
d14 = RegNo -> Operand
operandFromRegNo RegNo
46
d15 :: Operand
d15 = RegNo -> Operand
operandFromRegNo RegNo
47
d16 :: Operand
d16 = RegNo -> Operand
operandFromRegNo RegNo
48
d17 :: Operand
d17 = RegNo -> Operand
operandFromRegNo RegNo
d17RegNo
d18 :: Operand
d18 = RegNo -> Operand
operandFromRegNo RegNo
50
d19 :: Operand
d19 = RegNo -> Operand
operandFromRegNo RegNo
51
d20 :: Operand
d20 = RegNo -> Operand
operandFromRegNo RegNo
52
d21 :: Operand
d21 = RegNo -> Operand
operandFromRegNo RegNo
53
d22 :: Operand
d22 = RegNo -> Operand
operandFromRegNo RegNo
54
d23 :: Operand
d23 = RegNo -> Operand
operandFromRegNo RegNo
55
d24 :: Operand
d24 = RegNo -> Operand
operandFromRegNo RegNo
56
d25 :: Operand
d25 = RegNo -> Operand
operandFromRegNo RegNo
57
d26 :: Operand
d26 = RegNo -> Operand
operandFromRegNo RegNo
58
d27 :: Operand
d27 = RegNo -> Operand
operandFromRegNo RegNo
59
d28 :: Operand
d28 = RegNo -> Operand
operandFromRegNo RegNo
60
d29 :: Operand
d29 = RegNo -> Operand
operandFromRegNo RegNo
61
d30 :: Operand
d30 = RegNo -> Operand
operandFromRegNo RegNo
62
d31 :: Operand
d31 = RegNo -> Operand
operandFromRegNo RegNo
d31RegNo

fitsIn12bitImm :: (Num a, Ord a) => a -> Bool
fitsIn12bitImm :: forall a. (Num a, Ord a) => a -> Bool
fitsIn12bitImm a
off = a
off a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
forall a. Num a => a
intMin12bit Bool -> Bool -> Bool
&& a
off a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
forall a. Num a => a
intMax12bit

intMin12bit :: Num a => a
intMin12bit :: forall a. Num a => a
intMin12bit = -a
2048

intMax12bit :: Num a => a
intMax12bit :: forall a. Num a => a
intMax12bit = a
2047

fitsIn32bits  :: (Num a, Ord a, Bits a) => a -> Bool
fitsIn32bits :: forall a. (Num a, Ord a, Bits a) => a -> Bool
fitsIn32bits a
i = (-a
1 a -> RegNo -> a
forall a. Bits a => a -> RegNo -> a
`shiftL` RegNo
31) a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
i Bool -> Bool -> Bool
&& a
i a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= (a
1 a -> RegNo -> a
forall a. Bits a => a -> RegNo -> a
`shiftL` RegNo
31 a -> a -> a
forall a. Num a => a -> a -> a
-a
1)

isNbitEncodeable :: Int -> Integer -> Bool
isNbitEncodeable :: RegNo -> Integer -> Bool
isNbitEncodeable RegNo
n Integer
i = let shift :: RegNo
shift = RegNo
n RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
- RegNo
1 in (-Integer
1 Integer -> RegNo -> Integer
forall a. Bits a => a -> RegNo -> a
`shiftL` RegNo
shift) Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<= Integer
i Bool -> Bool -> Bool
&& Integer
i Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< (Integer
1 Integer -> RegNo -> Integer
forall a. Bits a => a -> RegNo -> a
`shiftL` RegNo
shift)

isEncodeableInWidth :: Width -> Integer -> Bool
isEncodeableInWidth :: Width -> Integer -> Bool
isEncodeableInWidth = RegNo -> Integer -> Bool
isNbitEncodeable (RegNo -> Integer -> Bool)
-> (Width -> RegNo) -> Width -> Integer -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Width -> RegNo
widthInBits

isIntOp :: Operand -> Bool
isIntOp :: Operand -> Bool
isIntOp = Bool -> Bool
not (Bool -> Bool) -> (Operand -> Bool) -> Operand -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Operand -> Bool
isFloatOp

isFloatOp :: Operand -> Bool
isFloatOp :: Operand -> Bool
isFloatOp (OpReg Width
_ Reg
reg) | Reg -> Bool
isFloatReg Reg
reg = Bool
True
isFloatOp Operand
_ = Bool
False

isFloatReg :: Reg -> Bool
isFloatReg :: Reg -> Bool
isFloatReg (RegReal (RealRegSingle RegNo
i)) | RegNo
i RegNo -> RegNo -> Bool
forall a. Ord a => a -> a -> Bool
> RegNo
31 = Bool
True
isFloatReg (RegVirtual (VirtualRegF Unique
_)) = Bool
True
isFloatReg (RegVirtual (VirtualRegD Unique
_)) = Bool
True
isFloatReg Reg
_ = Bool
False


-- | Making far branches

-- Conditional branch instructions can target labels in a range of +/- 4 KiB.
-- The assembler can transform this into a J instruction targeting +/- 1MiB.
-- There are rare cases where this is not enough (e.g. the Happy-generated
-- @Parser.hs@.) We need to manually transform these into register based jumps
-- using @ip@ (register reserved for calculations.) The trick is to invert the
-- condition, do a far jump in the fall-through case or a short jump when the
-- (inverted) condition is true.
makeFarBranches ::
  Platform ->
  LabelMap RawCmmStatics ->
  [NatBasicBlock Instr] ->
  UniqSM [NatBasicBlock Instr]
makeFarBranches :: Platform
-> LabelMap RawCmmStatics
-> [GenBasicBlock Instr]
-> UniqSM [GenBasicBlock Instr]
makeFarBranches Platform
_platform LabelMap RawCmmStatics
info_env [GenBasicBlock Instr]
blocks
  | NonEmpty RegNo -> RegNo
forall a. NonEmpty a -> a
NE.last NonEmpty RegNo
blockAddresses RegNo -> RegNo -> Bool
forall a. Ord a => a -> a -> Bool
< RegNo
nearLimit = [GenBasicBlock Instr] -> UniqSM [GenBasicBlock Instr]
forall a. a -> UniqSM a
forall (m :: * -> *) a. Monad m => a -> m a
return [GenBasicBlock Instr]
blocks
  | Bool
otherwise = [GenBasicBlock Instr] -> UniqSM [GenBasicBlock Instr]
forall a. a -> UniqSM a
forall (m :: * -> *) a. Monad m => a -> m a
return ([GenBasicBlock Instr] -> UniqSM [GenBasicBlock Instr])
-> [GenBasicBlock Instr] -> UniqSM [GenBasicBlock Instr]
forall a b. (a -> b) -> a -> b
$ (RegNo -> GenBasicBlock Instr -> GenBasicBlock Instr)
-> [RegNo] -> [GenBasicBlock Instr] -> [GenBasicBlock Instr]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith RegNo -> GenBasicBlock Instr -> GenBasicBlock Instr
handleBlock [RegNo]
blockAddressList [GenBasicBlock Instr]
blocks
  where
    blockAddresses :: NonEmpty RegNo
blockAddresses = (RegNo -> RegNo -> RegNo) -> RegNo -> [RegNo] -> NonEmpty RegNo
forall (f :: * -> *) b a.
Foldable f =>
(b -> a -> b) -> b -> f a -> NonEmpty b
NE.scanl RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
(+) RegNo
0 ([RegNo] -> NonEmpty RegNo) -> [RegNo] -> NonEmpty RegNo
forall a b. (a -> b) -> a -> b
$ (GenBasicBlock Instr -> RegNo) -> [GenBasicBlock Instr] -> [RegNo]
forall a b. (a -> b) -> [a] -> [b]
map GenBasicBlock Instr -> RegNo
forall {a}. GenBasicBlock a -> RegNo
blockLen [GenBasicBlock Instr]
blocks
    blockAddressList :: [RegNo]
blockAddressList = NonEmpty RegNo -> [RegNo]
forall a. NonEmpty a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList NonEmpty RegNo
blockAddresses
    blockLen :: GenBasicBlock a -> RegNo
blockLen (BasicBlock BlockId
_ [a]
instrs) = [a] -> RegNo
forall a. [a] -> RegNo
forall (t :: * -> *) a. Foldable t => t a -> RegNo
length [a]
instrs

    handleBlock :: RegNo -> GenBasicBlock Instr -> GenBasicBlock Instr
handleBlock RegNo
addr (BasicBlock BlockId
id [Instr]
instrs) =
      BlockId -> [Instr] -> GenBasicBlock Instr
forall i. BlockId -> [i] -> GenBasicBlock i
BasicBlock BlockId
id ((RegNo -> Instr -> Instr) -> [RegNo] -> [Instr] -> [Instr]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (BlockId -> RegNo -> Instr -> Instr
makeFar BlockId
id) [RegNo
addr ..] [Instr]
instrs)

    makeFar :: BlockId -> Int -> Instr -> Instr
    makeFar :: BlockId -> RegNo -> Instr -> Instr
makeFar BlockId
bid RegNo
addr orig :: Instr
orig@(BCOND Cond
cond Operand
op1 Operand
op2 tgt :: Target
tgt@(TBlock BlockId
tgtBid))
      | RegNo -> RegNo
forall a. Num a => a -> a
abs (RegNo
addr RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
- RegNo
targetAddr) RegNo -> RegNo -> Bool
forall a. Ord a => a -> a -> Bool
>= RegNo
nearLimit =
          RegNo -> RegNo -> Instr -> Instr
annotate RegNo
addr RegNo
targetAddr (Instr -> Instr) -> Instr -> Instr
forall a b. (a -> b) -> a -> b
$
            Cond -> Operand -> Operand -> Target -> Target -> Instr
BCOND_FAR Cond
cond Operand
op1 Operand
op2 (BlockId -> Target
TBlock BlockId
bid) Target
tgt
      | Bool
otherwise =
          RegNo -> RegNo -> Instr -> Instr
annotate RegNo
addr RegNo
targetAddr Instr
orig
      where
        targetAddr :: RegNo
targetAddr = Maybe RegNo -> RegNo
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe RegNo -> RegNo) -> Maybe RegNo -> RegNo
forall a b. (a -> b) -> a -> b
$ UniqFM BlockId RegNo -> BlockId -> Maybe RegNo
forall key elt. Uniquable key => UniqFM key elt -> key -> Maybe elt
lookupUFM UniqFM BlockId RegNo
blockAddressMap BlockId
tgtBid
    makeFar BlockId
_bid RegNo
addr orig :: Instr
orig@(B (TBlock BlockId
tgtBid))
      | RegNo -> RegNo
forall a. Num a => a -> a
abs (RegNo
addr RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
- RegNo
targetAddr) RegNo -> RegNo -> Bool
forall a. Ord a => a -> a -> Bool
>= RegNo
nearLimit =
          RegNo -> RegNo -> Instr -> Instr
annotate RegNo
addr RegNo
targetAddr (Instr -> Instr) -> Instr -> Instr
forall a b. (a -> b) -> a -> b
$
            BlockId -> Instr
B_FAR BlockId
tgtBid
      | Bool
otherwise =
          RegNo -> RegNo -> Instr -> Instr
annotate RegNo
addr RegNo
targetAddr Instr
orig
      where
        targetAddr :: RegNo
targetAddr = Maybe RegNo -> RegNo
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe RegNo -> RegNo) -> Maybe RegNo -> RegNo
forall a b. (a -> b) -> a -> b
$ UniqFM BlockId RegNo -> BlockId -> Maybe RegNo
forall key elt. Uniquable key => UniqFM key elt -> key -> Maybe elt
lookupUFM UniqFM BlockId RegNo
blockAddressMap BlockId
tgtBid
    makeFar BlockId
bid RegNo
addr (ANN SDoc
desc Instr
other) = SDoc -> Instr -> Instr
ANN SDoc
desc (Instr -> Instr) -> Instr -> Instr
forall a b. (a -> b) -> a -> b
$ BlockId -> RegNo -> Instr -> Instr
makeFar BlockId
bid RegNo
addr Instr
other
    makeFar BlockId
_bid RegNo
_ Instr
other = Instr
other

    -- 262144 (2^20 / 4) instructions are allowed; let's keep some distance, as
    -- we have pseudo-insns that are pretty-printed as multiple instructions,
    -- and it's just not worth the effort to calculate things exactly as linker
    -- relaxations are applied later (optimizing away our flaws.) The educated
    -- guess here is that every instruction does not emit more than two in the
    -- mean.
    nearLimit :: RegNo
nearLimit = RegNo
131072 RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
- LabelMap RawCmmStatics -> RegNo
forall a. LabelMap a -> RegNo
forall (map :: * -> *) a. IsMap map => map a -> RegNo
mapSize LabelMap RawCmmStatics
info_env RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
* RegNo
maxRetInfoTableSizeW

    blockAddressMap :: UniqFM BlockId RegNo
blockAddressMap = [(BlockId, RegNo)] -> UniqFM BlockId RegNo
forall key elt. Uniquable key => [(key, elt)] -> UniqFM key elt
listToUFM ([(BlockId, RegNo)] -> UniqFM BlockId RegNo)
-> [(BlockId, RegNo)] -> UniqFM BlockId RegNo
forall a b. (a -> b) -> a -> b
$ [BlockId] -> [RegNo] -> [(BlockId, RegNo)]
forall a b. [a] -> [b] -> [(a, b)]
zip ((GenBasicBlock Instr -> BlockId)
-> [GenBasicBlock Instr] -> [BlockId]
forall a b. (a -> b) -> [a] -> [b]
map GenBasicBlock Instr -> BlockId
forall i. GenBasicBlock i -> BlockId
blockId [GenBasicBlock Instr]
blocks) [RegNo]
blockAddressList

    -- We may want to optimize the limit in future. So, annotate the most
    -- important values of the decision.
    annotate :: Int -> Int -> Instr -> Instr
    annotate :: RegNo -> RegNo -> Instr -> Instr
annotate RegNo
addr RegNo
targetAddr Instr
instr =
      SDoc -> Instr -> Instr
ANN
        ( String -> SDoc
forall doc. IsLine doc => String -> doc
text (Instr -> String
instrCon Instr
instr)
            SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"targetAddr" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> SDoc
forall doc. IsLine doc => doc
colon
            SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> RegNo -> SDoc
forall doc. IsLine doc => RegNo -> doc
int RegNo
targetAddr SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> SDoc
forall doc. IsLine doc => doc
comma
            SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"offset" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> SDoc
forall doc. IsLine doc => doc
colon
            SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> RegNo -> SDoc
forall doc. IsLine doc => RegNo -> doc
int (RegNo
addr RegNo -> RegNo -> RegNo
forall a. Num a => a -> a -> a
- RegNo
targetAddr) SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> SDoc
forall doc. IsLine doc => doc
comma
            SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"nearLimit" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> SDoc
forall doc. IsLine doc => doc
colon
            SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> RegNo -> SDoc
forall doc. IsLine doc => RegNo -> doc
int RegNo
nearLimit
        )
        Instr
instr