mirror of
https://github.com/anoma/juvix.git
synced 2024-10-03 19:47:59 +03:00
Add an if
instruction to JuvixReg (#2855)
* Closes #2829 * Adds a transformation which converts `br` to `if` when the variable branched on was assigned in the previous instruction. The transformation itself doesn't check liveness and doesn't remove the assignment. Dead code elimination should be run afterwards to remove the assignment. * For Cairo, it only makes sense to convert `br` to `if` for equality comparisons against zero. The assignment before `br` will always become dead after converting `br` to `if`, because we convert to SSA before.
This commit is contained in:
parent
7cfddcf915
commit
4dcbb002fe
@ -41,7 +41,7 @@ repos:
|
||||
types_or: [json]
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: v17.0.2
|
||||
rev: v18.1.4
|
||||
hooks:
|
||||
- id: clang-format
|
||||
files: runtime/.+\.(c|h)$
|
||||
|
@ -33,10 +33,9 @@
|
||||
DECL_TAIL_APPLY_3; \
|
||||
juvix_program_start:
|
||||
|
||||
#define JUVIX_EPILOGUE \
|
||||
juvix_program_end: \
|
||||
STACK_POPT; \
|
||||
IO_INTERPRET; \
|
||||
#define JUVIX_EPILOGUE \
|
||||
juvix_program_end : STACK_POPT; \
|
||||
IO_INTERPRET; \
|
||||
io_print_toplevel(juvix_result);
|
||||
|
||||
// Temporary / local vars
|
||||
@ -45,9 +44,7 @@
|
||||
|
||||
// Begin a function definition. `max_stack` is the maximum stack allocation in
|
||||
// the function.
|
||||
#define JUVIX_FUNCTION(label, max_stack) \
|
||||
label: \
|
||||
STACK_ENTER((max_stack))
|
||||
#define JUVIX_FUNCTION(label, max_stack) label : STACK_ENTER((max_stack))
|
||||
|
||||
/*
|
||||
Macro sequence for function definition:
|
||||
@ -67,8 +64,7 @@ closure_label:
|
||||
*/
|
||||
|
||||
// Begin a function with no stack allocation.
|
||||
#define JUVIX_FUNCTION_NS(label) \
|
||||
label:
|
||||
#define JUVIX_FUNCTION_NS(label) label:
|
||||
|
||||
#define JUVIX_INT_ADD(var0, var1, var2) (var0 = smallint_add(var1, var2))
|
||||
#define JUVIX_INT_SUB(var0, var1, var2) (var0 = smallint_sub(var1, var2))
|
||||
@ -83,6 +79,10 @@ closure_label:
|
||||
#define JUVIX_VAL_EQ(var0, var1, var2) \
|
||||
(var0 = make_bool(juvix_equal(var1, var2)))
|
||||
|
||||
#define JUVIX_BOOL_INT_LT(var1, var2) (smallint_lt(var1, var2))
|
||||
#define JUVIX_BOOL_INT_LE(var1, var2) (smallint_le(var1, var2))
|
||||
#define JUVIX_BOOL_VAL_EQ(var1, var2) (make_bool(juvix_equal(var1, var2)))
|
||||
|
||||
#define JUVIX_STR_CONCAT(var0, var1, var2) CONCAT_CSTRINGS(var0, var1, var2)
|
||||
|
||||
#define JUVIX_STR_TO_INT(var0, var1) \
|
||||
|
@ -85,7 +85,8 @@ static inline void *palign(void *ptr, uintptr_t alignment) {
|
||||
return (void *)align((uintptr_t)ptr, alignment);
|
||||
}
|
||||
// `y` must be a power of 2
|
||||
#define ASSERT_ALIGNED(x, y) ASSERT(((uintptr_t)(x) & ((uintptr_t)(y)-1)) == 0)
|
||||
#define ASSERT_ALIGNED(x, y) \
|
||||
ASSERT(((uintptr_t)(x) & ((uintptr_t)(y) - 1)) == 0)
|
||||
|
||||
#if defined(API_LIBC) && defined(DEBUG)
|
||||
#define LOG(...) fprintf(stderr, __VA_ARGS__)
|
||||
|
@ -156,9 +156,9 @@ recurse' sig = go True
|
||||
fixMemIntOp mem
|
||||
OpIntMod ->
|
||||
fixMemIntOp mem
|
||||
OpIntLt ->
|
||||
OpBool OpIntLt ->
|
||||
fixMemBinOp' mem mkTypeInteger mkTypeInteger mkTypeBool
|
||||
OpIntLe ->
|
||||
OpBool OpIntLe ->
|
||||
fixMemBinOp' mem mkTypeInteger mkTypeInteger mkTypeBool
|
||||
OpFieldAdd ->
|
||||
fixMemFieldOp mem
|
||||
@ -168,7 +168,7 @@ recurse' sig = go True
|
||||
fixMemFieldOp mem
|
||||
OpFieldDiv ->
|
||||
fixMemFieldOp mem
|
||||
OpEq ->
|
||||
OpBool OpEq ->
|
||||
fixMemBinOp' mem TyDynamic TyDynamic mkTypeBool
|
||||
OpStrConcat ->
|
||||
fixMemBinOp' mem TyString TyString TyString
|
||||
|
@ -68,11 +68,11 @@ command = do
|
||||
"mod" ->
|
||||
return $ mkBinop' loc OpIntMod
|
||||
"lt" ->
|
||||
return $ mkBinop' loc OpIntLt
|
||||
return $ mkBinop' loc (OpBool OpIntLt)
|
||||
"le" ->
|
||||
return $ mkBinop' loc OpIntLe
|
||||
return $ mkBinop' loc (OpBool OpIntLe)
|
||||
"eq" ->
|
||||
return $ mkBinop' loc OpEq
|
||||
return $ mkBinop' loc (OpBool OpEq)
|
||||
"fadd" ->
|
||||
return $ mkBinop' loc OpFieldAdd
|
||||
"fsub" ->
|
||||
|
@ -251,6 +251,8 @@ fromRegInstr bNoStack info = \case
|
||||
fromCallClosures x
|
||||
Reg.Return x ->
|
||||
return $ fromReturn x
|
||||
Reg.If x ->
|
||||
fromIf x
|
||||
Reg.Branch x ->
|
||||
fromBranch x
|
||||
Reg.Case x ->
|
||||
@ -271,6 +273,12 @@ fromRegInstr bNoStack info = \case
|
||||
fromValue _instrBinopArg2
|
||||
]
|
||||
|
||||
getBoolOpMacro :: Reg.BoolOp -> Text
|
||||
getBoolOpMacro = \case
|
||||
Reg.OpIntLt -> "JUVIX_BOOL_INT_LT"
|
||||
Reg.OpIntLe -> "JUVIX_BOOL_INT_LE"
|
||||
Reg.OpEq -> "JUVIX_BOOL_VAL_EQ"
|
||||
|
||||
getBinaryOpMacro :: Reg.BinaryOp -> Text
|
||||
getBinaryOpMacro = \case
|
||||
Reg.OpIntAdd -> "JUVIX_INT_ADD"
|
||||
@ -278,9 +286,9 @@ fromRegInstr bNoStack info = \case
|
||||
Reg.OpIntMul -> "JUVIX_INT_MUL"
|
||||
Reg.OpIntDiv -> "JUVIX_INT_DIV"
|
||||
Reg.OpIntMod -> "JUVIX_INT_MOD"
|
||||
Reg.OpIntLt -> "JUVIX_INT_LT"
|
||||
Reg.OpIntLe -> "JUVIX_INT_LE"
|
||||
Reg.OpEq -> "JUVIX_VAL_EQ"
|
||||
Reg.OpBool Reg.OpIntLt -> "JUVIX_INT_LT"
|
||||
Reg.OpBool Reg.OpIntLe -> "JUVIX_INT_LE"
|
||||
Reg.OpBool Reg.OpEq -> "JUVIX_VAL_EQ"
|
||||
Reg.OpStrConcat -> "JUVIX_STR_CONCAT"
|
||||
Reg.OpFieldAdd -> unsupported "field type"
|
||||
Reg.OpFieldSub -> unsupported "field type"
|
||||
@ -504,6 +512,26 @@ fromRegInstr bNoStack info = \case
|
||||
integer argsNum,
|
||||
ExpressionVar lab
|
||||
]
|
||||
fromIf :: Reg.InstrIf -> Sem r [Statement]
|
||||
fromIf Reg.InstrIf {..} = do
|
||||
br1 <- fromRegCode bNoStack info _instrIfTrue
|
||||
br2 <- fromRegCode bNoStack info _instrIfFalse
|
||||
return
|
||||
[ StatementIf $
|
||||
If
|
||||
{ _ifCondition =
|
||||
macroCall
|
||||
"is_true"
|
||||
[ macroCall
|
||||
(getBoolOpMacro _instrIfOp)
|
||||
[ fromValue _instrIfArg1,
|
||||
fromValue _instrIfArg2
|
||||
]
|
||||
],
|
||||
_ifThen = StatementCompound br1,
|
||||
_ifElse = Just (StatementCompound br2)
|
||||
}
|
||||
]
|
||||
|
||||
fromBranch :: Reg.InstrBranch -> Sem r [Statement]
|
||||
fromBranch Reg.InstrBranch {..} = do
|
||||
|
@ -154,6 +154,8 @@ fromRegInstr info = \case
|
||||
fromCallClosures x
|
||||
Reg.Return x ->
|
||||
fromReturn x
|
||||
Reg.If x ->
|
||||
fromIf x
|
||||
Reg.Branch x ->
|
||||
fromBranch x
|
||||
Reg.Case x ->
|
||||
@ -173,16 +175,20 @@ fromRegInstr info = \case
|
||||
[fromValue _instrBinopArg1, fromValue _instrBinopArg2]
|
||||
)
|
||||
|
||||
getBoolOpName :: Reg.BoolOp -> Text
|
||||
getBoolOpName = \case
|
||||
Reg.OpIntLt -> "smallint_lt"
|
||||
Reg.OpIntLe -> "smallint_le"
|
||||
Reg.OpEq -> "juvix_equal"
|
||||
|
||||
getBinaryOpName :: Reg.BinaryOp -> Text
|
||||
getBinaryOpName = \case
|
||||
Reg.OpBool x -> getBoolOpName x
|
||||
Reg.OpIntAdd -> "smallint_add"
|
||||
Reg.OpIntSub -> "smallint_sub"
|
||||
Reg.OpIntMul -> "smallint_mul"
|
||||
Reg.OpIntDiv -> "smallint_div"
|
||||
Reg.OpIntMod -> "smallint_mod"
|
||||
Reg.OpIntLt -> "smallint_lt"
|
||||
Reg.OpIntLe -> "smallint_le"
|
||||
Reg.OpEq -> "juvix_equal"
|
||||
Reg.OpStrConcat -> unsupported "strings"
|
||||
Reg.OpFieldAdd -> unsupported "field type"
|
||||
Reg.OpFieldSub -> unsupported "field type"
|
||||
@ -349,6 +355,23 @@ fromRegInstr info = \case
|
||||
]
|
||||
]
|
||||
|
||||
fromIf :: Reg.InstrIf -> [Statement]
|
||||
fromIf Reg.InstrIf {..} =
|
||||
stmtsIf
|
||||
( mkCall
|
||||
"word_to_bool"
|
||||
[ ( mkCall
|
||||
(getBoolOpName _instrIfOp)
|
||||
[fromValue _instrIfArg1, fromValue _instrIfArg2]
|
||||
)
|
||||
]
|
||||
)
|
||||
br1
|
||||
br2
|
||||
where
|
||||
br1 = fromRegCode info _instrIfTrue
|
||||
br2 = fromRegCode info _instrIfFalse
|
||||
|
||||
fromBranch :: Reg.InstrBranch -> [Statement]
|
||||
fromBranch Reg.InstrBranch {..} =
|
||||
stmtsIf (mkCall "word_to_bool" [fromValue _instrBranchValue]) br1 br2
|
||||
|
@ -387,9 +387,9 @@ fromReg tab = mkResult $ run $ runLabelInfoBuilderWithNextId (Reg.getNextSymbolI
|
||||
goExtraBinop IntDiv res arg1 arg2
|
||||
Reg.OpIntMod ->
|
||||
goExtraBinop IntMod res arg1 arg2
|
||||
Reg.OpIntLt ->
|
||||
Reg.OpBool Reg.OpIntLt ->
|
||||
goExtraBinop IntLt res arg1 arg2
|
||||
Reg.OpIntLe ->
|
||||
Reg.OpBool Reg.OpIntLe ->
|
||||
goIntLe res arg1 arg2
|
||||
Reg.OpFieldAdd ->
|
||||
goNativeBinop FieldAdd res arg1 arg2
|
||||
@ -399,7 +399,7 @@ fromReg tab = mkResult $ run $ runLabelInfoBuilderWithNextId (Reg.getNextSymbolI
|
||||
goNativeBinop FieldMul res arg1 arg2
|
||||
Reg.OpFieldDiv ->
|
||||
goExtraBinop FieldDiv res arg1 arg2
|
||||
Reg.OpEq ->
|
||||
Reg.OpBool Reg.OpEq ->
|
||||
goEq res arg1 arg2
|
||||
Reg.OpStrConcat ->
|
||||
unsupported "strings"
|
||||
@ -527,6 +527,7 @@ fromReg tab = mkResult $ run $ runLabelInfoBuilderWithNextId (Reg.getNextSymbolI
|
||||
Reg.Call x -> goCall liveVars x
|
||||
Reg.TailCall x -> goTailCall x
|
||||
Reg.Return x -> goReturn x
|
||||
Reg.If x -> goIf liveVars x
|
||||
Reg.Branch x -> goBranch liveVars x
|
||||
Reg.Case x -> goCase liveVars x
|
||||
|
||||
@ -573,34 +574,48 @@ fromReg tab = mkResult $ run $ runLabelInfoBuilderWithNextId (Reg.getNextSymbolI
|
||||
goAssignApValue _instrReturnValue
|
||||
output'' Return
|
||||
|
||||
goIf :: HashSet Reg.VarRef -> Reg.InstrIf -> Sem r ()
|
||||
goIf liveVars Reg.InstrIf {..} = case _instrIfOp of
|
||||
Reg.OpEq
|
||||
| Reg.ValConst (Reg.ConstInt 0) <- _instrIfArg1 -> do
|
||||
v <- goValue _instrIfArg2
|
||||
goBranch' liveVars _instrIfOutVar _instrIfTrue _instrIfFalse v
|
||||
| Reg.ValConst (Reg.ConstInt 0) <- _instrIfArg2 -> do
|
||||
v <- goValue _instrIfArg1
|
||||
goBranch' liveVars _instrIfOutVar _instrIfTrue _instrIfFalse v
|
||||
_ -> impossible
|
||||
|
||||
goBranch :: HashSet Reg.VarRef -> Reg.InstrBranch -> Sem r ()
|
||||
goBranch liveVars Reg.InstrBranch {..} = do
|
||||
v <- goValue _instrBranchValue
|
||||
case v of
|
||||
Imm c
|
||||
| c == 0 -> goBlock blts failLab liveVars _instrBranchOutVar _instrBranchTrue
|
||||
| otherwise -> goBlock blts failLab liveVars _instrBranchOutVar _instrBranchFalse
|
||||
Ref r -> do
|
||||
symFalse <- freshSymbol
|
||||
symEnd <- freshSymbol
|
||||
let labFalse = LabelRef symFalse Nothing
|
||||
labEnd = LabelRef symEnd Nothing
|
||||
output'' $ mkJumpIf (Lab labFalse) r
|
||||
ap0 <- getAP
|
||||
vars <- getVars
|
||||
bltOff <- getBuiltinOffset
|
||||
goLocalBlock ap0 vars bltOff liveVars _instrBranchOutVar _instrBranchTrue
|
||||
-- _instrBranchOutVar is Nothing iff the branch returns
|
||||
when (isJust _instrBranchOutVar) $
|
||||
output'' (mkJumpRel (Val $ Lab labEnd))
|
||||
addrFalse <- getPC
|
||||
registerLabelAddress symFalse addrFalse
|
||||
output'' $ Label labFalse
|
||||
goLocalBlock ap0 vars bltOff liveVars _instrBranchOutVar _instrBranchFalse
|
||||
addrEnd <- getPC
|
||||
registerLabelAddress symEnd addrEnd
|
||||
output'' $ Label labEnd
|
||||
Lab {} -> impossible
|
||||
goBranch' liveVars _instrBranchOutVar _instrBranchTrue _instrBranchFalse v
|
||||
|
||||
goBranch' :: HashSet Reg.VarRef -> Maybe Reg.VarRef -> Reg.Block -> Reg.Block -> Value -> Sem r ()
|
||||
goBranch' liveVars outVar branchTrue branchFalse = \case
|
||||
Imm c
|
||||
| c == 0 -> goBlock blts failLab liveVars outVar branchTrue
|
||||
| otherwise -> goBlock blts failLab liveVars outVar branchFalse
|
||||
Ref r -> do
|
||||
symFalse <- freshSymbol
|
||||
symEnd <- freshSymbol
|
||||
let labFalse = LabelRef symFalse Nothing
|
||||
labEnd = LabelRef symEnd Nothing
|
||||
output'' $ mkJumpIf (Lab labFalse) r
|
||||
ap0 <- getAP
|
||||
vars <- getVars
|
||||
bltOff <- getBuiltinOffset
|
||||
goLocalBlock ap0 vars bltOff liveVars outVar branchTrue
|
||||
-- outVar is Nothing iff the branch returns
|
||||
when (isJust outVar) $
|
||||
output'' (mkJumpRel (Val $ Lab labEnd))
|
||||
addrFalse <- getPC
|
||||
registerLabelAddress symFalse addrFalse
|
||||
output'' $ Label labFalse
|
||||
goLocalBlock ap0 vars bltOff liveVars outVar branchFalse
|
||||
addrEnd <- getPC
|
||||
registerLabelAddress symEnd addrEnd
|
||||
output'' $ Label labEnd
|
||||
Lab {} -> impossible
|
||||
|
||||
goLoad :: Reg.Value -> Offset -> Sem r RValue
|
||||
goLoad val off = do
|
||||
|
@ -5,6 +5,10 @@ import Data.HashSet qualified as HashSet
|
||||
import Juvix.Compiler.Core.Extra
|
||||
import Juvix.Compiler.Core.Transformation.Base
|
||||
|
||||
-- | Checks if `node` is a case tree such that all leaves are constructor
|
||||
-- applications, and each constructor `C` matched on in `c` either occurs as a
|
||||
-- leaf in `node` at most once or the branch body in `c` associated with `C` is
|
||||
-- an immediate value.
|
||||
isConstructorTree :: Module -> Case -> Node -> Bool
|
||||
isConstructorTree md c node = case run $ runFail $ go mempty node of
|
||||
Just ctrsMap ->
|
||||
@ -29,6 +33,8 @@ isConstructorTree md c node = case run $ runFail $ go mempty node of
|
||||
tags' = HashSet.fromList tags
|
||||
Nothing -> True
|
||||
|
||||
-- Returns the map from tags to their number of occurrences in the leaves of
|
||||
-- the case tree.
|
||||
go :: (Member Fail r) => HashMap Tag Int -> Node -> Sem r (HashMap Tag Int)
|
||||
go ctrs = \case
|
||||
NCtr Constr {..} ->
|
||||
@ -39,6 +45,9 @@ isConstructorTree md c node = case run $ runFail $ go mempty node of
|
||||
_ ->
|
||||
fail
|
||||
|
||||
-- | Convert e.g. `case (if A C1 C2) of C1 := X | C2 := Y` to
|
||||
-- `if A (case C1 of C1 := X | C2 := Y) (case C2 of C1 := X | C2 := Y)`
|
||||
-- See: https://github.com/anoma/juvix/issues/2440
|
||||
convertNode :: Module -> Node -> Node
|
||||
convertNode md = dmap go
|
||||
where
|
||||
|
@ -534,9 +534,9 @@ compile = \case
|
||||
Tree.OpIntMul -> return (callStdlib StdlibMul args)
|
||||
Tree.OpIntDiv -> return (callStdlib StdlibDiv args)
|
||||
Tree.OpIntMod -> return (callStdlib StdlibMod args)
|
||||
Tree.OpIntLt -> return (callStdlib StdlibLt args)
|
||||
Tree.OpIntLe -> return (callStdlib StdlibLe args)
|
||||
Tree.OpEq -> testEq _nodeBinopArg1 _nodeBinopArg2
|
||||
Tree.OpBool Tree.OpIntLt -> return (callStdlib StdlibLt args)
|
||||
Tree.OpBool Tree.OpIntLe -> return (callStdlib StdlibLe args)
|
||||
Tree.OpBool Tree.OpEq -> testEq _nodeBinopArg1 _nodeBinopArg2
|
||||
Tree.OpStrConcat -> return (callStdlib StdlibCatBytes args)
|
||||
Tree.OpFieldAdd -> fieldErr
|
||||
Tree.OpFieldSub -> fieldErr
|
||||
|
@ -6,12 +6,15 @@ import Juvix.Prelude
|
||||
|
||||
data TransformationId
|
||||
= IdentityTrans
|
||||
| CleanupCairo
|
||||
| Cleanup
|
||||
| SSA
|
||||
| InitBranchVars
|
||||
| CopyPropagation
|
||||
| ConstantPropagation
|
||||
| DeadCodeElimination
|
||||
| BranchToIf
|
||||
| BranchOnZeroToIf
|
||||
| OptPhaseMain
|
||||
| OptPhaseCairo
|
||||
deriving stock (Data, Bounded, Enum, Show)
|
||||
@ -31,18 +34,21 @@ toRustTransformations :: [TransformationId]
|
||||
toRustTransformations = [Cleanup]
|
||||
|
||||
toCasmTransformations :: [TransformationId]
|
||||
toCasmTransformations = [Cleanup, SSA, OptPhaseCairo]
|
||||
toCasmTransformations = [CleanupCairo, SSA, OptPhaseCairo]
|
||||
|
||||
instance TransformationId' TransformationId where
|
||||
transformationText :: TransformationId -> Text
|
||||
transformationText = \case
|
||||
IdentityTrans -> strIdentity
|
||||
CleanupCairo -> strCleanupCairo
|
||||
Cleanup -> strCleanup
|
||||
SSA -> strSSA
|
||||
InitBranchVars -> strInitBranchVars
|
||||
CopyPropagation -> strCopyPropagation
|
||||
ConstantPropagation -> strConstantPropagation
|
||||
DeadCodeElimination -> strDeadCodeElimination
|
||||
BranchToIf -> strBranchToIf
|
||||
BranchOnZeroToIf -> strBranchOnZeroToIf
|
||||
OptPhaseMain -> strOptPhaseMain
|
||||
OptPhaseCairo -> strOptPhaseCairo
|
||||
|
||||
|
@ -17,6 +17,9 @@ strIdentity = "identity"
|
||||
strCleanup :: Text
|
||||
strCleanup = "cleanup"
|
||||
|
||||
strCleanupCairo :: Text
|
||||
strCleanupCairo = "cleanup-cairo"
|
||||
|
||||
strSSA :: Text
|
||||
strSSA = "ssa"
|
||||
|
||||
@ -32,6 +35,12 @@ strConstantPropagation = "constant-propagation"
|
||||
strDeadCodeElimination :: Text
|
||||
strDeadCodeElimination = "dead-code"
|
||||
|
||||
strBranchToIf :: Text
|
||||
strBranchToIf = "br-to-if"
|
||||
|
||||
strBranchOnZeroToIf :: Text
|
||||
strBranchOnZeroToIf = "brz-to-if"
|
||||
|
||||
strOptPhaseMain :: Text
|
||||
strOptPhaseMain = "opt-main"
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
module Juvix.Compiler.Reg.Extra.Base where
|
||||
|
||||
import Data.HashSet qualified as HashSet
|
||||
import Juvix.Compiler.Reg.Language
|
||||
|
||||
getResultVar :: Instruction -> Maybe VarRef
|
||||
@ -30,6 +31,7 @@ setResultVar instr vref = case instr of
|
||||
|
||||
getOutVar :: Instruction -> Maybe VarRef
|
||||
getOutVar = \case
|
||||
If x -> x ^. instrIfOutVar
|
||||
Branch x -> x ^. instrBranchOutVar
|
||||
Case x -> x ^. instrCaseOutVar
|
||||
_ -> Nothing
|
||||
@ -48,6 +50,7 @@ overValueRefs'' f = \case
|
||||
TailCall x -> TailCall <$> goTailCall x
|
||||
TailCallClosures x -> TailCallClosures <$> goTailCallClosures x
|
||||
Return x -> Return <$> goReturn x
|
||||
If x -> If <$> goIf x
|
||||
Branch x -> Branch <$> goBranch x
|
||||
Case x -> Case <$> goCase x
|
||||
Trace x -> Trace <$> goTrace x
|
||||
@ -162,6 +165,9 @@ overValueRefs'' f = \case
|
||||
goReturn :: InstrReturn -> m InstrReturn
|
||||
goReturn = overM instrReturnValue goValue
|
||||
|
||||
goIf :: InstrIf -> m InstrIf
|
||||
goIf = overM instrIfArg1 goValue >=> overM instrIfArg2 goValue
|
||||
|
||||
goBranch :: InstrBranch -> m InstrBranch
|
||||
goBranch = overM instrBranchValue goValue
|
||||
|
||||
@ -199,3 +205,18 @@ updateLiveVars' f = \case
|
||||
|
||||
updateLiveVars :: (VarRef -> VarRef) -> Instruction -> Instruction
|
||||
updateLiveVars f = updateLiveVars' (Just . f)
|
||||
|
||||
updateInstrLiveVars :: Instruction -> HashSet VarRef -> HashSet VarRef
|
||||
updateInstrLiveVars instr liveVars =
|
||||
HashSet.union
|
||||
(maybe liveVars (`HashSet.delete` liveVars) (getResultVar instr))
|
||||
(HashSet.fromList (getValueRefs instr))
|
||||
|
||||
computeBackwardLiveVars :: Instruction -> HashSet VarRef -> [HashSet VarRef] -> HashSet VarRef
|
||||
computeBackwardLiveVars instr live lives = case instr of
|
||||
If {} -> ulives
|
||||
Branch {} -> ulives
|
||||
Case {} -> ulives
|
||||
_ -> live
|
||||
where
|
||||
ulives = HashSet.unions lives
|
||||
|
@ -13,6 +13,8 @@ overSubBlocks f block = block'
|
||||
Call x -> Call x
|
||||
TailCall x -> TailCall x
|
||||
Return x -> Return x
|
||||
If x ->
|
||||
If $ over instrIfTrue f $ over instrIfFalse f x
|
||||
Branch x ->
|
||||
Branch $ over instrBranchTrue f $ over instrBranchFalse f x
|
||||
Case x ->
|
||||
@ -29,6 +31,8 @@ getSubBlocks block = maybe [] goFinal (block ^. blockFinal)
|
||||
Call {} -> []
|
||||
TailCall {} -> []
|
||||
Return {} -> []
|
||||
If x ->
|
||||
[x ^. instrIfTrue, x ^. instrIfFalse]
|
||||
Branch x ->
|
||||
[x ^. instrBranchTrue, x ^. instrBranchFalse]
|
||||
Case x ->
|
||||
@ -55,6 +59,7 @@ getOutVar :: FinalInstruction -> Maybe VarRef
|
||||
getOutVar = \case
|
||||
Call x -> Just $ x ^. instrCallResult
|
||||
ExtendClosure x -> Just $ x ^. instrExtendClosureResult
|
||||
If x -> x ^. instrIfOutVar
|
||||
Branch x -> x ^. instrBranchOutVar
|
||||
Case x -> x ^. instrCaseOutVar
|
||||
TailCall {} -> Nothing
|
||||
@ -110,6 +115,7 @@ getValueRefs' = \case
|
||||
Call x -> goCall x
|
||||
TailCall x -> goTailCall x
|
||||
Return x -> goReturn x
|
||||
If x -> goIf x
|
||||
Branch x -> goBranch x
|
||||
Case x -> goCase x
|
||||
where
|
||||
@ -132,6 +138,9 @@ getValueRefs' = \case
|
||||
goReturn :: InstrReturn -> [VarRef]
|
||||
goReturn InstrReturn {..} = getValueRefs'' _instrReturnValue
|
||||
|
||||
goIf :: InstrIf -> [VarRef]
|
||||
goIf InstrIf {..} = getValueRefs'' _instrIfArg1 ++ getValueRefs'' _instrIfArg2
|
||||
|
||||
goBranch :: InstrBranch -> [VarRef]
|
||||
goBranch InstrBranch {..} = getValueRefs'' _instrBranchValue
|
||||
|
||||
|
@ -44,6 +44,10 @@ computeMaxStackHeight lims = maximum . map go
|
||||
+ lims
|
||||
^. limitsDispatchStackSize
|
||||
Return {} -> 0
|
||||
If InstrIf {..} ->
|
||||
max
|
||||
(computeMaxStackHeight lims _instrIfTrue)
|
||||
(computeMaxStackHeight lims _instrIfFalse)
|
||||
Branch InstrBranch {..} ->
|
||||
max
|
||||
(computeMaxStackHeight lims _instrBranchTrue)
|
||||
@ -83,6 +87,10 @@ computeMaxCallClosuresArgsNum = maximum . map go
|
||||
TailCallClosures InstrTailCallClosures {..} ->
|
||||
length _instrTailCallClosuresArgs
|
||||
Return {} -> 0
|
||||
If InstrIf {..} ->
|
||||
max
|
||||
(computeMaxCallClosuresArgsNum _instrIfTrue)
|
||||
(computeMaxCallClosuresArgsNum _instrIfFalse)
|
||||
Branch InstrBranch {..} ->
|
||||
max
|
||||
(computeMaxCallClosuresArgsNum _instrBranchTrue)
|
||||
@ -135,6 +143,11 @@ computeStringMap strs = snd . run . execState (HashMap.size strs, strs) . mapM g
|
||||
mapM_ goVal _instrTailCallClosuresArgs
|
||||
Return InstrReturn {..} ->
|
||||
goVal _instrReturnValue
|
||||
If InstrIf {..} -> do
|
||||
goVal _instrIfArg1
|
||||
goVal _instrIfArg2
|
||||
mapM_ go _instrIfTrue
|
||||
mapM_ go _instrIfFalse
|
||||
Branch InstrBranch {..} -> do
|
||||
goVal _instrBranchValue
|
||||
mapM_ go _instrBranchTrue
|
||||
@ -179,6 +192,10 @@ computeLocalVarsNum = maximum . map go
|
||||
CallClosures InstrCallClosures {..} -> goVarRef _instrCallClosuresResult
|
||||
TailCallClosures {} -> 0
|
||||
Return {} -> 0
|
||||
If InstrIf {..} ->
|
||||
max
|
||||
(computeLocalVarsNum _instrIfTrue)
|
||||
(computeLocalVarsNum _instrIfFalse)
|
||||
Branch InstrBranch {..} ->
|
||||
max
|
||||
(computeLocalVarsNum _instrBranchTrue)
|
||||
|
@ -35,6 +35,11 @@ recurseF sig c = \case
|
||||
(c0, i0) <- (sig ^. forwardFun) i c
|
||||
(c', i') <-
|
||||
case i0 of
|
||||
If x@InstrIf {..} -> do
|
||||
(c1, is1) <- recurseF sig c0 _instrIfTrue
|
||||
(c2, is2) <- recurseF sig c0 _instrIfFalse
|
||||
let i' = If x {_instrIfTrue = is1, _instrIfFalse = is2}
|
||||
return $ (sig ^. forwardCombine) i' (c1 :| [c2])
|
||||
Branch x@InstrBranch {..} -> do
|
||||
(c1, is1) <- recurseF sig c0 _instrBranchTrue
|
||||
(c2, is2) <- recurseF sig c0 _instrBranchFalse
|
||||
@ -70,6 +75,10 @@ recurseB sig a = \case
|
||||
let a0 = (sig ^. backwardAdjust) a'
|
||||
(as, i') <-
|
||||
case i of
|
||||
If x@InstrIf {..} -> do
|
||||
(a1, is1) <- recurseB sig a0 _instrIfTrue
|
||||
(a2, is2) <- recurseB sig a0 _instrIfFalse
|
||||
return ([a1, a2], If x {_instrIfTrue = is1, _instrIfFalse = is2})
|
||||
Branch x@InstrBranch {..} -> do
|
||||
(a1, is1) <- recurseB sig a0 _instrBranchTrue
|
||||
(a2, is2) <- recurseB sig a0 _instrBranchFalse
|
||||
|
@ -60,6 +60,7 @@ runFunction hout infoTable args0 info0 = do
|
||||
CallClosures x -> goCallClosures args tmps instrs x
|
||||
TailCallClosures x -> goTailCallClosures args tmps instrs x
|
||||
Return x -> goReturn args tmps instrs x
|
||||
If x -> goIf args tmps instrs x
|
||||
Branch x -> goBranch args tmps instrs x
|
||||
Case x -> goCase args tmps instrs x
|
||||
Block x -> goBlock args tmps instrs x
|
||||
@ -261,6 +262,17 @@ runFunction hout infoTable args0 info0 = do
|
||||
| otherwise =
|
||||
throwRunError "return not in tail position" Nothing
|
||||
|
||||
goIf :: Args -> Vars s -> Code -> InstrIf -> ST s Val
|
||||
goIf args tmps instrs InstrIf {..} = do
|
||||
arg1 <- readValue args tmps _instrIfArg1
|
||||
arg2 <- readValue args tmps _instrIfArg2
|
||||
let val = binop (OpBool _instrIfOp) arg1 arg2
|
||||
r <- case val of
|
||||
ValBool True -> go args tmps _instrIfTrue
|
||||
ValBool False -> go args tmps _instrIfFalse
|
||||
_ -> throwRunError "expected a boolean" Nothing
|
||||
goNext args tmps r instrs
|
||||
|
||||
goBranch :: Args -> Vars s -> Code -> InstrBranch -> ST s Val
|
||||
goBranch args tmps instrs InstrBranch {..} = do
|
||||
val <- readValue args tmps _instrBranchValue
|
||||
|
@ -31,6 +31,7 @@ import Juvix.Data.Keyword.All
|
||||
kwFieldDiv,
|
||||
kwFieldMul,
|
||||
kwFieldSub,
|
||||
kwIf,
|
||||
kwLe_,
|
||||
kwLive,
|
||||
kwLt_,
|
||||
@ -70,6 +71,7 @@ allKeywords =
|
||||
kwStrcat,
|
||||
kwEcOp,
|
||||
kwEq,
|
||||
kwIf,
|
||||
kwShow,
|
||||
kwAtoi,
|
||||
kwTrace,
|
||||
|
@ -21,7 +21,8 @@ data Instruction
|
||||
| TailCallClosures InstrTailCallClosures
|
||||
| Return InstrReturn
|
||||
| ----
|
||||
Branch InstrBranch
|
||||
If InstrIf
|
||||
| Branch InstrBranch
|
||||
| Case InstrCase
|
||||
| ----
|
||||
Trace InstrTrace
|
||||
@ -54,6 +55,8 @@ data InstrTailCallClosures = InstrTailCallClosures
|
||||
}
|
||||
deriving stock (Eq)
|
||||
|
||||
type InstrIf = InstrIf' Code
|
||||
|
||||
type InstrBranch = InstrBranch' Code
|
||||
|
||||
type InstrCase = InstrCase' Code
|
||||
|
@ -30,9 +30,12 @@ data FinalInstruction
|
||||
| Call InstrCall
|
||||
| TailCall InstrTailCall
|
||||
| Return InstrReturn
|
||||
| If InstrIf
|
||||
| Branch InstrBranch
|
||||
| Case InstrCase
|
||||
|
||||
type InstrIf = InstrIf' Block
|
||||
|
||||
type InstrBranch = InstrBranch' Block
|
||||
|
||||
type InstrCase = InstrCase' Block
|
||||
|
@ -139,6 +139,18 @@ newtype InstrReturn = InstrReturn
|
||||
}
|
||||
deriving stock (Eq)
|
||||
|
||||
data InstrIf' a = InstrIf
|
||||
{ _instrIfOp :: BoolOp,
|
||||
_instrIfArg1 :: Value,
|
||||
_instrIfArg2 :: Value,
|
||||
_instrIfTrue :: a,
|
||||
_instrIfFalse :: a,
|
||||
-- | Output variable storing the result (corresponds to the top of the value
|
||||
-- stack in JuvixAsm after executing the branches)
|
||||
_instrIfOutVar :: Maybe VarRef
|
||||
}
|
||||
deriving stock (Eq, Functor)
|
||||
|
||||
data InstrBranch' a = InstrBranch
|
||||
{ _instrBranchValue :: Value,
|
||||
_instrBranchTrue :: a,
|
||||
@ -180,6 +192,7 @@ makeLenses ''InstrExtendClosure
|
||||
makeLenses ''InstrReturn
|
||||
makeLenses ''InstrTailCall
|
||||
makeLenses ''InstrCall
|
||||
makeLenses ''InstrIf'
|
||||
makeLenses ''InstrBranch'
|
||||
makeLenses ''InstrCase'
|
||||
makeLenses ''CaseBranch'
|
||||
|
@ -196,6 +196,30 @@ instance PrettyCode InstrReturn where
|
||||
val <- ppCode _instrReturnValue
|
||||
return $ primitive Str.ret <+> val
|
||||
|
||||
instance PrettyCode InstrIf where
|
||||
ppCode InstrIf {..} = do
|
||||
op <- Tree.ppCode _instrIfOp
|
||||
arg1 <- ppCode _instrIfArg1
|
||||
arg2 <- ppCode _instrIfArg2
|
||||
br1 <- ppCodeCode _instrIfTrue
|
||||
br2 <- ppCodeCode _instrIfFalse
|
||||
var <- ppOutVar _instrIfOutVar
|
||||
return $
|
||||
primitive Str.if_
|
||||
<+> op
|
||||
<+> arg1
|
||||
<+> arg2
|
||||
<> var
|
||||
<+> braces'
|
||||
( constr Str.true_ <> colon
|
||||
<+> braces' br1
|
||||
<> semi
|
||||
<> line
|
||||
<> constr Str.false_
|
||||
<> colon
|
||||
<+> braces' br2 <> semi
|
||||
)
|
||||
|
||||
instance PrettyCode InstrBranch where
|
||||
ppCode InstrBranch {..} = do
|
||||
val <- ppCode _instrBranchValue
|
||||
@ -259,6 +283,7 @@ instance PrettyCode Instruction where
|
||||
CallClosures x -> ppCode x
|
||||
TailCallClosures x -> ppCode x
|
||||
Return x -> ppCode x
|
||||
If x -> ppCode x
|
||||
Branch x -> ppCode x
|
||||
Case x -> ppCode x
|
||||
Block x -> ppCode x
|
||||
|
@ -10,6 +10,7 @@ import Juvix.Compiler.Reg.Transformation.Base
|
||||
import Juvix.Compiler.Reg.Transformation.Cleanup
|
||||
import Juvix.Compiler.Reg.Transformation.IdentityTrans
|
||||
import Juvix.Compiler.Reg.Transformation.InitBranchVars
|
||||
import Juvix.Compiler.Reg.Transformation.Optimize.BranchToIf
|
||||
import Juvix.Compiler.Reg.Transformation.Optimize.ConstantPropagation
|
||||
import Juvix.Compiler.Reg.Transformation.Optimize.CopyPropagation
|
||||
import Juvix.Compiler.Reg.Transformation.Optimize.DeadCodeElimination
|
||||
@ -24,10 +25,13 @@ applyTransformations ts tbl = foldM (flip appTrans) tbl ts
|
||||
appTrans = \case
|
||||
IdentityTrans -> return . identity
|
||||
Cleanup -> return . cleanup
|
||||
CleanupCairo -> return . cleanup' True
|
||||
SSA -> return . computeSSA
|
||||
InitBranchVars -> return . initBranchVars
|
||||
CopyPropagation -> return . copyPropagate
|
||||
ConstantPropagation -> return . constantPropagate
|
||||
DeadCodeElimination -> return . removeDeadAssignments
|
||||
BranchToIf -> return . convertBranchToIf
|
||||
BranchOnZeroToIf -> return . convertBranchOnZeroToIf
|
||||
OptPhaseMain -> Phase.Main.optimize
|
||||
OptPhaseCairo -> Phase.Cairo.optimize
|
||||
|
@ -1,11 +1,12 @@
|
||||
module Juvix.Compiler.Reg.Transformation.Cleanup where
|
||||
|
||||
import Juvix.Compiler.Reg.Extra.Base (updateLiveVars')
|
||||
import Juvix.Compiler.Reg.Extra.Recursors
|
||||
import Juvix.Compiler.Reg.Transformation.Base
|
||||
import Juvix.Compiler.Tree.Extra.Rep
|
||||
|
||||
cleanup :: InfoTable -> InfoTable
|
||||
cleanup tab = mapT (const (cmap go)) tab
|
||||
cleanup' :: Bool -> InfoTable -> InfoTable
|
||||
cleanup' bCairo tab = mapT (const (cmap go)) tab
|
||||
where
|
||||
go :: Code -> Code
|
||||
go = \case
|
||||
@ -17,4 +18,9 @@ cleanup tab = mapT (const (cmap go)) tab
|
||||
_caseBranchCode ++ is
|
||||
[] ->
|
||||
fromJust _instrCaseDefault ++ is
|
||||
Prealloc {} : is | bCairo -> is
|
||||
i : is | bCairo -> updateLiveVars' (const Nothing) i : is
|
||||
is -> is
|
||||
|
||||
cleanup :: InfoTable -> InfoTable
|
||||
cleanup = cleanup' False
|
||||
|
52
src/Juvix/Compiler/Reg/Transformation/Optimize/BranchToIf.hs
Normal file
52
src/Juvix/Compiler/Reg/Transformation/Optimize/BranchToIf.hs
Normal file
@ -0,0 +1,52 @@
|
||||
module Juvix.Compiler.Reg.Transformation.Optimize.BranchToIf where
|
||||
|
||||
import Juvix.Compiler.Reg.Extra
|
||||
import Juvix.Compiler.Reg.Transformation.Base
|
||||
|
||||
convertBranchToIf' :: (BoolOp -> Value -> Value -> Bool) -> InfoTable -> InfoTable
|
||||
convertBranchToIf' f = mapT (const goFun)
|
||||
where
|
||||
goFun :: Code -> Code
|
||||
goFun =
|
||||
snd
|
||||
. runIdentity
|
||||
. recurseB
|
||||
BackwardRecursorSig
|
||||
{ _backwardFun = \is () _ -> return ((), go is),
|
||||
_backwardAdjust = id
|
||||
}
|
||||
mempty
|
||||
|
||||
go :: Code -> Code
|
||||
go = \case
|
||||
binop@(Binop InstrBinop {..}) : Branch InstrBranch {..} : is'
|
||||
| OpBool op <- _instrBinopOpcode,
|
||||
f op _instrBinopArg1 _instrBinopArg2,
|
||||
VRef r <- _instrBranchValue,
|
||||
r == _instrBinopResult,
|
||||
r `notElem` getValueRefs binop ->
|
||||
binop
|
||||
: If
|
||||
InstrIf
|
||||
{ _instrIfOp = op,
|
||||
_instrIfArg1 = _instrBinopArg1,
|
||||
_instrIfArg2 = _instrBinopArg2,
|
||||
_instrIfOutVar = _instrBranchOutVar,
|
||||
_instrIfTrue = _instrBranchTrue,
|
||||
_instrIfFalse = _instrBranchFalse
|
||||
}
|
||||
: is'
|
||||
is -> is
|
||||
|
||||
convertBranchToIf :: InfoTable -> InfoTable
|
||||
convertBranchToIf = convertBranchToIf' (\_ _ _ -> True)
|
||||
|
||||
convertBranchOnZeroToIf :: InfoTable -> InfoTable
|
||||
convertBranchOnZeroToIf = convertBranchToIf' check
|
||||
where
|
||||
check :: BoolOp -> Value -> Value -> Bool
|
||||
check op arg1 arg2 = case op of
|
||||
OpEq
|
||||
| ValConst (ConstInt 0) <- arg1 -> True
|
||||
| ValConst (ConstInt 0) <- arg2 -> True
|
||||
_ -> False
|
@ -44,6 +44,7 @@ copyPropagate = mapT (const goFun)
|
||||
where
|
||||
mpv = combineMaps mpvs
|
||||
instr' = case instr of
|
||||
If x -> If $ over instrIfOutVar (fmap (adjustVarRef mpv)) x
|
||||
Branch x -> Branch $ over instrBranchOutVar (fmap (adjustVarRef mpv)) x
|
||||
Case x -> Case $ over instrCaseOutVar (fmap (adjustVarRef mpv)) x
|
||||
_ -> impossible
|
||||
|
@ -32,14 +32,7 @@ removeDeadAssignments = mapT (const goFun)
|
||||
_ ->
|
||||
(liveVars', instr : is')
|
||||
where
|
||||
liveVars' =
|
||||
HashSet.union
|
||||
(maybe liveVars (`HashSet.delete` liveVars) (getResultVar instr))
|
||||
(HashSet.fromList (getValueRefs instr))
|
||||
liveVars = case instr of
|
||||
Branch {} -> ulives
|
||||
Case {} -> ulives
|
||||
_ -> live
|
||||
ulives = HashSet.unions lives
|
||||
liveVars' = updateInstrLiveVars instr liveVars
|
||||
liveVars = computeBackwardLiveVars instr live lives
|
||||
[] ->
|
||||
(live, [])
|
||||
|
@ -1,7 +1,14 @@
|
||||
module Juvix.Compiler.Reg.Transformation.Optimize.Phase.Cairo where
|
||||
|
||||
import Juvix.Compiler.Reg.Transformation.Base
|
||||
import Juvix.Compiler.Reg.Transformation.Optimize.BranchToIf
|
||||
import Juvix.Compiler.Reg.Transformation.Optimize.DeadCodeElimination
|
||||
import Juvix.Compiler.Reg.Transformation.Optimize.Phase.Main qualified as Main
|
||||
|
||||
optimize :: (Member (Reader Options) r) => InfoTable -> Sem r InfoTable
|
||||
optimize = withOptimizationLevel 1 Main.optimize
|
||||
optimize =
|
||||
withOptimizationLevel 1 $
|
||||
Main.optimize
|
||||
>=> return
|
||||
. removeDeadAssignments
|
||||
. convertBranchOnZeroToIf
|
||||
|
@ -25,6 +25,7 @@ fromReg = over infoFunctions (fmap (over functionCode goCode))
|
||||
Reg.Call x -> mkBlock (Call x)
|
||||
Reg.TailCall x -> mkBlock (TailCall x)
|
||||
Reg.Return x -> mkBlock (Return x)
|
||||
Reg.If x -> mkBlock (If (fmap goCode x))
|
||||
Reg.Branch x -> mkBlock (Branch (fmap goCode x))
|
||||
Reg.Case x -> mkBlock (Case (fmap goCode x))
|
||||
Reg.CallClosures {} -> impossible
|
||||
|
@ -60,6 +60,7 @@ instruction =
|
||||
<|> (TailCall <$> instrTailCall)
|
||||
<|> (TailCallClosures <$> instrTailCallClosures)
|
||||
<|> (Return <$> instrReturn)
|
||||
<|> (If <$> instrIf)
|
||||
<|> (Branch <$> instrBranch)
|
||||
<|> (Case <$> instrCase)
|
||||
<|> (Block <$> instrBlock)
|
||||
@ -94,9 +95,9 @@ instrBinop vref =
|
||||
<|> parseBinaryOp kwMul_ OpIntMul vref
|
||||
<|> parseBinaryOp kwDiv_ OpIntDiv vref
|
||||
<|> parseBinaryOp kwMod_ OpIntMod vref
|
||||
<|> parseBinaryOp kwLt_ OpIntLt vref
|
||||
<|> parseBinaryOp kwLe_ OpIntLe vref
|
||||
<|> parseBinaryOp kwEq_ OpEq vref
|
||||
<|> parseBinaryOp kwLt_ (OpBool OpIntLt) vref
|
||||
<|> parseBinaryOp kwLe_ (OpBool OpIntLe) vref
|
||||
<|> parseBinaryOp kwEq_ (OpBool OpEq) vref
|
||||
<|> parseBinaryOp kwFieldAdd OpFieldAdd vref
|
||||
<|> parseBinaryOp kwFieldSub OpFieldSub vref
|
||||
<|> parseBinaryOp kwFieldMul OpFieldMul vref
|
||||
@ -367,6 +368,39 @@ instrReturn = do
|
||||
{ _instrReturnValue = val
|
||||
}
|
||||
|
||||
parseBoolOp :: ParsecS r BoolOp
|
||||
parseBoolOp =
|
||||
(kw kwLt_ >> return OpIntLt)
|
||||
<|> (kw kwLe_ >> return OpIntLe)
|
||||
<|> (kw kwEq_ >> return OpEq)
|
||||
|
||||
instrIf ::
|
||||
(Members '[Reader ParserSig, InfoTableBuilder, State LocalParams] r) =>
|
||||
ParsecS r InstrIf
|
||||
instrIf = do
|
||||
kw kwIf
|
||||
op <- parseBoolOp
|
||||
arg1 <- value
|
||||
arg2 <- value
|
||||
var <- optional outVar
|
||||
(br1, br2) <- braces $ do
|
||||
symbol "true:"
|
||||
br1 <- braces parseCode
|
||||
kw delimSemicolon
|
||||
symbol "false:"
|
||||
br2 <- braces parseCode
|
||||
kw delimSemicolon
|
||||
return (br1, br2)
|
||||
return
|
||||
InstrIf
|
||||
{ _instrIfOp = op,
|
||||
_instrIfArg1 = arg1,
|
||||
_instrIfArg2 = arg2,
|
||||
_instrIfTrue = br1,
|
||||
_instrIfFalse = br2,
|
||||
_instrIfOutVar = var
|
||||
}
|
||||
|
||||
instrBranch ::
|
||||
(Members '[Reader ParserSig, InfoTableBuilder, State LocalParams] r) =>
|
||||
ParsecS r InstrBranch
|
||||
|
@ -22,8 +22,8 @@ evalBinop op arg1 arg2 = case op of
|
||||
OpIntMod
|
||||
| arg2 == ValInteger 0 -> Left "division by zero"
|
||||
| otherwise -> goIntBinop rem arg1 arg2
|
||||
OpIntLe -> goIntCmpBinop (<=) arg1 arg2
|
||||
OpIntLt -> goIntCmpBinop (<) arg1 arg2
|
||||
OpBool OpIntLe -> goIntCmpBinop (<=) arg1 arg2
|
||||
OpBool OpIntLt -> goIntCmpBinop (<) arg1 arg2
|
||||
OpFieldAdd -> goFieldBinop fieldAdd arg1 arg2
|
||||
OpFieldSub -> goFieldBinop fieldSub arg1 arg2
|
||||
OpFieldMul -> goFieldBinop fieldMul arg1 arg2
|
||||
@ -31,7 +31,7 @@ evalBinop op arg1 arg2 = case op of
|
||||
ValField arg2'
|
||||
| fieldToInteger arg2' == 0 -> Left "division by zero"
|
||||
_ -> goFieldBinop fieldDiv arg1 arg2
|
||||
OpEq
|
||||
OpBool OpEq
|
||||
| arg1 == arg2 -> Right $ ValBool True
|
||||
| otherwise -> Right $ ValBool False
|
||||
OpStrConcat -> goStrConcat arg1 arg2
|
||||
|
@ -2,19 +2,23 @@ module Juvix.Compiler.Tree.Language.Builtins where
|
||||
|
||||
import Juvix.Prelude
|
||||
|
||||
data BoolOp
|
||||
= OpIntLt
|
||||
| OpIntLe
|
||||
| OpEq
|
||||
deriving stock (Eq)
|
||||
|
||||
data BinaryOp
|
||||
= OpIntAdd
|
||||
= OpBool BoolOp
|
||||
| OpIntAdd
|
||||
| OpIntSub
|
||||
| OpIntMul
|
||||
| OpIntDiv
|
||||
| OpIntMod
|
||||
| OpIntLt
|
||||
| OpIntLe
|
||||
| OpFieldAdd
|
||||
| OpFieldSub
|
||||
| OpFieldMul
|
||||
| OpFieldDiv
|
||||
| OpEq
|
||||
| OpStrConcat
|
||||
deriving stock (Eq)
|
||||
|
||||
@ -25,13 +29,13 @@ isCommutative = \case
|
||||
OpIntMul -> True
|
||||
OpIntDiv -> False
|
||||
OpIntMod -> False
|
||||
OpIntLt -> False
|
||||
OpIntLe -> False
|
||||
OpBool OpIntLt -> False
|
||||
OpBool OpIntLe -> False
|
||||
OpFieldAdd -> True
|
||||
OpFieldSub -> False
|
||||
OpFieldMul -> True
|
||||
OpFieldDiv -> False
|
||||
OpEq -> True
|
||||
OpBool OpEq -> True
|
||||
OpStrConcat -> False
|
||||
|
||||
data UnaryOp
|
||||
|
@ -198,21 +198,27 @@ instance PrettyCode Constant where
|
||||
ConstVoid {} ->
|
||||
return $ annotate (AnnKind KNameConstructor) Str.void
|
||||
|
||||
instance PrettyCode BinaryOp where
|
||||
instance PrettyCode BoolOp where
|
||||
ppCode op = return $ primitive $ case op of
|
||||
OpIntAdd -> Str.instrAdd
|
||||
OpIntSub -> Str.instrSub
|
||||
OpIntMul -> Str.instrMul
|
||||
OpIntDiv -> Str.instrDiv
|
||||
OpIntMod -> Str.instrMod
|
||||
OpIntLt -> Str.instrLt
|
||||
OpIntLe -> Str.instrLe
|
||||
OpFieldAdd -> Str.fadd
|
||||
OpFieldSub -> Str.fsub
|
||||
OpFieldMul -> Str.fmul
|
||||
OpFieldDiv -> Str.fdiv
|
||||
OpEq -> Str.instrEq
|
||||
OpStrConcat -> Str.instrStrConcat
|
||||
|
||||
instance PrettyCode BinaryOp where
|
||||
ppCode = \case
|
||||
OpBool x -> ppCode x
|
||||
op ->
|
||||
return $ primitive $ case op of
|
||||
OpIntAdd -> Str.instrAdd
|
||||
OpIntSub -> Str.instrSub
|
||||
OpIntMul -> Str.instrMul
|
||||
OpIntDiv -> Str.instrDiv
|
||||
OpIntMod -> Str.instrMod
|
||||
OpFieldAdd -> Str.fadd
|
||||
OpFieldSub -> Str.fsub
|
||||
OpFieldMul -> Str.fmul
|
||||
OpFieldDiv -> Str.fdiv
|
||||
OpStrConcat -> Str.instrStrConcat
|
||||
|
||||
instance PrettyCode BinaryOpcode where
|
||||
ppCode = \case
|
||||
|
@ -52,13 +52,13 @@ inferType tab funInfo = goInfer mempty
|
||||
OpIntMul -> checkBinop mkTypeInteger mkTypeInteger mkTypeInteger
|
||||
OpIntDiv -> checkBinop mkTypeInteger mkTypeInteger mkTypeInteger
|
||||
OpIntMod -> checkBinop mkTypeInteger mkTypeInteger mkTypeInteger
|
||||
OpIntLt -> checkBinop mkTypeInteger mkTypeInteger mkTypeBool
|
||||
OpIntLe -> checkBinop mkTypeInteger mkTypeInteger mkTypeBool
|
||||
OpBool OpIntLt -> checkBinop mkTypeInteger mkTypeInteger mkTypeBool
|
||||
OpBool OpIntLe -> checkBinop mkTypeInteger mkTypeInteger mkTypeBool
|
||||
OpFieldAdd -> checkBinop TyField TyField TyField
|
||||
OpFieldSub -> checkBinop TyField TyField TyField
|
||||
OpFieldMul -> checkBinop TyField TyField TyField
|
||||
OpFieldDiv -> checkBinop TyField TyField TyField
|
||||
OpEq -> checkBinop TyDynamic TyDynamic mkTypeBool
|
||||
OpBool OpEq -> checkBinop TyDynamic TyDynamic mkTypeBool
|
||||
OpStrConcat -> checkBinop TyString TyString TyString
|
||||
|
||||
goUnop :: BinderList Type -> NodeUnop -> Sem r Type
|
||||
|
@ -283,13 +283,13 @@ genCode infoTable fi =
|
||||
Core.OpIntMul -> PrimBinop OpIntMul
|
||||
Core.OpIntDiv -> PrimBinop OpIntDiv
|
||||
Core.OpIntMod -> PrimBinop OpIntMod
|
||||
Core.OpIntLt -> PrimBinop OpIntLt
|
||||
Core.OpIntLe -> PrimBinop OpIntLe
|
||||
Core.OpIntLt -> PrimBinop (OpBool OpIntLt)
|
||||
Core.OpIntLe -> PrimBinop (OpBool OpIntLe)
|
||||
Core.OpFieldAdd -> PrimBinop OpFieldAdd
|
||||
Core.OpFieldSub -> PrimBinop OpFieldSub
|
||||
Core.OpFieldMul -> PrimBinop OpFieldMul
|
||||
Core.OpFieldDiv -> PrimBinop OpFieldDiv
|
||||
Core.OpEq -> PrimBinop OpEq
|
||||
Core.OpEq -> PrimBinop (OpBool OpEq)
|
||||
Core.OpStrConcat -> PrimBinop OpStrConcat
|
||||
Core.OpSeq -> OpSeq
|
||||
_ -> impossible
|
||||
|
@ -75,13 +75,13 @@ parseBinop =
|
||||
<|> parseBinaryOp kwMul_ (PrimBinop OpIntMul)
|
||||
<|> parseBinaryOp kwDiv_ (PrimBinop OpIntDiv)
|
||||
<|> parseBinaryOp kwMod_ (PrimBinop OpIntMod)
|
||||
<|> parseBinaryOp kwLt_ (PrimBinop OpIntLt)
|
||||
<|> parseBinaryOp kwLe_ (PrimBinop OpIntLe)
|
||||
<|> parseBinaryOp kwLt_ (PrimBinop (OpBool OpIntLt))
|
||||
<|> parseBinaryOp kwLe_ (PrimBinop (OpBool OpIntLe))
|
||||
<|> parseBinaryOp kwFieldAdd (PrimBinop OpFieldAdd)
|
||||
<|> parseBinaryOp kwFieldSub (PrimBinop OpFieldSub)
|
||||
<|> parseBinaryOp kwFieldMul (PrimBinop OpFieldMul)
|
||||
<|> parseBinaryOp kwFieldDiv (PrimBinop OpFieldDiv)
|
||||
<|> parseBinaryOp kwEq_ (PrimBinop OpEq)
|
||||
<|> parseBinaryOp kwEq_ (PrimBinop (OpBool OpEq))
|
||||
<|> parseBinaryOp kwStrcat (PrimBinop OpStrConcat)
|
||||
<|> parseBinaryOp kwSeq_ OpSeq
|
||||
|
||||
|
@ -110,8 +110,7 @@ juvix_closure_plus:
|
||||
JUVIX_BRANCH(
|
||||
TMP(0),
|
||||
{
|
||||
PREALLOC(
|
||||
2, { STACK_PUSH(ARG(0)); }, { STACK_POP(ARG(0)); });
|
||||
PREALLOC(2, { STACK_PUSH(ARG(0)); }, { STACK_POP(ARG(0)); });
|
||||
ALLOC_CONSTR_PAIR(juvix_result);
|
||||
FST(juvix_result) = ARG(0);
|
||||
SND(juvix_result) = CONSTR_NIL;
|
||||
|
@ -219,8 +219,7 @@ juvix_closure_app_plus:
|
||||
JUVIX_BRANCH(
|
||||
TMP(0),
|
||||
{
|
||||
PREALLOC(
|
||||
2, { STACK_PUSH(ARG(0)); }, { STACK_POP(ARG(0)); });
|
||||
PREALLOC(2, { STACK_PUSH(ARG(0)); }, { STACK_POP(ARG(0)); });
|
||||
ALLOC_CONSTR_PAIR(juvix_result);
|
||||
FST(juvix_result) = ARG(0);
|
||||
SND(juvix_result) = CONSTR_NIL;
|
||||
|
@ -253,8 +253,7 @@ juvix_closure_app_plus:
|
||||
JUVIX_BRANCH(
|
||||
TMP(0),
|
||||
{
|
||||
PREALLOC(
|
||||
2, { STACK_PUSH(ARG(0)); }, { STACK_POP(ARG(0)); });
|
||||
PREALLOC(2, { STACK_PUSH(ARG(0)); }, { STACK_POP(ARG(0)); });
|
||||
ALLOC_CONSTR_PAIR(juvix_result);
|
||||
FST(juvix_result) = ARG(0);
|
||||
SND(juvix_result) = CONSTR_NIL;
|
||||
@ -266,8 +265,7 @@ juvix_closure_app_plus:
|
||||
ARG(0) = TMP(0);
|
||||
CALL(0, gen, juvix_label_gen_1);
|
||||
STACK_POP(ARG(0));
|
||||
PREALLOC(
|
||||
2, { STACK_PUSH(ARG(0)); }, { STACK_POP(ARG(0)); });
|
||||
PREALLOC(2, { STACK_PUSH(ARG(0)); }, { STACK_POP(ARG(0)); });
|
||||
ALLOC_CONSTR_PAIR(TMP(0));
|
||||
FST(TMP(0)) = ARG(0);
|
||||
SND(TMP(0)) = juvix_result;
|
||||
|
@ -29,8 +29,7 @@ juvix_closure_print:
|
||||
ARG(0) = CARG(0);
|
||||
JUVIX_FUNCTION(juvix_function_print, 1);
|
||||
{
|
||||
PREALLOC(
|
||||
2, { STACK_PUSH(ARG(0)); }, { STACK_POP(ARG(0)); });
|
||||
PREALLOC(2, { STACK_PUSH(ARG(0)); }, { STACK_POP(ARG(0)); });
|
||||
ALLOC_CONSTR_BOXED(juvix_result, UID_WRITE, 1);
|
||||
CONSTR_ARG(juvix_result, 0) = ARG(0);
|
||||
RETURN;
|
||||
|
@ -124,8 +124,7 @@ int main() {
|
||||
{ CARG(juvix_closure_nargs) = juvix_result; });
|
||||
CALL_CLOSURE(TMP(0), juvix_label_7);
|
||||
STACK_POP(TMP(1));
|
||||
PREALLOC(
|
||||
3, { STACK_PUSH(TMP(1)); }, { STACK_POP(TMP(1)); });
|
||||
PREALLOC(3, { STACK_PUSH(TMP(1)); }, { STACK_POP(TMP(1)); });
|
||||
ALLOC_CONSTR_BOXED(TMP(0), UID_CONS, 2);
|
||||
CONSTR_ARG(TMP(0), 0) = juvix_result;
|
||||
CONSTR_ARG(TMP(0), 1) = TMP(1);
|
||||
@ -158,8 +157,7 @@ juvix_closure_add_one:
|
||||
ARG(0) = TMP(0);
|
||||
CALL(0, juvix_function_gen, juvix_label_gen_1);
|
||||
STACK_POP(ARG(0));
|
||||
PREALLOC(
|
||||
3, { STACK_PUSH(ARG(0)); }, { STACK_POP(ARG(0)); });
|
||||
PREALLOC(3, { STACK_PUSH(ARG(0)); }, { STACK_POP(ARG(0)); });
|
||||
ALLOC_CONSTR_BOXED(TMP(0), UID_CONS, 2);
|
||||
CONSTR_ARG(TMP(0), 0) = ARG(0);
|
||||
CONSTR_ARG(TMP(0), 1) = juvix_result;
|
||||
|
Loading…
Reference in New Issue
Block a user