mirror of
https://github.com/anoma/juvix.git
synced 2024-09-11 16:26:33 +03:00
Improve closure calls in the runtime (#2396)
* Closes #1653 The running time improvement is 20-30% on benchmarks dominated by closure calls.
This commit is contained in:
parent
7c3b70459b
commit
1260853583
@ -11,8 +11,12 @@
|
||||
MEM_INIT; \
|
||||
funcall_init()
|
||||
|
||||
// MAX_ARGS is the maximum number of function arguments, at least 1.
|
||||
// MAX_ARGS is the maximum number of function arguments plus the maximum number
|
||||
// of supplied arguments, at least 3. For example, if the program contains `I I
|
||||
// I I 1` where `I` is a one-argument identity function, then MAX_ARGS is
|
||||
// 5.
|
||||
#define JUVIX_PROLOGUE(MAX_ARGS) \
|
||||
STATIC_ASSERT(MAX_ARGS >= 3); \
|
||||
MEM_DECLS; \
|
||||
UNUSED word_t juvix_temp_var; \
|
||||
FUNCALL_DECLS(MAX_ARGS); \
|
||||
@ -20,6 +24,13 @@
|
||||
STACK_PUSH_ADDR(LABEL_ADDR(juvix_program_end)); \
|
||||
goto juvix_program_start; \
|
||||
DECL_CALL_CLOSURES; \
|
||||
DECL_APPLY_CLOSURE; \
|
||||
DECL_APPLY_1; \
|
||||
DECL_TAIL_APPLY_1; \
|
||||
DECL_APPLY_2; \
|
||||
DECL_TAIL_APPLY_2; \
|
||||
DECL_APPLY_3; \
|
||||
DECL_TAIL_APPLY_3; \
|
||||
juvix_program_start:
|
||||
|
||||
#define JUVIX_EPILOGUE \
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef JUVIX_FUNCALL_H
|
||||
#define JUVIX_FUNCALL_H
|
||||
|
||||
#include <juvix/funcall/apply.h>
|
||||
#include <juvix/funcall/funcall.h>
|
||||
#include <juvix/funcall/stacktrace.h>
|
||||
|
||||
|
228
runtime/src/juvix/funcall/apply.h
Normal file
228
runtime/src/juvix/funcall/apply.h
Normal file
@ -0,0 +1,228 @@
|
||||
#ifndef JUVIX_FUNCALL_APPLY_H
|
||||
#define JUVIX_FUNCALL_APPLY_H
|
||||
|
||||
#include <juvix/funcall/funcall.h>
|
||||
|
||||
#define DECL_APPLY_CLOSURE
|
||||
#define juvix_apply_closure juvix_ccl_closure
|
||||
|
||||
#define GOTO_APPLY_CLOSURE \
|
||||
STACKTRACE_PUSH(get_closure_fuid(juvix_apply_closure)); \
|
||||
STORED_GOTO(get_closure_addr(juvix_apply_closure));
|
||||
|
||||
#define TAIL_GOTO_APPLY_CLOSURE \
|
||||
STACKTRACE_REPLACE(get_closure_fuid(juvix_apply_closure)); \
|
||||
STACK_LEAVE; \
|
||||
STORED_GOTO(get_closure_addr(juvix_apply_closure))
|
||||
|
||||
#define RETURN_APPLY \
|
||||
STACKTRACE_PUSH(0); \
|
||||
RETURN_NS;
|
||||
|
||||
#define RETURN_TAIL_APPLY RETURN
|
||||
|
||||
#define GEN_APPLY_1(GOTO_CLOSURE, RETURN_CLOSURE, label) \
|
||||
do { \
|
||||
size_t juvix_apply_largs; \
|
||||
label: \
|
||||
juvix_apply_largs = get_closure_largs(juvix_apply_closure); \
|
||||
if (juvix_apply_largs == 1) { \
|
||||
GOTO_CLOSURE; \
|
||||
} else { \
|
||||
ASSERT(juvix_apply_largs > 1); \
|
||||
size_t n = get_closure_nargs(juvix_apply_closure); \
|
||||
PREALLOC( \
|
||||
n + CLOSURE_SKIP + 1 + 1, \
|
||||
{ \
|
||||
STACK_PUSH(juvix_apply_closure); \
|
||||
STACK_PUSH(CARG(n)); \
|
||||
}, \
|
||||
{ \
|
||||
STACK_POP(CARG(n)); \
|
||||
STACK_POP(juvix_apply_closure); \
|
||||
}); \
|
||||
EXTEND_CLOSURE(juvix_result, juvix_apply_closure, 1, { \
|
||||
CLOSURE_ARG(juvix_result, juvix_closure_nargs) = \
|
||||
CARG(juvix_closure_nargs); \
|
||||
}); \
|
||||
RETURN_CLOSURE; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define GEN_APPLY_2(GOTO_CLOSURE, RETURN_CLOSURE, label) \
|
||||
do { \
|
||||
size_t juvix_apply_largs; \
|
||||
label: \
|
||||
juvix_apply_largs = get_closure_largs(juvix_apply_closure); \
|
||||
if (juvix_apply_largs == 1) { \
|
||||
size_t n = get_closure_nargs(juvix_apply_closure); \
|
||||
STACK_PUSH(CARG(n + 1)); \
|
||||
CALL_CLOSURE(juvix_apply_closure, label##_return_1); \
|
||||
juvix_apply_closure = juvix_result; \
|
||||
ASSIGN_CARGS(juvix_apply_closure, \
|
||||
{ STACK_POP(CARG(juvix_closure_nargs)); }); \
|
||||
goto juvix_apply_1; \
|
||||
} else if (juvix_apply_largs == 2) { \
|
||||
GOTO_CLOSURE; \
|
||||
} else { \
|
||||
ASSERT(juvix_apply_largs > 2); \
|
||||
size_t n = get_closure_nargs(juvix_apply_closure); \
|
||||
PREALLOC( \
|
||||
n + CLOSURE_SKIP + 1 + 2, \
|
||||
{ \
|
||||
STACK_PUSH(juvix_apply_closure); \
|
||||
STACK_PUSH(CARG(n)); \
|
||||
STACK_PUSH(CARG(n + 1)); \
|
||||
}, \
|
||||
{ \
|
||||
STACK_POP(CARG(n + 1)); \
|
||||
STACK_POP(CARG(n)); \
|
||||
STACK_POP(juvix_apply_closure); \
|
||||
}); \
|
||||
EXTEND_CLOSURE(juvix_result, juvix_apply_closure, 2, { \
|
||||
CLOSURE_ARG(juvix_result, juvix_closure_nargs) = \
|
||||
CARG(juvix_closure_nargs); \
|
||||
CLOSURE_ARG(juvix_result, juvix_closure_nargs + 1) = \
|
||||
CARG(juvix_closure_nargs + 1); \
|
||||
}); \
|
||||
RETURN_CLOSURE; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define GEN_APPLY_3(GOTO_CLOSURE, RETURN_CLOSURE, label) \
|
||||
do { \
|
||||
label: \
|
||||
switch (get_closure_largs(juvix_apply_closure)) { \
|
||||
case 1: { \
|
||||
size_t n = get_closure_nargs(juvix_apply_closure); \
|
||||
STACK_PUSH(CARG(n + 2)); \
|
||||
STACK_PUSH(CARG(n + 1)); \
|
||||
CALL_CLOSURE(juvix_apply_closure, label##_return_1); \
|
||||
juvix_apply_closure = juvix_result; \
|
||||
ASSIGN_CARGS(juvix_apply_closure, { \
|
||||
STACK_POP(CARG(juvix_closure_nargs)); \
|
||||
STACK_POP(CARG(juvix_closure_nargs + 1)); \
|
||||
}); \
|
||||
goto juvix_apply_2; \
|
||||
} \
|
||||
case 2: { \
|
||||
size_t n = get_closure_nargs(juvix_apply_closure); \
|
||||
STACK_PUSH(CARG(n + 2)); \
|
||||
CALL_CLOSURE(juvix_apply_closure, label##_return_2); \
|
||||
juvix_apply_closure = juvix_result; \
|
||||
ASSIGN_CARGS(juvix_apply_closure, \
|
||||
{ STACK_POP(CARG(juvix_closure_nargs)); }); \
|
||||
goto juvix_apply_1; \
|
||||
} \
|
||||
case 3: \
|
||||
GOTO_CLOSURE; \
|
||||
default: { \
|
||||
size_t n = get_closure_nargs(juvix_apply_closure); \
|
||||
PREALLOC( \
|
||||
n + CLOSURE_SKIP + 1 + 3, \
|
||||
{ \
|
||||
STACK_PUSH(juvix_apply_closure); \
|
||||
STACK_PUSH(CARG(n)); \
|
||||
STACK_PUSH(CARG(n + 1)); \
|
||||
STACK_PUSH(CARG(n + 2)); \
|
||||
}, \
|
||||
{ \
|
||||
STACK_POP(CARG(n + 2)); \
|
||||
STACK_POP(CARG(n + 1)); \
|
||||
STACK_POP(CARG(n)); \
|
||||
STACK_POP(juvix_apply_closure); \
|
||||
}); \
|
||||
EXTEND_CLOSURE(juvix_result, juvix_apply_closure, 3, { \
|
||||
CLOSURE_ARG(juvix_result, juvix_closure_nargs) = \
|
||||
CARG(juvix_closure_nargs); \
|
||||
CLOSURE_ARG(juvix_result, juvix_closure_nargs + 1) = \
|
||||
CARG(juvix_closure_nargs + 1); \
|
||||
CLOSURE_ARG(juvix_result, juvix_closure_nargs + 2) = \
|
||||
CARG(juvix_closure_nargs + 2); \
|
||||
}); \
|
||||
RETURN_CLOSURE; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DECL_APPLY_1 \
|
||||
GEN_APPLY_1(GOTO_APPLY_CLOSURE, RETURN_APPLY, juvix_apply_1)
|
||||
|
||||
#define DECL_TAIL_APPLY_1 \
|
||||
GEN_APPLY_1(TAIL_GOTO_APPLY_CLOSURE, RETURN_TAIL_APPLY, juvix_tail_apply_1)
|
||||
|
||||
#define DECL_APPLY_2 \
|
||||
GEN_APPLY_2(GOTO_APPLY_CLOSURE, RETURN_APPLY, juvix_apply_2)
|
||||
|
||||
#define DECL_TAIL_APPLY_2 \
|
||||
GEN_APPLY_2(TAIL_GOTO_APPLY_CLOSURE, RETURN_TAIL_APPLY, juvix_tail_apply_2)
|
||||
|
||||
#define DECL_APPLY_3 \
|
||||
GEN_APPLY_3(GOTO_APPLY_CLOSURE, RETURN_APPLY, juvix_apply_3)
|
||||
|
||||
#define DECL_TAIL_APPLY_3 \
|
||||
GEN_APPLY_3(TAIL_GOTO_APPLY_CLOSURE, RETURN_TAIL_APPLY, juvix_tail_apply_3)
|
||||
|
||||
#define APPLY_1(cl, label) \
|
||||
juvix_apply_closure = cl; \
|
||||
STACK_PUSH_ADDR(LABEL_ADDR(label)); \
|
||||
goto juvix_apply_1; \
|
||||
label: \
|
||||
STACK_POPT; \
|
||||
STACKTRACE_POP;
|
||||
|
||||
#define TAIL_APPLY_1(cl) \
|
||||
juvix_apply_closure = cl; \
|
||||
goto juvix_tail_apply_1;
|
||||
|
||||
#define APPLY_2(cl, label) \
|
||||
juvix_apply_closure = cl; \
|
||||
STACK_PUSH_ADDR(LABEL_ADDR(label)); \
|
||||
goto juvix_apply_2; \
|
||||
label: \
|
||||
STACK_POPT; \
|
||||
STACKTRACE_POP;
|
||||
|
||||
#define TAIL_APPLY_2(cl) \
|
||||
juvix_apply_closure = cl; \
|
||||
goto juvix_tail_apply_2;
|
||||
|
||||
#define APPLY_3(cl, label) \
|
||||
juvix_apply_closure = cl; \
|
||||
STACK_PUSH_ADDR(LABEL_ADDR(label)); \
|
||||
goto juvix_apply_3; \
|
||||
label: \
|
||||
STACK_POPT; \
|
||||
STACKTRACE_POP;
|
||||
|
||||
#define TAIL_APPLY_3(cl) \
|
||||
juvix_apply_closure = cl; \
|
||||
goto juvix_tail_apply_3;
|
||||
|
||||
#define APPLY(cl, N, label) \
|
||||
do { \
|
||||
if (get_closure_largs(cl) == N) { \
|
||||
CALL_CLOSURE(cl, label##_apply_return_1); \
|
||||
} else { \
|
||||
int n = (int)get_closure_nargs(cl); \
|
||||
for (int juvix_idx = n + N - 1; juvix_idx >= n; --juvix_idx) { \
|
||||
STACK_PUSH(CARG(juvix_idx)); \
|
||||
} \
|
||||
CALL_CLOSURES(cl, N, label##_apply_return_2); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TAIL_APPLY(cl, N) \
|
||||
do { \
|
||||
if (get_closure_largs(cl) == N) { \
|
||||
TAIL_CALL_CLOSURE(cl); \
|
||||
} else { \
|
||||
int n = (int)get_closure_nargs(cl); \
|
||||
for (int juvix_idx = n + N - 1; juvix_idx >= n; --juvix_idx) { \
|
||||
STACK_PUSH(CARG(juvix_idx)); \
|
||||
} \
|
||||
TAIL_CALL_CLOSURES(cl, N); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif // JUVIX_FUNCALL_APPLY_H
|
@ -115,7 +115,7 @@
|
||||
|
||||
#define TAIL_CALL_CLOSURE_NS(cl) \
|
||||
STACKTRACE_REPLACE(get_closure_fuid(cl)); \
|
||||
goto *get_closure_addr(cl)
|
||||
STORED_GOTO(get_closure_addr(cl))
|
||||
|
||||
#define TAIL_CALL_CLOSURE(cl) \
|
||||
STACK_LEAVE; \
|
||||
|
@ -4,8 +4,11 @@ import Data.HashMap.Strict qualified as HashMap
|
||||
import Juvix.Compiler.Asm.Options
|
||||
import Juvix.Compiler.Asm.Transformation.Base
|
||||
|
||||
computeCodePrealloc :: forall r. (Members '[Error AsmError, Reader Options] r) => InfoTable -> Code -> Sem r Code
|
||||
computeCodePrealloc tab code = prealloc <$> foldS sig code (0, [])
|
||||
computeMaxArgsNum :: InfoTable -> Int
|
||||
computeMaxArgsNum tab = maximum (map (^. functionArgsNum) (HashMap.elems (tab ^. infoFunctions)))
|
||||
|
||||
computeCodePrealloc :: forall r. (Members '[Error AsmError, Reader Options] r) => Int -> InfoTable -> Code -> Sem r Code
|
||||
computeCodePrealloc maxArgsNum tab code = prealloc <$> foldS sig code (0, [])
|
||||
where
|
||||
-- returns the maximum memory use and the mapping result (Code with the
|
||||
-- Prealloc instructions inserted)
|
||||
@ -32,7 +35,7 @@ computeCodePrealloc tab code = prealloc <$> foldS sig code (0, [])
|
||||
return (k + size, cmd : c)
|
||||
ExtendClosure {} -> do
|
||||
opts <- ask
|
||||
let size = opts ^. optLimits . limitsMaxClosureSize
|
||||
let size = opts ^. optLimits . limitsClosureHeadSize + maxArgsNum
|
||||
return (k + size, cmd : c)
|
||||
Call {} -> return (0, cmd : prealloc acc)
|
||||
TailCall {} -> return (0, cmd : prealloc acc)
|
||||
@ -78,14 +81,15 @@ computeCodePrealloc tab code = prealloc <$> foldS sig code (0, [])
|
||||
prealloc (0, c) = c
|
||||
prealloc (n, c) = mkInstr (Prealloc (InstrPrealloc n)) : c
|
||||
|
||||
computeFunctionPrealloc :: (Members '[Error AsmError, Reader Options] r) => InfoTable -> FunctionInfo -> Sem r FunctionInfo
|
||||
computeFunctionPrealloc tab = liftCodeTransformation (computeCodePrealloc tab)
|
||||
computeFunctionPrealloc :: (Members '[Error AsmError, Reader Options] r) => Int -> InfoTable -> FunctionInfo -> Sem r FunctionInfo
|
||||
computeFunctionPrealloc maxArgsNum tab = liftCodeTransformation (computeCodePrealloc maxArgsNum tab)
|
||||
|
||||
computePrealloc :: (Members '[Error AsmError, Reader Options] r) => InfoTable -> Sem r InfoTable
|
||||
computePrealloc tab = liftFunctionTransformation (computeFunctionPrealloc tab) tab
|
||||
computePrealloc tab =
|
||||
liftFunctionTransformation (computeFunctionPrealloc (computeMaxArgsNum tab) tab) tab
|
||||
|
||||
checkCodePrealloc :: forall r. (Members '[Error AsmError, Reader Options] r) => InfoTable -> Code -> Sem r Bool
|
||||
checkCodePrealloc tab code = do
|
||||
checkCodePrealloc :: forall r. (Members '[Error AsmError, Reader Options] r) => Int -> InfoTable -> Code -> Sem r Bool
|
||||
checkCodePrealloc maxArgsNum tab code = do
|
||||
f <- foldS sig code id
|
||||
return $ f 0 >= 0
|
||||
where
|
||||
@ -114,7 +118,7 @@ checkCodePrealloc tab code = do
|
||||
return $ \k -> cont (k - size)
|
||||
ExtendClosure {} -> do
|
||||
opts <- ask
|
||||
let size = opts ^. optLimits . limitsMaxClosureSize
|
||||
let size = opts ^. optLimits . limitsClosureHeadSize + maxArgsNum
|
||||
return $ \k -> cont (k - size)
|
||||
Binop StrConcat -> do
|
||||
opts <- ask
|
||||
@ -148,4 +152,4 @@ checkPrealloc opts tab =
|
||||
Right b -> b
|
||||
where
|
||||
sb :: Sem '[Reader Options, Error AsmError] Bool
|
||||
sb = allM (checkCodePrealloc tab . (^. functionCode)) (HashMap.elems (tab ^. infoFunctions))
|
||||
sb = allM (checkCodePrealloc (computeMaxArgsNum tab) tab . (^. functionCode)) (HashMap.elems (tab ^. infoFunctions))
|
||||
|
@ -23,7 +23,8 @@ data Limits = Limits
|
||||
_limitsMaxStackDelta :: Int,
|
||||
_limitsMaxFunctionAlloc :: Int,
|
||||
_limitsDispatchStackSize :: Int,
|
||||
_limitsBuiltinUIDsNum :: Int
|
||||
_limitsBuiltinUIDsNum :: Int,
|
||||
_limitsSpecialisedApply :: Int
|
||||
}
|
||||
deriving stock (Eq, Show)
|
||||
|
||||
@ -45,7 +46,8 @@ getLimits tgt debug = case tgt of
|
||||
_limitsMaxStackDelta = 16368,
|
||||
_limitsMaxFunctionAlloc = 16368,
|
||||
_limitsDispatchStackSize = 4,
|
||||
_limitsBuiltinUIDsNum = 8
|
||||
_limitsBuiltinUIDsNum = 8,
|
||||
_limitsSpecialisedApply = 3
|
||||
}
|
||||
TargetCNative64 ->
|
||||
Limits
|
||||
@ -59,7 +61,8 @@ getLimits tgt debug = case tgt of
|
||||
_limitsMaxStackDelta = 8184,
|
||||
_limitsMaxFunctionAlloc = 8184,
|
||||
_limitsDispatchStackSize = 4,
|
||||
_limitsBuiltinUIDsNum = 8
|
||||
_limitsBuiltinUIDsNum = 8,
|
||||
_limitsSpecialisedApply = 3
|
||||
}
|
||||
TargetGeb ->
|
||||
defaultLimits
|
||||
@ -83,5 +86,6 @@ defaultLimits =
|
||||
_limitsMaxStackDelta = maxInt,
|
||||
_limitsMaxFunctionAlloc = maxInt,
|
||||
_limitsDispatchStackSize = maxInt,
|
||||
_limitsBuiltinUIDsNum = maxInt
|
||||
_limitsBuiltinUIDsNum = maxInt,
|
||||
_limitsSpecialisedApply = 0
|
||||
}
|
||||
|
@ -118,7 +118,11 @@ fromReg lims tab =
|
||||
mainBody :: [Statement]
|
||||
mainBody =
|
||||
argDecls
|
||||
++ [StatementExpr $ macroCall "JUVIX_PROLOGUE" [integer (info ^. Reg.extraInfoMaxArgsNum)]]
|
||||
++ [ StatementExpr $
|
||||
macroCall
|
||||
"JUVIX_PROLOGUE"
|
||||
[integer (info ^. Reg.extraInfoMaxArgsNum + info ^. Reg.extraInfoMaxCallClosuresArgsNum)]
|
||||
]
|
||||
++ makeCStrings
|
||||
++ [ stmtAssign (ExpressionVar "juvix_constrs_num") (integer (info ^. Reg.extraInfoConstrsNum)),
|
||||
stmtAssign (ExpressionVar "juvix_constr_info") (ExpressionVar "juvix_constr_info_array"),
|
||||
@ -422,32 +426,55 @@ fromRegInstr bNoStack info = \case
|
||||
++ stmtsPopVars _instrCallLiveVars
|
||||
|
||||
fromTailCallClosures :: Reg.InstrCallClosures -> [Statement]
|
||||
fromTailCallClosures Reg.InstrCallClosures {..} =
|
||||
stmtsPush (reverse (map fromValue _instrCallClosuresArgs))
|
||||
++ [ StatementExpr $
|
||||
macroCall
|
||||
"TAIL_CALL_CLOSURES"
|
||||
[ fromVarRef _instrCallClosuresValue,
|
||||
integer (length _instrCallClosuresArgs)
|
||||
]
|
||||
]
|
||||
fromTailCallClosures Reg.InstrCallClosures {..}
|
||||
| argsNum <= 3 =
|
||||
stmtsAssignCArgs _instrCallClosuresValue _instrCallClosuresArgs
|
||||
++ [ StatementExpr $
|
||||
macroCall
|
||||
("TAIL_APPLY_" <> show argsNum)
|
||||
[fromVarRef _instrCallClosuresValue]
|
||||
]
|
||||
| otherwise =
|
||||
stmtsAssignCArgs _instrCallClosuresValue _instrCallClosuresArgs
|
||||
++ [ StatementExpr $
|
||||
macroCall
|
||||
"TAIL_APPLY"
|
||||
[ fromVarRef _instrCallClosuresValue,
|
||||
integer argsNum
|
||||
]
|
||||
]
|
||||
where
|
||||
argsNum = length _instrCallClosuresArgs
|
||||
|
||||
fromCallClosures :: Reg.InstrCallClosures -> Sem r [Statement]
|
||||
fromCallClosures Reg.InstrCallClosures {..} = do
|
||||
lab <- freshLabel
|
||||
return $
|
||||
stmtsPushVars _instrCallClosuresLiveVars
|
||||
++ stmtsPush (reverse (map fromValue _instrCallClosuresArgs))
|
||||
++ [ StatementExpr $
|
||||
macroCall
|
||||
"CALL_CLOSURES"
|
||||
[ fromVarRef _instrCallClosuresValue,
|
||||
integer (length _instrCallClosuresArgs),
|
||||
ExpressionVar lab
|
||||
],
|
||||
++ stmtsAssignCArgs _instrCallClosuresValue _instrCallClosuresArgs
|
||||
++ [ call lab,
|
||||
stmtAssign (fromVarRef _instrCallClosuresResult) (ExpressionVar "juvix_result")
|
||||
]
|
||||
++ stmtsPopVars _instrCallClosuresLiveVars
|
||||
where
|
||||
argsNum = length _instrCallClosuresArgs
|
||||
call lab =
|
||||
if
|
||||
| argsNum <= 3 ->
|
||||
StatementExpr $
|
||||
macroCall
|
||||
("APPLY_" <> show argsNum)
|
||||
[ fromVarRef _instrCallClosuresValue,
|
||||
ExpressionVar lab
|
||||
]
|
||||
| otherwise ->
|
||||
StatementExpr $
|
||||
macroCall
|
||||
"APPLY"
|
||||
[ fromVarRef _instrCallClosuresValue,
|
||||
integer argsNum,
|
||||
ExpressionVar lab
|
||||
]
|
||||
|
||||
fromBranch :: Reg.InstrBranch -> Sem r [Statement]
|
||||
fromBranch Reg.InstrBranch {..} = do
|
||||
|
@ -59,6 +59,41 @@ computeMaxStackHeight lims = maximum . map go
|
||||
)
|
||||
(maybe 0 (computeMaxStackHeight lims) _instrCaseDefault)
|
||||
|
||||
computeMaxCallClosuresArgsNum :: Code -> Int
|
||||
computeMaxCallClosuresArgsNum = maximum . map go
|
||||
where
|
||||
go :: Instruction -> Int
|
||||
go = \case
|
||||
Nop -> 0
|
||||
Binop {} -> 0
|
||||
Show {} -> 0
|
||||
StrToInt {} -> 0
|
||||
Assign {} -> 0
|
||||
Trace {} -> 0
|
||||
Dump -> 0
|
||||
Failure {} -> 0
|
||||
Prealloc InstrPrealloc {} -> 0
|
||||
Alloc {} -> 0
|
||||
AllocClosure {} -> 0
|
||||
ExtendClosure {} -> 0
|
||||
Call InstrCall {} -> 0
|
||||
CallClosures InstrCallClosures {..} ->
|
||||
length _instrCallClosuresArgs
|
||||
Return {} -> 0
|
||||
Branch InstrBranch {..} ->
|
||||
max
|
||||
(computeMaxCallClosuresArgsNum _instrBranchTrue)
|
||||
(computeMaxCallClosuresArgsNum _instrBranchFalse)
|
||||
Case InstrCase {..} ->
|
||||
max
|
||||
( maximum
|
||||
( map
|
||||
(computeMaxCallClosuresArgsNum . (^. caseBranchCode))
|
||||
_instrCaseBranches
|
||||
)
|
||||
)
|
||||
(maybe 0 computeMaxCallClosuresArgsNum _instrCaseDefault)
|
||||
|
||||
computeStringMap :: HashMap Text Int -> Code -> HashMap Text Int
|
||||
computeStringMap strs = snd . run . execState (HashMap.size strs, strs) . mapM go
|
||||
where
|
||||
@ -119,6 +154,7 @@ data ExtraInfo = ExtraInfo
|
||||
_extraInfoStringMap :: HashMap Text Int,
|
||||
_extraInfoMaxStackHeight :: HashMap Symbol Int,
|
||||
_extraInfoMaxArgsNum :: Int,
|
||||
_extraInfoMaxCallClosuresArgsNum :: Int,
|
||||
_extraInfoConstrsNum :: Int,
|
||||
_extraInfoFunctionsNum :: Int
|
||||
}
|
||||
@ -158,6 +194,11 @@ computeExtraInfo lims tab =
|
||||
(tab ^. infoFunctions),
|
||||
_extraInfoMaxArgsNum =
|
||||
maximum (map (^. functionArgsNum) (HashMap.elems (tab ^. infoFunctions))),
|
||||
_extraInfoMaxCallClosuresArgsNum =
|
||||
maximum
|
||||
( lims ^. limitsSpecialisedApply
|
||||
: map (computeMaxCallClosuresArgsNum . (^. functionCode)) (HashMap.elems (tab ^. infoFunctions))
|
||||
),
|
||||
_extraInfoConstrsNum =
|
||||
length (userConstrs tab) + lims ^. limitsBuiltinUIDsNum,
|
||||
_extraInfoFunctionsNum =
|
||||
|
@ -364,5 +364,10 @@ tests =
|
||||
"Test061: Traits"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test061.juvix")
|
||||
$(mkRelFile "out/test061.out")
|
||||
$(mkRelFile "out/test061.out"),
|
||||
posTest
|
||||
"Test062: Overapplication"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test062.juvix")
|
||||
$(mkRelFile "out/test062.out")
|
||||
]
|
||||
|
@ -133,5 +133,15 @@ tests =
|
||||
"Test020: Higher-order function composition"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test020.c")
|
||||
$(mkRelFile "out/test020.out")
|
||||
$(mkRelFile "out/test020.out"),
|
||||
PosTest
|
||||
"Test021: Higher-order functions with apply"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test021.c")
|
||||
$(mkRelFile "out/test021.out"),
|
||||
PosTest
|
||||
"Test022: Dynamic closure extension with apply"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test022.c")
|
||||
$(mkRelFile "out/test022.out")
|
||||
]
|
||||
|
1
tests/Compilation/positive/out/test062.out
Normal file
1
tests/Compilation/positive/out/test062.out
Normal file
@ -0,0 +1 @@
|
||||
1
|
12
tests/Compilation/positive/test062.juvix
Normal file
12
tests/Compilation/positive/test062.juvix
Normal file
@ -0,0 +1,12 @@
|
||||
-- Overapplication
|
||||
module test062;
|
||||
|
||||
import Stdlib.Data.Nat open;
|
||||
|
||||
{-# inline: false #-}
|
||||
I {A} (x : A) : A := x;
|
||||
|
||||
{-# inline: false #-}
|
||||
I' {A} (x : A) : A := x;
|
||||
|
||||
main : Nat := I' (I I I I 1);
|
1
tests/runtime/positive/out/test021.out
Normal file
1
tests/runtime/positive/out/test021.out
Normal file
@ -0,0 +1 @@
|
||||
4
|
3
tests/runtime/positive/out/test022.out
Normal file
3
tests/runtime/positive/out/test022.out
Normal file
@ -0,0 +1,3 @@
|
||||
36
|
||||
22
|
||||
8
|
@ -2,11 +2,8 @@
|
||||
|
||||
#include <juvix/api.h>
|
||||
|
||||
#define JUVIX_DECL_ARGS UNUSED DECL_ARG(0)
|
||||
|
||||
int main() {
|
||||
JUVIX_DECL_ARGS;
|
||||
JUVIX_PROLOGUE(1);
|
||||
JUVIX_PROLOGUE(3);
|
||||
juvix_result = make_smallint(789);
|
||||
JUVIX_EPILOGUE;
|
||||
return 0;
|
||||
|
@ -2,11 +2,8 @@
|
||||
|
||||
#include <juvix/api.h>
|
||||
|
||||
#define JUVIX_DECL_ARGS UNUSED DECL_ARG(0)
|
||||
|
||||
int main() {
|
||||
JUVIX_DECL_ARGS;
|
||||
JUVIX_PROLOGUE(1);
|
||||
JUVIX_PROLOGUE(3);
|
||||
DECL_TMP(0);
|
||||
DECL_TMP(1);
|
||||
DECL_TMP(2);
|
||||
|
@ -2,16 +2,13 @@
|
||||
|
||||
#include <juvix/api.h>
|
||||
|
||||
#define JUVIX_DECL_ARGS UNUSED DECL_ARG(0)
|
||||
|
||||
#define CONSTRS_NUM (BUILTIN_UIDS_NUM + 1)
|
||||
|
||||
static constr_info_t juvix_constr_info_array[CONSTRS_NUM] = {
|
||||
BUILTIN_UIDS_INFO, {"box", 0, APP_FIXITY}};
|
||||
|
||||
int main() {
|
||||
JUVIX_DECL_ARGS;
|
||||
JUVIX_PROLOGUE(1);
|
||||
JUVIX_PROLOGUE(3);
|
||||
|
||||
juvix_constrs_num = CONSTRS_NUM;
|
||||
juvix_constr_info = juvix_constr_info_array;
|
||||
|
@ -2,16 +2,13 @@
|
||||
|
||||
#include <juvix/api.h>
|
||||
|
||||
#define JUVIX_DECL_ARGS \
|
||||
DECL_ARG(0); \
|
||||
DECL_ARG(1)
|
||||
|
||||
static constr_info_t juvix_constr_info_array[BUILTIN_UIDS_NUM] = {
|
||||
BUILTIN_UIDS_INFO};
|
||||
|
||||
int main() {
|
||||
JUVIX_DECL_ARGS;
|
||||
JUVIX_PROLOGUE(2);
|
||||
DECL_ARG(0);
|
||||
DECL_ARG(1);
|
||||
JUVIX_PROLOGUE(3);
|
||||
|
||||
juvix_constrs_num = BUILTIN_UIDS_NUM;
|
||||
juvix_constr_info = juvix_constr_info_array;
|
||||
|
@ -2,10 +2,6 @@
|
||||
|
||||
#include <juvix/api.h>
|
||||
|
||||
#define JUVIX_DECL_ARGS \
|
||||
DECL_REG_ARG(0); \
|
||||
DECL_REG_ARG(1)
|
||||
|
||||
#define CONSTRS_NUM (BUILTIN_UIDS_NUM + 2)
|
||||
|
||||
static constr_info_t juvix_constr_info_array[CONSTRS_NUM] = {
|
||||
@ -17,8 +13,9 @@ static constr_info_t juvix_constr_info_array[CONSTRS_NUM] = {
|
||||
#define CONSTR_NIL MAKE_HEADER(UID_NIL, 0)
|
||||
|
||||
int main() {
|
||||
JUVIX_DECL_ARGS;
|
||||
JUVIX_PROLOGUE(2);
|
||||
DECL_REG_ARG(0);
|
||||
DECL_REG_ARG(1);
|
||||
JUVIX_PROLOGUE(3);
|
||||
|
||||
juvix_constrs_num = CONSTRS_NUM;
|
||||
juvix_constr_info = juvix_constr_info_array;
|
||||
|
@ -2,16 +2,13 @@
|
||||
|
||||
#include <juvix/api.h>
|
||||
|
||||
#define JUVIX_DECL_ARGS \
|
||||
DECL_ARG(0); \
|
||||
DECL_ARG(1)
|
||||
|
||||
static constr_info_t juvix_constr_info_array[BUILTIN_UIDS_NUM] = {
|
||||
BUILTIN_UIDS_INFO};
|
||||
|
||||
int main() {
|
||||
JUVIX_DECL_ARGS;
|
||||
JUVIX_PROLOGUE(2);
|
||||
DECL_ARG(0);
|
||||
DECL_ARG(1);
|
||||
JUVIX_PROLOGUE(3);
|
||||
|
||||
juvix_constrs_num = BUILTIN_UIDS_NUM;
|
||||
juvix_constr_info = juvix_constr_info_array;
|
||||
|
@ -2,16 +2,13 @@
|
||||
|
||||
#include <juvix/api.h>
|
||||
|
||||
#define JUVIX_DECL_ARGS \
|
||||
DECL_ARG(0); \
|
||||
DECL_ARG(1)
|
||||
|
||||
static constr_info_t juvix_constr_info_array[BUILTIN_UIDS_NUM] = {
|
||||
BUILTIN_UIDS_INFO};
|
||||
|
||||
int main() {
|
||||
JUVIX_DECL_ARGS;
|
||||
JUVIX_PROLOGUE(2);
|
||||
DECL_ARG(0);
|
||||
DECL_ARG(1);
|
||||
JUVIX_PROLOGUE(3);
|
||||
|
||||
juvix_constrs_num = BUILTIN_UIDS_NUM;
|
||||
juvix_constr_info = juvix_constr_info_array;
|
||||
|
101
tests/runtime/positive/test021.c
Normal file
101
tests/runtime/positive/test021.c
Normal file
@ -0,0 +1,101 @@
|
||||
/* Higher-order functions with apply */
|
||||
|
||||
#include <juvix/api.h>
|
||||
|
||||
#define JUVIX_DECL_ARGS \
|
||||
DECL_ARG(0); \
|
||||
DECL_ARG(1); \
|
||||
DECL_ARG(2);
|
||||
|
||||
static constr_info_t juvix_constr_info_array[BUILTIN_UIDS_NUM] = {
|
||||
BUILTIN_UIDS_INFO};
|
||||
|
||||
int main() {
|
||||
JUVIX_DECL_ARGS;
|
||||
JUVIX_PROLOGUE(3);
|
||||
|
||||
juvix_constrs_num = BUILTIN_UIDS_NUM;
|
||||
juvix_constr_info = juvix_constr_info_array;
|
||||
|
||||
CALL(0, juvix_function_main, juvix_label_0);
|
||||
goto juvix_program_end;
|
||||
|
||||
JUVIX_FUNCTION(juvix_function_S, 3 + DISPATCH_STACK_SIZE);
|
||||
{
|
||||
STACK_PUSH(ARG(0));
|
||||
STACK_PUSH(ARG(2));
|
||||
ASSIGN_CARGS(ARG(1), { CARG(juvix_closure_nargs) = ARG(2); });
|
||||
APPLY_1(ARG(1), juvix_label_1);
|
||||
STACK_POP(ARG(2));
|
||||
STACK_POP(ARG(0));
|
||||
ASSIGN_CARGS(ARG(0), {
|
||||
CARG(juvix_closure_nargs) = ARG(2);
|
||||
CARG(juvix_closure_nargs + 1) = juvix_result;
|
||||
});
|
||||
TAIL_APPLY_2(ARG(0));
|
||||
}
|
||||
|
||||
juvix_closure_K:
|
||||
ARG(0) = CARG(0);
|
||||
ARG(1) = CARG(1);
|
||||
JUVIX_FUNCTION_NS(juvix_function_K);
|
||||
{
|
||||
juvix_result = ARG(0);
|
||||
RETURN_NS;
|
||||
}
|
||||
|
||||
juvix_closure_I:
|
||||
ARG(0) = CARG(0);
|
||||
JUVIX_FUNCTION(juvix_function_I, 2);
|
||||
{
|
||||
STACK_PUSH(ARG(0));
|
||||
PREALLOC(1 + CLOSURE_SKIP, {}, {});
|
||||
ALLOC_CLOSURE(ARG(0), 0, LABEL_ADDR(juvix_closure_K), 0, 2);
|
||||
ARG(1) = ARG(0);
|
||||
STACK_POP(ARG(2));
|
||||
TAIL_CALL(0, juvix_function_S);
|
||||
}
|
||||
|
||||
JUVIX_FUNCTION(juvix_function_main, MAX_STACK_DELTA);
|
||||
{
|
||||
DECL_TMP(0); // holds 1
|
||||
DECL_TMP(1); // holds calloc I 0
|
||||
DECL_TMP(2); // holds 2
|
||||
ARG(0) = make_smallint(1);
|
||||
CALL(0, juvix_function_I, juvix_label_2);
|
||||
TMP(0) = juvix_result;
|
||||
ALLOC_CLOSURE(TMP(1), 0, LABEL_ADDR(juvix_closure_I), 0, 1);
|
||||
STACK_PUSH(TMP(0));
|
||||
STACK_PUSH(TMP(1));
|
||||
ARG(0) = TMP(1);
|
||||
CALL(0, juvix_function_I, juvix_label_3);
|
||||
TMP(1) = STACK_TOP;
|
||||
ASSIGN_CARGS(TMP(1), { CARG(juvix_closure_nargs) = juvix_result; });
|
||||
CALL_CLOSURE(TMP(1), juvix_label_4);
|
||||
STACK_POP(TMP(1));
|
||||
STACK_POP(TMP(0));
|
||||
STACK_PUSH(TMP(1));
|
||||
ASSIGN_CARGS(juvix_result, { CARG(juvix_closure_nargs) = TMP(0); });
|
||||
CALL_CLOSURE(juvix_result, juvix_label_5);
|
||||
STACK_POP(TMP(1));
|
||||
JUVIX_INT_ADD(TMP(2), TMP(0), juvix_result);
|
||||
STACK_PUSH(TMP(2));
|
||||
STACK_PUSH(TMP(2));
|
||||
STACK_PUSH(TMP(1));
|
||||
STACK_PUSH(TMP(1));
|
||||
STACK_PUSH(TMP(1));
|
||||
STACK_PUSH(TMP(1));
|
||||
STACK_PUSH(TMP(1));
|
||||
STACK_PUSH(TMP(1));
|
||||
STACK_PUSH(TMP(1));
|
||||
STACK_PUSH(TMP(1));
|
||||
CALL_CLOSURES(TMP(1), 9, juvix_label_6);
|
||||
STACK_POP(TMP(2));
|
||||
JUVIX_INT_ADD(TMP(1), juvix_result, TMP(2));
|
||||
juvix_result = TMP(1);
|
||||
RETURN;
|
||||
}
|
||||
|
||||
JUVIX_EPILOGUE;
|
||||
return 0;
|
||||
}
|
110
tests/runtime/positive/test022.c
Normal file
110
tests/runtime/positive/test022.c
Normal file
@ -0,0 +1,110 @@
|
||||
/* Dynamic closure extension with apply */
|
||||
|
||||
#include <juvix/api.h>
|
||||
|
||||
#define JUVIX_DECL_ARGS \
|
||||
DECL_REG_ARG(0); \
|
||||
DECL_REG_ARG(1); \
|
||||
DECL_REG_ARG(2)
|
||||
|
||||
static constr_info_t juvix_constr_info_array[BUILTIN_UIDS_NUM] = {
|
||||
BUILTIN_UIDS_INFO};
|
||||
|
||||
int main() {
|
||||
JUVIX_DECL_ARGS;
|
||||
JUVIX_PROLOGUE(3);
|
||||
|
||||
juvix_constrs_num = BUILTIN_UIDS_NUM;
|
||||
juvix_constr_info = juvix_constr_info_array;
|
||||
|
||||
CALL(0, juvix_function_main, juvix_label_0);
|
||||
goto juvix_program_end;
|
||||
|
||||
juvix_closure_f:
|
||||
ARG(0) = CARG(0);
|
||||
ARG(1) = CARG(1);
|
||||
ARG(2) = CARG(2);
|
||||
JUVIX_FUNCTION_NS(juvix_function_f);
|
||||
{
|
||||
DECL_TMP(0);
|
||||
JUVIX_INT_ADD(TMP(0), ARG(1), ARG(2));
|
||||
JUVIX_INT_MUL(juvix_result, ARG(0), TMP(0));
|
||||
RETURN_NS;
|
||||
}
|
||||
|
||||
juvix_closure_app:
|
||||
ARG(0) = CARG(0);
|
||||
ARG(1) = CARG(1);
|
||||
JUVIX_FUNCTION_NS(juvix_function_app);
|
||||
{
|
||||
ASSIGN_CARGS(ARG(0), { CARG(juvix_closure_nargs) = ARG(1); });
|
||||
TAIL_CALL_CLOSURE_NS(ARG(0));
|
||||
}
|
||||
|
||||
juvix_closure_g:
|
||||
ARG(0) = CARG(0);
|
||||
JUVIX_FUNCTION(juvix_function_g, 2 + DISPATCH_STACK_SIZE);
|
||||
{
|
||||
ASSIGN_CARGS(ARG(0), {
|
||||
CARG(juvix_closure_nargs) = make_smallint(2);
|
||||
CARG(juvix_closure_nargs + 1) = make_smallint(1);
|
||||
});
|
||||
TAIL_APPLY_2(ARG(0));
|
||||
}
|
||||
|
||||
JUVIX_FUNCTION(juvix_function_h, 1 + DISPATCH_STACK_SIZE);
|
||||
{
|
||||
ASSIGN_CARGS(ARG(0), { CARG(juvix_closure_nargs) = ARG(1); });
|
||||
TAIL_APPLY_1(ARG(0));
|
||||
}
|
||||
|
||||
juvix_closure_inc:
|
||||
ARG(0) = CARG(0);
|
||||
JUVIX_FUNCTION_NS(juvix_function_inc);
|
||||
{
|
||||
JUVIX_INT_ADD(juvix_result, ARG(0), make_smallint(1));
|
||||
RETURN_NS;
|
||||
}
|
||||
|
||||
JUVIX_FUNCTION(juvix_function_main, MAX_STACK_DELTA);
|
||||
{
|
||||
DECL_TMP(0);
|
||||
DECL_TMP(1);
|
||||
ALLOC_CLOSURE(TMP(0), 0, LABEL_ADDR(juvix_closure_f), 0, 3);
|
||||
ASSIGN_CARGS(TMP(0), {
|
||||
CARG(juvix_closure_nargs) = make_smallint(3);
|
||||
CARG(juvix_closure_nargs + 1) = make_smallint(2);
|
||||
});
|
||||
APPLY_2(TMP(0), juvix_label_1);
|
||||
ALLOC_CLOSURE(TMP(0), 0, LABEL_ADDR(juvix_closure_app), 0, 2);
|
||||
ASSIGN_CARGS(TMP(0), {
|
||||
CARG(juvix_closure_nargs) = juvix_result;
|
||||
CARG(juvix_closure_nargs + 1) = make_smallint(10);
|
||||
});
|
||||
APPLY_2(TMP(0), juvix_label_2);
|
||||
JUVIX_TRACE(juvix_result);
|
||||
|
||||
ALLOC_CLOSURE(TMP(0), 0, LABEL_ADDR(juvix_closure_f), 0, 3);
|
||||
ALLOC_CLOSURE(TMP(1), 0, LABEL_ADDR(juvix_closure_g), 0, 1);
|
||||
ASSIGN_CARGS(TMP(1), {
|
||||
CARG(juvix_closure_nargs) = TMP(0);
|
||||
CARG(juvix_closure_nargs + 1) = make_smallint(10);
|
||||
});
|
||||
APPLY_2(TMP(1), juvix_label_3);
|
||||
JUVIX_TRACE(juvix_result);
|
||||
|
||||
ALLOC_CLOSURE(ARG(1), 0, LABEL_ADDR(juvix_closure_inc), 0, 1);
|
||||
ALLOC_CLOSURE(ARG(0), 0, LABEL_ADDR(juvix_closure_app), 0, 2);
|
||||
CALL(0, juvix_function_h, juvix_label_4);
|
||||
ASSIGN_CARGS(juvix_result,
|
||||
{ CARG(juvix_closure_nargs) = make_smallint(7); });
|
||||
APPLY_1(juvix_result, juvix_label_5);
|
||||
JUVIX_TRACE(juvix_result);
|
||||
|
||||
juvix_result = OBJ_VOID;
|
||||
RETURN;
|
||||
}
|
||||
|
||||
JUVIX_EPILOGUE;
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user