diff options
author | tomsmeding <tom.smeding@gmail.com> | 2017-01-31 21:12:32 +0100 |
---|---|---|
committer | tomsmeding <tom.smeding@gmail.com> | 2017-01-31 21:13:47 +0100 |
commit | 7e36aa5ccb1575ca141b865dc7b8abe39a6c0581 (patch) | |
tree | 85194a1ac6fb1e5541ba728e752c6de279351f38 | |
parent | 3eb9d5d4fe233d08f09198744e6e7328605c8275 (diff) |
Handle non-returning void functions, and error on missing return
-rw-r--r-- | codegen.hs | 31 | ||||
-rw-r--r-- | nl/test_string.nl | 1 |
2 files changed, 27 insertions, 5 deletions
@@ -254,7 +254,7 @@ genFunctions (Program decs) = liftM (mapMaybe id) $ mapM gen decs allBlocks = Map.empty, variables = Map.empty }) - firstbb <- genFunctionBlock body args + firstbb <- genFunctionBlock body (rettype, name) args cleanupTrampolines blockmap <- liftM allBlocks get let bbs' = map snd $ filter (\x -> fst x /= firstbb) $ Map.toList blockmap @@ -269,8 +269,8 @@ genFunctions (Program decs) = liftM (mapMaybe id) $ mapM gen decs -genFunctionBlock :: Block -> [(Type,Name)] -> CGMonad LLName -genFunctionBlock bl args = do +genFunctionBlock :: Block -> (Type, Name) -> [(Type, Name)] -> CGMonad LLName +genFunctionBlock bl (rettype, fname) args = do firstbb <- newBlock let prepArg :: (Type,Name) -> CGMonad () prepArg (t,n) = do @@ -282,15 +282,24 @@ genFunctionBlock bl args = do sequence_ $ map prepArg args termbb <- newBlock - setTerminator $ A.Unreachable [] + setTerminator $ if rettype == TypeVoid then A.Ret Nothing [] else A.Unreachable [] bodybb <- genBlock bl termbb changeBlock firstbb setTerminator $ A.Br (A.Name bodybb) [] + + if rettype /= TypeVoid + then whenM (bbIsReferenced termbb) $ throwError $ + "Control reaches end of non-void function '" ++ fname ++ "'" + else return () + if length args > 0 then return firstbb else return bodybb +whenM :: (Monad m) => m Bool -> m a -> m () +whenM cond value = cond >>= \c -> if c then void value else return () + genBlock :: Block -> LLName -- name of BasicBlock following this Block -> CGMonad LLName -- name of first BasicBlock @@ -628,6 +637,20 @@ cleanupTrampolines = do | otherwise = A.Name x changeName _ _ (A.UnName _) = undefined +bbIsReferenced :: LLName -> CGMonad Bool +bbIsReferenced bb = do + bbs <- liftM allBlocks get + return $ any checkBlock bbs + where + checkBlock :: A.BasicBlock -> Bool + checkBlock (A.BasicBlock name instrs (_ A.:= term)) = checkBlock (A.BasicBlock name instrs (A.Do term)) + checkBlock (A.BasicBlock _ _ (A.Do term)) = case term of + (A.Ret _ _) -> False + (A.CondBr _ (A.Name d1) (A.Name d2) _) -> d1 == bb || d2 == bb + (A.Br (A.Name d) _) -> d == bb + (A.Unreachable _) -> False + _ -> undefined + toLLVMType :: Type -> A.Type toLLVMType (TypeInt s) = A.IntegerType $ fromIntegral s diff --git a/nl/test_string.nl b/nl/test_string.nl index ccba9a1..d120b48 100644 --- a/nl/test_string.nl +++ b/nl/test_string.nl @@ -6,7 +6,6 @@ extern func void(int) putchar; void f(char c) { putchar(c); - return; } int main(int argc, ptr(string) argv) { |