Skip to content

Commit

Permalink
[JIT] Adhoc template application
Browse files Browse the repository at this point in the history
Using variadic args (32 bit). Much nicer than linking templates 'by
hand', which is useful for the optimizer. Also, the template application
can be made more clever than a simple copy.
  • Loading branch information
bdw committed Jul 6, 2018
1 parent 5130003 commit 6b788bd
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 60 deletions.
86 changes: 86 additions & 0 deletions docs/jit/todo.org
Expand Up @@ -330,6 +330,92 @@ and then warn about anything that's not a link address.
have the large_const op refer to the large_const table (i.e. not the
regular const)

NB - I didn't do the @ notation, because it turns out we need to
specially handle the indirected constants, and because of platform
differences, we also make the distinction between large constants in
general (MVMint64 or MVMnum64) and pointer constants, because pointers
have different sizes per architecture, and general large constants do
not.


** Encode (parts of) info as flags

Even when we'd have 32 bit operands and we'd (wastefully) use 16 bits
for the operator (rather than 8 which would be till 4x more than we
use now), we still have 16 perfectly good bits left. What I want to do
is to make info mostly sparse, so that:

- we can use a hashtable to represent all nodes that do have info
- we can encode all relevant attributes 'inline'

Which would be:
- number-of-args (redundant but nice, especially if it gets rid of the
first-child-node-is-arg-count nonsense)
- we could maximize this to 16? (4 bits) or 32 (5 bits)
- size (1,2,4,8) (2 bits or 3 bits)
- that may be a bit aggressive, we may want to support SIMD?
- type flag (int/num/str/obj) (2 bits or 5 bits if we want to encode
the whole field)

All that would remain of info would be spesh_ins, meaning that this
would become sufficiently sparse to use a hash table, which would mean
we no longer need to resize the number of args.

#+BEGIN_SRC C
typedef union {
struct {
MVMint16 o; /* operator */
MVMuint8 c; /* number of children */
MVMuint8 s : 4; /* size of result */
MVMuint8 t : 4; /* type of result */
}
MVMint32 r; /* reference */
} MVMJitExprNode;
#+END_SRC

** REPR-Specialized expression code

Parts needed:
+ A hook for instructions with operands of known repr type to insert a template
+ So how do we know which instruction/operand this is? (Hardcode with a switch, maybe)
+ Runtime hook should be similar to spesh hook
+ We should probably pass the tree and let the repr do manipulations itself for maximum flexibility
+ and have a default hook which attempts to apply a template
+ return root if succesful, otherwise -1 (in which case we can fallback to the normal mode)
+ should have a separate jit flags entry which is also settable by
the specializer (for jittivity, template destructiveness, possibly
other things)
+ operands loading must be public / template apply must become 'public methods'
+ Compile-time support for arbitrary templates in the expression templates
+ I think adding to a makefile list is acceptable, in general, but
it would be nice if we could have a substitution rule that would
make sure the expression templates are compiled 'automatically'

#+BEGIN_SRC makefile
EPXR_TEMPLATES=src/jit/core_expr.h \
src/6model/reprs/MMArray_expr.h \
src/6model/reprs/NativeRef_expr.h \
src/6model/reprs/MultiDimArray_expr.h \
# preferefably, we'd match the .expr with the file name automatically

src/6model/reprs/%.c: src/6model/reprs/%_expr.h # would be ideal, but this is not automatically picked up
# Expression list tables
%_expr_tables.h: %.expr tools/expr-template-compiler.pl src/core/oplist src/jit/expr_ops.h
$(PERL) -Itools/ tools/expr-template-compiler.pl -o $@ $<
#+END_SRC

** FLAGVAL ALL/ANY

Basically, flagval all/any is legal according to the type system, it
will just never work. We should translate it to (IF (ALL|ANY ..)
(CONST 1 1) (CONST 0 1))

The problem is, replacing all references to the node. (This is common
with the optimizer, which also needs it).

We don't actually need this yet, but we don't guard against it
either. (So maybe install an oops in analyze first).

** Use explicit stack for tree walking

Simple, mechanical transformation. I wonder if we can have a maximum
Expand Down
117 changes: 57 additions & 60 deletions src/jit/expr.c
Expand Up @@ -83,54 +83,35 @@ MVMint32 MVM_jit_expr_op_is_binary_noncommutative(MVMThreadContext *tc, MVMint32

static MVMint32 MVM_jit_expr_add_regaddr(MVMThreadContext *tc, MVMJitExprTree *tree,
MVMuint16 reg) {
MVMint32 num = tree->nodes_num;
MVMJitExprNode template[] = { MVM_JIT_LOCAL,
MVM_JIT_ADDR, num, reg * MVM_JIT_REG_SZ };
MVM_VECTOR_APPEND(tree->nodes, template, sizeof(template)/sizeof(MVMJitExprNode));
return num + 1;
return MVM_jit_expr_apply_template_adhoc(tc, tree, "nnl.",
MVM_JIT_LOCAL,
MVM_JIT_ADDR, 0, reg * MVM_JIT_REG_SZ) + 1;
}

static MVMint32 MVM_jit_expr_add_loadframe(MVMThreadContext *tc, MVMJitExprTree *tree) {
MVMint32 num = tree->nodes_num;
MVMJitExprNode template[] = { MVM_JIT_TC,
MVM_JIT_ADDR, num, offsetof(MVMThreadContext, cur_frame),
MVM_JIT_LOAD, num + 1, sizeof(MVMFrame*) };
MVM_VECTOR_APPEND(tree->nodes, template, sizeof(template)/sizeof(MVMJitExprNode));
return num + 4;
return MVM_jit_expr_apply_template_adhoc(tc, tree, "nnl.nl.",
MVM_JIT_TC,
MVM_JIT_ADDR, 0, offsetof(MVMThreadContext, cur_frame),
MVM_JIT_LOAD, 1, sizeof(MVMFrame*)) + 4;
}



static MVMint32 MVM_jit_expr_add_load(MVMThreadContext *tc, MVMJitExprTree *tree,
MVMint32 addr) {
MVMint32 num = tree->nodes_num;
MVMJitExprNode template[] = { MVM_JIT_LOAD, addr, MVM_JIT_REG_SZ };
MVM_VECTOR_APPEND(tree->nodes, template, sizeof(template)/sizeof(MVMJitExprNode));
return num;
return MVM_jit_expr_apply_template_adhoc(tc, tree, "n..", MVM_JIT_LOAD, addr, MVM_JIT_REG_SZ);
}


static MVMint32 MVM_jit_expr_add_store(MVMThreadContext *tc, MVMJitExprTree *tree,
MVMint32 addr, MVMint32 val, MVMint32 sz) {
MVMint32 num = tree->nodes_num;
MVMJitExprNode template[] = { MVM_JIT_STORE, addr, val, sz };
MVM_VECTOR_APPEND(tree->nodes, template, sizeof(template)/sizeof(MVMJitExprNode));
return num;
return MVM_jit_expr_apply_template_adhoc(tc, tree, "n...", MVM_JIT_STORE, addr, val, sz);
}


static MVMint32 MVM_jit_expr_add_cast(MVMThreadContext *tc, MVMJitExprTree *tree, MVMint32 node, MVMint32 to_size, MVMint32 from_size, MVMint32 is_signed) {
MVMint32 num = tree->nodes_num;
MVMJitExprNode template[] = { MVM_JIT_CAST, node, to_size, from_size, is_signed };
MVM_VECTOR_APPEND(tree->nodes, template, sizeof(template)/sizeof(MVMJitExprNode));
return num;
static MVMint32 MVM_jit_expr_add_cast(MVMThreadContext *tc, MVMJitExprTree *tree,
MVMint32 node, MVMint32 to_size, MVMint32 from_size, MVMint32 is_signed) {
return MVM_jit_expr_apply_template_adhoc(tc, tree, "n....", MVM_JIT_CAST, node, to_size, from_size, is_signed);
}

static MVMint32 MVM_jit_expr_add_label(MVMThreadContext *tc, MVMJitExprTree *tree, MVMint32 label) {
MVMint32 num = tree->nodes_num;
MVMJitExprNode template[] = { MVM_JIT_MARK, label };
MVM_VECTOR_APPEND(tree->nodes, template, sizeof(template)/sizeof(template[0]));
return num;
return MVM_jit_expr_apply_template_adhoc(tc, tree, "n.", MVM_JIT_MARK, label);
}

static MVMint32 MVM_jit_expr_add_lexaddr(MVMThreadContext *tc, MVMJitExprTree *tree,
Expand All @@ -140,31 +121,28 @@ static MVMint32 MVM_jit_expr_add_lexaddr(MVMThreadContext *tc, MVMJitExprTree *t
MVMint32 num = MVM_jit_expr_add_loadframe(tc, tree);
for (i = 0; i < outers; i++) {
/* (load (addr $val (&offsetof MVMFrame outer)) (&sizeof MVMFrame*)) */
MVMJitExprNode template[] = { MVM_JIT_ADDR, num, offsetof(MVMFrame, outer),
MVM_JIT_LOAD, tree->nodes_num, sizeof(MVMFrame*) };
MVM_VECTOR_APPEND(tree->nodes, template, sizeof(template)/sizeof(MVMJitExprNode));
num = tree->nodes_num - 3;
num = MVM_jit_expr_apply_template_adhoc(tc, tree, "n..nl.",
MVM_JIT_ADDR, num, offsetof(MVMFrame, outer),
MVM_JIT_LOAD, 0, sizeof(MVMFrame*)) + 3;

}
/* (addr (load (addr $frame (&offsetof MVMFrame env)) ptr_sz) ptr_sz*idx) */
{
MVMJitExprNode template[] = {
MVM_JIT_ADDR, num, offsetof(MVMFrame, env), /* (addr $frame (&offsetof MVMFrame env)) */
MVM_JIT_LOAD, tree->nodes_num, MVM_JIT_PTR_SZ, /* (load $addr ptr_sz) */
MVM_JIT_ADDR, tree->nodes_num + 3, idx * MVM_JIT_REG_SZ /* (addr $frame_env idx*reg_sz) */
};
MVM_VECTOR_APPEND(tree->nodes, template, sizeof(template)/sizeof(MVMJitExprNode));
num = tree->nodes_num - 3;
}
return num;
return MVM_jit_expr_apply_template_adhoc(tc, tree, "n..nl.nl.",
/* (addr $frame (&offsetof MVMFrame env)) */
MVM_JIT_ADDR, num, offsetof(MVMFrame, env),
/* (load $addr ptr_sz) */
MVM_JIT_LOAD, 0, MVM_JIT_PTR_SZ,
/* (addr $frame_env idx*reg_sz) */
MVM_JIT_ADDR, 3, idx * MVM_JIT_REG_SZ) + 6;
}


static MVMint32 MVM_jit_expr_add_const(MVMThreadContext *tc, MVMJitExprTree *tree,
MVMSpeshOperand opr, MVMuint8 info) {

MVMJitExprNode template[] = { MVM_JIT_CONST, 0, 0 };
MVMint32 num = tree->nodes_num;
MVMint32 size = 3;
MVMJitExprNode template[] = { MVM_JIT_CONST, 0, 0 };
MVMint32 num = tree->nodes_num;
MVMint32 size = 3;
switch(info & MVM_operand_type_mask) {
case MVM_operand_int8:
template[1] = opr.lit_i8;
Expand Down Expand Up @@ -343,32 +321,51 @@ static void check_template(MVMThreadContext *tc, const MVMJitExprTemplate *templ
}

/* Add template to nodes, filling in operands and linking tree nodes. Return template root */
MVMint32 MVM_jit_expr_apply_template(MVMThreadContext *tc, MVMJitExprTree *tree,
const MVMJitExprTemplate *template, MVMint32 *operands) {
static MVMint32 apply_template(MVMThreadContext *tc, MVMJitExprTree *tree, MVMint32 len, char *info,
MVMJitExprNode *code, MVMint32 *operands) {
MVMint32 i, num;
num = tree->nodes_num;
MVM_VECTOR_ENSURE_SPACE(tree->nodes, template->len);
MVM_VECTOR_ENSURE_SPACE(tree->nodes, len);
/* Loop over string until the end */
for (i = 0; template->info[i]; i++) {
switch (template->info[i]) {
for (i = 0; info[i]; i++) {
switch (info[i]) {
case 'l':
/* link template-relative to nodes-relative */
tree->nodes[num+i] = template->code[i] + num;
tree->nodes[num+i] = code[i] + num;
break;
case 'f':
/* add operand node into the nodes */
tree->nodes[num+i] = operands[template->code[i]];
tree->nodes[num+i] = operands[code[i]];
break;
default:
/* copy from template to nodes */
tree->nodes[num+i] = template->code[i];
/* copy from template to nodes (./n) */
tree->nodes[num+i] = code[i];
break;
}
}
tree->nodes_num = num + template->len;
return num + template->root; /* root relative to nodes */
tree->nodes_num = num + len;
return num;
}

MVMint32 MVM_jit_expr_apply_template(MVMThreadContext *tc, MVMJitExprTree *tree,
const MVMJitExprTemplate *template, MVMint32 *operands) {
return apply_template(tc, tree, template->len, (char*)template->info,
(MVMJitExprNode*)template->code, operands) + template->root;
}

/* this will fail with more than 16 nodes, which is just as fine */
MVMint32 MVM_jit_expr_apply_template_adhoc(MVMThreadContext *tc, MVMJitExprTree *tree,
char *info, ...) {
MVMJitExprNode code[16];
MVMint32 i;
va_list args;
va_start(args, info);
for (i = 0; info[i] != 0; i++) {
code[i] = va_arg(args, MVMint32);
}
va_end(args);
return apply_template(tc, tree, i, info, code, NULL);
}


/* Collect tree analysis information, add stores of computed values */
Expand Down
2 changes: 2 additions & 0 deletions src/jit/expr.h
Expand Up @@ -102,6 +102,8 @@ MVMint32 MVM_jit_expr_op_negate_flag(MVMThreadContext *tc, MVMint32 op);
MVMint32 MVM_jit_expr_op_is_binary_noncommutative(MVMThreadContext *tc, MVMint32 op);

MVMJitExprTree * MVM_jit_expr_tree_build(MVMThreadContext *tc, MVMJitGraph *jg, MVMSpeshIterator *iter);
MVMint32 MVM_jit_expr_apply_template(MVMThreadContext *tc, MVMJitExprTree *tree, const MVMJitExprTemplate*, MVMint32 *operands);
MVMint32 MVM_jit_expr_apply_template_adhoc(MVMThreadContext *tc, MVMJitExprTree *tree, char *template, ...);
void MVM_jit_expr_tree_traverse(MVMThreadContext *tc, MVMJitExprTree *tree, MVMJitTreeTraverser *traverser);
void MVM_jit_expr_tree_destroy(MVMThreadContext *tc, MVMJitExprTree *tree);
MVMint32 MVM_jit_expr_tree_get_nodes(MVMThreadContext *tc, MVMJitExprTree *tree,
Expand Down

0 comments on commit 6b788bd

Please sign in to comment.