From e9a22addcc16c147d1356519682255c594364710 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Sun, 10 Nov 2024 21:57:30 +0100 Subject: [PATCH] Map local variables in IR to their original names --- TODO | 4 - lib/Language/Elna/Backend/Allocator.hs | 16 +- lib/Language/Elna/Backend/Intermediate.hs | 10 +- lib/Language/Elna/Glue.hs | 72 ++-- lib/Language/Elna/RiscV/CodeGenerator.hs | 418 +++++++++------------- 5 files changed, 233 insertions(+), 287 deletions(-) diff --git a/TODO b/TODO index 5da4303..a0ab264 100644 --- a/TODO +++ b/TODO @@ -3,10 +3,6 @@ - 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. -- Glue always generates the same intermediate variable (LocalVariable 0) for - local variables. (LocalVariable 0) is handled the same as temporary variables - that are currently saved only in registers. There space on the stack allocated - for local variables. # ELF generation diff --git a/lib/Language/Elna/Backend/Allocator.hs b/lib/Language/Elna/Backend/Allocator.hs index 0c3e5c3..23cf2b4 100644 --- a/lib/Language/Elna/Backend/Allocator.hs +++ b/lib/Language/Elna/Backend/Allocator.hs @@ -4,10 +4,13 @@ module Language.Elna.Backend.Allocator , allocate ) where -import Data.HashMap.Strict (HashMap) import Data.Vector (Vector) -import Language.Elna.Backend.Intermediate (Operand(..), Quadruple(..), Variable(..)) -import Language.Elna.Location (Identifier(..)) +import Language.Elna.Backend.Intermediate + ( ProcedureQuadruples(..) + , Operand(..) + , Quadruple(..) + , Variable(..) + ) newtype Store r = Store r @@ -18,9 +21,10 @@ newtype MachineConfiguration r = MachineConfiguration allocate :: forall r . MachineConfiguration r - -> HashMap Identifier (Vector (Quadruple Variable)) - -> HashMap Identifier (Vector (Quadruple (Store r))) -allocate MachineConfiguration{..} = fmap function + -> ProcedureQuadruples Variable + -> ProcedureQuadruples (Store r) +allocate MachineConfiguration{..} (ProcedureQuadruples quadruples) = + ProcedureQuadruples $ function <$> quadruples where function :: Vector (Quadruple Variable) -> Vector (Quadruple (Store r)) function = fmap quadruple diff --git a/lib/Language/Elna/Backend/Intermediate.hs b/lib/Language/Elna/Backend/Intermediate.hs index c4dcf18..8e5619d 100644 --- a/lib/Language/Elna/Backend/Intermediate.hs +++ b/lib/Language/Elna/Backend/Intermediate.hs @@ -1,14 +1,18 @@ module Language.Elna.Backend.Intermediate - ( Operand(..) + ( ProcedureQuadruples(..) + , Operand(..) , Quadruple(..) , Label(..) , Variable(..) ) where import Data.Int (Int32) +import Data.HashMap.Strict (HashMap) +import Data.Vector (Vector) import Data.Word (Word32) import Data.Text (Text) import qualified Data.Text as Text +import Language.Elna.Location (Identifier(..)) newtype Label = Label { unLabel :: Text } deriving Eq @@ -30,6 +34,10 @@ data Operand v | VariableOperand v deriving (Eq, Show) +newtype ProcedureQuadruples v = + ProcedureQuadruples (HashMap Identifier (Vector (Quadruple v))) + deriving (Eq, Show) + data Quadruple v = StartQuadruple | StopQuadruple diff --git a/lib/Language/Elna/Glue.hs b/lib/Language/Elna/Glue.hs index 8f28696..fd68297 100644 --- a/lib/Language/Elna/Glue.hs +++ b/lib/Language/Elna/Glue.hs @@ -4,7 +4,7 @@ module Language.Elna.Glue import Control.Monad.Trans.State (State, gets, modify', runState) import Data.Bifunctor (Bifunctor(..)) -import Data.Foldable (Foldable(..)) +import Data.Foldable (Foldable(..), traverse_) import Data.HashMap.Strict (HashMap) import qualified Data.HashMap.Strict as HashMap import Data.Maybe (catMaybes) @@ -18,6 +18,7 @@ import qualified Language.Elna.Frontend.AST as AST import Language.Elna.Frontend.Types (Type(..)) import Language.Elna.Backend.Intermediate ( Label(..) + , ProcedureQuadruples(..) , Operand(..) , Quadruple(..) , Variable(..) @@ -25,10 +26,12 @@ import Language.Elna.Backend.Intermediate 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(..)) data Paste = Paste { temporaryCounter :: Word32 , labelCounter :: Word32 + , localMap :: HashMap Identifier Variable } newtype Glue a = Glue @@ -47,31 +50,45 @@ instance Monad Glue where (Glue x) >>= f = Glue $ x >>= (runGlue . f) -glue :: SymbolTable -> AST.Program -> HashMap AST.Identifier (Vector (Quadruple Variable)) +glue :: SymbolTable -> AST.Program -> ProcedureQuadruples Variable glue globalTable = fst - . flip runState Paste{ temporaryCounter = 0, labelCounter = 0 } + . flip runState emptyPaste . runGlue . program globalTable + where + emptyPaste = Paste + { temporaryCounter = 0 + , labelCounter = 0 + , localMap = mempty + } -program - :: SymbolTable - -> AST.Program - -> Glue (HashMap AST.Identifier (Vector (Quadruple Variable))) -program globalTable (AST.Program declarations) = HashMap.fromList . catMaybes +program :: SymbolTable -> AST.Program -> Glue (ProcedureQuadruples Variable) +program globalTable (AST.Program declarations) + = ProcedureQuadruples . HashMap.fromList . catMaybes <$> traverse (declaration globalTable) declarations declaration :: SymbolTable -> AST.Declaration -> Glue (Maybe (AST.Identifier, Vector (Quadruple Variable))) -declaration globalTable (AST.ProcedureDeclaration procedureName _ _ statements) - = Just - . (procedureName,) - . Vector.cons StartQuadruple - . flip Vector.snoc StopQuadruple - . fold - <$> traverse (statement globalTable) statements +declaration globalTable (AST.ProcedureDeclaration procedureName _ variableDeclarations statements) + = traverse_ registerVariable variableDeclarations + >> statements' <$> traverse (statement globalTable) statements + where + registerVariable (AST.VariableDeclaration identifier _) = do + currentCounter <- fmap (fromIntegral . HashMap.size) + $ Glue $ gets $ getField @"localMap" + Glue $ modify' $ modifier identifier $ LocalVariable currentCounter + modifier identifier currentCounter generator = generator + { localMap = HashMap.insert identifier currentCounter + $ getField @"localMap" generator + } + statements' = Just + . (procedureName,) + . Vector.cons StartQuadruple + . flip Vector.snoc StopQuadruple + . fold declaration _ (AST.TypeDefinition _ _) = pure Nothing statement :: SymbolTable -> AST.Statement -> Glue (Vector (Quadruple Variable)) @@ -104,15 +121,16 @@ statement localTable (AST.AssignmentStatement variableAccess' assignee) = do (rhsOperand, rhsStatements) <- expression localTable assignee let variableType' = variableType variableAccess' localTable accessResult <- variableAccess localTable variableAccess' Nothing variableType' mempty - pure $ rhsStatements <> case accessResult of + lhsStatements <- case accessResult of {-(AST.Identifier identifier, Just accumulatedIndex, accumulatedStatements) -> Vector.snoc accumulatedStatements $ ArrayAssignQuadruple rhsOperand accumulatedIndex $ LocalVariable identifier -} - (AST.Identifier identifier, Nothing, accumulatedStatements) -> - Vector.snoc accumulatedStatements - $ AssignQuadruple rhsOperand - $ LocalVariable 0 + (identifier, _Nothing, accumulatedStatements) + -> Vector.snoc accumulatedStatements + . AssignQuadruple rhsOperand + <$> lookupLocal identifier + pure $ rhsStatements <> lhsStatements {- statement localTable (AST.WhileStatement whileCondition whileStatement) = do (conditionStatements, jumpConstructor) <- condition localTable whileCondition startLabel <- createLabel @@ -135,6 +153,10 @@ createTemporary = do { temporaryCounter = getField @"temporaryCounter" generator + 1 } +lookupLocal :: Identifier -> Glue Variable +lookupLocal identifier = + fmap (HashMap.! identifier) $ Glue $ gets $ getField @"localMap" + createLabel :: Glue Label createLabel = do currentCounter <- Glue $ gets $ getField @"labelCounter" @@ -242,13 +264,13 @@ expression localTable = \case (AST.DivisionExpression lhs rhs) -> binaryExpression DivisionQuadruple lhs rhs (AST.VariableExpression variableExpression) -> do - pure (VariableOperand (LocalVariable 0), mempty) - {- let variableType' = variableType variableExpression localTable + let variableType' = variableType variableExpression localTable variableAccess' <- variableAccess localTable variableExpression Nothing variableType' mempty case variableAccess' of - (AST.Identifier identifier, Nothing, statements) -> - pure (VariableOperand (Variable identifier), statements) - (AST.Identifier identifier, Just operand, statements) -> do + (identifier, _Nothing, statements) + -> (, statements) . VariableOperand + <$> lookupLocal identifier + {-(AST.Identifier identifier, Just operand, statements) -> do arrayAddress <- createTemporary let arrayStatement = ArrayQuadruple (Variable identifier) operand arrayAddress pure diff --git a/lib/Language/Elna/RiscV/CodeGenerator.hs b/lib/Language/Elna/RiscV/CodeGenerator.hs index c082812..d84ea6c 100644 --- a/lib/Language/Elna/RiscV/CodeGenerator.hs +++ b/lib/Language/Elna/RiscV/CodeGenerator.hs @@ -6,7 +6,6 @@ module Language.Elna.RiscV.CodeGenerator ) where import Control.Monad.Trans.State (State, get, evalState, modify') -import Data.HashMap.Strict (HashMap) import qualified Data.HashMap.Strict as HashMap import Data.Int (Int32) import Data.Word (Word32) @@ -14,7 +13,12 @@ import Data.Vector (Vector) import qualified Data.Vector as Vector import qualified Language.Elna.Architecture.RiscV as RiscV import Language.Elna.Backend.Allocator (MachineConfiguration(..), Store(..)) -import Language.Elna.Backend.Intermediate (Label(..), Operand(..), Quadruple(..)) +import Language.Elna.Backend.Intermediate + ( Label(..) + , Operand(..) + , ProcedureQuadruples(..) + , Quadruple(..) + ) import Language.Elna.Location (Identifier(..)) import Data.Bits (Bits(..)) import Data.Foldable (Foldable(..), foldlM) @@ -80,11 +84,11 @@ createLabel = do $ Text.Builder.toLazyText $ Text.Builder.decimal currentCounter -generateRiscV :: HashMap Identifier (Vector RiscVQuadruple) -> Vector Statement -generateRiscV = flip evalState 0 - . runRiscVGenerator - . foldlM go Vector.empty - . HashMap.toList +generateRiscV :: ProcedureQuadruples RiscVStore -> Vector Statement +generateRiscV (ProcedureQuadruples quadruples) = flip evalState 0 + $ runRiscVGenerator + $ foldlM go Vector.empty + $ HashMap.toList quadruples where go accumulator (Identifier key, value) = let code = Vector.cons (JumpLabel key [GlobalDirective, FunctionDirective]) @@ -114,32 +118,10 @@ quadruple StopQuadruple = pure $ Vector.fromList , 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) ] -quadruple (AddQuadruple operand1 operand2 (Store register)) - | IntOperand immediateOperand1 <- operand1 - , IntOperand immediateOperand2 <- operand2 = - pure $ lui (immediateOperand1 + immediateOperand2) register - | VariableOperand variableOperand1 <- operand1 - , VariableOperand variableOperand2 <- operand2 = - let Store operandRegister1 = variableOperand1 - Store operandRegister2 = variableOperand2 - in pure $ Vector.singleton $ Instruction - $ RiscV.BaseInstruction RiscV.Op - $ RiscV.R register RiscV.ADD operandRegister1 operandRegister2 (RiscV.Funct7 0b0000000) - | VariableOperand variableOperand1 <- operand1 - , IntOperand immediateOperand2 <- operand2 = - addImmediateRegister variableOperand1 immediateOperand2 - | IntOperand immediateOperand1 <- operand1 - , VariableOperand variableOperand2 <- operand2 = - addImmediateRegister variableOperand2 immediateOperand1 - where - addImmediateRegister variableOperand immediateOperand = - let statements = lui immediateOperand register - Store operandRegister = variableOperand - in pure $ Vector.snoc statements - $ Instruction - $ RiscV.BaseInstruction RiscV.Op - $ RiscV.R register RiscV.ADD register operandRegister - $ RiscV.Funct7 0b0000000 +quadruple (AddQuadruple operand1 operand2 store) = + commutativeBinary (+) RiscV.ADD (RiscV.Funct7 0b0000000) (operand1, operand2) store +quadruple (ProductQuadruple operand1 operand2 store) = + commutativeBinary (*) RiscV.MUL (RiscV.Funct7 0b0000001) (operand1, operand2) store quadruple (SubtractionQuadruple operand1 operand2 (Store register)) | IntOperand immediateOperand1 <- operand1 , IntOperand immediateOperand2 <- operand2 = @@ -180,32 +162,6 @@ quadruple (NegationQuadruple operand1 (Store register)) $ RiscV.BaseInstruction RiscV.Op $ RiscV.R register RiscV.SUB RiscV.Zero operandRegister1 $ RiscV.Funct7 0b0100000 -quadruple (ProductQuadruple operand1 operand2 (Store register)) - | IntOperand immediateOperand1 <- operand1 - , IntOperand immediateOperand2 <- operand2 = - pure $ lui (immediateOperand1 * immediateOperand2) register - | VariableOperand variableOperand1 <- operand1 - , VariableOperand variableOperand2 <- operand2 = - let Store operandRegister1 = variableOperand1 - Store operandRegister2 = variableOperand2 - in pure $ Vector.singleton $ Instruction - $ RiscV.BaseInstruction RiscV.Op - $ RiscV.R register RiscV.MUL operandRegister1 operandRegister2 (RiscV.Funct7 0b0000001) - | VariableOperand variableOperand1 <- operand1 - , IntOperand immediateOperand2 <- operand2 = - multiplyImmediateRegister variableOperand1 immediateOperand2 - | IntOperand immediateOperand1 <- operand1 - , VariableOperand variableOperand2 <- operand2 = - multiplyImmediateRegister variableOperand2 immediateOperand1 - where - multiplyImmediateRegister variableOperand immediateOperand = - let statements = lui immediateOperand register - Store operandRegister = variableOperand - in pure $ Vector.snoc statements - $ Instruction - $ RiscV.BaseInstruction RiscV.Op - $ RiscV.R register RiscV.MUL register operandRegister - $ RiscV.Funct7 0b0000001 quadruple (DivisionQuadruple operand1 operand2 (Store register)) | IntOperand immediateOperand1 <- operand1 , IntOperand immediateOperand2 <- operand2 = @@ -261,198 +217,18 @@ quadruple (DivisionQuadruple operand1 operand2 (Store register)) ] quadruple (LabelQuadruple (Label label)) = pure $ Vector.singleton $ JumpLabel label mempty quadruple (GoToQuadruple label) = pure $ Vector.singleton $ unconditionalJal label -quadruple (EqualQuadruple operand1 operand2 goToLabel) - | IntOperand immediateOperand1 <- operand1 - , IntOperand immediateOperand2 <- operand2 = - if immediateOperand1 == immediateOperand2 - then pure $ Vector.singleton $ unconditionalJal goToLabel - else pure Vector.empty - | VariableOperand variableOperand1 <- operand1 - , VariableOperand variableOperand2 <- operand2 = do - let Store operandRegister1 = variableOperand1 - Store operandRegister2 = variableOperand2 - Label goToLabel' = goToLabel - pure $ Vector.singleton - $ Instruction - $ RiscV.RelocatableInstruction RiscV.Branch - $ RiscV.RBranch goToLabel' RiscV.BEQ operandRegister1 operandRegister2 - | VariableOperand variableOperand1 <- operand1 - , IntOperand immediateOperand2 <- operand2 = - compareImmediateRegister variableOperand1 immediateOperand2 - | IntOperand immediateOperand1 <- operand1 - , VariableOperand variableOperand2 <- operand2 = - compareImmediateRegister variableOperand2 immediateOperand1 - where - compareImmediateRegister variableOperand immediateOperand = - let statements = lui immediateOperand immediateRegister - Store operandRegister = variableOperand - Label goToLabel' = goToLabel - in pure $ Vector.snoc statements - $ Instruction - $ RiscV.RelocatableInstruction RiscV.Branch - $ RiscV.RBranch goToLabel' RiscV.BEQ operandRegister immediateRegister -quadruple (NonEqualQuadruple operand1 operand2 goToLabel) - | IntOperand immediateOperand1 <- operand1 - , IntOperand immediateOperand2 <- operand2 = - if immediateOperand1 /= immediateOperand2 - then pure $ Vector.singleton $ unconditionalJal goToLabel - else pure Vector.empty - | VariableOperand variableOperand1 <- operand1 - , VariableOperand variableOperand2 <- operand2 = do - let Store operandRegister1 = variableOperand1 - Store operandRegister2 = variableOperand2 - Label goToLabel' = goToLabel - pure $ Vector.singleton - $ Instruction - $ RiscV.RelocatableInstruction RiscV.Branch - $ RiscV.RBranch goToLabel' RiscV.BNE operandRegister1 operandRegister2 - | VariableOperand variableOperand1 <- operand1 - , IntOperand immediateOperand2 <- operand2 = - compareImmediateRegister variableOperand1 immediateOperand2 - | IntOperand immediateOperand1 <- operand1 - , VariableOperand variableOperand2 <- operand2 = - compareImmediateRegister variableOperand2 immediateOperand1 - where - compareImmediateRegister variableOperand immediateOperand = - let statements = lui immediateOperand immediateRegister - Store operandRegister = variableOperand - Label goToLabel' = goToLabel - in pure $ Vector.snoc statements - $ Instruction - $ RiscV.RelocatableInstruction RiscV.Branch - $ RiscV.RBranch goToLabel' RiscV.BNE operandRegister immediateRegister -quadruple (LessQuadruple operand1 operand2 goToLabel) - | IntOperand immediateOperand1 <- operand1 - , IntOperand immediateOperand2 <- operand2 = - if immediateOperand1 < immediateOperand2 - then pure $ Vector.singleton $ unconditionalJal goToLabel - else pure Vector.empty - | VariableOperand variableOperand1 <- operand1 - , VariableOperand variableOperand2 <- operand2 = do - let Store operandRegister1 = variableOperand1 - Store operandRegister2 = variableOperand2 - Label goToLabel' = goToLabel - pure $ Vector.singleton - $ Instruction - $ RiscV.RelocatableInstruction RiscV.Branch - $ RiscV.RBranch goToLabel' RiscV.BLT operandRegister1 operandRegister2 - | VariableOperand variableOperand1 <- operand1 - , IntOperand immediateOperand2 <- operand2 = - let statements2 = lui immediateOperand2 immediateRegister - Store operandRegister1 = variableOperand1 - Label goToLabel' = goToLabel - in pure $ Vector.snoc statements2 - $ Instruction - $ RiscV.RelocatableInstruction RiscV.Branch - $ RiscV.RBranch goToLabel' RiscV.BLT operandRegister1 immediateRegister - | IntOperand immediateOperand1 <- operand1 - , VariableOperand variableOperand2 <- operand2 = - let statements1 = lui immediateOperand1 immediateRegister - Store operandRegister2 = variableOperand2 - Label goToLabel' = goToLabel - in pure $ Vector.snoc statements1 - $ Instruction - $ RiscV.RelocatableInstruction RiscV.Branch - $ RiscV.RBranch goToLabel' RiscV.BLT immediateRegister operandRegister2 -quadruple (GreaterQuadruple operand1 operand2 goToLabel) - | IntOperand immediateOperand1 <- operand1 - , IntOperand immediateOperand2 <- operand2 = - if immediateOperand1 > immediateOperand2 - then pure $ Vector.singleton $ unconditionalJal goToLabel - else pure Vector.empty - | VariableOperand variableOperand1 <- operand1 - , VariableOperand variableOperand2 <- operand2 = do - let Store operandRegister1 = variableOperand1 - Store operandRegister2 = variableOperand2 - Label goToLabel' = goToLabel - pure $ Vector.singleton - $ Instruction - $ RiscV.RelocatableInstruction RiscV.Branch - $ RiscV.RBranch goToLabel' RiscV.BLT operandRegister2 operandRegister1 - | VariableOperand variableOperand1 <- operand1 - , IntOperand immediateOperand2 <- operand2 = - let statements2 = lui immediateOperand2 immediateRegister - Store operandRegister1 = variableOperand1 - Label goToLabel' = goToLabel - in pure $ Vector.snoc statements2 - $ Instruction - $ RiscV.RelocatableInstruction RiscV.Branch - $ RiscV.RBranch goToLabel' RiscV.BLT immediateRegister operandRegister1 - | IntOperand immediateOperand1 <- operand1 - , VariableOperand variableOperand2 <- operand2 = - let statements1 = lui immediateOperand1 immediateRegister - Store operandRegister2 = variableOperand2 - Label goToLabel' = goToLabel - in pure $ Vector.snoc statements1 - $ Instruction - $ RiscV.RelocatableInstruction RiscV.Branch - $ RiscV.RBranch goToLabel' RiscV.BLT operandRegister2 immediateRegister -quadruple (LessOrEqualQuadruple operand1 operand2 goToLabel) - | IntOperand immediateOperand1 <- operand1 - , IntOperand immediateOperand2 <- operand2 = - if immediateOperand1 <= immediateOperand2 - then pure $ Vector.singleton $ unconditionalJal goToLabel - else pure Vector.empty - | VariableOperand variableOperand1 <- operand1 - , VariableOperand variableOperand2 <- operand2 = do - let Store operandRegister1 = variableOperand1 - Store operandRegister2 = variableOperand2 - Label goToLabel' = goToLabel - pure $ Vector.singleton - $ Instruction - $ RiscV.RelocatableInstruction RiscV.Branch - $ RiscV.RBranch goToLabel' RiscV.BGE operandRegister2 operandRegister1 - | VariableOperand variableOperand1 <- operand1 - , IntOperand immediateOperand2 <- operand2 = - let statements2 = lui immediateOperand2 immediateRegister - Store operandRegister1 = variableOperand1 - Label goToLabel' = goToLabel - in pure $ Vector.snoc statements2 - $ Instruction - $ RiscV.RelocatableInstruction RiscV.Branch - $ RiscV.RBranch goToLabel' RiscV.BGE immediateRegister operandRegister1 - | IntOperand immediateOperand1 <- operand1 - , VariableOperand variableOperand2 <- operand2 = - let statements1 = lui immediateOperand1 immediateRegister - Store operandRegister2 = variableOperand2 - Label goToLabel' = goToLabel - in pure $ Vector.snoc statements1 - $ Instruction - $ RiscV.RelocatableInstruction RiscV.Branch - $ RiscV.RBranch goToLabel' RiscV.BGE operandRegister2 immediateRegister -quadruple (GreaterOrEqualQuadruple operand1 operand2 goToLabel) - | IntOperand immediateOperand1 <- operand1 - , IntOperand immediateOperand2 <- operand2 = - if immediateOperand1 >= immediateOperand2 - then pure $ Vector.singleton $ unconditionalJal goToLabel - else pure Vector.empty - | VariableOperand variableOperand1 <- operand1 - , VariableOperand variableOperand2 <- operand2 = - let Store operandRegister1 = variableOperand1 - Store operandRegister2 = variableOperand2 - Label goToLabel' = goToLabel - in pure $ Vector.singleton - $ Instruction - $ RiscV.RelocatableInstruction RiscV.Branch - $ RiscV.RBranch goToLabel' RiscV.BGE operandRegister1 operandRegister2 - | VariableOperand variableOperand1 <- operand1 - , IntOperand immediateOperand2 <- operand2 = - let statements2 = lui immediateOperand2 immediateRegister - Store operandRegister1 = variableOperand1 - Label goToLabel' = goToLabel - in pure $ Vector.snoc statements2 - $ Instruction - $ RiscV.RelocatableInstruction RiscV.Branch - $ RiscV.RBranch goToLabel' RiscV.BGE operandRegister1 immediateRegister - | IntOperand immediateOperand1 <- operand1 - , VariableOperand variableOperand2 <- operand2 = - let statements1 = lui immediateOperand1 immediateRegister - Store operandRegister2 = variableOperand2 - Label goToLabel' = goToLabel - in pure $ Vector.snoc statements1 - $ Instruction - $ RiscV.RelocatableInstruction RiscV.Branch - $ RiscV.RBranch goToLabel' RiscV.BGE immediateRegister operandRegister2 +quadruple (EqualQuadruple operand1 operand2 goToLabel) = + commutativeComparison (==) RiscV.BEQ (operand1, operand2) goToLabel +quadruple (NonEqualQuadruple operand1 operand2 goToLabel) = + commutativeComparison (/=) RiscV.BNE (operand1, operand2) goToLabel +quadruple (LessQuadruple operand1 operand2 goToLabel) = + lessThan (operand1, operand2) goToLabel +quadruple (GreaterQuadruple operand1 operand2 goToLabel) = + lessThan (operand2, operand1) goToLabel +quadruple (LessOrEqualQuadruple operand1 operand2 goToLabel) = + lessOrEqualThan (operand1, operand2) goToLabel +quadruple (GreaterOrEqualQuadruple operand1 operand2 goToLabel) = + lessOrEqualThan (operand2, operand1) goToLabel quadruple (AssignQuadruple operand1 (Store register)) | IntOperand immediateOperand1 <- operand1 = pure $ lui immediateOperand1 register @@ -489,3 +265,143 @@ lui intValue targetRegister where hi = intValue `shiftR` 12 lo = fromIntegral intValue + +commutativeBinary + :: (Int32 -> Int32 -> Int32) + -> RiscV.Funct3 + -> RiscV.Funct7 + -> (Operand RiscVStore, Operand RiscVStore) + -> Store RiscV.XRegister + -> RiscVGenerator (Vector Statement) +commutativeBinary immediateOperation funct3 funct7 (operand1, operand2) (Store register) + | IntOperand immediateOperand1 <- operand1 + , IntOperand immediateOperand2 <- operand2 = pure + $ lui (immediateOperation immediateOperand1 immediateOperand2) register + | VariableOperand variableOperand1 <- operand1 + , VariableOperand variableOperand2 <- operand2 = + let Store operandRegister1 = variableOperand1 + Store operandRegister2 = variableOperand2 + in pure $ Vector.singleton $ Instruction + $ RiscV.BaseInstruction RiscV.Op + $ RiscV.R register funct3 operandRegister1 operandRegister2 funct7 + | VariableOperand variableOperand1 <- operand1 + , IntOperand immediateOperand2 <- operand2 = + commutativeImmediateRegister variableOperand1 immediateOperand2 + | IntOperand immediateOperand1 <- operand1 + , VariableOperand variableOperand2 <- operand2 = + commutativeImmediateRegister variableOperand2 immediateOperand1 + where + commutativeImmediateRegister variableOperand immediateOperand = + let statements = lui immediateOperand register + Store operandRegister = variableOperand + in pure $ Vector.snoc statements + $ Instruction + $ RiscV.BaseInstruction RiscV.Op + $ RiscV.R register funct3 register operandRegister funct7 + +commutativeComparison + :: (Int32 -> Int32 -> Bool) + -> RiscV.Funct3 + -> (Operand RiscVStore, Operand RiscVStore) + -> Label + -> RiscVGenerator (Vector Statement) +commutativeComparison immediateOperation funct3 (operand1, operand2) goToLabel + | IntOperand immediateOperand1 <- operand1 + , IntOperand immediateOperand2 <- operand2 = + if immediateOperation immediateOperand1 immediateOperand2 + then pure $ Vector.singleton $ unconditionalJal goToLabel + else pure Vector.empty + | VariableOperand variableOperand1 <- operand1 + , VariableOperand variableOperand2 <- operand2 = do + let Store operandRegister1 = variableOperand1 + Store operandRegister2 = variableOperand2 + Label goToLabel' = goToLabel + pure $ Vector.singleton + $ Instruction + $ RiscV.RelocatableInstruction RiscV.Branch + $ RiscV.RBranch goToLabel' funct3 operandRegister1 operandRegister2 + | VariableOperand variableOperand1 <- operand1 + , IntOperand immediateOperand2 <- operand2 = + compareImmediateRegister variableOperand1 immediateOperand2 + | IntOperand immediateOperand1 <- operand1 + , VariableOperand variableOperand2 <- operand2 = + compareImmediateRegister variableOperand2 immediateOperand1 + where + compareImmediateRegister variableOperand immediateOperand = + let statements = lui immediateOperand immediateRegister + Store operandRegister = variableOperand + Label goToLabel' = goToLabel + in pure $ Vector.snoc statements + $ Instruction + $ RiscV.RelocatableInstruction RiscV.Branch + $ RiscV.RBranch goToLabel' funct3 operandRegister immediateRegister + +lessThan :: (Operand RiscVStore, Operand RiscVStore) -> Label -> RiscVGenerator (Vector Statement) +lessThan (operand1, operand2) goToLabel + | IntOperand immediateOperand1 <- operand1 + , IntOperand immediateOperand2 <- operand2 = + if immediateOperand1 < immediateOperand2 + then pure $ Vector.singleton $ unconditionalJal goToLabel + else pure Vector.empty + | VariableOperand variableOperand1 <- operand1 + , VariableOperand variableOperand2 <- operand2 = do + let Store operandRegister1 = variableOperand1 + Store operandRegister2 = variableOperand2 + Label goToLabel' = goToLabel + pure $ Vector.singleton + $ Instruction + $ RiscV.RelocatableInstruction RiscV.Branch + $ RiscV.RBranch goToLabel' RiscV.BLT operandRegister1 operandRegister2 + | VariableOperand variableOperand1 <- operand1 + , IntOperand immediateOperand2 <- operand2 = + let statements2 = lui immediateOperand2 immediateRegister + Store operandRegister1 = variableOperand1 + Label goToLabel' = goToLabel + in pure $ Vector.snoc statements2 + $ Instruction + $ RiscV.RelocatableInstruction RiscV.Branch + $ RiscV.RBranch goToLabel' RiscV.BLT operandRegister1 immediateRegister + | IntOperand immediateOperand1 <- operand1 + , VariableOperand variableOperand2 <- operand2 = + let statements1 = lui immediateOperand1 immediateRegister + Store operandRegister2 = variableOperand2 + Label goToLabel' = goToLabel + in pure $ Vector.snoc statements1 + $ Instruction + $ RiscV.RelocatableInstruction RiscV.Branch + $ RiscV.RBranch goToLabel' RiscV.BLT immediateRegister operandRegister2 + +lessOrEqualThan :: (Operand RiscVStore, Operand RiscVStore) -> Label -> RiscVGenerator (Vector Statement) +lessOrEqualThan (operand1, operand2) goToLabel + | IntOperand immediateOperand1 <- operand1 + , IntOperand immediateOperand2 <- operand2 = + if immediateOperand1 <= immediateOperand2 + then pure $ Vector.singleton $ unconditionalJal goToLabel + else pure Vector.empty + | VariableOperand variableOperand1 <- operand1 + , VariableOperand variableOperand2 <- operand2 = do + let Store operandRegister1 = variableOperand1 + Store operandRegister2 = variableOperand2 + Label goToLabel' = goToLabel + pure $ Vector.singleton + $ Instruction + $ RiscV.RelocatableInstruction RiscV.Branch + $ RiscV.RBranch goToLabel' RiscV.BGE operandRegister2 operandRegister1 + | VariableOperand variableOperand1 <- operand1 + , IntOperand immediateOperand2 <- operand2 = + let statements2 = lui immediateOperand2 immediateRegister + Store operandRegister1 = variableOperand1 + Label goToLabel' = goToLabel + in pure $ Vector.snoc statements2 + $ Instruction + $ RiscV.RelocatableInstruction RiscV.Branch + $ RiscV.RBranch goToLabel' RiscV.BGE immediateRegister operandRegister1 + | IntOperand immediateOperand1 <- operand1 + , VariableOperand variableOperand2 <- operand2 = + let statements1 = lui immediateOperand1 immediateRegister + Store operandRegister2 = variableOperand2 + Label goToLabel' = goToLabel + in pure $ Vector.snoc statements1 + $ Instruction + $ RiscV.RelocatableInstruction RiscV.Branch + $ RiscV.RBranch goToLabel' RiscV.BGE operandRegister2 immediateRegister