+----- Splicing between blocks
+-- Given a middle node, a block, and a successor BlockId,
+-- we can insert the middle node between the block and the successor.
+-- We return the updated block and a list of new blocks that must be added
+-- to the graph.
+-- The semantics is a bit tricky. We consider cases on the last node:
+-- o For a branch, we can just insert before the branch,
+-- but sometimes the optimizer does better if we actually insert
+-- a fresh basic block, enabling some common blockification.
+-- o For a conditional branch, switch statement, or call, we must insert
+-- a new basic block.
+-- o For a jump, or return, this operation is impossible.
+
+insertBetween :: MonadUnique m => CmmBlock -> [Middle] -> BlockId -> m (CmmBlock, [CmmBlock])
+insertBetween b ms succId = insert $ goto_end $ unzip b
+ where insert (h, LastOther (LastBranch bid)) =
+ if bid == succId then
+ do (bid', bs) <- newBlocks
+ return (zipht h $ ZLast $ LastOther (LastBranch bid'), bs)
+ else panic "tried to insert between non-adjacent blocks"
+ insert (h, LastOther (LastCondBranch c t f)) =
+ do (t', tbs) <- if t == succId then newBlocks else return $ (t, [])
+ (f', fbs) <- if f == succId then newBlocks else return $ (f, [])
+ return (zipht h $ ZLast $ LastOther (LastCondBranch c t' f'), tbs ++ fbs)
+ insert (h, LastOther (LastCall e (Just k))) =
+ if k == succId then
+ do (id', bs) <- newBlocks
+ return (zipht h $ ZLast $ LastOther (LastCall e (Just id')), bs)
+ else panic "tried to insert between non-adjacent blocks"
+ insert (_, LastOther (LastCall _ Nothing)) =
+ panic "cannot insert after non-returning call"
+ insert (h, LastOther (LastSwitch e ks)) =
+ do (ids, bs) <- mapAndUnzipM mbNewBlocks ks
+ return (zipht h $ ZLast $ LastOther (LastSwitch e ids), join bs)
+ insert (_, LastOther LastReturn) = panic "cannot insert after return"
+ insert (_, LastOther (LastJump _)) = panic "cannot insert after jump"
+ insert (_, LastExit) = panic "cannot insert after exit"
+ newBlocks = do id <- liftM BlockId $ getUniqueM
+ return $ (id, [Block id $
+ foldr ZTail (ZLast (LastOther (LastBranch succId))) ms])
+ mbNewBlocks (Just k) = if k == succId then liftM lift newBlocks
+ else return (Just k, [])
+ mbNewBlocks Nothing = return (Nothing, [])
+ lift (id, bs) = (Just id, bs)
+
+
+----------------------------------------------------------------------