{-# LANGUAGE CPP #-}
#include "HsVersions.h"
#include "nativeGen/NCG.h"
module SPARC.Instr (
        RI(..),
        riZero,
        fpRelEA,
        moveSp,
        isUnconditionalJump,
        Instr(..),
        maxSpillSlots
)
where
import GhcPrelude
import SPARC.Stack
import SPARC.Imm
import SPARC.AddrMode
import SPARC.Cond
import SPARC.Regs
import SPARC.Base
import TargetReg
import Instruction
import RegClass
import Reg
import Format
import CLabel
import CodeGen.Platform
import BlockId
import DynFlags
import Cmm
import FastString
import Outputable
import Platform
data RI
        = RIReg Reg
        | RIImm Imm
riZero :: RI -> Bool
riZero (RIImm (ImmInt 0))                       = True
riZero (RIImm (ImmInteger 0))                   = True
riZero (RIReg (RegReal (RealRegSingle 0)))      = True
riZero _                                        = False
fpRelEA :: Int -> Reg -> Instr
fpRelEA n dst
   = ADD False False fp (RIImm (ImmInt (n * wordLength))) dst
moveSp :: Int -> Instr
moveSp n
   = ADD False False sp (RIImm (ImmInt (n * wordLength))) sp
isUnconditionalJump :: Instr -> Bool
isUnconditionalJump ii
 = case ii of
        CALL{}          -> True
        JMP{}           -> True
        JMP_TBL{}       -> True
        BI ALWAYS _ _   -> True
        BF ALWAYS _ _   -> True
        _               -> False
instance Instruction Instr where
        regUsageOfInstr         = sparc_regUsageOfInstr
        patchRegsOfInstr        = sparc_patchRegsOfInstr
        isJumpishInstr          = sparc_isJumpishInstr
        jumpDestsOfInstr        = sparc_jumpDestsOfInstr
        patchJumpInstr          = sparc_patchJumpInstr
        mkSpillInstr            = sparc_mkSpillInstr
        mkLoadInstr             = sparc_mkLoadInstr
        takeDeltaInstr          = sparc_takeDeltaInstr
        isMetaInstr             = sparc_isMetaInstr
        mkRegRegMoveInstr       = sparc_mkRegRegMoveInstr
        takeRegRegMoveInstr     = sparc_takeRegRegMoveInstr
        mkJumpInstr             = sparc_mkJumpInstr
        mkStackAllocInstr       = panic "no sparc_mkStackAllocInstr"
        mkStackDeallocInstr     = panic "no sparc_mkStackDeallocInstr"
data Instr
        
        
        = COMMENT FastString
        
        
        | LDATA   Section CmmStatics
        
        
        
        | NEWBLOCK BlockId
        
        | DELTA   Int
        
        
        | LD            Format AddrMode Reg             
        | ST            Format Reg AddrMode             
        
        
        
        
        
        
        | ADD           Bool Bool Reg RI Reg            
        | SUB           Bool Bool Reg RI Reg            
        | UMUL          Bool Reg RI Reg                 
        | SMUL          Bool Reg RI Reg                 
        
        
        
        
        
        | UDIV          Bool Reg RI Reg                 
        | SDIV          Bool Reg RI Reg                 
        | RDY           Reg                             
        | WRY           Reg  Reg                        
        
        | AND           Bool Reg RI Reg                 
        | ANDN          Bool Reg RI Reg                 
        | OR            Bool Reg RI Reg                 
        | ORN           Bool Reg RI Reg                 
        | XOR           Bool Reg RI Reg                 
        | XNOR          Bool Reg RI Reg                 
        | SLL           Reg RI Reg                      
        | SRL           Reg RI Reg                      
        | SRA           Reg RI Reg                      
        
        | SETHI         Imm Reg                         
        
        
        | NOP
        
        
        
        
        | FABS          Format Reg Reg                  
        | FADD          Format Reg Reg Reg              
        | FCMP          Bool Format Reg Reg             
        | FDIV          Format Reg Reg Reg              
        | FMOV          Format Reg Reg                  
        | FMUL          Format Reg Reg Reg              
        | FNEG          Format Reg Reg                  
        | FSQRT         Format Reg Reg                  
        | FSUB          Format Reg Reg Reg              
        | FxTOy         Format Format Reg Reg           
        
        | BI            Cond Bool BlockId               
        | BF            Cond Bool BlockId               
        | JMP           AddrMode                        
        
        
        
        | JMP_TBL       AddrMode [Maybe BlockId] CLabel
        | CALL          (Either Imm Reg) Int Bool       
sparc_regUsageOfInstr :: Platform -> Instr -> RegUsage
sparc_regUsageOfInstr platform instr
 = case instr of
    LD    _ addr reg            -> usage (regAddr addr,         [reg])
    ST    _ reg addr            -> usage (reg : regAddr addr,   [])
    ADD   _ _ r1 ar r2          -> usage (r1 : regRI ar,        [r2])
    SUB   _ _ r1 ar r2          -> usage (r1 : regRI ar,        [r2])
    UMUL    _ r1 ar r2          -> usage (r1 : regRI ar,        [r2])
    SMUL    _ r1 ar r2          -> usage (r1 : regRI ar,        [r2])
    UDIV    _ r1 ar r2          -> usage (r1 : regRI ar,        [r2])
    SDIV    _ r1 ar r2          -> usage (r1 : regRI ar,        [r2])
    RDY       rd                -> usage ([],                   [rd])
    WRY       r1 r2             -> usage ([r1, r2],             [])
    AND     _ r1 ar r2          -> usage (r1 : regRI ar,        [r2])
    ANDN    _ r1 ar r2          -> usage (r1 : regRI ar,        [r2])
    OR      _ r1 ar r2          -> usage (r1 : regRI ar,        [r2])
    ORN     _ r1 ar r2          -> usage (r1 : regRI ar,        [r2])
    XOR     _ r1 ar r2          -> usage (r1 : regRI ar,        [r2])
    XNOR    _ r1 ar r2          -> usage (r1 : regRI ar,        [r2])
    SLL       r1 ar r2          -> usage (r1 : regRI ar,        [r2])
    SRL       r1 ar r2          -> usage (r1 : regRI ar,        [r2])
    SRA       r1 ar r2          -> usage (r1 : regRI ar,        [r2])
    SETHI   _ reg               -> usage ([],                   [reg])
    FABS    _ r1 r2             -> usage ([r1],                 [r2])
    FADD    _ r1 r2 r3          -> usage ([r1, r2],             [r3])
    FCMP    _ _  r1 r2          -> usage ([r1, r2],             [])
    FDIV    _ r1 r2 r3          -> usage ([r1, r2],             [r3])
    FMOV    _ r1 r2             -> usage ([r1],                 [r2])
    FMUL    _ r1 r2 r3          -> usage ([r1, r2],             [r3])
    FNEG    _ r1 r2             -> usage ([r1],                 [r2])
    FSQRT   _ r1 r2             -> usage ([r1],                 [r2])
    FSUB    _ r1 r2 r3          -> usage ([r1, r2],             [r3])
    FxTOy   _ _  r1 r2          -> usage ([r1],                 [r2])
    JMP     addr                -> usage (regAddr addr, [])
    JMP_TBL addr _ _            -> usage (regAddr addr, [])
    CALL  (Left _  )  _ True    -> noUsage
    CALL  (Left _  )  n False   -> usage (argRegs n, callClobberedRegs)
    CALL  (Right reg) _ True    -> usage ([reg], [])
    CALL  (Right reg) n False   -> usage (reg : (argRegs n), callClobberedRegs)
    _                           -> noUsage
  where
    usage (src, dst)
     = RU (filter (interesting platform) src)
          (filter (interesting platform) dst)
    regAddr (AddrRegReg r1 r2)  = [r1, r2]
    regAddr (AddrRegImm r1 _)   = [r1]
    regRI (RIReg r)             = [r]
    regRI  _                    = []
interesting :: Platform -> Reg -> Bool
interesting platform reg
 = case reg of
        RegVirtual _                    -> True
        RegReal (RealRegSingle r1)      -> freeReg platform r1
        RegReal (RealRegPair r1 _)      -> freeReg platform r1
sparc_patchRegsOfInstr :: Instr -> (Reg -> Reg) -> Instr
sparc_patchRegsOfInstr instr env = case instr of
    LD    fmt addr reg          -> LD fmt (fixAddr addr) (env reg)
    ST    fmt reg addr          -> ST fmt (env reg) (fixAddr addr)
    ADD   x cc r1 ar r2         -> ADD   x cc  (env r1) (fixRI ar) (env r2)
    SUB   x cc r1 ar r2         -> SUB   x cc  (env r1) (fixRI ar) (env r2)
    UMUL    cc r1 ar r2         -> UMUL    cc  (env r1) (fixRI ar) (env r2)
    SMUL    cc r1 ar r2         -> SMUL    cc  (env r1) (fixRI ar) (env r2)
    UDIV    cc r1 ar r2         -> UDIV    cc  (env r1) (fixRI ar) (env r2)
    SDIV    cc r1 ar r2         -> SDIV    cc  (env r1) (fixRI ar) (env r2)
    RDY   rd                    -> RDY         (env rd)
    WRY   r1 r2                 -> WRY         (env r1) (env r2)
    AND   b r1 ar r2            -> AND   b     (env r1) (fixRI ar) (env r2)
    ANDN  b r1 ar r2            -> ANDN  b     (env r1) (fixRI ar) (env r2)
    OR    b r1 ar r2            -> OR    b     (env r1) (fixRI ar) (env r2)
    ORN   b r1 ar r2            -> ORN   b     (env r1) (fixRI ar) (env r2)
    XOR   b r1 ar r2            -> XOR   b     (env r1) (fixRI ar) (env r2)
    XNOR  b r1 ar r2            -> XNOR  b     (env r1) (fixRI ar) (env r2)
    SLL   r1 ar r2              -> SLL         (env r1) (fixRI ar) (env r2)
    SRL   r1 ar r2              -> SRL         (env r1) (fixRI ar) (env r2)
    SRA   r1 ar r2              -> SRA         (env r1) (fixRI ar) (env r2)
    SETHI imm reg               -> SETHI imm (env reg)
    FABS  s r1 r2               -> FABS    s   (env r1) (env r2)
    FADD  s r1 r2 r3            -> FADD    s   (env r1) (env r2) (env r3)
    FCMP  e s r1 r2             -> FCMP e  s   (env r1) (env r2)
    FDIV  s r1 r2 r3            -> FDIV    s   (env r1) (env r2) (env r3)
    FMOV  s r1 r2               -> FMOV    s   (env r1) (env r2)
    FMUL  s r1 r2 r3            -> FMUL    s   (env r1) (env r2) (env r3)
    FNEG  s r1 r2               -> FNEG    s   (env r1) (env r2)
    FSQRT s r1 r2               -> FSQRT   s   (env r1) (env r2)
    FSUB  s r1 r2 r3            -> FSUB    s   (env r1) (env r2) (env r3)
    FxTOy s1 s2 r1 r2           -> FxTOy s1 s2 (env r1) (env r2)
    JMP     addr                -> JMP     (fixAddr addr)
    JMP_TBL addr ids l          -> JMP_TBL (fixAddr addr) ids l
    CALL  (Left i) n t          -> CALL (Left i) n t
    CALL  (Right r) n t         -> CALL (Right (env r)) n t
    _                           -> instr
  where
    fixAddr (AddrRegReg r1 r2)  = AddrRegReg   (env r1) (env r2)
    fixAddr (AddrRegImm r1 i)   = AddrRegImm   (env r1) i
    fixRI (RIReg r)             = RIReg (env r)
    fixRI other                 = other
sparc_isJumpishInstr :: Instr -> Bool
sparc_isJumpishInstr instr
 = case instr of
        BI{}            -> True
        BF{}            -> True
        JMP{}           -> True
        JMP_TBL{}       -> True
        CALL{}          -> True
        _               -> False
sparc_jumpDestsOfInstr :: Instr -> [BlockId]
sparc_jumpDestsOfInstr insn
  = case insn of
        BI   _ _ id     -> [id]
        BF   _ _ id     -> [id]
        JMP_TBL _ ids _ -> [id | Just id <- ids]
        _               -> []
sparc_patchJumpInstr :: Instr -> (BlockId -> BlockId) -> Instr
sparc_patchJumpInstr insn patchF
  = case insn of
        BI cc annul id  -> BI cc annul (patchF id)
        BF cc annul id  -> BF cc annul (patchF id)
        JMP_TBL n ids l -> JMP_TBL n (map (fmap patchF) ids) l
        _               -> insn
sparc_mkSpillInstr
    :: DynFlags
    -> Reg      
    -> Int      
    -> Int      
    -> Instr
sparc_mkSpillInstr dflags reg _ slot
 = let  platform = targetPlatform dflags
        off      = spillSlotToOffset dflags slot
        off_w    = 1 + (off `div` 4)
        fmt      = case targetClassOfReg platform reg of
                        RcInteger -> II32
                        RcFloat   -> FF32
                        RcDouble  -> FF64
    in ST fmt reg (fpRel (negate off_w))
sparc_mkLoadInstr
    :: DynFlags
    -> Reg      
    -> Int      
    -> Int      
    -> Instr
sparc_mkLoadInstr dflags reg _ slot
  = let platform = targetPlatform dflags
        off      = spillSlotToOffset dflags slot
        off_w    = 1 + (off `div` 4)
        fmt      = case targetClassOfReg platform reg of
                        RcInteger -> II32
                        RcFloat   -> FF32
                        RcDouble  -> FF64
        in LD fmt (fpRel (- off_w)) reg
sparc_takeDeltaInstr
        :: Instr
        -> Maybe Int
sparc_takeDeltaInstr instr
 = case instr of
        DELTA i         -> Just i
        _               -> Nothing
sparc_isMetaInstr
        :: Instr
        -> Bool
sparc_isMetaInstr instr
 = case instr of
        COMMENT{}       -> True
        LDATA{}         -> True
        NEWBLOCK{}      -> True
        DELTA{}         -> True
        _               -> False
sparc_mkRegRegMoveInstr
    :: Platform
    -> Reg
    -> Reg
    -> Instr
sparc_mkRegRegMoveInstr platform src dst
        | srcClass      <- targetClassOfReg platform src
        , dstClass      <- targetClassOfReg platform dst
        , srcClass == dstClass
        = case srcClass of
                RcInteger -> ADD  False False src (RIReg g0) dst
                RcDouble  -> FMOV FF64 src dst
                RcFloat   -> FMOV FF32 src dst
        | otherwise
        = panic "SPARC.Instr.mkRegRegMoveInstr: classes of src and dest not the same"
sparc_takeRegRegMoveInstr :: Instr -> Maybe (Reg,Reg)
sparc_takeRegRegMoveInstr instr
 = case instr of
        ADD False False src (RIReg src2) dst
         | g0 == src2           -> Just (src, dst)
        FMOV FF64 src dst       -> Just (src, dst)
        FMOV FF32  src dst      -> Just (src, dst)
        _                       -> Nothing
sparc_mkJumpInstr
        :: BlockId
        -> [Instr]
sparc_mkJumpInstr id
 =       [BI ALWAYS False id
        , NOP]