#include "MachDeps.h"
-- NCG stuff:
+import SPARC.CodeGen.Sanity
import SPARC.CodeGen.Amode
import SPARC.CodeGen.CondCode
import SPARC.CodeGen.Gen64
-> NatM ( [NatBasicBlock Instr]
, [NatCmmTop Instr])
-basicBlockCodeGen (BasicBlock id stmts) = do
+basicBlockCodeGen cmm@(BasicBlock id stmts) = do
instrs <- stmtsToInstrs stmts
let
(top,other_blocks,statics)
mkBlocks instr (instrs,blocks,statics)
= (instr:instrs, blocks, statics)
+ -- do intra-block sanity checking
blocksChecked
- = map checkBlockEnd
+ = map (checkBlock cmm)
$ BasicBlock id top : other_blocks
return (blocksChecked, statics)
--- | Enforce the invariant that all basic blocks must end with a jump.
--- For SPARC this is a jump, then a nop for the branch delay slot.
---
--- If the branch isn't there then the register liveness determinator
--- will get the liveness information wrong. This will cause a bad
--- allocation, which is seriously difficult to debug.
---
--- If there is an instr in the branch delay slot, then the allocator
--- will also get confused and give a bad allocation.
---
-checkBlockEnd
- :: NatBasicBlock Instr -> NatBasicBlock Instr
-
-checkBlockEnd block@(BasicBlock _ instrs)
- | Just (i1, i2) <- takeLast2 instrs
- , isJumpishInstr i1
- , NOP <- i2
- = block
-
- | otherwise
- = pprPanic
- ("SPARC.CodeGen: bad instrs at end of block\n")
- (text "block:\n" <> ppr block)
-
-takeLast2 :: [a] -> Maybe (a, a)
-takeLast2 xx
- = case xx of
- [] -> Nothing
- _:[] -> Nothing
- x1:x2:[] -> Just (x1, x2)
- _:xs -> takeLast2 xs
-
-
-- | Convert some Cmm statements to SPARC instructions.
stmtsToInstrs :: [CmmStmt] -> NatM InstrBlock
stmtsToInstrs stmts
--- /dev/null
+
+-- | One ounce of sanity checking is worth 10000000000000000 ounces
+-- of staring blindly at assembly code trying to find the problem..
+--
+module SPARC.CodeGen.Sanity (
+ checkBlock
+)
+
+where
+
+import SPARC.Instr
+import SPARC.Ppr ()
+import Instruction
+
+import Cmm
+
+import Outputable
+
+
+-- | Enforce intra-block invariants.
+--
+checkBlock
+ :: CmmBasicBlock -> NatBasicBlock Instr -> NatBasicBlock Instr
+
+checkBlock cmm block@(BasicBlock _ instrs)
+ | checkBlockInstrs instrs
+ = block
+
+ | otherwise
+ = pprPanic
+ ("SPARC.CodeGen: bad block\n")
+ ( vcat [ text " -- cmm -----------------\n"
+ , ppr cmm
+ , text " -- native code ---------\n"
+ , ppr 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
+
+