-- | One ounce of sanity checking is worth 10000000000000000 ounces
-- of staring blindly at assembly code trying to find the problem..
module GHC.CmmToAsm.SPARC.CodeGen.Sanity (
        checkBlock
)

where

import GHC.Prelude
import GHC.Platform

import GHC.CmmToAsm.SPARC.Instr
import GHC.CmmToAsm.SPARC.Ppr        () -- For Outputable instances
import GHC.CmmToAsm.Types

import GHC.Cmm

import GHC.Utils.Outputable
import GHC.Utils.Panic


-- | Enforce intra-block invariants.
--
checkBlock :: Platform
           -> CmmBlock
           -> NatBasicBlock Instr
           -> NatBasicBlock Instr

checkBlock platform cmm block@(BasicBlock _ instrs)
        | checkBlockInstrs instrs
        = block

        | otherwise
        = pprPanic
                ("SPARC.CodeGen: bad block\n")
                ( vcat  [ text " -- cmm -----------------\n"
                        , pdoc platform cmm
                        , text " -- native code ---------\n"
                        , pdoc platform block ])


checkBlockInstrs :: [Instr] -> Bool
checkBlockInstrs ii

        -- An unconditional jumps end the block.
        --      There must be an unconditional jump in the block, otherwise
        --      the register liveness determinator will get the liveness
        --      information wrong.
        --
        --      If the block ends with a cmm call that never returns
        --      then there can be unreachable instructions after the jump,
        --      but we don't mind here.
        --
        | instr : NOP : _       <- ii
        , isUnconditionalJump instr
        = True

        -- All jumps must have a NOP in their branch delay slot.
        --      The liveness determinator and register allocators aren't smart
        --      enough to handle branch delay slots.
        --
        | instr : NOP : is      <- ii
        , isJumpishInstr instr
        = checkBlockInstrs is

        -- keep checking
        | _:i2:is               <- ii
        = checkBlockInstrs (i2:is)

        -- this block is no good
        | otherwise
        = False
