packages feed

hLLVM-0.5.0.0: src/Llvm/Pass/PhiFixUp.hs

{-# OPTIONS_GHC -cpp #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE GADTs #-}

module Llvm.Pass.PhiFixUp (phiFixUp) where

import Compiler.Hoopl
import Llvm.Data.Ir
import Control.Monad (liftM)

import Llvm.Pass.Rewriter
#ifdef DEBUG
import Debug.Trace
#endif 

-- | this pass fix up Phi instructions that have the parameters from unreachable code
type LiveLabel = LabelMap Label -- all the searchable labels
lattice :: LiveLabel -> DataflowLattice LiveLabel
lattice live = DataflowLattice { fact_name = "Live Label"
                               , fact_bot = live
                               , fact_join = add
                               }
    where add _ (OldFact old) (NewFact new) = (ch, j)
              where 
                j = new `mapUnion` old
                ch= changeIf (mapSize j > mapSize old)


fwdTransfer :: FwdTransfer (Node a) LiveLabel
fwdTransfer = mkFTransfer live
  where
    live :: Node a e x -> LiveLabel -> Fact x LiveLabel
    live (Nlabel _) f = f
    live (Pinst _) f = f 
    live (Cinst _) f = f 
    live t@(Tinst n) f  = tinstft t n f
    tinstft :: Node a O C -> TerminatorInstWithDbg -> LiveLabel -> Fact C LiveLabel
    tinstft n (TerminatorInstWithDbg term _) f =  
      let targets = successors n -- targetOf term
      in case targets of
        [] -> mapEmpty
        l -> mkFactBase (lattice f) (map (\x -> (x, f)) l)
                                                     

fwdRewrite :: forall a.forall m. FuelMonad m => FwdRewrite m (Node a) LiveLabel
fwdRewrite = mkFRewrite d
   where
     d :: Node a e x -> LiveLabel -> m (Maybe (Graph (Node a) e x))
     d (Pinst n) f = removePhi n f 
     d _ _ = return Nothing


removePhi :: forall a. forall m. FuelMonad m => PhiInstWithDbg -> Fact O LiveLabel -> m (Maybe (Graph (Node a) O O))
#ifdef DEBUG
removePhi x live | trace ("removePhi is called over " ++ show x) False = undefined
removePhi x live | trace ("removePhi is called with " ++ show live) False = undefined
removePhi x live | trace ("removePhi is called with " ++ show live) False = undefined
#endif
removePhi (PhiInstWithDbg (PhiInst lhs t ins) dbgs) live = 
  if liveOperands == ins then
    return $ Nothing
  else if liveOperands == [] then
         return $ Just emptyGraph
       else 
         return $ Just $ nodeToGraph (Pinst $ PhiInstWithDbg (PhiInst lhs t liveOperands) dbgs)
   where 
#ifdef DEBUG
     isAlive x s | trace ("isAlive is called with " ++ show x ++ "  " ++ show s) False = undefined
     isAlive x s | trace ("isAlive result is " ++ show (hooplLabelOf x `mapMember` s)) False = undefined
#endif                                                                                          
     isAlive x s = x `mapMember` s
     liveOperands = foldl (\p -> \x@(_, li) -> 
                            if isAlive li live then x:p else p) [] (reverse ins)


fwdPass :: forall a.forall m. FuelMonad m => LiveLabel -> FwdPass m (Node a) LiveLabel
fwdPass f = FwdPass { fp_lattice = lattice f
                    , fp_transfer = fwdTransfer
                    , fp_rewrite = fwdRewrite
                    }

phiFixUp :: (CheckpointMonad m, FuelMonad m) => LabelMap Label -> Label -> Graph (Node a) C C -> m (Graph (Node a) C C)
#ifdef DEBUG
phiFixUp idom entry graph | trace ("phiFixUp with idom " ++ show idom) False = undefined
phiFixUp idom entry graph | trace ("phiFixUp with entry " ++ show entry) False = undefined
#endif
phiFixUp idom entry graph = 
  let idom0 = mapInsert entry entry idom
      fwd = fwdPass idom0
  in do { (graph0, _, _) <- analyzeAndRewriteFwd fwd (JustC [entry]) graph
                            (mapInsert entry idom0 mapEmpty)
        ; return graph0
        }