module DDC.Llvm.Analysis.Defs ( Def (..) , takeDefOfInstr , defsOfBlock) where import DDC.Llvm.Syntax import Data.Map (Map) import qualified Data.Foldable as Seq import qualified Data.Map as Map -- | How a variable is defined. data Def -- | Variable is given a non-constant value. = DefVar -- | Variable is an alias of another variable. | DefAlias Var -- | Variable binds some closed, constant expression. | DefClosedConstant Exp deriving Show -- | Collect information about how all the local variables in this block -- are defined. defsOfBlock :: Block -> Map Var (Label, Def) defsOfBlock block = Map.fromList $ [ (v, (blockLabel block, def)) | Just (v, def) <- map (takeDefOfInstr . annotInstr) $ Seq.toList $ blockInstrs block ] -- | If this instruction defines a variable, -- then collect some information about it. takeDefOfInstr :: Instr -> Maybe (Var, Def) takeDefOfInstr instr = case instr of -- Comments IComment{} -> Nothing -- Set meta instruction. ISet v1 x2 | XVar v2 <- x2 -> Just (v1, DefAlias v2) | isClosedConstantExp x2 -> Just (v1, DefClosedConstant x2) | otherwise -> Just (v1, DefVar) -- No operation. INop -> Nothing -- Phi nodes -- Even if both branches are constant, -- we can't form an expression to represent this, -- so the result gets marked as non-constant. IPhi v _ -> Just (v, DefVar) -- Terminator Instructions IReturn{} -> Nothing IBranch{} -> Nothing IBranchIf{} -> Nothing ISwitch{} -> Nothing IUnreachable{} -> Nothing -- Binary Operators IOp v _ _ _ -> Just (v, DefVar) -- Conversion Operators IConv v _ _ -> Just (v, DefVar) -- Get element pointer IGet v _ _ -> Just (v, DefVar) -- Load a value from memory. ILoad v _ -> Just (v, DefVar) -- Store a value to memory. IStore{} -> Nothing -- Comparisons ICmp v _ _ _ -> Just (v, DefVar) -- Function calls ICall mv _ _ _ _ _ _ -> case mv of Just v -> Just (v, DefVar) _ -> Nothing