ddc-core-llvm-0.4.2.1: DDC/Llvm/Transform/Calls.hs
-- | Attach calling conventions to ICall instructions.
module DDC.Llvm.Transform.Calls
(attachCallConvs)
where
import DDC.Llvm.Syntax
-- | Attach calling conventions to call instructions.
attachCallConvs :: Module -> Module
attachCallConvs mm
= let funcs' = map (callsFunction mm) $ modFuncs mm
in mm { modFuncs = funcs' }
-- | Attach calling conventions to call instructions in a function.
callsFunction :: Module -> Function -> Function
callsFunction mm fun
= let blocks' = map (callsBlock mm) $ funBlocks fun
in fun { funBlocks = blocks' }
-- | Attach calling conventions to call instructions in a block.
callsBlock :: Module -> Block -> Block
callsBlock mm block
= let instrs' = fmap (callsInstr mm) $ blockInstrs block
in block { blockInstrs = instrs' }
-- | Attach calling conventions to call instructions,
-- leaving other instructions unharmed.
callsInstr :: Module -> AnnotInstr -> AnnotInstr
callsInstr mm ai@(AnnotInstr i annots)
= case i of
ICall mv ct mcc t n xs ats
-> let Just cc2 = callConvOfName mm n
cc' = mergeCallConvs mcc cc2
in AnnotInstr (ICall mv ct (Just cc') t n xs ats)
annots
_ -> ai
-- | Lookup the calling convention for the given name.
callConvOfName :: Module -> Name -> Maybe CallConv
callConvOfName mm name
-- Functions defined at top level can have different calling
-- conventions.
| NameGlobal str <- name
, Just cc2 <- lookupCallConv str mm
= Just cc2
-- Unknown functions bound to variables are assumed to have
-- the standard calling convention.
| NameLocal _ <- name
= Just CC_Ccc
| otherwise = Nothing
-- | If there is a calling convention attached directly to an ICall
-- instruction then it must match any we get from the environment.
mergeCallConvs :: Maybe CallConv -> CallConv -> CallConv
mergeCallConvs mc cc
= case mc of
Nothing -> cc
Just cc'
| cc == cc' -> cc
| otherwise
-> error $ unlines
[ "DDC.LLVM.Transform.Clean"
, " Not overriding exising calling convention." ]