Add array assignment to the IR
This commit is contained in:
parent
147967c04b
commit
0c40bca60b
10
TODO
10
TODO
@ -1,9 +1,3 @@
|
|||||||
# Intermediate code generation
|
|
||||||
|
|
||||||
- To access named parameters inside a procedure, IR should be able to reference
|
|
||||||
them. During the generation the needed information (e.g. offsets or registers)
|
|
||||||
can be extracted from the symbol table and saved in the operands.
|
|
||||||
|
|
||||||
# ELF generation
|
# ELF generation
|
||||||
|
|
||||||
- Don't ignore relocations where the symbol is not defined in the symbol table.
|
- Don't ignore relocations where the symbol is not defined in the symbol table.
|
||||||
@ -14,7 +8,3 @@
|
|||||||
- Each temporary variable gets a tn register where n is the variable index. If
|
- Each temporary variable gets a tn register where n is the variable index. If
|
||||||
there more variables the allocation will fail with out of bounds runtime
|
there more variables the allocation will fail with out of bounds runtime
|
||||||
error. Implement spill over.
|
error. Implement spill over.
|
||||||
|
|
||||||
# Language
|
|
||||||
|
|
||||||
- Array support.
|
|
||||||
|
@ -135,6 +135,10 @@ quadruple = \case
|
|||||||
AssignQuadruple operand1 variable -> do
|
AssignQuadruple operand1 variable -> do
|
||||||
operand1' <- operand operand1
|
operand1' <- operand operand1
|
||||||
AssignQuadruple operand1' <$> storeVariable variable
|
AssignQuadruple operand1' <$> storeVariable variable
|
||||||
|
ArrayAssignQuadruple operand1 operand2 variable -> do
|
||||||
|
operand1' <- operand operand1
|
||||||
|
operand2' <- operand operand2
|
||||||
|
ArrayAssignQuadruple operand1' operand2' <$> storeVariable variable
|
||||||
|
|
||||||
operand :: Operand Variable -> Allocator r (Operand (Store r))
|
operand :: Operand Variable -> Allocator r (Operand (Store r))
|
||||||
operand (IntOperand x) = pure $ IntOperand x
|
operand (IntOperand x) = pure $ IntOperand x
|
||||||
|
@ -50,8 +50,8 @@ data Quadruple v
|
|||||||
| DivisionQuadruple (Operand v) (Operand v) v
|
| DivisionQuadruple (Operand v) (Operand v) v
|
||||||
| GoToQuadruple Label
|
| GoToQuadruple Label
|
||||||
| AssignQuadruple (Operand v) v
|
| AssignQuadruple (Operand v) v
|
||||||
{-| ArrayQuadruple Variable Operand Variable
|
{-| ArrayQuadruple Variable Operand Variable -}
|
||||||
| ArrayAssignQuadruple Operand Operand Variable -}
|
| ArrayAssignQuadruple (Operand v) (Operand v) v
|
||||||
| LessOrEqualQuadruple (Operand v) (Operand v) Label
|
| LessOrEqualQuadruple (Operand v) (Operand v) Label
|
||||||
| GreaterOrEqualQuadruple (Operand v) (Operand v) Label
|
| GreaterOrEqualQuadruple (Operand v) (Operand v) Label
|
||||||
| GreaterQuadruple (Operand v) (Operand v) Label
|
| GreaterQuadruple (Operand v) (Operand v) Label
|
||||||
|
@ -176,16 +176,16 @@ instance Show Expression
|
|||||||
show (DivisionExpression lhs rhs) = concat [show lhs, " / ", show rhs]
|
show (DivisionExpression lhs rhs) = concat [show lhs, " / ", show rhs]
|
||||||
show (VariableExpression variable) = show variable
|
show (VariableExpression variable) = show variable
|
||||||
|
|
||||||
newtype VariableAccess
|
data VariableAccess
|
||||||
= VariableAccess Identifier
|
= VariableAccess Identifier
|
||||||
-- | ArrayAccess VariableAccess Expression
|
| ArrayAccess VariableAccess Expression
|
||||||
deriving Eq
|
deriving Eq
|
||||||
|
|
||||||
instance Show VariableAccess
|
instance Show VariableAccess
|
||||||
where
|
where
|
||||||
show (VariableAccess variableName) = show variableName
|
show (VariableAccess variableName) = show variableName
|
||||||
{- show (ArrayAccess arrayAccess elementIndex) =
|
show (ArrayAccess arrayAccess elementIndex) =
|
||||||
concat [show arrayAccess, "[", show elementIndex, "]"] -}
|
concat [show arrayAccess, "[", show elementIndex, "]"]
|
||||||
|
|
||||||
data Condition
|
data Condition
|
||||||
= EqualCondition Expression Expression
|
= EqualCondition Expression Expression
|
||||||
|
@ -202,18 +202,6 @@ condition globalTable (AST.GreaterOrEqualCondition lhs rhs)
|
|||||||
variableAccess :: SymbolTable -> AST.VariableAccess -> NameAnalysis ()
|
variableAccess :: SymbolTable -> AST.VariableAccess -> NameAnalysis ()
|
||||||
variableAccess globalTable (AST.VariableAccess identifier) =
|
variableAccess globalTable (AST.VariableAccess identifier) =
|
||||||
checkSymbol globalTable identifier
|
checkSymbol globalTable identifier
|
||||||
{- variableAccess globalTable (AST.ArrayAccess arrayExpression indexExpression)
|
variableAccess globalTable (AST.ArrayAccess arrayExpression indexExpression)
|
||||||
= variableAccess globalTable arrayExpression
|
= variableAccess globalTable arrayExpression
|
||||||
>> expression globalTable indexExpression
|
>> expression globalTable indexExpression
|
||||||
|
|
||||||
enter :: Identifier -> Info -> SymbolTable -> NameAnalysis SymbolTable
|
|
||||||
enter identifier info table
|
|
||||||
= maybe (identifierAlreadyDefinedError identifier) pure
|
|
||||||
$ SymbolTable.enter identifier info table
|
|
||||||
|
|
||||||
identifierAlreadyDefinedError :: Identifier -> NameAnalysis a
|
|
||||||
identifierAlreadyDefinedError = NameAnalysis
|
|
||||||
. lift
|
|
||||||
. throwE
|
|
||||||
. IdentifierAlreadyDefinedError
|
|
||||||
-}
|
|
||||||
|
@ -93,10 +93,10 @@ expressionP :: Parser Expression
|
|||||||
expressionP = makeExprParser termP operatorTable
|
expressionP = makeExprParser termP operatorTable
|
||||||
|
|
||||||
variableAccessP :: Parser VariableAccess
|
variableAccessP :: Parser VariableAccess
|
||||||
variableAccessP = VariableAccess <$> identifierP {- do
|
variableAccessP = do
|
||||||
identifier <- identifierP
|
identifier <- identifierP
|
||||||
indices <- many $ bracketsP expressionP
|
indices <- many $ bracketsP expressionP
|
||||||
pure $ foldr (flip ArrayAccess) (VariableAccess identifier) indices -}
|
pure $ foldr (flip ArrayAccess) (VariableAccess identifier) indices
|
||||||
|
|
||||||
conditionP :: Parser Condition
|
conditionP :: Parser Condition
|
||||||
conditionP = do
|
conditionP = do
|
||||||
|
@ -11,7 +11,7 @@ import Control.Monad.Trans.Reader (ReaderT, runReaderT, withReaderT, ask, asks)
|
|||||||
import Data.Foldable (traverse_)
|
import Data.Foldable (traverse_)
|
||||||
import qualified Data.Vector as Vector
|
import qualified Data.Vector as Vector
|
||||||
import qualified Language.Elna.Frontend.AST as AST
|
import qualified Language.Elna.Frontend.AST as AST
|
||||||
import Language.Elna.Frontend.SymbolTable (Info(..), {-ParameterInfo(..), -}SymbolTable)
|
import Language.Elna.Frontend.SymbolTable (Info(..), ParameterInfo(..), SymbolTable)
|
||||||
import qualified Language.Elna.Frontend.SymbolTable as SymbolTable
|
import qualified Language.Elna.Frontend.SymbolTable as SymbolTable
|
||||||
import Language.Elna.Frontend.Types (Type(..), booleanType, intType)
|
import Language.Elna.Frontend.Types (Type(..), booleanType, intType)
|
||||||
import Language.Elna.Location (Identifier(..))
|
import Language.Elna.Location (Identifier(..))
|
||||||
@ -31,11 +31,10 @@ data Error
|
|||||||
| ArithmeticExpressionError Type
|
| ArithmeticExpressionError Type
|
||||||
| ComparisonExpressionError Type Type
|
| ComparisonExpressionError Type Type
|
||||||
| InvalidConditionTypeError Type
|
| InvalidConditionTypeError Type
|
||||||
{- | InvalidAssignmentError Type
|
{- | ExpectedLvalueError AST.Expression
|
||||||
| ExpectedLvalueError AST.Expression
|
| ArgumentTypeMismatchError Type Type -}
|
||||||
| ArgumentTypeMismatchError Type Type
|
|
||||||
| ArrayIndexError Type
|
| ArrayIndexError Type
|
||||||
| ArrayAccessError Type -}
|
| ArrayAccessError Type
|
||||||
deriving Eq
|
deriving Eq
|
||||||
|
|
||||||
instance Show Error
|
instance Show Error
|
||||||
@ -56,6 +55,10 @@ instance Show Error
|
|||||||
<> show lhs <> "\" and \"" <> show rhs <> "\""
|
<> show lhs <> "\" and \"" <> show rhs <> "\""
|
||||||
show (InvalidConditionTypeError got) =
|
show (InvalidConditionTypeError got) =
|
||||||
"Expected a condition to be a boolean, got: " <> show got
|
"Expected a condition to be a boolean, got: " <> show got
|
||||||
|
show (ArrayIndexError got) =
|
||||||
|
"Expected an array index expression to be an integer, got: " <> show got
|
||||||
|
show (ArrayAccessError got) =
|
||||||
|
"Expected to encounter an array, got: " <> show got
|
||||||
|
|
||||||
newtype TypeAnalysis a = TypeAnalysis
|
newtype TypeAnalysis a = TypeAnalysis
|
||||||
{ runTypeAnalysis :: ReaderT SymbolTable (Except Error) a
|
{ runTypeAnalysis :: ReaderT SymbolTable (Except Error) a
|
||||||
@ -127,7 +130,7 @@ statement globalTable = \case
|
|||||||
Nothing -> TypeAnalysis $ lift $ throwE
|
Nothing -> TypeAnalysis $ lift $ throwE
|
||||||
$ UndefinedSymbolError procedureName
|
$ UndefinedSymbolError procedureName
|
||||||
where
|
where
|
||||||
checkArgument SymbolTable.ParameterInfo{} _argument = pure () {-
|
checkArgument ParameterInfo{} _argument = pure () {-
|
||||||
argumentType <- expression globalTable argument
|
argumentType <- expression globalTable argument
|
||||||
unless (argumentType == type')
|
unless (argumentType == type')
|
||||||
$ TypeAnalysis $ lift $ throwE $ ArgumentTypeMismatchError type' argumentType
|
$ TypeAnalysis $ lift $ throwE $ ArgumentTypeMismatchError type' argumentType
|
||||||
@ -145,7 +148,7 @@ variableAccess globalTable (AST.VariableAccess identifier) = do
|
|||||||
$ UnexpectedVariableInfoError anotherInfo
|
$ UnexpectedVariableInfoError anotherInfo
|
||||||
Nothing -> TypeAnalysis $ lift $ throwE
|
Nothing -> TypeAnalysis $ lift $ throwE
|
||||||
$ UndefinedSymbolError identifier
|
$ UndefinedSymbolError identifier
|
||||||
{-variableAccess globalTable (AST.ArrayAccess arrayExpression indexExpression) = do
|
variableAccess globalTable (AST.ArrayAccess arrayExpression indexExpression) = do
|
||||||
arrayType <- variableAccess globalTable arrayExpression
|
arrayType <- variableAccess globalTable arrayExpression
|
||||||
indexType <- expression globalTable indexExpression
|
indexType <- expression globalTable indexExpression
|
||||||
unless (indexType == intType)
|
unless (indexType == intType)
|
||||||
@ -154,7 +157,7 @@ variableAccess globalTable (AST.VariableAccess identifier) = do
|
|||||||
ArrayType _ baseType -> pure baseType
|
ArrayType _ baseType -> pure baseType
|
||||||
nonArrayType -> TypeAnalysis $ lift $ throwE
|
nonArrayType -> TypeAnalysis $ lift $ throwE
|
||||||
$ ArrayAccessError nonArrayType
|
$ ArrayAccessError nonArrayType
|
||||||
-}
|
|
||||||
expression :: SymbolTable -> AST.Expression -> TypeAnalysis Type
|
expression :: SymbolTable -> AST.Expression -> TypeAnalysis Type
|
||||||
expression globalTable = \case
|
expression globalTable = \case
|
||||||
AST.VariableExpression variableExpression ->
|
AST.VariableExpression variableExpression ->
|
||||||
|
@ -230,27 +230,30 @@ variableAccess
|
|||||||
-> Glue (AST.Identifier, Maybe (Operand Variable), Vector (Quadruple Variable))
|
-> Glue (AST.Identifier, Maybe (Operand Variable), Vector (Quadruple Variable))
|
||||||
variableAccess _ (AST.VariableAccess identifier) accumulatedIndex _ accumulatedStatements =
|
variableAccess _ (AST.VariableAccess identifier) accumulatedIndex _ accumulatedStatements =
|
||||||
pure (identifier, accumulatedIndex, accumulatedStatements)
|
pure (identifier, accumulatedIndex, accumulatedStatements)
|
||||||
{- variableAccess localTable (AST.ArrayAccess access1 index1) Nothing (ArrayType _ baseType) _ = do
|
variableAccess localTable accessKind accumulatedIndex arrayType statements
|
||||||
(indexPlace, statements) <- expression localTable index1
|
| (AST.ArrayAccess access1 index1) <- accessKind
|
||||||
variableAccess localTable access1 (Just indexPlace) baseType statements
|
, (ArrayType arraySize baseType) <- arrayType = do
|
||||||
variableAccess localTable (AST.ArrayAccess arrayAccess' arrayIndex) (Just baseIndex) (ArrayType arraySize baseType) statements = do
|
(indexPlace, statements') <- expression localTable index1
|
||||||
(indexPlace, statements') <- expression localTable arrayIndex
|
case accumulatedIndex of
|
||||||
|
Just baseIndex -> do
|
||||||
resultVariable <- createTemporary
|
resultVariable <- createTemporary
|
||||||
let resultOperand = VariableOperand resultVariable
|
let resultOperand = VariableOperand resultVariable
|
||||||
indexCalculation = Vector.fromList
|
indexCalculation = Vector.fromList
|
||||||
[ ProductQuadruple (IntOperand $ fromIntegral arraySize) baseIndex resultVariable
|
[ ProductQuadruple (IntOperand $ fromIntegral arraySize) baseIndex resultVariable
|
||||||
, AddQuadruple indexPlace resultOperand resultVariable
|
, AddQuadruple indexPlace resultOperand resultVariable
|
||||||
]
|
]
|
||||||
in variableAccess localTable arrayAccess' (Just resultOperand) baseType
|
in variableAccess localTable access1 (Just resultOperand) baseType
|
||||||
$ statements <> indexCalculation <> statements'
|
$ statements <> indexCalculation <> statements'
|
||||||
|
Nothing ->
|
||||||
|
variableAccess localTable access1 (Just indexPlace) baseType statements'
|
||||||
variableAccess _ _ _ _ _ = error "Array access operator doesn't match the type."
|
variableAccess _ _ _ _ _ = error "Array access operator doesn't match the type."
|
||||||
-}
|
|
||||||
variableType :: AST.VariableAccess -> SymbolTable -> Type
|
variableType :: AST.VariableAccess -> SymbolTable -> Type
|
||||||
variableType (AST.VariableAccess identifier) symbolTable
|
variableType (AST.VariableAccess identifier) symbolTable
|
||||||
| Just (TypeInfo type') <- SymbolTable.lookup identifier symbolTable = type'
|
| Just (TypeInfo type') <- SymbolTable.lookup identifier symbolTable = type'
|
||||||
| 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 -> Glue (Operand Variable, Vector (Quadruple Variable))
|
expression :: SymbolTable -> AST.Expression -> Glue (Operand Variable, Vector (Quadruple Variable))
|
||||||
expression localTable = \case
|
expression localTable = \case
|
||||||
|
@ -259,6 +259,42 @@ quadruple _ (AssignQuadruple operand1 store)
|
|||||||
$ RiscV.BaseInstruction RiscV.OpImm
|
$ RiscV.BaseInstruction RiscV.OpImm
|
||||||
$ RiscV.I storeRegister RiscV.ADDI operandRegister1 0
|
$ RiscV.I storeRegister RiscV.ADDI operandRegister1 0
|
||||||
in pure $ statements1 <> Vector.cons instruction storeStatements
|
in pure $ statements1 <> Vector.cons instruction storeStatements
|
||||||
|
quadruple _ (ArrayAssignQuadruple assigneeOperand indexOperand store)
|
||||||
|
| IntOperand immediateAssigneeOperand <- assigneeOperand =
|
||||||
|
let (storeRegister, storeStatements) = storeWithOffset store indexOperand
|
||||||
|
in pure $ lui immediateAssigneeOperand storeRegister <> storeStatements
|
||||||
|
| VariableOperand variableAssigneeOperand <- assigneeOperand =
|
||||||
|
let (assigneeOperandRegister, assigneeStatements) = loadFromStore variableAssigneeOperand
|
||||||
|
(storeRegister, storeStatements) = storeWithOffset store indexOperand
|
||||||
|
instruction = Instruction
|
||||||
|
$ RiscV.BaseInstruction RiscV.OpImm
|
||||||
|
$ RiscV.I storeRegister RiscV.ADDI assigneeOperandRegister 0
|
||||||
|
in pure $ assigneeStatements <> Vector.cons instruction storeStatements
|
||||||
|
where
|
||||||
|
storeWithOffset :: RiscVStore -> Operand RiscVStore -> (RiscV.XRegister, Vector Statement)
|
||||||
|
storeWithOffset (RegisterStore register) _ = (register, mempty)
|
||||||
|
storeWithOffset (StackStore offset register) (IntOperand indexOffset) =
|
||||||
|
let storeInstruction = Instruction
|
||||||
|
$ RiscV.BaseInstruction RiscV.Store
|
||||||
|
$ RiscV.S (fromIntegral $ offset + indexOffset) RiscV.SW RiscV.S0 register
|
||||||
|
in (register, Vector.singleton storeInstruction)
|
||||||
|
storeWithOffset (StackStore offset register) (VariableOperand indexOffset) =
|
||||||
|
let baseRegisterInstruction = Instruction
|
||||||
|
$ RiscV.BaseInstruction RiscV.OpImm
|
||||||
|
$ RiscV.I immediateRegister RiscV.ADDI RiscV.S0 0
|
||||||
|
(indexRegister, indexStatements) = loadFromStore indexOffset
|
||||||
|
registerWithOffset = Instruction
|
||||||
|
$ RiscV.BaseInstruction RiscV.OpImm
|
||||||
|
$ RiscV.I immediateRegister RiscV.ADDI indexRegister 0
|
||||||
|
storeInstruction = Instruction
|
||||||
|
$ RiscV.BaseInstruction RiscV.Store
|
||||||
|
$ RiscV.S (fromIntegral offset) RiscV.SW immediateRegister register
|
||||||
|
statements = Vector.fromList
|
||||||
|
[ baseRegisterInstruction
|
||||||
|
, registerWithOffset
|
||||||
|
, storeInstruction
|
||||||
|
]
|
||||||
|
in (register, indexStatements <> statements)
|
||||||
|
|
||||||
unconditionalJal :: Label -> Statement
|
unconditionalJal :: Label -> Statement
|
||||||
unconditionalJal (Label goToLabel) = Instruction
|
unconditionalJal (Label goToLabel) = Instruction
|
||||||
|
0
tests/expectations/array_element_assignment.txt
Normal file
0
tests/expectations/array_element_assignment.txt
Normal file
3
tests/vm/array_element_assignment.elna
Normal file
3
tests/vm/array_element_assignment.elna
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
proc main() {
|
||||||
|
var a: array[1] of int;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user