llvm-pretty-bc-parser-0.5.0.0: src/Data/LLVM/BitCode/IR/Values.hs
{-# LANGUAGE ViewPatterns #-}
module Data.LLVM.BitCode.IR.Values (
getValueTypePair
, getValue
, getFnValueById, getFnValueById'
, parseValueSymbolTableBlock
) where
import Data.LLVM.BitCode.Bitstream
import Data.LLVM.BitCode.Match
import Data.LLVM.BitCode.Parse
import Data.LLVM.BitCode.Record
import Text.LLVM.AST
import Control.Monad ((<=<),foldM)
-- Value Table -----------------------------------------------------------------
-- | Get either a value from the value table, with its value, or parse a value
-- and a type.
getValueTypePair :: ValueTable -> Record -> Int -> Parse (Typed PValue, Int)
getValueTypePair t r ix = do
let field = parseField r
n <- adjustId =<< field ix numeric
mb <- lookupValueAbs n
case mb of
-- value is already present in the incremental table
Just tv -> return (tv, ix+1)
-- forward reference to the entry in the final table
Nothing -> do
ty <- getType =<< field (ix+1) numeric
cxt <- getContext
let ref = forwardRef cxt n t
-- generate the forward reference to the value only, as we already know
-- what the type should be.
return (Typed ty (typedValue ref), ix+2)
-- | Get a single value from the value table.
--getValueNoFwdRef :: Type -> Int -> Parse (Typed PValue)
--getValueNoFwdRef ty n = label "getValueNoFwdRef" (getFnValueById ty =<< adjustId n)
getFnValueById :: (HasMdTable m, HasParseEnv m, HasValueTable m, MonadFail m)
=> Type -> Int -> m (Typed PValue)
getFnValueById = getFnValueById' Nothing
getValue :: ValueTable -> Type -> Int -> Parse (Typed PValue)
getValue vt ty n = label "getValue" (getFnValueById' (Just vt) ty =<< adjustId n)
-- | Lookup a value by its absolute id, or perhaps some metadata.
getFnValueById' :: (HasMdTable m, HasParseEnv m, HasValueTable m, MonadFail m)
=> Maybe ValueTable -> Type -> Int -> m (Typed PValue)
getFnValueById' mbVt ty n = case ty of
PrimType Metadata -> do
cxt <- getContext
md <- getMdTable
return (forwardRef cxt n md)
_ -> do
mb <- lookupValueAbs n
case mb of
Just tv -> return tv
-- forward reference
Nothing -> do
mbName <- entryNameMb n
case mbName of
Just name -> return (Typed ty (ValIdent (Ident name)))
Nothing
| Just vt <- mbVt ->
do cxt <- getContext
return (forwardRef cxt n vt)
| otherwise ->
fail "Unable to create forward reference"
-- Value Symbol Table Entries --------------------------------------------------
vstCodeEntry :: Match Entry Record
vstCodeEntry = hasRecordCode 1 <=< fromEntry
vstCodeBBEntry :: Match Entry Record
vstCodeBBEntry = hasRecordCode 2 <=< fromEntry
vstCodeFNEntry :: Match Entry Record
vstCodeFNEntry = hasRecordCode 3 <=< fromEntry
-- Value Symbol Table Parsing --------------------------------------------------
parseValueSymbolTableBlock :: [Entry] -> Parse ValueSymtab
parseValueSymbolTableBlock = foldM parseValueSymbolTableBlockEntry mempty
parseValueSymbolTableBlockEntry :: ValueSymtab -> Entry -> Parse ValueSymtab
parseValueSymbolTableBlockEntry vs (vstCodeEntry -> Just r) = do
-- VST_ENTRY: [valid, namechar x N]
-- TODO: fail if version >= 2? These aren't supposed to be around anymore.
let field = parseField r
valid <- field 0 numeric
name <- field 1 cstring
return (addEntry valid name vs)
parseValueSymbolTableBlockEntry vs (vstCodeBBEntry -> Just r) = do
-- VST_BBENTRY: [bbid, namechar x N]
-- TODO: fail if version >= 2? These aren't supposed to be around anymore.
let field = parseField r
bbid <- field 0 numeric
name <- field 1 cstring
return (addBBEntry bbid name vs)
parseValueSymbolTableBlockEntry vs (vstCodeFNEntry -> Just r) = do
-- VST_FNENTRY: [valid, offset, namechar x N]
let field = parseField r
valid <- field 0 numeric
offset <- field 1 numeric
case length (recordFields r) of
2 -> return (addFwdFNEntry valid offset vs)
3 -> do
name <- field 2 cstring
return (addFNEntry valid offset name vs)
_ -> fail "unexpected number of parameters to FNENTRY"
parseValueSymbolTableBlockEntry vs (abbrevDef -> Just _) =
-- skip abbreviation definitions, they're already resolved
return vs
parseValueSymbolTableBlockEntry vs (block -> Just _) =
-- skip blocks, there are no known subblocks.
return vs
parseValueSymbolTableBlockEntry _ e =
fail ("value symtab: unexpected entry: " ++ show e)