module LLVM.Analysis.NoReturn (
NoReturnSummary,
noReturnAnalysis
) where
import Control.Monad.Reader
import Data.HashSet ( HashSet )
import qualified Data.HashSet as S
import LLVM.Analysis
import LLVM.Analysis.CFG
import LLVM.Analysis.Dataflow
type NoReturnSummary = HashSet Function
data ReturnInfo = RI { unRI :: !Bool }
deriving (Show)
instance Eq ReturnInfo where
(RI r1) == (RI r2) = r1 == r2
instance MeetSemiLattice ReturnInfo where
meet (RI r1) (RI r2) = RI (r1 && r2)
instance BoundedMeetSemiLattice ReturnInfo where
top = RI False
data AnalysisEnvironment m =
AE { externalSummary :: ExternalFunction -> m Bool
, internalSummary :: HashSet Function
}
type AnalysisMonad m = ReaderT (AnalysisEnvironment m) m
instance (Monad m) => DataflowAnalysis (AnalysisMonad m) ReturnInfo where
transfer = returnTransfer
noReturnAnalysis :: (Monad m, HasCFG cfg)
=> (ExternalFunction -> m Bool)
-> cfg
-> HashSet Function
-> m (HashSet Function)
noReturnAnalysis extSummary cfgLike summ = do
let cfg = getCFG cfgLike
f = getFunction cfg
env = AE extSummary summ
localRes <- runReaderT (forwardDataflow top cfg) env
let exitInsts = filter (instructionReachable cfg) (functionExitInstructions f)
exitInfos = map (dataflowResult localRes) exitInsts
exitVal = foldr ((&&) . unRI) True exitInfos
case exitVal of
False -> return summ
True -> return $! S.insert f summ
returnTransfer :: (Monad m) => ReturnInfo -> Instruction -> AnalysisMonad m ReturnInfo
returnTransfer ri i =
case i of
CallInst { callFunction = calledFunc } ->
dispatchCall ri calledFunc
InvokeInst { invokeFunction = calledFunc } ->
dispatchCall ri calledFunc
_ -> return ri
dispatchCall :: (Monad m) => ReturnInfo -> Value -> AnalysisMonad m ReturnInfo
dispatchCall ri v =
case valueContent' v of
FunctionC f -> do
intSumm <- asks internalSummary
case S.member f intSumm of
True -> return $! RI True
False -> return ri
ExternalFunctionC ef -> do
extSumm <- asks externalSummary
isNoRet <- lift $ extSumm ef
case isNoRet of
True -> return $! RI True
False -> return ri
_ -> return ri