Generate IR and target code

This commit is contained in:
Eugen Wissner 2024-09-25 23:06:02 +02:00
parent b30bbcab28
commit 8eaeb5afa3
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
4 changed files with 152 additions and 111 deletions

4
TODO
View File

@ -1,6 +1,8 @@
# Intermediate code generation # Intermediate code generation
- Traverse the AST and generate IR. - Calculate maximum number of arguments that a function can have. Put procedure
arguments onto the stack, above the stack pointer. Should the offsets be
calculated during IR generation or target code generation?
# ELF generation # ELF generation

View File

@ -4,8 +4,12 @@ module Language.Elna.CodeGenerator
) where ) where
import Data.ByteString (ByteString) import Data.ByteString (ByteString)
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.Vector (Vector) import Data.Vector (Vector)
import qualified Data.Vector as Vector import qualified Data.Vector as Vector
import qualified Data.Text.Encoding as Text.Encoding
import Language.Elna.Location (Identifier(..))
import Language.Elna.Intermediate (Quadruple(..)) import Language.Elna.Intermediate (Quadruple(..))
import qualified Language.Elna.Architecture.RiscV as RiscV import qualified Language.Elna.Architecture.RiscV as RiscV
import Language.Elna.SymbolTable (SymbolTable) import Language.Elna.SymbolTable (SymbolTable)
@ -20,9 +24,27 @@ data Statement
| JumpLabel ByteString [Directive] | JumpLabel ByteString [Directive]
deriving Eq deriving Eq
generateCode :: SymbolTable -> Vector Quadruple -> Vector Statement generateCode :: SymbolTable -> HashMap Identifier (Vector Quadruple) -> Vector Statement
generateCode _ _ = Vector.fromList generateCode _ = HashMap.foldlWithKey' go Vector.empty
[ JumpLabel "main" [GlobalDirective, FunctionDirective] where
, Instruction (RiscV.CallInstruction "printi") go accumulator (Identifier key) value =
let code = Vector.cons (JumpLabel (Text.Encoding.encodeUtf8 key) [GlobalDirective, FunctionDirective])
$ Vector.foldMap quadruple value
in accumulator <> code
quadruple :: Quadruple -> Vector Statement
quadruple StartQuadruple = Vector.fromList
[ Instruction (RiscV.BaseInstruction RiscV.OpImm $ RiscV.I RiscV.SP RiscV.ADDI RiscV.SP (negate 4))
, Instruction (RiscV.BaseInstruction RiscV.Store $ RiscV.S 0 RiscV.SW RiscV.SP RiscV.S0)
, Instruction (RiscV.BaseInstruction RiscV.Store $ RiscV.S 4 RiscV.SW RiscV.SP RiscV.RA)
, Instruction (RiscV.BaseInstruction RiscV.OpImm $ RiscV.I RiscV.S0 RiscV.ADDI RiscV.SP 4)
]
quadruple (ParameterQuadruple _) = mempty
quadruple (CallQuadruple callName _) = Vector.singleton
$ Instruction (RiscV.CallInstruction callName)
quadruple StopQuadruple = Vector.fromList
[ Instruction (RiscV.BaseInstruction RiscV.Load $ RiscV.I RiscV.S0 RiscV.LW RiscV.SP 0)
, Instruction (RiscV.BaseInstruction RiscV.Load $ RiscV.I RiscV.RA RiscV.LW RiscV.SP 4)
, Instruction (RiscV.BaseInstruction RiscV.OpImm $ RiscV.I RiscV.SP RiscV.ADDI RiscV.SP 4)
, Instruction (RiscV.BaseInstruction RiscV.Jalr $ RiscV.I RiscV.RA RiscV.JALR RiscV.Zero 0) , Instruction (RiscV.BaseInstruction RiscV.Jalr $ RiscV.I RiscV.RA RiscV.JALR RiscV.Zero 0)
] ]

View File

@ -1,66 +1,36 @@
module Language.Elna.Intermediate module Language.Elna.Intermediate
( Quadruple(..) ( Operand(..)
, Quadruple(..)
{- , Label(..) {- , Label(..)
, Operand(..)
, Variable(..) -} , Variable(..) -}
, intermediate , intermediate
) where ) where
import Data.Bifunctor (Bifunctor(..))
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.Vector (Vector) import Data.Vector (Vector)
import qualified Data.Vector as Vector import qualified Data.Vector as Vector
import Data.Int (Int32)
import Data.Word (Word32)
import Data.Text (Text)
import qualified Language.Elna.AST as AST import qualified Language.Elna.AST as AST
import Language.Elna.SymbolTable (SymbolTable{-, Info(..) -}) import Language.Elna.SymbolTable (SymbolTable{-, Info(..) -})
import Data.Foldable (Foldable(..))
import Control.Monad.Trans.State (State, runState)
import Data.Maybe (catMaybes)
newtype Operand
= IntOperand Int32
-- | VariableOperand Variable
deriving (Eq, Show)
data Quadruple data Quadruple
= StartQuadruple = StartQuadruple
| StopQuadruple | StopQuadruple
deriving (Eq, Show) | ParameterQuadruple Operand
| CallQuadruple Text Word32
intermediate :: SymbolTable -> AST.Program -> {- HashMap AST.Identifier (-} Vector Quadruple --) {-| GoToQuadruple Label
intermediate _globalTable = const $ Vector.fromList [StartQuadruple, StopQuadruple]
{- = fst
. flip runState mempty
. runIntermediate
. program globalTable -}
{-
import Data.Bifunctor (Bifunctor(..))
import Data.Int (Int32)
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.Text (Text)
import Data.Word (Word32)
import Language.Elna.Types (Type(..))
import qualified Language.Elna.SymbolTable as SymbolTable
import Data.Foldable (Foldable(..), foldrM)
import GHC.Records (HasField(..))
import qualified Data.Text as Text
import qualified Data.Text.Lazy.Builder.Int as Text.Builder
import qualified Data.Text.Lazy.Builder as Text.Builder
import qualified Data.Text.Lazy as Text.Lazy
data Operand
= VariableOperand Variable
| IntOperand Int32
deriving (Eq, Show)
newtype Label = Label Text
deriving Eq
instance Show Label
where
show (Label label) = '.' : Text.unpack label
data Variable = Variable Text | TempVariable Int32
deriving Eq
instance Show Variable
where
show (Variable variable) = '$' : Text.unpack variable
show (TempVariable variable) = '$' : show variable
data Quadruple
= StartQuadruple
| GoToQuadruple Label
| AssignQuadruple Operand Variable | AssignQuadruple Operand Variable
| ArrayQuadruple Variable Operand Variable | ArrayQuadruple Variable Operand Variable
| ArrayAssignQuadruple Operand Operand Variable | ArrayAssignQuadruple Operand Operand Variable
@ -75,54 +45,65 @@ data Quadruple
| GreaterQuadruple Operand Operand Label | GreaterQuadruple Operand Operand Label
| LessOrEqualQuadruple Operand Operand Label | LessOrEqualQuadruple Operand Operand Label
| GreaterOrEqualQuadruple Operand Operand Label | GreaterOrEqualQuadruple Operand Operand Label
| LabelQuadruple Label | LabelQuadruple Label -}
| ParameterQuadruple Operand
| CallQuadruple Variable Word32
| StopQuadruple
deriving (Eq, Show) deriving (Eq, Show)
createLabel :: Intermediate Label newtype Intermediate a = Intermediate
createLabel = do { runIntermediate :: State Word32 a }
currentCounter <- Intermediate $ gets labelCounter
Intermediate $ modify' modifier
pure
$ Label
$ Text.Lazy.toStrict
$ Text.Builder.toLazyText
$ Text.Builder.decimal currentCounter
where
modifier generator = generator
{ labelCounter = getField @"labelCounter" generator + 1
}
createTemporary :: Intermediate Variable instance Functor Intermediate
createTemporary = do
currentCounter <- Intermediate $ gets temporaryCounter
Intermediate $ modify' modifier
pure $ TempVariable currentCounter
where where
modifier generator = generator fmap f (Intermediate x) = Intermediate $ f <$> x
{ temporaryCounter = getField @"temporaryCounter" generator + 1
} instance Applicative Intermediate
where
pure = Intermediate . pure
(Intermediate f) <*> (Intermediate x) = Intermediate $ f <*> x
instance Monad Intermediate
where
(Intermediate x) >>= f = Intermediate $ x >>= (runIntermediate . f)
intermediate :: SymbolTable -> AST.Program -> HashMap AST.Identifier (Vector Quadruple)
intermediate globalTable
= fst
. flip runState 0
. runIntermediate
. program globalTable
program program
:: SymbolTable :: SymbolTable
-> AST.Program -> AST.Program
-> Intermediate (HashMap AST.Identifier (Vector Quadruple)) -> Intermediate (HashMap AST.Identifier (Vector Quadruple))
program globalTable (AST.Program declarations) = program globalTable (AST.Program declarations) = HashMap.fromList . catMaybes
foldrM go HashMap.empty declarations <$> traverse (declaration globalTable) declarations
where
go (AST.TypeDefinition _ _) accumulator = pure accumulator declaration
go (AST.ProcedureDefinition procedureName _ _ statements) accumulator = do :: SymbolTable
translatedStatements <- Vector.cons StartQuadruple -> AST.Declaration
. flip Vector.snoc StopQuadruple -> Intermediate (Maybe (AST.Identifier, Vector Quadruple))
. fold declaration globalTable (AST.ProcedureDeclaration procedureName _ _ statements)
<$> traverse (statement globalTable) statements = Just
pure $ HashMap.insert procedureName translatedStatements accumulator . (procedureName,)
. Vector.cons StartQuadruple
. flip Vector.snoc StopQuadruple
. fold
<$> traverse (statement globalTable) statements
-- declaration (AST.TypeDefinition _ _) accumulator = pure accumulator
statement :: SymbolTable -> AST.Statement -> Intermediate (Vector Quadruple) statement :: SymbolTable -> AST.Statement -> Intermediate (Vector Quadruple)
statement _ AST.EmptyStatement = pure mempty statement _ AST.EmptyStatement = pure mempty
statement localTable (AST.AssignmentStatement variableAccess' assignee) = do statement localTable (AST.CallStatement (AST.Identifier callName) arguments) = do
visitedArguments <- traverse (expression localTable) arguments
let (parameterStatements, argumentStatements)
= bimap (Vector.fromList . fmap ParameterQuadruple) Vector.concat
$ unzip visitedArguments
in pure
$ Vector.snoc (argumentStatements <> parameterStatements)
$ CallQuadruple callName
$ fromIntegral
$ Vector.length argumentStatements
{- statement localTable (AST.AssignmentStatement variableAccess' assignee) = do
(rhsOperand, rhsStatements) <- expression localTable assignee (rhsOperand, rhsStatements) <- expression localTable assignee
let variableType' = variableType variableAccess' localTable let variableType' = variableType variableAccess' localTable
accessResult <- variableAccess localTable variableAccess' Nothing variableType' mempty accessResult <- variableAccess localTable variableAccess' Nothing variableType' mempty
@ -158,18 +139,47 @@ statement localTable (AST.WhileStatement whileCondition whileStatement) = do
<> Vector.fromList [jumpConstructor startLabel, GoToQuadruple endLabel, LabelQuadruple startLabel] <> Vector.fromList [jumpConstructor startLabel, GoToQuadruple endLabel, LabelQuadruple startLabel]
<> whileStatements <> whileStatements
<> Vector.fromList [GoToQuadruple conditionLabel, LabelQuadruple endLabel] <> Vector.fromList [GoToQuadruple conditionLabel, LabelQuadruple endLabel]
statement localTable (AST.CallStatement (AST.Identifier callName) arguments) = do
visitedArguments <- traverse (expression localTable) arguments
let (parameterStatements, argumentStatements)
= bimap (Vector.fromList . fmap ParameterQuadruple) Vector.concat
$ unzip visitedArguments
in pure
$ Vector.snoc (argumentStatements <> parameterStatements)
$ CallQuadruple (Variable callName)
$ fromIntegral
$ Vector.length argumentStatements
statement localTable (AST.CompoundStatement statements) = statement localTable (AST.CompoundStatement statements) =
fold <$> traverse (statement localTable) statements fold <$> traverse (statement localTable) statements -}
{-
import Language.Elna.Types (Type(..))
import qualified Language.Elna.SymbolTable as SymbolTable
import GHC.Records (HasField(..))
import qualified Data.Text.Lazy.Builder.Int as Text.Builder
import qualified Data.Text.Lazy.Builder as Text.Builder
import qualified Data.Text.Lazy as Text.Lazy
newtype Label = Label Text
deriving Eq
instance Show Label
where
show (Label label) = '.' : Text.unpack label
createLabel :: Intermediate Label
createLabel = do
currentCounter <- Intermediate $ gets labelCounter
Intermediate $ modify' modifier
pure
$ Label
$ Text.Lazy.toStrict
$ Text.Builder.toLazyText
$ Text.Builder.decimal currentCounter
where
modifier generator = generator
{ labelCounter = getField @"labelCounter" generator + 1
}
createTemporary :: Intermediate Variable
createTemporary = do
currentCounter <- Intermediate $ gets temporaryCounter
Intermediate $ modify' modifier
pure $ TempVariable currentCounter
where
modifier generator = generator
{ temporaryCounter = getField @"temporaryCounter" generator + 1
}
condition condition
:: SymbolTable :: SymbolTable
@ -245,10 +255,11 @@ variableType (AST.VariableAccess identifier) symbolTable
| otherwise = error "Undefined type." | otherwise = error "Undefined type."
variableType (AST.ArrayAccess arrayAccess' _) symbolTable = variableType (AST.ArrayAccess arrayAccess' _) symbolTable =
variableType arrayAccess' symbolTable variableType arrayAccess' symbolTable
-}
expression :: SymbolTable -> AST.Expression -> Intermediate (Operand, Vector Quadruple) expression :: SymbolTable -> AST.Expression -> Intermediate (Operand, Vector Quadruple)
expression localTable = \case expression _localTable = \case
(AST.VariableExpression variableExpression) -> do (AST.LiteralExpression literal') -> pure (literal literal', mempty)
{- (AST.VariableExpression variableExpression) -> do
let variableType' = variableType variableExpression localTable let variableType' = variableType variableExpression localTable
variableAccess' <- variableAccess localTable variableExpression Nothing variableType' mempty variableAccess' <- variableAccess localTable variableExpression Nothing variableType' mempty
case variableAccess' of case variableAccess' of
@ -261,7 +272,6 @@ expression localTable = \case
( VariableOperand arrayAddress ( VariableOperand arrayAddress
, Vector.snoc statements arrayStatement , Vector.snoc statements arrayStatement
) )
(AST.LiteralExpression literal') -> pure (literal literal', mempty)
(AST.NegationExpression negation) -> do (AST.NegationExpression negation) -> do
(operand, statements) <- expression localTable negation (operand, statements) <- expression localTable negation
tempVariable <- createTemporary tempVariable <- createTemporary
@ -288,11 +298,18 @@ expression localTable = \case
, Vector.snoc (lhsStatements <> rhsStatements) newQuadruple , Vector.snoc (lhsStatements <> rhsStatements) newQuadruple
) )
data Variable = Variable Text | TempVariable Int32
deriving Eq
instance Show Variable
where
show (Variable variable) = '$' : Text.unpack variable
show (TempVariable variable) = '$' : show variable
-}
literal :: AST.Literal -> Operand literal :: AST.Literal -> Operand
literal (AST.IntegerLiteral integer) = IntOperand integer literal (AST.IntegerLiteral integer) = IntOperand integer
literal (AST.HexadecimalLiteral integer) = IntOperand integer {-literal (AST.HexadecimalLiteral integer) = IntOperand integer
literal (AST.CharacterLiteral character) = IntOperand $ fromIntegral character literal (AST.CharacterLiteral character) = IntOperand $ fromIntegral character
literal (AST.BooleanLiteral boolean) literal (AST.BooleanLiteral boolean)
| boolean = IntOperand 1 | boolean = IntOperand 1
| otherwise = IntOperand 0 | otherwise = IntOperand 0 -}
-}

View File

@ -6,10 +6,10 @@
.text .text
printi: printi:
addi sp, sp, -8 addi sp, sp, -4
sw s0, 0(sp) sw s0, 0(sp)
sw ra, 4(sp) sw ra, 4(sp)
addi s0, sp, 8 addi s0, sp, 4
addi t0, a0, 0 addi t0, a0, 0
addi a0, a0, '0' addi a0, a0, '0'
@ -28,7 +28,7 @@ printi:
lw s0, 0(sp) lw s0, 0(sp)
lw ra, 4(sp) lw ra, 4(sp)
addi sp, sp, 8 addi sp, sp, 4
ret ret
_start: _start: