From 1acd2d1de70b4980243a5883ed95ff482a178693 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Mon, 9 Jul 2018 21:24:22 -0400 Subject: [PATCH] Inlining for all built in comparators. --- src/core/asm.c | 5 +++ src/core/bytecode.c | 7 ++- src/core/cfuns.c | 100 +++++++++++++++++++++++++++++++++++++++--- src/core/compile.h | 12 +++++ src/core/corelib.c | 18 +++++--- src/core/math.c | 27 ------------ src/core/vm.c | 37 ++++++++++++++++ src/include/dst/dst.h | 5 +++ 8 files changed, 172 insertions(+), 39 deletions(-) diff --git a/src/core/asm.c b/src/core/asm.c index 37ccb379..ec90b02c 100644 --- a/src/core/asm.c +++ b/src/core/asm.c @@ -76,6 +76,7 @@ static const DstInstructionDef dst_ops[] = { {"eq", DOP_EQUALS}, {"eqi", DOP_EQUALS_INTEGER}, {"eqim", DOP_EQUALS_IMMEDIATE}, + {"eqn", DOP_NUMERIC_EQUAL}, {"eqr", DOP_EQUALS_REAL}, {"err", DOP_ERROR}, {"get", DOP_GET}, @@ -83,7 +84,9 @@ static const DstInstructionDef dst_ops[] = { {"gt", DOP_GREATER_THAN}, {"gti", DOP_GREATER_THAN_INTEGER}, {"gtim", DOP_GREATER_THAN_IMMEDIATE}, + {"gtn", DOP_NUMERIC_GREATER_THAN}, {"gtr", DOP_GREATER_THAN_REAL}, + {"gten", DOP_NUMERIC_GREATER_THAN_EQUAL}, {"gter", DOP_GREATER_THAN_EQUAL_REAL}, {"jmp", DOP_JUMP}, {"jmpif", DOP_JUMP_IF}, @@ -99,7 +102,9 @@ static const DstInstructionDef dst_ops[] = { {"lt", DOP_LESS_THAN}, {"lti", DOP_LESS_THAN_INTEGER}, {"ltim", DOP_LESS_THAN_IMMEDIATE}, + {"ltn", DOP_NUMERIC_LESS_THAN}, {"ltr", DOP_LESS_THAN_REAL}, + {"lten", DOP_NUMERIC_LESS_THAN_EQUAL}, {"lter", DOP_LESS_THAN_EQUAL_REAL}, {"mkarr", DOP_MAKE_ARRAY}, {"mkbuf", DOP_MAKE_BUFFER}, diff --git a/src/core/bytecode.c b/src/core/bytecode.c index ce88fd75..14f59a42 100644 --- a/src/core/bytecode.c +++ b/src/core/bytecode.c @@ -102,7 +102,12 @@ enum DstInstructionType dst_instructions[DOP_INSTRUCTION_COUNT] = { DIT_S, /* DOP_MAKE_TUPLE */ DIT_S, /* DOP_MAKE_STRUCT */ DIT_S, /* DOP_MAKE_TABLE */ - DIT_S /* DOP_MAKE_STRING */ + DIT_S, /* DOP_MAKE_STRING */ + DIT_SSS, /* DOP_NUMERIC_LESS_THAN */ + DIT_SSS, /* DOP_NUMERIC_LESS_THAN_EQUAL */ + DIT_SSS, /* DOP_NUMERIC_GREATER_THAN */ + DIT_SSS, /* DOP_NUMERIC_GREATER_THAN_EQUAL */ + DIT_SSS /* DOP_NUMERIC_EQUAL */ }; /* Verify some bytecode */ diff --git a/src/core/cfuns.c b/src/core/cfuns.c index 40ba424f..ae1ba1f5 100644 --- a/src/core/cfuns.c +++ b/src/core/cfuns.c @@ -118,7 +118,7 @@ static DstSlot do_apply1(DstFopts opts, DstSlot *args) { return target; } -/* Varidadic operatros specialization */ +/* Varidadic operators specialization */ static DstSlot do_add(DstFopts opts, DstSlot *args) { return opreduce(opts, args, DOP_ADD, dst_wrap_integer(0)); @@ -154,6 +154,82 @@ static DstSlot do_bnot(DstFopts opts, DstSlot *args) { return genericSS(opts, DOP_BNOT, args[0]); } +/* Specialization for comparators */ +static DstSlot compreduce( + DstFopts opts, + DstSlot *args, + int op, + int invert) { + DstCompiler *c = opts.compiler; + int32_t i, len; + len = dst_v_count(args); + int32_t *labels = NULL; + DstSlot t; + if (len < 2) { + return invert + ? dstc_cslot(dst_wrap_false()) + : dstc_cslot(dst_wrap_true()); + } + t = dstc_gettarget(opts); + for (i = 1; i < len; i++) { + dstc_emit_sss(c, op, t, args[i - 1], args[i], 1); + if (i != (len - 1)) { + int32_t label = dstc_emit_si(c, DOP_JUMP_IF_NOT, t, 0, 1); + dst_v_push(labels, label); + } + } + int32_t end = dst_v_count(c->buffer); + if (invert) { + dstc_emit_si(c, DOP_JUMP_IF, t, 3, 0); + dstc_emit_s(c, DOP_LOAD_TRUE, t, 1); + dstc_emit(c, DOP_JUMP | (2 << 8)); + dstc_emit_s(c, DOP_LOAD_FALSE, t, 1); + } + for (i = 0; i < dst_v_count(labels); i++) { + int32_t label = labels[i]; + c->buffer[label] |= ((end - label) << 16); + } + dst_v_free(labels); + return t; +} + +static DstSlot do_order_gt(DstFopts opts, DstSlot *args) { + return compreduce(opts, args, DOP_GREATER_THAN, 0); +} +static DstSlot do_order_lt(DstFopts opts, DstSlot *args) { + return compreduce(opts, args, DOP_LESS_THAN, 0); +} +static DstSlot do_order_gte(DstFopts opts, DstSlot *args) { + return compreduce(opts, args, DOP_LESS_THAN, 1); +} +static DstSlot do_order_lte(DstFopts opts, DstSlot *args) { + return compreduce(opts, args, DOP_GREATER_THAN, 1); +} +static DstSlot do_order_eq(DstFopts opts, DstSlot *args) { + return compreduce(opts, args, DOP_EQUALS, 0); +} +static DstSlot do_order_neq(DstFopts opts, DstSlot *args) { + return compreduce(opts, args, DOP_EQUALS, 1); +} +static DstSlot do_gt(DstFopts opts, DstSlot *args) { + return compreduce(opts, args, DOP_NUMERIC_GREATER_THAN, 0); +} +static DstSlot do_lt(DstFopts opts, DstSlot *args) { + return compreduce(opts, args, DOP_NUMERIC_LESS_THAN, 0); +} +static DstSlot do_gte(DstFopts opts, DstSlot *args) { + return compreduce(opts, args, DOP_NUMERIC_GREATER_THAN_EQUAL, 0); +} +static DstSlot do_lte(DstFopts opts, DstSlot *args) { + return compreduce(opts, args, DOP_NUMERIC_LESS_THAN_EQUAL, 0); +} +static DstSlot do_eq(DstFopts opts, DstSlot *args) { + return compreduce(opts, args, DOP_NUMERIC_EQUAL, 0); +} +static DstSlot do_neq(DstFopts opts, DstSlot *args) { + return compreduce(opts, args, DOP_NUMERIC_EQUAL, 1); +} + /* Arranged by tag */ static const DstFunOptimizer optimizers[] = { {fixarity0, do_debug}, @@ -174,14 +250,28 @@ static const DstFunOptimizer optimizers[] = { {NULL, do_lshift}, {NULL, do_rshift}, {NULL, do_rshiftu}, - {fixarity1, do_bnot} + {fixarity1, do_bnot}, + {NULL, do_order_gt}, + {NULL, do_order_lt}, + {NULL, do_order_gte}, + {NULL, do_order_lte}, + {NULL, do_order_eq}, + {NULL, do_order_neq}, + {NULL, do_gt}, + {NULL, do_lt}, + {NULL, do_gte}, + {NULL, do_lte}, + {NULL, do_eq}, + {NULL, do_neq} }; const DstFunOptimizer *dstc_funopt(uint32_t flags) { uint32_t tag = flags & DST_FUNCDEF_FLAG_TAG; - if (tag == 0 || tag >= - ((sizeof(optimizers)/sizeof(uint32_t) - 1))) + if (tag == 0) return NULL; - return optimizers + tag - 1; + uint32_t index = tag - 1; + if (index >= (sizeof(optimizers)/sizeof(optimizers[0]))) + return NULL; + return optimizers + index; } diff --git a/src/core/compile.h b/src/core/compile.h index 50481816..9b4ae9a3 100644 --- a/src/core/compile.h +++ b/src/core/compile.h @@ -46,6 +46,18 @@ #define DST_FUN_RSHIFT 17 #define DST_FUN_RSHIFTU 18 #define DST_FUN_BNOT 19 +#define DST_FUN_ORDER_GT 20 +#define DST_FUN_ORDER_LT 21 +#define DST_FUN_ORDER_GTE 22 +#define DST_FUN_ORDER_LTE 23 +#define DST_FUN_ORDER_EQ 24 +#define DST_FUN_ORDER_NEQ 25 +#define DST_FUN_GT 26 +#define DST_FUN_LT 27 +#define DST_FUN_GTE 28 +#define DST_FUN_LTE 29 +#define DST_FUN_EQ 30 +#define DST_FUN_NEQ 31 /* Compiler typedefs */ typedef struct DstCompiler DstCompiler; diff --git a/src/core/corelib.c b/src/core/corelib.c index 6ec94db3..d940ce25 100644 --- a/src/core/corelib.c +++ b/src/core/corelib.c @@ -527,12 +527,18 @@ DstTable *dst_core_env(void) { templatize_varop(env, DST_FUN_RSHIFTU, ">>>", 1, 1, DOP_SHIFT_RIGHT_UNSIGNED); /* Variadic comparators */ - templatize_comparator(env, 0, "order>", 0, DOP_GREATER_THAN); - templatize_comparator(env, 0, "order<", 0, DOP_LESS_THAN); - templatize_comparator(env, 0, "order>=", 1, DOP_LESS_THAN); - templatize_comparator(env, 0, "order<=", 1, DOP_GREATER_THAN); - templatize_comparator(env, 0, "=", 0, DOP_EQUALS); - templatize_comparator(env, 0, "not=", 1, DOP_EQUALS); + templatize_comparator(env, DST_FUN_ORDER_GT, "order>", 0, DOP_GREATER_THAN); + templatize_comparator(env, DST_FUN_ORDER_LT, "order<", 0, DOP_LESS_THAN); + templatize_comparator(env, DST_FUN_ORDER_GTE, "order>=", 1, DOP_LESS_THAN); + templatize_comparator(env, DST_FUN_ORDER_LTE, "order<=", 1, DOP_GREATER_THAN); + templatize_comparator(env, DST_FUN_ORDER_EQ, "=", 0, DOP_EQUALS); + templatize_comparator(env, DST_FUN_ORDER_NEQ, "not=", 1, DOP_EQUALS); + templatize_comparator(env, DST_FUN_GT, ">", 0, DOP_NUMERIC_GREATER_THAN); + templatize_comparator(env, DST_FUN_LT, "<", 0, DOP_NUMERIC_LESS_THAN); + templatize_comparator(env, DST_FUN_GTE, ">=", 0, DOP_NUMERIC_GREATER_THAN_EQUAL); + templatize_comparator(env, DST_FUN_LTE, "<=", 0, DOP_NUMERIC_LESS_THAN_EQUAL); + templatize_comparator(env, DST_FUN_EQ, "==", 0, DOP_NUMERIC_EQUAL); + templatize_comparator(env, DST_FUN_NEQ, "not==", 1, DOP_NUMERIC_EQUAL); dst_env_def(env, "VERSION", dst_cstringv(DST_VERSION)); diff --git a/src/core/math.c b/src/core/math.c index 8b419c03..070df06b 100644 --- a/src/core/math.c +++ b/src/core/math.c @@ -129,35 +129,8 @@ static int dst_not(DstArgs args) { DST_RETURN_BOOLEAN(args, !dst_truthy(args.v[0])); } -#define DEF_NUMERIC_COMP(name, op) \ -int dst_numeric_##name(DstArgs args) { \ - int32_t i; \ - for (i = 1; i < args.n; i++) { \ - double x = 0, y = 0; \ - DST_ARG_NUMBER(x, args, i-1);\ - DST_ARG_NUMBER(y, args, i);\ - if (!(x op y)) { \ - DST_RETURN(args, dst_wrap_false()); \ - } \ - } \ - DST_RETURN(args, dst_wrap_true()); \ -} - -DEF_NUMERIC_COMP(gt, >) -DEF_NUMERIC_COMP(lt, <) -DEF_NUMERIC_COMP(lte, <=) -DEF_NUMERIC_COMP(gte, >=) -DEF_NUMERIC_COMP(eq, ==) -DEF_NUMERIC_COMP(neq, !=) - static const DstReg cfuns[] = { {"%", dst_remainder}, - {"==", dst_numeric_eq}, - {"not==", dst_numeric_neq}, - {"<", dst_numeric_lt}, - {">", dst_numeric_gt}, - {"<=", dst_numeric_lte}, - {">=", dst_numeric_gte}, {"not", dst_not}, {"int", dst_int}, {"real", dst_real}, diff --git a/src/core/vm.c b/src/core/vm.c index 09959301..f152e4b6 100644 --- a/src/core/vm.c +++ b/src/core/vm.c @@ -190,6 +190,11 @@ static void *op_lookup[255] = { &&label_DOP_MAKE_STRUCT, &&label_DOP_MAKE_TABLE, &&label_DOP_MAKE_TUPLE, + &&label_DOP_NUMERIC_LESS_THAN, + &&label_DOP_NUMERIC_LESS_THAN_EQUAL, + &&label_DOP_NUMERIC_GREATER_THAN, + &&label_DOP_NUMERIC_GREATER_THAN_EQUAL, + &&label_DOP_NUMERIC_EQUAL, &&label_unknown_op }; #else @@ -257,6 +262,23 @@ static void *op_lookup[255] = { vm_next();\ } +#define vm_numcomp(op)\ + {\ + Dst op1 = stack[oparg(2, 0xFF)];\ + Dst op2 = stack[oparg(3, 0xFF)];\ + vm_assert_types(op1, DST_TFLAG_NUMBER);\ + vm_assert_types(op2, DST_TFLAG_NUMBER);\ + stack[oparg(1, 0xFF)] = dst_wrap_boolean(dst_checktype(op1, DST_INTEGER)\ + ? (dst_checktype(op2, DST_INTEGER)\ + ? dst_unwrap_integer(op1) op dst_unwrap_integer(op2)\ + : (double)dst_unwrap_integer(op1) op dst_unwrap_real(op2))\ + : (dst_checktype(op2, DST_INTEGER)\ + ? dst_unwrap_real(op1) op (double)dst_unwrap_integer(op2)\ + : dst_unwrap_real(op1) op dst_unwrap_real(op2)));\ + pc++;\ + vm_next();\ + } + /* Main interpreter loop. Semantically is a switch on * (*pc & 0xFF) inside of an infinte loop. */ VM_START(); @@ -325,6 +347,21 @@ static void *op_lookup[255] = { VM_OP(DOP_MULTIPLY) vm_binop(*); + VM_OP(DOP_NUMERIC_LESS_THAN) + vm_numcomp(<); + + VM_OP(DOP_NUMERIC_LESS_THAN_EQUAL) + vm_numcomp(<=); + + VM_OP(DOP_NUMERIC_GREATER_THAN) + vm_numcomp(>); + + VM_OP(DOP_NUMERIC_GREATER_THAN_EQUAL) + vm_numcomp(>=); + + VM_OP(DOP_NUMERIC_EQUAL) + vm_numcomp(==); + VM_OP(DOP_DIVIDE_INTEGER) vm_assert(dst_unwrap_integer(stack[oparg(3, 0xFF)]) != 0, "integer divide error"); vm_assert(!(dst_unwrap_integer(stack[oparg(3, 0xFF)]) == -1 && diff --git a/src/include/dst/dst.h b/src/include/dst/dst.h index 1f615914..227471fe 100644 --- a/src/include/dst/dst.h +++ b/src/include/dst/dst.h @@ -811,6 +811,11 @@ enum DstOpCode { DOP_MAKE_STRUCT, DOP_MAKE_TABLE, DOP_MAKE_TUPLE, + DOP_NUMERIC_LESS_THAN, + DOP_NUMERIC_LESS_THAN_EQUAL, + DOP_NUMERIC_GREATER_THAN, + DOP_NUMERIC_GREATER_THAN_EQUAL, + DOP_NUMERIC_EQUAL, DOP_INSTRUCTION_COUNT };