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

module GHC.CmmToAsm.AArch64.Instr

where

import GHC.Prelude

import GHC.CmmToAsm.AArch64.Cond
import GHC.CmmToAsm.AArch64.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 Control.Monad (replicateM)
import Data.Maybe (fromMaybe)

import GHC.Stack

-- | TODO: verify this!
stackFrameHeaderSize :: Platform -> Int
stackFrameHeaderSize :: Platform -> RegNo
stackFrameHeaderSize Platform
_ = RegNo
64

-- | 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
--  = 0 -- set to zero, to see when allocMoreStack has to fire.
    = let platform :: Platform
platform = NCGConfig -> Platform
ncgPlatform NCGConfig
config
      in ((NCGConfig -> RegNo
ncgSpillPreallocSize NCGConfig
config forall a. Num a => a -> a -> a
- Platform -> RegNo
stackFrameHeaderSize Platform
platform)
         forall a. Integral a => a -> a -> a
`div` RegNo
spillSlotSize) forall a. Num a => a -> a -> a
- RegNo
1

-- | Convert a spill slot number to a *byte* offset, with no sign.
spillSlotToOffset :: NCGConfig -> Int -> Int
spillSlotToOffset :: NCGConfig -> RegNo -> RegNo
spillSlotToOffset NCGConfig
config RegNo
slot
   = Platform -> RegNo
stackFrameHeaderSize (NCGConfig -> Platform
ncgPlatform NCGConfig
config) forall a. Num a => a -> a -> a
+ RegNo
spillSlotSize 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
text String
"RegUsage(reads:" SDoc -> SDoc -> SDoc
<+> forall a. Outputable a => a -> SDoc
ppr [Reg]
reads SDoc -> SDoc -> SDoc
<> SDoc
comma SDoc -> SDoc -> SDoc
<+> String -> SDoc
text String
"writes:" SDoc -> SDoc -> SDoc
<+> forall a. Outputable a => a -> SDoc
ppr [Reg]
writes SDoc -> SDoc -> SDoc
<> Char -> SDoc
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 forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  CMN Operand
l Operand
r                  -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
l forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
r, [])
  CMP Operand
l Operand
r                  -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
l forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
r, [])
  MSUB Operand
dst Operand
src1 Operand
src2 Operand
src3  -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2 forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src3, Operand -> [Reg]
regOp Operand
dst)
  MUL Operand
dst Operand
src1 Operand
src2        -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 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 forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  SMULL Operand
dst Operand
src1 Operand
src2      -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  SDIV Operand
dst Operand
src1 Operand
src2       -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 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 forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  UDIV Operand
dst Operand
src1 Operand
src2       -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 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)
  SBFX 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)
  SXTB Operand
dst Operand
src             -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src, Operand -> [Reg]
regOp Operand
dst)
  UXTB Operand
dst Operand
src             -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src, Operand -> [Reg]
regOp Operand
dst)
  SXTH Operand
dst Operand
src             -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src, Operand -> [Reg]
regOp Operand
dst)
  UXTH Operand
dst Operand
src             -> ([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 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 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 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 forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  EON Operand
dst Operand
src1 Operand
src2        -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  EOR Operand
dst Operand
src1 Operand
src2        -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 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 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 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)
  MOVK Operand
dst Operand
src             -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src, Operand -> [Reg]
regOp Operand
dst)
  MVN Operand
dst Operand
src              -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src, Operand -> [Reg]
regOp Operand
dst)
  ORR Operand
dst Operand
src1 Operand
src2        -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  ROR Operand
dst Operand
src1 Operand
src2        -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, Operand -> [Reg]
regOp Operand
dst)
  TST Operand
src1 Operand
src2            -> ([Reg], [Reg]) -> RegUsage
usage (Operand -> [Reg]
regOp Operand
src1 forall a. [a] -> [a] -> [a]
++ Operand -> [Reg]
regOp Operand
src2, [])
  -- 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, [])
  BCOND Cond
_ Target
t                -> ([Reg], [Reg]) -> RegUsage
usage (Target -> [Reg]
regTarget Target
t, [])
  BL Target
t [Reg]
ps [Reg]
_rs              -> ([Reg], [Reg]) -> RegUsage
usage (Target -> [Reg]
regTarget Target
t forall a. [a] -> [a] -> [a]
++ [Reg]
ps, [Reg]
callerSavedRegisters)

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

  -- 8. Synchronization Instructions -------------------------------------------
  Instr
DMBSY                    -> ([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
_ -> forall a. String -> a
panic forall a b. (a -> b) -> a -> b
$ String
"regUsageOfInstr: " 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 (forall a. (a -> Bool) -> [a] -> [a]
filter (Platform -> Reg -> Bool
interesting Platform
platform) [Reg]
src)
                              (forall a. (a -> Bool) -> [a] -> [a]
filter (Platform -> Reg -> Bool
interesting Platform
platform) [Reg]
dst)

        regAddr :: AddrMode -> [Reg]
        regAddr :: AddrMode -> [Reg]
regAddr (AddrRegReg Reg
r1 Reg
r2) = [Reg
r1, Reg
r2]
        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 (OpRegExt Width
_ Reg
r1 ExtMode
_ RegNo
_) = [Reg
r1]
        regOp (OpRegShift Width
_ Reg
r1 ShiftMode
_ RegNo
_) = [Reg
r1]
        regOp (OpAddr AddrMode
a) = AddrMode -> [Reg]
regAddr AddrMode
a
        regOp (OpImm Imm
_) = []
        regOp (OpImmShift Imm
_ ShiftMode
_ RegNo
_) = []
        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
        interesting Platform
_        (RegReal (RealRegPair{}))
            = forall a. String -> a
panic String
"AArch64.Instr.interesting: no reg pairs on this arch"

-- 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 ==================================================================================================================================|
-- | <---- argument passing -------------> | IR | <------- tmp registers --------> | IP0| IP1| PL | <------------------- callee saved ------------> | FP | LR | SP |
-- | <------ free registers --------------------------------------------------------------------> | BR | Sp | Hp | R1 | R2 | R3 | R4 | R5 | R6 | SL | -- | -- | -- |
-- |== SIMD/FP Registers ==========================================================================================================================================|
-- | <---- argument passing -------------> | <-- callee saved (lower 64 bits) ---> | <--------------------------------------- caller saved ----------------------> |
-- | <------ free registers -------------> | F1 | F2 | F3 | F4 | D1 | D2 | D3 | D4 | <------ free registers -----------------------------------------------------> |
-- '---------------------------------------------------------------------------------------------------------------------------------------------------------------'
-- IR: Indirect result location register, IP: Intra-procedure register, PL: Platform register, FP: Frame pointer, LR: Link register, SP: Stack pointer
-- BR: Base, SL: SpLim
callerSavedRegisters :: [Reg]
callerSavedRegisters :: [Reg]
callerSavedRegisters
    = forall a b. (a -> b) -> [a] -> [b]
map RegNo -> Reg
regSingle [RegNo
0..RegNo
18]
    forall a. [a] -> [a] -> [a]
++ forall a b. (a -> b) -> [a] -> [b]
map RegNo -> Reg
regSingle [RegNo
32..RegNo
39]
    forall a. [a] -> [a] -> [a]
++ forall a b. (a -> b) -> [a] -> [b]
map RegNo -> Reg
regSingle [RegNo
48..RegNo
63]

-- | 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 Operand
o1 Operand
o2      -> Operand -> Operand -> Instr
CMN (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2)
    CMP Operand
o1 Operand
o2      -> Operand -> Operand -> Instr
CMP (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2)
    MSUB Operand
o1 Operand
o2 Operand
o3 Operand
o4 -> Operand -> Operand -> Operand -> Operand -> Instr
MSUB (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3) (Operand -> Operand
patchOp Operand
o4)
    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)
    SMULL Operand
o1 Operand
o2 Operand
o3 -> Operand -> Operand -> Operand -> Instr
SMULL (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2)  (Operand -> Operand
patchOp Operand
o3)
    SDIV Operand
o1 Operand
o2 Operand
o3  -> Operand -> Operand -> Operand -> Instr
SDIV (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)
    UDIV Operand
o1 Operand
o2 Operand
o3  -> Operand -> Operand -> Operand -> Instr
UDIV (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)
    SBFX Operand
o1 Operand
o2 Operand
o3 Operand
o4 -> Operand -> Operand -> Operand -> Operand -> Instr
SBFX (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)
    SXTB Operand
o1 Operand
o2       -> Operand -> Operand -> Instr
SXTB (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2)
    UXTB Operand
o1 Operand
o2       -> Operand -> Operand -> Instr
UXTB (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2)
    SXTH Operand
o1 Operand
o2       -> Operand -> Operand -> Instr
SXTH (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2)
    UXTH Operand
o1 Operand
o2       -> Operand -> Operand -> Instr
UXTH (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2)

    -- 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)
    ANDS Operand
o1 Operand
o2 Operand
o3  -> Operand -> Operand -> Operand -> Instr
ANDS (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
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)
    EON Operand
o1 Operand
o2 Operand
o3   -> Operand -> Operand -> Operand -> Instr
EON  (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)
    EOR Operand
o1 Operand
o2 Operand
o3   -> Operand -> Operand -> Operand -> Instr
EOR  (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)
    MOVK Operand
o1 Operand
o2     -> Operand -> Operand -> Instr
MOVK (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2)
    MVN Operand
o1 Operand
o2      -> Operand -> Operand -> Instr
MVN  (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2)
    ORR Operand
o1 Operand
o2 Operand
o3   -> Operand -> Operand -> Operand -> Instr
ORR  (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)
    ROR Operand
o1 Operand
o2 Operand
o3   -> Operand -> Operand -> Operand -> Instr
ROR  (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)
    TST Operand
o1 Operand
o2      -> Operand -> Operand -> Instr
TST  (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2)

    -- 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)
    BL Target
t [Reg]
rs [Reg]
ts     -> Target -> [Reg] -> [Reg] -> Instr
BL (Target -> Target
patchTarget Target
t) [Reg]
rs [Reg]
ts
    BCOND Cond
c Target
t      -> Cond -> Target -> Instr
BCOND Cond
c (Target -> Target
patchTarget Target
t)

    -- 5. Atomic Instructions --------------------------------------------------
    -- 6. Conditional Instructions ---------------------------------------------
    CSET Operand
o Cond
c       -> Operand -> Cond -> Instr
CSET (Operand -> Operand
patchOp Operand
o) Cond
c
    CBZ Operand
o Target
l        -> Operand -> Target -> Instr
CBZ (Operand -> Operand
patchOp Operand
o) Target
l
    CBNZ Operand
o Target
l       -> Operand -> Target -> Instr
CBNZ (Operand -> Operand
patchOp Operand
o) Target
l
    -- 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)
    LDR Format
f Operand
o1 Operand
o2    -> Format -> Operand -> Operand -> Instr
LDR Format
f (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2)
    STP Format
f Operand
o1 Operand
o2 Operand
o3 -> Format -> Operand -> Operand -> Operand -> Instr
STP Format
f (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)
    LDP Format
f Operand
o1 Operand
o2 Operand
o3 -> Format -> Operand -> Operand -> Operand -> Instr
LDP Format
f (Operand -> Operand
patchOp Operand
o1) (Operand -> Operand
patchOp Operand
o2) (Operand -> Operand
patchOp Operand
o3)

    -- 8. Synchronization Instructions -----------------------------------------
    Instr
DMBSY          -> Instr
DMBSY

    -- 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
_              -> forall a. String -> a
panic forall a b. (a -> b) -> a -> b
$ String
"patchRegsOfInstr: " 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 (OpRegExt Width
w Reg
r ExtMode
x RegNo
s) = Width -> Reg -> ExtMode -> RegNo -> Operand
OpRegExt Width
w (Reg -> Reg
env Reg
r) ExtMode
x RegNo
s
        patchOp (OpRegShift Width
w Reg
r ShiftMode
m RegNo
s) = Width -> Reg -> ShiftMode -> RegNo -> Operand
OpRegShift Width
w (Reg -> Reg
env Reg
r) ShiftMode
m RegNo
s
        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 (AddrRegReg Reg
r1 Reg
r2) = Reg -> Reg -> AddrMode
AddrRegReg (Reg -> Reg
env Reg
r1) (Reg -> Reg
env Reg
r2)
        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
    CBZ{} -> Bool
True
    CBNZ{} -> Bool
True
    J{} -> Bool
True
    B{} -> Bool
True
    BL{} -> Bool
True
    BCOND{} -> Bool
True
    Instr
_ -> Bool
False

-- | 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.
jumpDestsOfInstr :: Instr -> [BlockId]
jumpDestsOfInstr :: Instr -> [BlockId]
jumpDestsOfInstr (ANN SDoc
_ Instr
i) = Instr -> [BlockId]
jumpDestsOfInstr Instr
i
jumpDestsOfInstr (CBZ Operand
_ Target
t) = [ BlockId
id | TBlock BlockId
id <- [Target
t]]
jumpDestsOfInstr (CBNZ Operand
_ Target
t) = [ BlockId
id | TBlock BlockId
id <- [Target
t]]
jumpDestsOfInstr (J Target
t) = [BlockId
id | TBlock BlockId
id <- [Target
t]]
jumpDestsOfInstr (B Target
t) = [BlockId
id | TBlock BlockId
id <- [Target
t]]
jumpDestsOfInstr (BL Target
t [Reg]
_ [Reg]
_) = [ BlockId
id | TBlock BlockId
id <- [Target
t]]
jumpDestsOfInstr (BCOND Cond
_ Target
t) = [ BlockId
id | TBlock BlockId
id <- [Target
t]]
jumpDestsOfInstr Instr
_ = []

-- | Change the destination of this 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)
        CBZ Operand
r (TBlock BlockId
bid) -> Operand -> Target -> Instr
CBZ Operand
r (BlockId -> Target
TBlock (BlockId -> BlockId
patchF BlockId
bid))
        CBNZ Operand
r (TBlock BlockId
bid) -> Operand -> Target -> Instr
CBNZ Operand
r (BlockId -> Target
TBlock (BlockId -> BlockId
patchF BlockId
bid))
        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))
        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 (TBlock BlockId
bid) -> Cond -> Target -> Instr
BCOND Cond
c (BlockId -> Target
TBlock (BlockId -> BlockId
patchF BlockId
bid))
        Instr
_ -> forall a. String -> a
panic forall a b. (a -> b) -> a -> b
$ String
"patchJumpInstr: " 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 (ip0) 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 poitner
-- always poitns 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 (NCGConfig -> RegNo -> RegNo
spillSlotToOffset NCGConfig
config RegNo
slot) forall a. Num a => a -> a -> a
- RegNo
delta of
    RegNo
imm | -RegNo
256 forall a. Ord a => a -> a -> Bool
<= RegNo
imm Bool -> Bool -> Bool
&& RegNo
imm forall a. Ord a => a -> a -> Bool
<= RegNo
255                               -> [ RegNo -> Instr
mkStrSp RegNo
imm ]
    RegNo
imm | RegNo
imm forall a. Ord a => a -> a -> Bool
> RegNo
0 Bool -> Bool -> Bool
&& RegNo
imm forall a. Bits a => a -> a -> a
.&. RegNo
0x7 forall a. Eq a => a -> a -> Bool
== RegNo
0x0 Bool -> Bool -> Bool
&& RegNo
imm forall a. Ord a => a -> a -> Bool
<= RegNo
0xfff           -> [ RegNo -> Instr
mkStrSp RegNo
imm ]
    RegNo
imm | RegNo
imm forall a. Ord a => a -> a -> Bool
> RegNo
0xfff Bool -> Bool -> Bool
&& RegNo
imm forall a. Ord a => a -> a -> Bool
<= RegNo
0xffffff Bool -> Bool -> Bool
&& RegNo
imm forall a. Bits a => a -> a -> a
.&. RegNo
0x7 forall a. Eq a => a -> a -> Bool
== RegNo
0x0    -> [ RegNo -> Instr
mkIp0SpillAddr (RegNo
imm forall a. Bits a => a -> a -> a
.&~. RegNo
0xfff)
                                                                     , RegNo -> Instr
mkStrIp0 (RegNo
imm forall a. Bits a => a -> a -> a
.&.  RegNo
0xfff)
                                                                     ]
    RegNo
imm -> forall a. HasCallStack => String -> SDoc -> a
pprPanic String
"mkSpillInstr" (String -> SDoc
text String
"Unable to spill into" SDoc -> SDoc -> SDoc
<+> RegNo -> SDoc
int RegNo
imm)
    where
        a
a .&~. :: a -> a -> a
.&~. a
b = a
a forall a. Bits a => a -> a -> a
.&. (forall a. Bits a => a -> a
complement a
b)

        fmt :: Format
fmt = case Reg
reg of
            RegReal (RealRegSingle RegNo
n) | RegNo
n forall a. Ord a => a -> a -> Bool
< RegNo
32 -> Format
II64
            Reg
_                                  -> Format
FF64
        mkIp0SpillAddr :: RegNo -> Instr
mkIp0SpillAddr RegNo
imm = SDoc -> Instr -> Instr
ANN (String -> SDoc
text String
"Spill: IP0 <- SP + " SDoc -> SDoc -> SDoc
<> RegNo -> SDoc
int RegNo
imm) forall a b. (a -> b) -> a -> b
$ Operand -> Operand -> Operand -> Instr
ADD Operand
ip0 Operand
sp (Imm -> Operand
OpImm (RegNo -> Imm
ImmInt RegNo
imm))
        mkStrSp :: RegNo -> Instr
mkStrSp RegNo
imm = SDoc -> Instr -> Instr
ANN (String -> SDoc
text String
"Spill@" SDoc -> SDoc -> SDoc
<> RegNo -> SDoc
int (RegNo
off forall a. Num a => a -> a -> a
- RegNo
delta)) 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 (RegNo -> Reg
regSingle RegNo
31) (RegNo -> Imm
ImmInt RegNo
imm)))
        mkStrIp0 :: RegNo -> Instr
mkStrIp0 RegNo
imm = SDoc -> Instr -> Instr
ANN (String -> SDoc
text String
"Spill@" SDoc -> SDoc -> SDoc
<> RegNo -> SDoc
int (RegNo
off forall a. Num a => a -> a -> a
- RegNo
delta)) 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 (RegNo -> Reg
regSingle RegNo
16) (RegNo -> Imm
ImmInt RegNo
imm)))

        off :: RegNo
off = NCGConfig -> RegNo -> RegNo
spillSlotToOffset NCGConfig
config 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 (NCGConfig -> RegNo -> RegNo
spillSlotToOffset NCGConfig
config RegNo
slot) forall a. Num a => a -> a -> a
- RegNo
delta of
    RegNo
imm | -RegNo
256 forall a. Ord a => a -> a -> Bool
<= RegNo
imm Bool -> Bool -> Bool
&& RegNo
imm forall a. Ord a => a -> a -> Bool
<= RegNo
255                               -> [ RegNo -> Instr
mkLdrSp RegNo
imm ]
    RegNo
imm | RegNo
imm forall a. Ord a => a -> a -> Bool
> RegNo
0 Bool -> Bool -> Bool
&& RegNo
imm forall a. Bits a => a -> a -> a
.&. RegNo
0x7 forall a. Eq a => a -> a -> Bool
== RegNo
0x0 Bool -> Bool -> Bool
&& RegNo
imm forall a. Ord a => a -> a -> Bool
<= RegNo
0xfff           -> [ RegNo -> Instr
mkLdrSp RegNo
imm ]
    RegNo
imm | RegNo
imm forall a. Ord a => a -> a -> Bool
> RegNo
0xfff Bool -> Bool -> Bool
&& RegNo
imm forall a. Ord a => a -> a -> Bool
<= RegNo
0xffffff Bool -> Bool -> Bool
&& RegNo
imm forall a. Bits a => a -> a -> a
.&. RegNo
0x7 forall a. Eq a => a -> a -> Bool
== RegNo
0x0    -> [ RegNo -> Instr
mkIp0SpillAddr (RegNo
imm forall a. Bits a => a -> a -> a
.&~. RegNo
0xfff)
                                                                     , RegNo -> Instr
mkLdrIp0 (RegNo
imm forall a. Bits a => a -> a -> a
.&.  RegNo
0xfff)
                                                                     ]
    RegNo
imm -> forall a. HasCallStack => String -> SDoc -> a
pprPanic String
"mkSpillInstr" (String -> SDoc
text String
"Unable to spill into" SDoc -> SDoc -> SDoc
<+> RegNo -> SDoc
int RegNo
imm)
    where
        a
a .&~. :: a -> a -> a
.&~. a
b = a
a forall a. Bits a => a -> a -> a
.&. (forall a. Bits a => a -> a
complement a
b)

        fmt :: Format
fmt = case Reg
reg of
            RegReal (RealRegSingle RegNo
n) | RegNo
n forall a. Ord a => a -> a -> Bool
< RegNo
32 -> Format
II64
            Reg
_                                  -> Format
FF64

        mkIp0SpillAddr :: RegNo -> Instr
mkIp0SpillAddr RegNo
imm = SDoc -> Instr -> Instr
ANN (String -> SDoc
text String
"Reload: IP0 <- SP + " SDoc -> SDoc -> SDoc
<> RegNo -> SDoc
int RegNo
imm) forall a b. (a -> b) -> a -> b
$ Operand -> Operand -> Operand -> Instr
ADD Operand
ip0 Operand
sp (Imm -> Operand
OpImm (RegNo -> Imm
ImmInt RegNo
imm))
        mkLdrSp :: RegNo -> Instr
mkLdrSp RegNo
imm = SDoc -> Instr -> Instr
ANN (String -> SDoc
text String
"Reload@" SDoc -> SDoc -> SDoc
<> RegNo -> SDoc
int (RegNo
off forall a. Num a => a -> a -> a
- RegNo
delta)) 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 (RegNo -> Reg
regSingle RegNo
31) (RegNo -> Imm
ImmInt RegNo
imm)))
        mkLdrIp0 :: RegNo -> Instr
mkLdrIp0 RegNo
imm = SDoc -> Instr -> Instr
ANN (String -> SDoc
text String
"Reload@" SDoc -> SDoc -> SDoc
<> RegNo -> SDoc
int (RegNo
off forall a. Num a => a -> a -> a
- RegNo
delta)) 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 (RegNo -> Reg
regSingle RegNo
16) (RegNo -> Imm
ImmInt RegNo
imm)))

        off :: RegNo
off = NCGConfig -> RegNo -> RegNo
spillSlotToOffset NCGConfig
config 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) = forall a. a -> Maybe a
Just RegNo
i
takeDeltaInstr Instr
_         = 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 (String -> SDoc
text String
"Reg->Reg Move: " SDoc -> SDoc -> SDoc
<> forall a. Outputable a => a -> SDoc
ppr Reg
src SDoc -> SDoc -> SDoc
<> String -> SDoc
text String
" -> " SDoc -> SDoc -> SDoc
<> forall a. Outputable a => a -> SDoc
ppr Reg
dst) forall a b. (a -> b) -> a -> b
$ Operand -> Operand -> Instr
MOV (Width -> Reg -> Operand
OpReg Width
W64 Reg
dst) (Width -> Reg -> Operand
OpReg Width
W64 Reg
src)

-- | Take the source and destination from this reg -> reg move instruction
-- or Nothing if it's not one
takeRegRegMoveInstr :: Instr -> Maybe (Reg,Reg)
--takeRegRegMoveInstr (MOV (OpReg fmt dst) (OpReg fmt' src)) | fmt == fmt' = Just (src, dst)
takeRegRegMoveInstr :: Instr -> Maybe (Reg, Reg)
takeRegRegMoveInstr Instr
_ = forall a. Maybe a
Nothing

-- | Make an unconditional jump instruction.
mkJumpInstr :: BlockId -> [Instr]
mkJumpInstr :: BlockId -> [Instr]
mkJumpInstr BlockId
id = [Target -> Instr
B (BlockId -> Target
TBlock BlockId
id)]

mkStackAllocInstr :: Platform -> Int -> [Instr]
mkStackAllocInstr :: Platform -> RegNo -> [Instr]
mkStackAllocInstr Platform
platform RegNo
n
    | RegNo
n forall a. Eq a => a -> a -> Bool
== RegNo
0 = []
    | RegNo
n forall a. Ord a => a -> a -> Bool
> RegNo
0 Bool -> Bool -> Bool
&& RegNo
n forall a. Ord a => a -> a -> Bool
< RegNo
4096 = [ SDoc -> Instr -> Instr
ANN (String -> SDoc
text String
"Alloc More Stack") forall a b. (a -> b) -> a -> b
$ Operand -> Operand -> Operand -> Instr
SUB Operand
sp Operand
sp (Imm -> Operand
OpImm (RegNo -> Imm
ImmInt RegNo
n)) ]
    | RegNo
n forall a. Ord a => a -> a -> Bool
> RegNo
0 =  SDoc -> Instr -> Instr
ANN (String -> SDoc
text String
"Alloc More Stack") (Operand -> Operand -> Operand -> Instr
SUB Operand
sp Operand
sp (Imm -> Operand
OpImm (RegNo -> Imm
ImmInt RegNo
4095))) forall a. a -> [a] -> [a]
: Platform -> RegNo -> [Instr]
mkStackAllocInstr Platform
platform (RegNo
n forall a. Num a => a -> a -> a
- RegNo
4095)
mkStackAllocInstr Platform
_platform RegNo
n = forall a. HasCallStack => String -> SDoc -> a
pprPanic String
"mkStackAllocInstr" (RegNo -> SDoc
int RegNo
n)

mkStackDeallocInstr :: Platform -> Int -> [Instr]
mkStackDeallocInstr :: Platform -> RegNo -> [Instr]
mkStackDeallocInstr Platform
platform RegNo
n
    | RegNo
n forall a. Eq a => a -> a -> Bool
== RegNo
0 = []
    | RegNo
n forall a. Ord a => a -> a -> Bool
> RegNo
0 Bool -> Bool -> Bool
&& RegNo
n forall a. Ord a => a -> a -> Bool
< RegNo
4096 = [ SDoc -> Instr -> Instr
ANN (String -> SDoc
text String
"Dealloc More Stack") forall a b. (a -> b) -> a -> b
$ Operand -> Operand -> Operand -> Instr
ADD Operand
sp Operand
sp (Imm -> Operand
OpImm (RegNo -> Imm
ImmInt RegNo
n)) ]
    | RegNo
n forall a. Ord a => a -> a -> Bool
> RegNo
0 =  SDoc -> Instr -> Instr
ANN (String -> SDoc
text String
"Dealloc More Stack") (Operand -> Operand -> Operand -> Instr
ADD Operand
sp Operand
sp (Imm -> Operand
OpImm (RegNo -> Imm
ImmInt RegNo
4095))) forall a. a -> [a] -> [a]
: Platform -> RegNo -> [Instr]
mkStackDeallocInstr Platform
platform (RegNo
n forall a. Num a => a -> a -> a
- RegNo
4095)
mkStackDeallocInstr Platform
_platform RegNo
n = forall a. HasCallStack => String -> SDoc -> a
pprPanic String
"mkStackDeallocInstr" (RegNo -> SDoc
int RegNo
n)

--
-- See note [extra spill slots] in X86/Instr.hs
--
allocMoreStack
  :: Platform
  -> Int
  -> NatCmmDecl statics GHC.CmmToAsm.AArch64.Instr.Instr
  -> UniqSM (NatCmmDecl statics GHC.CmmToAsm.AArch64.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
_) = 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 = forall a i b. GenCmmDecl a (LabelMap i) (ListGraph b) -> [BlockId]
entryBlocks NatCmmDecl statics Instr
proc

    [Unique]
uniqs <- forall (m :: * -> *) a. Applicative m => RegNo -> m a -> m [a]
replicateM (forall (t :: * -> *) a. Foldable t => t a -> RegNo
length [BlockId]
entries) forall (m :: * -> *). MonadUnique m => m Unique
getUniqueM

    let
      delta :: RegNo
delta = ((RegNo
x forall a. Num a => a -> a -> a
+ RegNo
stackAlign forall a. Num a => a -> a -> a
- RegNo
1) forall a. Integral a => a -> a -> a
`quot` RegNo
stackAlign) forall a. Num a => a -> a -> a
* RegNo
stackAlign -- round up
        where x :: RegNo
x = RegNo
slots 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 = (forall a b. [a] -> [b] -> [(a, b)]
zip [BlockId]
entries (forall a b. (a -> b) -> [a] -> [b]
map Unique -> BlockId
mkBlockId [Unique]
uniqs))

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

      insert_stack_insn :: GenBasicBlock Instr -> [GenBasicBlock Instr]
insert_stack_insn (BasicBlock BlockId
id [Instr]
insns)
        | Just BlockId
new_blockid <- forall (map :: * -> *) a.
IsMap map =>
KeyOf map -> map a -> Maybe a
mapLookup BlockId
id LabelMap BlockId
new_blockmap
        = [ forall i. BlockId -> [i] -> GenBasicBlock i
BasicBlock BlockId
id forall a b. (a -> b) -> a -> b
$ [Instr]
alloc forall a. [a] -> [a] -> [a]
++ [ Target -> Instr
B (BlockId -> Target
TBlock BlockId
new_blockid) ]
          , forall i. BlockId -> [i] -> GenBasicBlock i
BasicBlock BlockId
new_blockid [Instr]
block' ]
        | Bool
otherwise
        = [ forall i. BlockId -> [i] -> GenBasicBlock i
BasicBlock BlockId
id [Instr]
block' ]
        where
          block' :: [Instr]
block' = 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 forall a. [a] -> [a] -> [a]
++ (Instr
insn forall a. a -> [a] -> [a]
: [Instr]
r)
        ANN SDoc
_ (J Target
_) -> [Instr]
dealloc forall a. [a] -> [a] -> [a]
++ (Instr
insn forall a. a -> [a] -> [a]
: [Instr]
r)
        Instr
_other | Instr -> [BlockId]
jumpDestsOfInstr Instr
insn forall a. Eq a => a -> a -> Bool
/= []
            -> Instr -> (BlockId -> BlockId) -> Instr
patchJumpInstr Instr
insn BlockId -> BlockId
retarget forall a. a -> [a] -> [a]
: [Instr]
r
        Instr
_other -> Instr
insn forall a. a -> [a] -> [a]
: [Instr]
r

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

      new_code :: [GenBasicBlock Instr]
new_code = forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap GenBasicBlock Instr -> [GenBasicBlock Instr]
insert_stack_insn [GenBasicBlock Instr]
code
    -- in
    forall (m :: * -> *) a. Monad m => a -> m a
return (forall d h g. h -> CLabel -> [GlobalReg] -> g -> GenCmmDecl d h g
CmmProc LabelMap RawCmmStatics
info CLabel
lbl [GlobalReg]
live (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.
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 --------------------------------------------------
    | SXTB Operand Operand
    | UXTB Operand Operand
    | SXTH Operand Operand
    | UXTH Operand Operand
    -- | SXTW Operand Operand
    -- | SXTX Operand Operand
    | PUSH_STACK_FRAME
    | POP_STACK_FRAME
    -- 1. Arithmetic Instructions ----------------------------------------------
    -- | ADC Operand Operand Operang -- rd = rn + rm + C
    -- | ADCS ...
    | ADD Operand Operand Operand -- rd = rn + rm
    -- | ADDS Operand Operand Operand -- rd = rn + rm
    -- | ADR ...
    -- | ADRP ...
    | CMN Operand Operand -- rd + op2
    | CMP Operand Operand -- rd - op2
    -- | MADD ...
    -- | MNEG ...
    | MSUB Operand Operand Operand Operand -- rd = ra - rn × rm
    | MUL Operand Operand Operand -- rd = rn × rm
    | NEG Operand Operand -- rd = -op2
    -- | NEGS ...
    -- | NGC ...
    -- | NGCS ...
    -- | SBC ...
    -- | SBCS ...
    | SDIV Operand Operand Operand -- rd = rn ÷ rm
    -- | SMADDL ...
    -- | SMNEGL ...
    -- | SMSUBL ...
    | SMULH Operand Operand Operand
    | SMULL Operand Operand Operand
    | SUB Operand Operand Operand -- rd = rn - op2
    -- | SUBS ...
    | UDIV Operand Operand Operand -- rd = rn ÷ rm
    -- | UMADDL ...  -- Xd = Xa + Wn × Wm
    -- | UMNEGL ... -- Xd = - Wn × Wm
    -- | UMSUBL ... -- Xd = Xa - Wn × Wm
    -- | UMULH ... -- Xd = (Xn × Xm)_127:64
    -- | UMULL ... -- Xd = Wn × Wm

    -- 2. Bit Manipulation Instructions ----------------------------------------
    | SBFM Operand Operand Operand Operand -- rd = rn[i,j]
    -- SXTB = SBFM <Wd>, <Wn>, #0, #7
    -- SXTH = SBFM <Wd>, <Wn>, #0, #15
    -- SXTW = SBFM <Wd>, <Wn>, #0, #31
    | UBFM Operand Operand Operand Operand -- rd = rn[i,j]
    -- UXTB = UBFM <Wd>, <Wn>, #0, #7
    -- UXTH = UBFM <Wd>, <Wn>, #0, #15
    -- Signed/Unsigned bitfield extract
    | SBFX Operand Operand Operand Operand -- rd = rn[i,j]
    | 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
    | BIC Operand Operand Operand -- rd = rn & ~op2
    | BICS Operand Operand Operand -- rd = rn & ~op2
    | EON Operand Operand Operand -- rd = rn ⊕ ~op2
    | EOR 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
    | MOVK Operand Operand
    -- | MOVN Operand Operand
    -- | MOVZ Operand Operand
    | MVN Operand Operand -- rd = ~rn
    | ORN Operand Operand Operand -- rd = rn | ~op2
    | ORR Operand Operand Operand -- rd = rn | op2
    | ROR Operand Operand Operand -- rd = rn ≫ rm  or  rd = rn ≫ #i, i is 6 bits
    | TST Operand Operand -- rn & op2
    -- 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
    | LDR Format Operand Operand -- ldr 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
    | CSET Operand Cond   -- if(cond) op <- 1 else op <- 0

    | CBZ Operand Target  -- if op == 0, then branch.
    | CBNZ Operand Target -- if op /= 0, then branch.
    -- Branching.
    | 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)
    | BL Target [Reg] [Reg] -- branch and link (e.g. set x30 to next pc, and branch)
    | BCOND Cond Target   -- branch with condition. b.<cond>

    -- 8. Synchronization Instructions -----------------------------------------
    | DMBSY
    -- 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

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"
      SXTB{} -> String
"SXTB"
      UXTB{} -> String
"UXTB"
      SXTH{} -> String
"SXTH"
      UXTH{} -> String
"UXTH"
      PUSH_STACK_FRAME{} -> String
"PUSH_STACK_FRAME"
      POP_STACK_FRAME{} -> String
"POP_STACK_FRAME"
      ADD{} -> String
"ADD"
      CMN{} -> String
"CMN"
      CMP{} -> String
"CMP"
      MSUB{} -> String
"MSUB"
      MUL{} -> String
"MUL"
      NEG{} -> String
"NEG"
      SDIV{} -> String
"SDIV"
      SMULH{} -> String
"SMULH"
      SMULL{} -> String
"SMULL"
      SUB{} -> String
"SUB"
      UDIV{} -> String
"UDIV"
      SBFM{} -> String
"SBFM"
      UBFM{} -> String
"UBFM"
      SBFX{} -> String
"SBFX"
      UBFX{} -> String
"UBFX"
      AND{} -> String
"AND"
      ANDS{} -> String
"ANDS"
      ASR{} -> String
"ASR"
      BIC{} -> String
"BIC"
      BICS{} -> String
"BICS"
      EON{} -> String
"EON"
      EOR{} -> String
"EOR"
      LSL{} -> String
"LSL"
      LSR{} -> String
"LSR"
      MOV{} -> String
"MOV"
      MOVK{} -> String
"MOVK"
      MVN{} -> String
"MVN"
      ORN{} -> String
"ORN"
      ORR{} -> String
"ORR"
      ROR{} -> String
"ROR"
      TST{} -> String
"TST"
      STR{} -> String
"STR"
      LDR{} -> String
"LDR"
      STP{} -> String
"STP"
      LDP{} -> String
"LDP"
      CSET{} -> String
"CSET"
      CBZ{} -> String
"CBZ"
      CBNZ{} -> String
"CBNZ"
      J{} -> String
"J"
      B{} -> String
"B"
      BL{} -> String
"BL"
      BCOND{} -> String
"BCOND"
      DMBSY{} -> String
"DMBSY"
      FCVT{} -> String
"FCVT"
      SCVTF{} -> String
"SCVTF"
      FCVTZS{} -> String
"FCVTZS"
      FABS{} -> String
"FABS"

data Target
    = TBlock BlockId
    | TLabel CLabel
    | TReg   Reg


-- Extension
-- {Unsigned|Signed}XT{Byte|Half|Word|Doube}
data ExtMode
    = EUXTB | EUXTH | EUXTW | EUXTX
    | ESXTB | ESXTH | ESXTW | ESXTX
    deriving (ExtMode -> ExtMode -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ExtMode -> ExtMode -> Bool
$c/= :: ExtMode -> ExtMode -> Bool
== :: ExtMode -> ExtMode -> Bool
$c== :: ExtMode -> ExtMode -> Bool
Eq, RegNo -> ExtMode -> ShowS
[ExtMode] -> ShowS
ExtMode -> String
forall a.
(RegNo -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ExtMode] -> ShowS
$cshowList :: [ExtMode] -> ShowS
show :: ExtMode -> String
$cshow :: ExtMode -> String
showsPrec :: RegNo -> ExtMode -> ShowS
$cshowsPrec :: RegNo -> ExtMode -> ShowS
Show)

data ShiftMode
    = SLSL | SLSR | SASR | SROR
    deriving (ShiftMode -> ShiftMode -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ShiftMode -> ShiftMode -> Bool
$c/= :: ShiftMode -> ShiftMode -> Bool
== :: ShiftMode -> ShiftMode -> Bool
$c== :: ShiftMode -> ShiftMode -> Bool
Eq, RegNo -> ShiftMode -> ShowS
[ShiftMode] -> ShowS
ShiftMode -> String
forall a.
(RegNo -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ShiftMode] -> ShowS
$cshowList :: [ShiftMode] -> ShowS
show :: ShiftMode -> String
$cshow :: ShiftMode -> String
showsPrec :: RegNo -> ShiftMode -> ShowS
$cshowsPrec :: RegNo -> ShiftMode -> ShowS
Show)


-- We can also add ExtShift to Extension.
-- However at most 3bits.
type ExtShift = Int
-- at most 6bits
type RegShift = Int

data Operand
        = OpReg Width Reg            -- register
        | OpRegExt Width Reg ExtMode ExtShift -- rm, <ext>[, <shift left>]
        | OpRegShift Width Reg ShiftMode RegShift     -- rm, <shift>, <0-64>
        | OpImm Imm            -- immediate value
        | OpImmShift Imm ShiftMode RegShift
        | OpAddr AddrMode       -- memory reference
        deriving (Operand -> Operand -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Operand -> Operand -> Bool
$c/= :: Operand -> Operand -> Bool
== :: Operand -> Operand -> Bool
$c== :: Operand -> Operand -> Bool
Eq, RegNo -> Operand -> ShowS
[Operand] -> ShowS
Operand -> String
forall a.
(RegNo -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Operand] -> ShowS
$cshowList :: [Operand] -> ShowS
show :: Operand -> String
$cshow :: Operand -> String
showsPrec :: RegNo -> Operand -> ShowS
$cshowsPrec :: RegNo -> Operand -> ShowS
Show)

-- Smart constructors
opReg :: Width -> Reg -> Operand
opReg :: Width -> Reg -> Operand
opReg = Width -> Reg -> Operand
OpReg

xzr, wzr, sp, ip0 :: Operand
xzr :: Operand
xzr = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle (-RegNo
1)))
wzr :: Operand
wzr = Width -> Reg -> Operand
OpReg Width
W32 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle (-RegNo
1)))
sp :: Operand
sp  = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
31))
ip0 :: Operand
ip0 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
16))

_x :: Int -> Operand
_x :: RegNo -> Operand
_x RegNo
i = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
i))
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  = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle  RegNo
0))
x1 :: Operand
x1  = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle  RegNo
1))
x2 :: Operand
x2  = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle  RegNo
2))
x3 :: Operand
x3  = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle  RegNo
3))
x4 :: Operand
x4  = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle  RegNo
4))
x5 :: Operand
x5  = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle  RegNo
5))
x6 :: Operand
x6  = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle  RegNo
6))
x7 :: Operand
x7  = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle  RegNo
7))
x8 :: Operand
x8  = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle  RegNo
8))
x9 :: Operand
x9  = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle  RegNo
9))
x10 :: Operand
x10 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
10))
x11 :: Operand
x11 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
11))
x12 :: Operand
x12 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
12))
x13 :: Operand
x13 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
13))
x14 :: Operand
x14 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
14))
x15 :: Operand
x15 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
15))
x16 :: Operand
x16 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
16))
x17 :: Operand
x17 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
17))
x18 :: Operand
x18 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
18))
x19 :: Operand
x19 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
19))
x20 :: Operand
x20 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
20))
x21 :: Operand
x21 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
21))
x22 :: Operand
x22 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
22))
x23 :: Operand
x23 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
23))
x24 :: Operand
x24 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
24))
x25 :: Operand
x25 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
25))
x26 :: Operand
x26 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
26))
x27 :: Operand
x27 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
27))
x28 :: Operand
x28 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
28))
x29 :: Operand
x29 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
29))
x30 :: Operand
x30 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
30))
x31 :: Operand
x31 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
31))

_d :: Int -> Operand
_d :: RegNo -> Operand
_d = Width -> Reg -> Operand
OpReg Width
W64 forall b c a. (b -> c) -> (a -> b) -> a -> c
. RealReg -> Reg
RegReal forall b c a. (b -> c) -> (a -> b) -> a -> c
. RegNo -> RealReg
RealRegSingle
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  = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
32))
d1 :: Operand
d1  = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
33))
d2 :: Operand
d2  = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
34))
d3 :: Operand
d3  = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
35))
d4 :: Operand
d4  = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
36))
d5 :: Operand
d5  = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
37))
d6 :: Operand
d6  = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
38))
d7 :: Operand
d7  = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
39))
d8 :: Operand
d8  = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
40))
d9 :: Operand
d9  = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
41))
d10 :: Operand
d10 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
42))
d11 :: Operand
d11 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
43))
d12 :: Operand
d12 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
44))
d13 :: Operand
d13 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
45))
d14 :: Operand
d14 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
46))
d15 :: Operand
d15 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
47))
d16 :: Operand
d16 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
48))
d17 :: Operand
d17 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
49))
d18 :: Operand
d18 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
50))
d19 :: Operand
d19 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
51))
d20 :: Operand
d20 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
52))
d21 :: Operand
d21 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
53))
d22 :: Operand
d22 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
54))
d23 :: Operand
d23 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
55))
d24 :: Operand
d24 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
56))
d25 :: Operand
d25 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
57))
d26 :: Operand
d26 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
58))
d27 :: Operand
d27 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
59))
d28 :: Operand
d28 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
60))
d29 :: Operand
d29 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
61))
d30 :: Operand
d30 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
62))
d31 :: Operand
d31 = Width -> Reg -> Operand
OpReg Width
W64 (RealReg -> Reg
RegReal (RegNo -> RealReg
RealRegSingle RegNo
63))

opRegUExt :: Width -> Reg -> Operand
opRegUExt :: Width -> Reg -> Operand
opRegUExt Width
W64 Reg
r = Width -> Reg -> ExtMode -> RegNo -> Operand
OpRegExt Width
W64 Reg
r ExtMode
EUXTX RegNo
0
opRegUExt Width
W32 Reg
r = Width -> Reg -> ExtMode -> RegNo -> Operand
OpRegExt Width
W32 Reg
r ExtMode
EUXTW RegNo
0
opRegUExt Width
W16 Reg
r = Width -> Reg -> ExtMode -> RegNo -> Operand
OpRegExt Width
W16 Reg
r ExtMode
EUXTH RegNo
0
opRegUExt Width
W8  Reg
r = Width -> Reg -> ExtMode -> RegNo -> Operand
OpRegExt Width
W8  Reg
r ExtMode
EUXTB RegNo
0
opRegUExt Width
w  Reg
_r = forall a. HasCallStack => String -> SDoc -> a
pprPanic String
"opRegUExt" (forall a. Outputable a => a -> SDoc
ppr Width
w)

opRegSExt :: Width -> Reg -> Operand
opRegSExt :: Width -> Reg -> Operand
opRegSExt Width
W64 Reg
r = Width -> Reg -> ExtMode -> RegNo -> Operand
OpRegExt Width
W64 Reg
r ExtMode
ESXTX RegNo
0
opRegSExt Width
W32 Reg
r = Width -> Reg -> ExtMode -> RegNo -> Operand
OpRegExt Width
W32 Reg
r ExtMode
ESXTW RegNo
0
opRegSExt Width
W16 Reg
r = Width -> Reg -> ExtMode -> RegNo -> Operand
OpRegExt Width
W16 Reg
r ExtMode
ESXTH RegNo
0
opRegSExt Width
W8  Reg
r = Width -> Reg -> ExtMode -> RegNo -> Operand
OpRegExt Width
W8  Reg
r ExtMode
ESXTB RegNo
0
opRegSExt Width
w  Reg
_r = forall a. HasCallStack => String -> SDoc -> a
pprPanic String
"opRegSExt" (forall a. Outputable a => a -> SDoc
ppr Width
w)