    module Instruction (
    	RegUsage(..),
    	noUsage,
    	NatCmm,
    	NatCmmTop,
    	NatBasicBlock,
    	Instruction(..)
    )

    where

    import Reg

    import BlockId
    import Cmm

    -- | Holds a list of source and destination registers used by a
    --	particular instruction.
    --
    --   Machine registers that are pre-allocated to stgRegs are filtered
    --	out, because they are uninteresting from a register allocation
    --	standpoint.  (We wouldn't want them to end up on the free list!)
    --
    --   As far as we are concerned, the fixed registers simply don't exist
    --	(for allocation purposes, anyway).
    --
    data RegUsage
    	= RU [Reg] [Reg]

    -- | No regs read or written to.
    noUsage :: RegUsage
    noUsage  = RU [] []

    -- Our flavours of the Cmm types
    -- Type synonyms for Cmm populated with native code
    type NatCmm instr
    	= GenCmm
    		CmmStatic
    		[CmmStatic]
    		(ListGraph instr)

    type NatCmmTop instr
    	= GenCmmTop
    		CmmStatic
    		[CmmStatic]
    		(ListGraph instr)

    type NatBasicBlock instr
    	= GenBasicBlock instr

    -- | Common things that we can do with instructions, on all architectures.
    --	These are used by the shared parts of the native code generator,
    --	specifically the register allocators.
    --
    class 	Instruction instr where

    	-- | 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.
    	--
    	regUsageOfInstr
    		:: instr
    		-> RegUsage

    	-- | Apply a given mapping to all the register references in this
    	--	instruction.
    	patchRegsOfInstr
    		:: instr
    		-> (Reg -> Reg)
    		-> instr

    	-- | 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

    	-- | Give the possible destinations of this jump instruction.
    	--	Must be defined for all jumpish instructions.
    	jumpDestsOfInstr
    		:: instr -> [BlockId]

    	-- | Change the destination of this jump instruction.
    	--	Used in the linear allocator when adding fixup blocks for join
    	--	points.
    	patchJumpInstr
    		:: instr
    		-> (BlockId -> BlockId)
    		-> instr

    	-- | An instruction to spill a register into a spill slot.
    	mkSpillInstr
    		:: Reg		-- ^ the reg to spill
    		-> Int		-- ^ the current stack delta
    		-> Int		-- ^ spill slot to use
    		-> instr

    	-- | An instruction to reload a register from a spill slot.
    	mkLoadInstr
    		:: Reg		-- ^ the reg to reload.
    		-> Int		-- ^ the current stack delta
    		-> Int		-- ^ the spill slot to use
    		-> instr

    	-- | See if this instruction is telling us the current C stack delta
    	takeDeltaInstr
    		:: instr
    		-> Maybe Int

    	-- | Check whether this instruction is some meta thing inserted into
    	--	the instruction stream for other purposes.
    	--
    	--	Not something that has to be treated as a real machine instruction
    	--	and have its registers allocated.
    	--
    	--	eg, comments, delta, ldata, etc.
    	isMetaInstr
    		:: instr
    		-> Bool

    	-- | Copy the value in a register to another one.
    	--	Must work for all register classes.
    	mkRegRegMoveInstr
    		:: Reg		-- ^ source register
    		-> Reg 		-- ^ destination register
    		-> instr

    	-- | Take the source and destination from this reg -> reg move instruction
    	--	or Nothing if it's not one
    	takeRegRegMoveInstr
    		:: instr
    		-> Maybe (Reg, Reg)

    	-- | Make an unconditional jump instruction.
    	--	For architectures with branch delay slots, its ok to put
    	--	a NOP after the jump. Don't fill the delay slot with an
    	--	instruction that references regs or you'll confuse the
    	--	linear allocator.
    	mkJumpInstr
    		:: BlockId
    		-> [instr]