module LLVM.Analysis.NoReturn (
noReturnAnalysis
) where
import Control.Monad.Trans.Class
import Control.Monad.Trans.Reader
import Data.HashSet ( HashSet )
import qualified Data.HashSet as S
import LLVM.Analysis
import LLVM.Analysis.CFG
import LLVM.Analysis.Dataflow
data ReturnInfo = NotReturned
| Returned
| WillNeverReturn
deriving (Show, Eq)
meet :: ReturnInfo -> ReturnInfo -> ReturnInfo
meet Returned _ = Returned
meet _ Returned = Returned
meet WillNeverReturn _ = WillNeverReturn
meet _ WillNeverReturn = WillNeverReturn
meet NotReturned NotReturned = NotReturned
data AnalysisEnvironment m =
AE { externalSummary :: ExternalFunction -> m Bool
, internalSummary :: HashSet Function
}
type AnalysisMonad m = ReaderT (AnalysisEnvironment m) m
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
analysis = fwdDataflowAnalysis NotReturned meet returnTransfer
localRes <- runReaderT (dataflow cfg analysis NotReturned) env
case dataflowResult localRes of
WillNeverReturn -> return $! S.insert f summ
NotReturned -> return $! S.insert f summ
Returned -> return 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
UnreachableInst {} -> return WillNeverReturn
ResumeInst {} -> return WillNeverReturn
RetInst {} -> return Returned
_ -> 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 WillNeverReturn
False -> return ri
ExternalFunctionC ef -> do
extSumm <- asks externalSummary
isNoRet <- lift $ extSumm ef
case isNoRet of
True -> return WillNeverReturn
False -> return ri
_ -> return ri