Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
9ad70ec
Create JoinIR AST
Technius Feb 23, 2019
e244864
Add an annotated JoinIR AST that uses extensible records
Technius Feb 24, 2019
daa628b
Implement pretty printing for JoinIR
Technius Feb 24, 2019
0ddb2bb
Use a newer version of vinyl
Technius Feb 26, 2019
fd6b30d
Add a function to extract types from annotated JoinIR ASTs
Technius Feb 26, 2019
67e9e5d
Add some helper functions for dealing with annotated JoinIR AST
Technius Feb 26, 2019
aa24be0
Fix let expressions in JoinIR to include next expression
Technius Feb 28, 2019
f9c1280
[skip-ci] Non-working attempt at JoinIR codegen
Technius Feb 28, 2019
d43b0f4
[skip ci] Finish JoinIR codegen
Technius Mar 5, 2019
bb9235d
[skip ci] WIP start on AST to JoinIR transformation
Technius Mar 23, 2019
603418f
[skip ci] WIP finish most of AST to Join IR transforms
Technius Mar 25, 2019
bc71900
Complete AST to Join IR transformation (not tested yet)
Technius Mar 26, 2019
1a42cd9
Fix JoinIR code generation variable binding bug
Technius Mar 26, 2019
cafb6a6
Remove code generation for Simpl AST
Technius Mar 26, 2019
3c48d34
Improve JoinIR pretty printing
Technius Mar 28, 2019
e14de82
[skip ci] WIP modify Join IR to support more efficient control flow
Technius Mar 31, 2019
c4b4d26
Update AST to JoinIR transformation
Technius Apr 1, 2019
28c469f
Rename CodegenJoin to Codegen
Technius Apr 2, 2019
38ab68a
Implement JoinIR AST verification algorithm
Technius Apr 2, 2019
001bcd5
Refactor JoinIR syntax definitions to JoinIR subfolder
Technius Apr 2, 2019
d24ae79
Fix JoinIR if cfe pretty printing
Technius Apr 2, 2019
247439c
For JoinIR Verify: Export VerifyError, take VerifyCtx as argument
Technius Apr 3, 2019
fa650af
Add unit tests for JoinIR verification
Technius Apr 3, 2019
757acba
Documentation and code cleanup for JoinIR
Technius Apr 3, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,13 @@ dependencies:
- prettyprinter
- unification-fd
- mtl
- monad-supply
- containers
- bytestring
- optparse-applicative
- safe-exceptions
- vinyl
- singletons

ghc-options:
- -Wall
Expand Down Expand Up @@ -86,3 +89,5 @@ tests:
- -with-rtsopts=-N
dependencies:
- simpl-lang
- tasty
- tasty-hunit
5 changes: 5 additions & 0 deletions src/Simpl/Ast.hs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,11 @@ isComplexType = \case
TyFun _ _ -> True
_ -> False

functionTypeResult :: Type -> Type
functionTypeResult (Fix ty) = case ty of
TyFun _ res -> functionTypeResult res
_ -> Fix ty

instance Pretty Type where
pretty = para go
where
Expand Down
191 changes: 191 additions & 0 deletions src/Simpl/AstToJoinIR.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-|
Module : Simpl.AstToJoinIR
Description : Provides a function to normalize SimPL AST, transforming it into
JoinIR.
-}
module Simpl.AstToJoinIR
( astToJoinIR
) where

import Control.Monad.Supply
import Control.Monad.Reader hiding (guard)
import Data.Functor.Foldable (Fix(..), unfix)
import Data.Functor.Identity
import Data.Text (Text)
import Data.String (fromString)

import Simpl.Ast (Type)
import Simpl.SymbolTable
import qualified Simpl.Ast as A
import qualified Simpl.JoinIR.Syntax as J

-- * Public API

astToJoinIR :: SymbolTable (A.AnnExpr Type) -> SymbolTable (J.AnnExpr '[ 'J.ExprType])
astToJoinIR = runTransform transformTable

-- * Transformation Monad

newtype TransformT m a =
TransformT { unTransform :: ReaderT (SymbolTable (A.AnnExpr Type)) (SupplyT Int m) a }
deriving ( Functor
, Applicative
, Monad
, MonadReader (SymbolTable (A.AnnExpr Type))
, MonadFreshVar)

type Transform = TransformT Identity

type MonadFreshVar = MonadSupply Int

varSupply :: [Int]
varSupply = [0..]

runTransformT :: Monad m => TransformT m a -> SymbolTable (A.AnnExpr Type) -> m a
runTransformT m table
= fmap fst
. flip runSupplyT varSupply
. flip runReaderT table
. unTransform
$ m

runTransform :: Transform a -> SymbolTable (A.AnnExpr Type) -> a
runTransform m table = runIdentity (runTransformT m table)

-- | Generates a fresh name using the given prefix and lookup function
freshName :: (MonadReader (SymbolTable (A.AnnExpr Type)) m, MonadFreshVar m)
=> Text -- ^ Prefix
-> (Text -> SymbolTable (A.AnnExpr Type) -> Maybe a) -- ^ Lookup function
-> m Text
freshName prefix lookupFun = do
next <- (prefix <>) . fromString . show <$> supply
asks (lookupFun next) >>= \case
Nothing -> pure next
Just _ -> freshName prefix lookupFun

freshVar, freshLabel :: (MonadReader (SymbolTable (A.AnnExpr Type)) m, MonadFreshVar m) => m Text
-- | Generate a fresh variable name
freshVar = freshName "var" symTabLookupVar
-- | Generate a fresh join label
freshLabel = freshName "join" symTabLookupFun

-- * Private utility functions

makeJexpr :: Type
-> J.JExprF (J.AnnExpr '[ 'J.ExprType])
-> J.AnnExpr '[ 'J.ExprType]
makeJexpr ty = Fix . J.addField (J.withType ty) . J.toAnnExprF

astType :: A.AnnExpr Type -> Type
astType = A.annGetAnn . unfix

-- * ANF Transformation

-- | Perform ANF transformation on the given symbol table
transformTable :: (MonadReader (SymbolTable (A.AnnExpr Type)) m, MonadFreshVar m)
=> m (SymbolTable (J.AnnExpr '[ 'J.ExprType]))
transformTable = do
table <- ask
symTabTraverseExprs (\(args, ty, expr) -> (args, ty, transformExpr expr)) table

-- | Perform ANF transformation on the given expression
transformExpr :: (MonadReader (SymbolTable (A.AnnExpr Type)) m, MonadFreshVar m)
=> A.AnnExpr Type
-> m (J.AnnExpr '[ 'J.ExprType])
transformExpr expr = anfTransform expr (pure . makeJexpr (astType expr) . J.JVal)

-- | Perform ANF transformation on the branch, afterwards handling control flow.
transformBranch :: (MonadReader (SymbolTable (A.AnnExpr Type)) m, MonadFreshVar m)
=> J.ControlFlow (J.AnnExpr '[ 'J.ExprType]) -- ^ Control flow handler
-> A.Branch (A.AnnExpr Type) -- ^ Branches
-> m (J.JBranch (J.AnnExpr '[ 'J.ExprType]))
transformBranch cf (A.BrAdt adtName argNames expr) = do
jexpr <- anfTransform expr (pure . makeJexpr (astType expr) . J.JVal)
pure $ J.BrAdt adtName argNames (J.Cfe jexpr cf)


-- | Main ANF transformation logic. Given the SimPL AST, this function will
-- normalize the AST, and then it will feed the final JValue into the given
-- continuation to produce the resulting JoinIR AST.
anfTransform :: (MonadReader (SymbolTable (A.AnnExpr Type)) m, MonadFreshVar m)
=> A.AnnExpr Type -- ^ Expression to translate
-> (J.JValue -> m (J.AnnExpr '[ 'J.ExprType])) -- ^ Continuation
-> m (J.AnnExpr '[ 'J.ExprType])
anfTransform (Fix (A.AnnExprF ty exprf)) cont = case exprf of
A.Lit lit -> cont (J.JLit lit)
A.Var name -> cont (J.JVar name)
A.Let name bindExpr next ->
anfTransform bindExpr $ \bindVal ->
makeJexpr (A.annGetAnn (unfix bindExpr)) . J.JLet name bindVal <$>
local (symTabInsertVar name ty) (anfTransform next cont)
A.BinOp op left right ->
anfTransform left $ \jleft ->
anfTransform right $ \jright -> do
name <- freshVar
makeJexpr ty . J.JApp name (J.CBinOp op) [jleft, jright] <$>
local (symTabInsertVar name ty) (cont (J.JVar name))
A.If guard trueBr falseBr ->
anfTransform guard $ \jguard -> do
lbl <- freshLabel
trueBr' <- anfTransform trueBr (pure . makeJexpr (astType trueBr) . J.JVal)
falseBr' <- anfTransform falseBr (pure . makeJexpr (astType falseBr) . J.JVal)
name <- freshVar
let jmp = J.JJump lbl
let guardTy = A.annGetAnn (unfix guard)
let guardCfe = makeJexpr guardTy (J.JVal jguard)
let cfe = J.Cfe guardCfe (J.JIf (J.Cfe trueBr' jmp) (J.Cfe falseBr' jmp))
-- TODO: Make JJoin node placement more efficient
makeJexpr ty . J.JJoin lbl name cfe <$>
local (symTabInsertVar name ty) (cont (J.JVar name))
A.Case branches expr ->
anfTransform expr $ \jexpr -> do
lbl <- freshLabel
let jexprTy = A.annGetAnn (unfix expr)
jbranches <- traverse (transformBranch (J.JJump lbl)) branches
let jexprCfe = J.Cfe (makeJexpr jexprTy (J.JVal jexpr)) (J.JCase jbranches)
name <- freshVar
-- TODO: Make JJoin node placement more efficient
makeJexpr ty . J.JJoin lbl name jexprCfe <$>
local (symTabInsertVar name ty) (cont (J.JVar name))
A.Cons ctorName args ->
collectArgs args $ \argVals -> do
varName <- freshVar
makeJexpr ty . J.JApp varName (J.CCtor ctorName) argVals <$>
local (symTabInsertVar varName ty) (cont (J.JVar varName))
A.App funcName args ->
collectArgs args $ \argVals -> do
varName <- freshVar
makeJexpr ty . J.JApp varName (J.CFunc funcName) argVals <$>
local (symTabInsertVar varName ty) (cont (J.JVar varName))
A.Cast expr numTy ->
anfTransform expr $ \jexpr -> do
varName <- freshVar
makeJexpr ty . J.JApp varName (J.CCast numTy) [jexpr] <$>
local (symTabInsertVar varName ty) (cont (J.JVar varName))
A.Print expr ->
anfTransform expr $ \jexpr -> do
varName <- freshVar
makeJexpr ty . J.JApp varName J.CPrint [jexpr] <$>
local (symTabInsertVar varName ty) (cont (J.JVar varName))
A.FunRef name -> do
varName <- freshVar
makeJexpr ty . J.JApp varName (J.CFunRef name) [] <$>
local (symTabInsertVar varName ty) (cont (J.JVar varName))

-- | Normalize each expression in sequential order, and then run the
-- continuation with the expression values.
collectArgs :: (MonadReader (SymbolTable (A.AnnExpr Type)) m, MonadFreshVar m)
=> [A.AnnExpr Type] -- ^ Argument expressions
-> ([J.JValue] -> m (J.AnnExpr '[ 'J.ExprType])) -- ^ Continuation
-> m (J.AnnExpr '[ 'J.ExprType])
collectArgs = go []
where
go vals [] mcont = mcont (reverse vals)
go vals (x:xs) mcont = anfTransform x $ \v -> go (v:vals) xs mcont
Loading