Add allocator convertion functions

This commit is contained in:
Eugen Wissner 2024-10-01 00:02:19 +02:00
parent c2c923276f
commit bbb15a0218
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
5 changed files with 80 additions and 29 deletions

5
TODO
View File

@ -25,4 +25,7 @@
- Temporary variables always use the same register, t0. Allocate registers for - Temporary variables always use the same register, t0. Allocate registers for
temporaries. temporaries.
# Type analysis # Other
- Type analysis.
- Move platform dependent code generation into a submodule.

View File

@ -1,3 +1,39 @@
module Language.Elna.Allocator module Language.Elna.Allocator
( ( MachineConfiguration(..)
, Store(..)
, allocate
) where ) where
import Data.HashMap.Strict (HashMap)
import Data.Vector (Vector)
import Language.Elna.Intermediate (Operand(..), Quadruple(..), Variable(..))
import Language.Elna.Location (Identifier(..))
newtype Store r = Store r
newtype MachineConfiguration r = MachineConfiguration
{ temporaryRegister :: r
}
allocate
:: forall r
. MachineConfiguration r
-> HashMap Identifier (Vector (Quadruple Variable))
-> HashMap Identifier (Vector (Quadruple (Store r)))
allocate MachineConfiguration{..} = fmap function
where
function :: Vector (Quadruple Variable) -> Vector (Quadruple (Store r))
function = fmap quadruple
quadruple :: Quadruple Variable -> Quadruple (Store r)
quadruple StartQuadruple = StartQuadruple
quadruple StopQuadruple = StopQuadruple
quadruple (ParameterQuadruple operand1) =
ParameterQuadruple (operand operand1)
quadruple (CallQuadruple name count) = CallQuadruple name count
quadruple (AddQuadruple operand1 operand2 _) =
AddQuadruple (operand operand1) (operand operand2) (Store temporaryRegister)
quadruple (SubtractionQuadruple operand1 operand2 _) =
SubtractionQuadruple (operand operand1) (operand operand2) (Store temporaryRegister)
operand :: Operand Variable -> Operand (Store r)
operand (IntOperand x) = IntOperand x
operand (VariableOperand _) = VariableOperand (Store temporaryRegister)

View File

@ -1,6 +1,7 @@
module Language.Elna.CodeGenerator module Language.Elna.CodeGenerator
( Statement(..) ( Statement(..)
, generateCode , generateRiscV
, riscVConfiguration
) where ) where
import Data.ByteString (ByteString) import Data.ByteString (ByteString)
@ -10,10 +11,10 @@ import Data.Int (Int32)
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 qualified Data.Text.Encoding as Text.Encoding
import Language.Elna.Allocator (MachineConfiguration(..), Store(..))
import Language.Elna.Location (Identifier(..)) import Language.Elna.Location (Identifier(..))
import Language.Elna.Intermediate (Operand(..), Quadruple(..), Variable(..)) import Language.Elna.Intermediate (Operand(..), Quadruple(..))
import qualified Language.Elna.Architecture.RiscV as RiscV import qualified Language.Elna.Architecture.RiscV as RiscV
import Language.Elna.SymbolTable (SymbolTable)
import Data.Bits (Bits(..)) import Data.Bits (Bits(..))
data Directive data Directive
@ -26,15 +27,24 @@ data Statement
| JumpLabel ByteString [Directive] | JumpLabel ByteString [Directive]
deriving Eq deriving Eq
generateCode :: SymbolTable -> HashMap Identifier (Vector Quadruple) -> Vector Statement riscVConfiguration :: MachineConfiguration RiscV.XRegister
generateCode _ = HashMap.foldlWithKey' go Vector.empty riscVConfiguration = MachineConfiguration
{ temporaryRegister = RiscV.T0
}
type RiscVStore = Store RiscV.XRegister
type RiscVQuadruple = Quadruple RiscVStore
type RiscVOperand = Operand RiscVStore
generateRiscV :: HashMap Identifier (Vector RiscVQuadruple) -> Vector Statement
generateRiscV = HashMap.foldlWithKey' go Vector.empty
where where
go accumulator (Identifier key) value = go accumulator (Identifier key) value =
let code = Vector.cons (JumpLabel (Text.Encoding.encodeUtf8 key) [GlobalDirective, FunctionDirective]) let code = Vector.cons (JumpLabel (Text.Encoding.encodeUtf8 key) [GlobalDirective, FunctionDirective])
$ Vector.foldMap quadruple value $ Vector.foldMap quadruple value
in accumulator <> code in accumulator <> code
quadruple :: Quadruple -> Vector Statement quadruple :: RiscVQuadruple -> Vector Statement
quadruple StartQuadruple = Vector.fromList quadruple StartQuadruple = Vector.fromList
[ Instruction (RiscV.BaseInstruction RiscV.OpImm $ RiscV.I RiscV.SP RiscV.ADDI RiscV.SP (negate 4)) [ 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 0 RiscV.SW RiscV.SP RiscV.S0)
@ -57,25 +67,25 @@ quadruple StopQuadruple = Vector.fromList
, Instruction (RiscV.BaseInstruction RiscV.OpImm $ RiscV.I RiscV.SP RiscV.ADDI 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)
] ]
quadruple (AddQuadruple operand1 operand2 (TempVariable _)) = quadruple (AddQuadruple operand1 operand2 (Store register)) =
let (operandRegister1, statements1) = loadImmediateOrRegister operand1 RiscV.A0 let (operandRegister1, statements1) = loadImmediateOrRegister operand1 RiscV.A0
(operandRegister2, statements2) = loadImmediateOrRegister operand2 RiscV.A1 (operandRegister2, statements2) = loadImmediateOrRegister operand2 RiscV.A1
in Vector.snoc (statements1 <> statements2) in Vector.snoc (statements1 <> statements2)
$ Instruction $ Instruction
$ RiscV.BaseInstruction RiscV.Op $ RiscV.BaseInstruction RiscV.Op
$ RiscV.R RiscV.T0 RiscV.ADD operandRegister1 operandRegister2 (RiscV.Funct7 0b0000000) $ RiscV.R register RiscV.ADD operandRegister1 operandRegister2 (RiscV.Funct7 0b0000000)
quadruple (SubtractionQuadruple operand1 operand2 (TempVariable _)) = quadruple (SubtractionQuadruple operand1 operand2 (Store register)) =
let (operandRegister1, statements1) = loadImmediateOrRegister operand1 RiscV.A0 let (operandRegister1, statements1) = loadImmediateOrRegister operand1 RiscV.A0
(operandRegister2, statements2) = loadImmediateOrRegister operand2 RiscV.A1 (operandRegister2, statements2) = loadImmediateOrRegister operand2 RiscV.A1
in Vector.snoc (statements1 <> statements2) in Vector.snoc (statements1 <> statements2)
$ Instruction $ Instruction
$ RiscV.BaseInstruction RiscV.Op $ RiscV.BaseInstruction RiscV.Op
$ RiscV.R RiscV.T0 RiscV.SUB operandRegister1 operandRegister2 (RiscV.Funct7 0b0100000) $ RiscV.R register RiscV.SUB operandRegister1 operandRegister2 (RiscV.Funct7 0b0100000)
loadImmediateOrRegister :: Operand -> RiscV.XRegister -> (RiscV.XRegister, Vector Statement) loadImmediateOrRegister :: RiscVOperand -> RiscV.XRegister -> (RiscV.XRegister, Vector Statement)
loadImmediateOrRegister (IntOperand intValue) targetRegister = loadImmediateOrRegister (IntOperand intValue) targetRegister =
(targetRegister, lui intValue targetRegister) (targetRegister, lui intValue targetRegister)
loadImmediateOrRegister (VariableOperand _) _ = (RiscV.T0, Vector.empty) loadImmediateOrRegister (VariableOperand (Store register)) _ = (register, Vector.empty)
lui :: Int32 -> RiscV.XRegister -> Vector Statement lui :: Int32 -> RiscV.XRegister -> Vector Statement
lui intValue targetRegister lui intValue targetRegister

View File

@ -28,18 +28,18 @@ instance Show Variable
-- show (Variable variable) = '$' : Text.unpack variable -- show (Variable variable) = '$' : Text.unpack variable
show (TempVariable variable) = '$' : show variable show (TempVariable variable) = '$' : show variable
data Operand data Operand v
= IntOperand Int32 = IntOperand Int32
| VariableOperand Variable | VariableOperand v
deriving (Eq, Show) deriving (Eq, Show)
data Quadruple data Quadruple v
= StartQuadruple = StartQuadruple
| StopQuadruple | StopQuadruple
| ParameterQuadruple Operand | ParameterQuadruple (Operand v)
| CallQuadruple Text Word32 | CallQuadruple Text Word32
| AddQuadruple Operand Operand Variable | AddQuadruple (Operand v) (Operand v) v
| SubtractionQuadruple Operand Operand Variable | SubtractionQuadruple (Operand v) (Operand v) v
{-| GoToQuadruple Label {-| GoToQuadruple Label
| AssignQuadruple Operand Variable | AssignQuadruple Operand Variable
| ArrayQuadruple Variable Operand Variable | ArrayQuadruple Variable Operand Variable
@ -72,7 +72,7 @@ instance Monad Intermediate
where where
(Intermediate x) >>= f = Intermediate $ x >>= (runIntermediate . f) (Intermediate x) >>= f = Intermediate $ x >>= (runIntermediate . f)
intermediate :: SymbolTable -> AST.Program -> HashMap AST.Identifier (Vector Quadruple) intermediate :: SymbolTable -> AST.Program -> HashMap AST.Identifier (Vector (Quadruple Variable))
intermediate globalTable intermediate globalTable
= fst = fst
. flip runState 0 . flip runState 0
@ -82,14 +82,14 @@ intermediate globalTable
program program
:: SymbolTable :: SymbolTable
-> AST.Program -> AST.Program
-> Intermediate (HashMap AST.Identifier (Vector Quadruple)) -> Intermediate (HashMap AST.Identifier (Vector (Quadruple Variable)))
program globalTable (AST.Program declarations) = HashMap.fromList . catMaybes program globalTable (AST.Program declarations) = HashMap.fromList . catMaybes
<$> traverse (declaration globalTable) declarations <$> traverse (declaration globalTable) declarations
declaration declaration
:: SymbolTable :: SymbolTable
-> AST.Declaration -> AST.Declaration
-> Intermediate (Maybe (AST.Identifier, Vector Quadruple)) -> Intermediate (Maybe (AST.Identifier, Vector (Quadruple Variable)))
declaration globalTable (AST.ProcedureDeclaration procedureName _ _ statements) declaration globalTable (AST.ProcedureDeclaration procedureName _ _ statements)
= Just = Just
. (procedureName,) . (procedureName,)
@ -99,7 +99,7 @@ declaration globalTable (AST.ProcedureDeclaration procedureName _ _ statements)
<$> traverse (statement globalTable) statements <$> traverse (statement globalTable) statements
-- declaration (AST.TypeDefinition _ _) accumulator = pure accumulator -- declaration (AST.TypeDefinition _ _) accumulator = pure accumulator
statement :: SymbolTable -> AST.Statement -> Intermediate (Vector Quadruple) statement :: SymbolTable -> AST.Statement -> Intermediate (Vector (Quadruple Variable))
statement _ AST.EmptyStatement = pure mempty statement _ AST.EmptyStatement = pure mempty
statement localTable (AST.CallStatement (AST.Identifier callName) arguments) = do statement localTable (AST.CallStatement (AST.Identifier callName) arguments) = do
visitedArguments <- traverse (expression localTable) arguments visitedArguments <- traverse (expression localTable) arguments
@ -260,7 +260,7 @@ variableType (AST.VariableAccess identifier) symbolTable
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 Variable, Vector (Quadruple Variable))
expression localTable = \case expression localTable = \case
(AST.LiteralExpression literal') -> pure (literal literal', mempty) (AST.LiteralExpression literal') -> pure (literal literal', mempty)
(AST.SumExpression lhs rhs) -> binaryExpression AddQuadruple lhs rhs (AST.SumExpression lhs rhs) -> binaryExpression AddQuadruple lhs rhs
@ -302,7 +302,7 @@ expression localTable = \case
, Vector.snoc (lhsStatements <> rhsStatements) newQuadruple , Vector.snoc (lhsStatements <> rhsStatements) newQuadruple
) )
literal :: AST.Literal -> Operand literal :: AST.Literal -> Operand Variable
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

View File

@ -5,11 +5,12 @@ module Main
import Language.Elna.CommandLine (CommandLine(..), commandLine, execParser) import Language.Elna.CommandLine (CommandLine(..), commandLine, execParser)
import Language.Elna.PrinterWriter (riscv32Elf) import Language.Elna.PrinterWriter (riscv32Elf)
import Language.Elna.Object.Elf (elfObject) import Language.Elna.Object.Elf (elfObject)
import Language.Elna.Allocator (allocate)
import Language.Elna.Parser (programP) import Language.Elna.Parser (programP)
import Language.Elna.NameAnalysis (nameAnalysis) import Language.Elna.NameAnalysis (nameAnalysis)
import Language.Elna.TypeAnalysis (typeAnalysis) import Language.Elna.TypeAnalysis (typeAnalysis)
import Language.Elna.Intermediate (intermediate) import Language.Elna.Intermediate (intermediate)
import Language.Elna.CodeGenerator (generateCode) import Language.Elna.CodeGenerator (generateRiscV, riscVConfiguration)
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
import System.FilePath (replaceExtension, takeFileName) import System.FilePath (replaceExtension, takeFileName)
import Text.Megaparsec (runParser, errorBundlePretty) import Text.Megaparsec (runParser, errorBundlePretty)
@ -31,7 +32,8 @@ main = execParser commandLine >>= withCommandLine
$ errorBundlePretty errorBundle $ errorBundlePretty errorBundle
withSymbolTable output program symbolTable = withSymbolTable output program symbolTable =
let _ = typeAnalysis symbolTable program let _ = typeAnalysis symbolTable program
intermediate' = intermediate symbolTable program instructions = generateRiscV
instructions = generateCode symbolTable intermediate' $ allocate riscVConfiguration
$ intermediate symbolTable program
in elfObject output in elfObject output
$ riscv32Elf instructions $ riscv32Elf instructions