1
1
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:
Łukasz Czajka 2023-09-29 14:20:00 +02:00 committed by GitHub
parent 7c3b70459b
commit 1260853583
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 610 additions and 72 deletions

View File

@ -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 \

View File

@ -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>

View 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

View File

@ -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; \

View File

@ -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))

View File

@ -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
}

View File

@ -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

View File

@ -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 =

View File

@ -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")
]

View File

@ -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")
]

View File

@ -0,0 +1 @@
1

View 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);

View File

@ -0,0 +1 @@
4

View File

@ -0,0 +1,3 @@
36
22
8

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View 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;
}

View 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;
}