From b71d28201e7858258b65ee085722478988752c74 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Wed, 4 Dec 2024 16:11:06 +0100 Subject: [PATCH] Make IR for array access --- lib/Language/Elna/Backend/Allocator.hs | 4 +++ lib/Language/Elna/Backend/Intermediate.hs | 2 +- lib/Language/Elna/Glue.hs | 15 +++++---- lib/Language/Elna/RiscV/CodeGenerator.hs | 32 +++++++++++++++++++ .../expectations/array_element_assignment.txt | 1 + tests/expectations/print_array_element.txt | 2 ++ tests/vm/array_element_assignment.elna | 3 ++ tests/vm/print_array_element.elna | 8 +++++ 8 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 tests/expectations/print_array_element.txt create mode 100644 tests/vm/print_array_element.elna diff --git a/lib/Language/Elna/Backend/Allocator.hs b/lib/Language/Elna/Backend/Allocator.hs index acdf3e5..aa4e7d5 100644 --- a/lib/Language/Elna/Backend/Allocator.hs +++ b/lib/Language/Elna/Backend/Allocator.hs @@ -139,6 +139,10 @@ quadruple = \case operand1' <- operand operand1 operand2' <- operand operand2 ArrayAssignQuadruple operand1' operand2' <$> storeVariable variable + ArrayQuadruple variable1 operand1 variable2 -> ArrayQuadruple + <$> storeVariable variable1 + <*> operand operand1 + <*> storeVariable variable2 operand :: Operand Variable -> Allocator r (Operand (Store r)) operand (IntOperand x) = pure $ IntOperand x diff --git a/lib/Language/Elna/Backend/Intermediate.hs b/lib/Language/Elna/Backend/Intermediate.hs index dcf0ede..bb0ae7e 100644 --- a/lib/Language/Elna/Backend/Intermediate.hs +++ b/lib/Language/Elna/Backend/Intermediate.hs @@ -50,7 +50,7 @@ data Quadruple v | DivisionQuadruple (Operand v) (Operand v) v | GoToQuadruple Label | AssignQuadruple (Operand v) v - {-| ArrayQuadruple Variable Operand Variable -} + | ArrayQuadruple v (Operand v) v | ArrayAssignQuadruple (Operand v) (Operand v) v | LessOrEqualQuadruple (Operand v) (Operand v) Label | GreaterOrEqualQuadruple (Operand v) (Operand v) Label diff --git a/lib/Language/Elna/Glue.hs b/lib/Language/Elna/Glue.hs index 3cd46e3..2b34363 100644 --- a/lib/Language/Elna/Glue.hs +++ b/lib/Language/Elna/Glue.hs @@ -26,6 +26,7 @@ import Language.Elna.Frontend.SymbolTable (Info(..), SymbolTable) import qualified Language.Elna.Frontend.SymbolTable as SymbolTable import GHC.Records (HasField(..)) import Language.Elna.Frontend.AST (Identifier(..)) +import Debug.Trace (traceShow) data Paste = Paste { temporaryCounter :: Word32 @@ -71,11 +72,12 @@ declaration :: SymbolTable -> AST.Declaration -> Glue (Maybe (AST.Identifier, Vector (Quadruple Variable))) -declaration globalTable (AST.ProcedureDeclaration procedureName parameters variableDeclarations statements) - = Glue (modify' resetTemporaryCounter) - >> traverseWithIndex registerVariable variableDeclarations - >> traverseWithIndex registerParameter (reverse parameters) - >> nameQuadruplesTuple <$> traverse (statement globalTable) statements +declaration globalTable (AST.ProcedureDeclaration procedureName parameters variableDeclarations statements) = + let Just (ProcedureInfo localTable _) = SymbolTable.lookup procedureName globalTable + in Glue (modify' resetTemporaryCounter) + >> traverseWithIndex registerVariable variableDeclarations + >> traverseWithIndex registerParameter (reverse parameters) + >> nameQuadruplesTuple <$> traverse (statement localTable) statements where traverseWithIndex f = traverse_ (uncurry f) . zip [0..] registerParameter index (AST.Parameter identifier _ _) = @@ -251,7 +253,8 @@ variableAccess _ _ _ _ _ = error "Array access operator doesn't match the type." variableType :: AST.VariableAccess -> SymbolTable -> Type variableType (AST.VariableAccess identifier) symbolTable | Just (TypeInfo type') <- SymbolTable.lookup identifier symbolTable = type' - | otherwise = error "Undefined type." + | Just (VariableInfo _ type') <- SymbolTable.lookup identifier symbolTable = type' + | otherwise = traceShow identifier $ error "Undefined type." variableType (AST.ArrayAccess arrayAccess' _) symbolTable = variableType arrayAccess' symbolTable diff --git a/lib/Language/Elna/RiscV/CodeGenerator.hs b/lib/Language/Elna/RiscV/CodeGenerator.hs index 6e7a8cd..a1dcdbe 100644 --- a/lib/Language/Elna/RiscV/CodeGenerator.hs +++ b/lib/Language/Elna/RiscV/CodeGenerator.hs @@ -295,6 +295,38 @@ quadruple _ (ArrayAssignQuadruple assigneeOperand indexOperand store) , storeInstruction ] in (register, indexStatements <> statements) +quadruple _ (ArrayQuadruple assigneeVariable indexOperand store) = + let (operandRegister1, statements1) = loadWithOffset assigneeVariable indexOperand + (storeRegister, storeStatements) = storeToStore store + instruction = Instruction + $ RiscV.BaseInstruction RiscV.OpImm + $ RiscV.I storeRegister RiscV.ADDI operandRegister1 0 + in pure $ statements1 <> Vector.cons instruction storeStatements + where + loadWithOffset :: RiscVStore -> Operand RiscVStore -> (RiscV.XRegister, Vector Statement) + loadWithOffset (RegisterStore register) _ = (register, mempty) + loadWithOffset (StackStore offset register) (IntOperand indexOffset) = + let loadInstruction = Instruction + $ RiscV.BaseInstruction RiscV.Load + $ RiscV.I register RiscV.LW RiscV.S0 (fromIntegral $ offset + indexOffset) + in (register, Vector.singleton loadInstruction) + loadWithOffset (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 + loadInstruction = Instruction + $ RiscV.BaseInstruction RiscV.Load + $ RiscV.I register RiscV.SW immediateRegister (fromIntegral offset) + statements = Vector.fromList + [ baseRegisterInstruction + , registerWithOffset + , loadInstruction + ] + in (register, indexStatements <> statements) unconditionalJal :: Label -> Statement unconditionalJal (Label goToLabel) = Instruction diff --git a/tests/expectations/array_element_assignment.txt b/tests/expectations/array_element_assignment.txt index e69de29..7ed6ff8 100644 --- a/tests/expectations/array_element_assignment.txt +++ b/tests/expectations/array_element_assignment.txt @@ -0,0 +1 @@ +5 diff --git a/tests/expectations/print_array_element.txt b/tests/expectations/print_array_element.txt new file mode 100644 index 0000000..b3172d1 --- /dev/null +++ b/tests/expectations/print_array_element.txt @@ -0,0 +1,2 @@ +5 +7 diff --git a/tests/vm/array_element_assignment.elna b/tests/vm/array_element_assignment.elna index 4d76031..d1f00d6 100644 --- a/tests/vm/array_element_assignment.elna +++ b/tests/vm/array_element_assignment.elna @@ -1,3 +1,6 @@ proc main() { var a: array[1] of int; + a[0] := 5; + + printi(a[0]); } diff --git a/tests/vm/print_array_element.elna b/tests/vm/print_array_element.elna new file mode 100644 index 0000000..4c9d0cd --- /dev/null +++ b/tests/vm/print_array_element.elna @@ -0,0 +1,8 @@ +proc main() { + var a: array[2] of int; + a[0] := 5; + a[1] := 7; + + printi(a[0]); + printi(a[1]); +}