Permalink
Browse files

Try to resolve two-operand code

A reserved register (rax) is used as scratch space for transforming
three-operand code to two-operand code as required by x86.

This or some earlier commit seem to introduce a memory leak + infinite
loop in the rakudo build process.
  • Loading branch information...
1 parent e6fdb10 commit 349b3605d1a9a943ba71448aeaaf8b6da91ed284 @bdw bdw committed Jan 20, 2017
Showing with 65 additions and 46 deletions.
  1. +1 −1 src/jit/expr.h
  2. +3 −3 src/jit/x64/arch.h
  3. +61 −42 src/jit/x64/tiles.dasc
View
@@ -159,7 +159,7 @@ struct MVMJitTreeTraverser {
const MVMJitExprOpInfo * MVM_jit_expr_op_info(MVMThreadContext *tc, MVMint32 op);
/* properties of expression ops */
MVMint32 MVM_jit_expr_op_negate_flag(MVMThreadContext *tc, MVMint32 op);
-MVMint32 MVM_jit_expor_op_is_binary_noncommutative(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);
void MVM_jit_expr_tree_traverse(MVMThreadContext *tc, MVMJitExprTree *tree, MVMJitTreeTraverser *traverser);
View
@@ -30,10 +30,10 @@
#if MVM_JIT_PLATFORM == MVM_JIT_PLATFORM_POSIX
-/* Define the GPR set usable for general calculations */
+/* Define the GPR set usable for general calculations. RAX is reserved for
+ * internal use by tiles */
#define MVM_JIT_ARCH_AVAILABLE_GPR(_) \
- _(RAX) __COMMA__ \
_(RCX) __COMMA__ \
_(RDX) __COMMA__ \
_(RSI) __COMMA__ \
@@ -73,13 +73,13 @@
/* Microsoft why you give us so few registers :-( */
#define MVM_JIT_ARCH_AVAILABLE_GPR(_) \
- _(RAX) __COMMA__ \
_(RCX) __COMMA__ \
_(RDX) __COMMA__ \
_(R8) __COMMA__ \
_(R9) __COMMA__ \
_(R10) __COMMA__ \
_(R11)
+
#define MVM_JIT_ARCH_NONVOLATILE_GPR(_) \
_(RBX) __COMMA__ \
_(RSP) __COMMA__ \
View
@@ -1,6 +1,10 @@
+/* -*-C-*- */
#include "tile_decl.h"
+/* NB: The rax/eax/ax/al/ah register is *reserved* for internal use in tiles by
+ * the register allocator. Using rax will never overwrite an allocated value */
+/* basic memory traffic tiles */
MVM_JIT_TILE_DECL(addr) {
MVMint8 out = tile->values[0];
MVMint8 base = tile->values[1];
@@ -219,19 +223,9 @@ MVM_JIT_TILE_DECL(cast) {
/* movsx is apparantly not defined for double-to-quadword conversions,
* which forces us to use the rax register like it's 1978. It might be easier
* to bithack the sign-extension manually, but I'm not sure how.. */
- if (from_reg == MVM_JIT_ARCH_X64_RAX) {
- | cdqe;
- if (to_reg != MVM_JIT_ARCH_X64_RAX) {
- | mov Rq(to_reg), rax;
- /* restore the eax as it was, clearing the upper bytes */
- | mov eax, Rd(to_reg);
- }
- } else if (to_reg == MVM_JIT_ARCH_X64_RAX) {
- | mov eax, Rd(from_reg);
- | cdqe;
- } else {
- MVM_oops(tc, "Register pre-coloring NYI");
- }
+ | mov eax, Rd(from_reg);
+ | cdqe;
+ | mov Rq(to_reg), rax;
break;
default:
MVM_oops(tc, "Unsuported signed cast %d -> %d\n", from_size, to_size);
@@ -270,19 +264,51 @@ MVM_JIT_TILE_DECL(cast_load_addr) {
MVM_oops(tc, "NYI");
}
+/* binary operations have special requirements because x86 is two-operand form, e.g:
+ * r0 = r0 <op> r1
+ * whereas the JIT uses a three-operand model:
+ * r0 = r1 <op> r2 */
-MVM_JIT_TILE_DECL(add_reg) {
- MVMint8 out = tile->values[0];
- MVMint8 in1 = tile->values[1];
- MVMint8 in2 = tile->values[2];
- if (out == in2) {
- | add Rq(out), Rq(in2);
+static void ensure_two_operand_pre(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitTile *tile, MVMint8 reg[2]) {
+ MVMint8 out = tile->values[0], in1 = tile->values[1], in2 = tile->values[2];
+ if (out == in1) {
+ reg[0] = in1;
+ reg[1] = in2;
+ } else if (out == in2) {
+ if (MVM_jit_expr_op_is_binary_noncommutative(tc, tile->op)) {
+ | mov rax, Rq(in1);
+ reg[0] = MVM_JIT_ARCH_X64_RAX;
+ reg[1] = in2;
+ } else {
+ /* in this case, r2 <op> r1 == r0 <op> r1 */
+ reg[0] = out;
+ reg[1] = in1;
+ }
} else {
+ /* insert a copy */
| mov Rq(out), Rq(in1);
- | add Rq(out), Rq(in2);
+ /* use r0, r2 */
+ reg[0] = out;
+ reg[1] = in2;
+ }
+}
+
+static void ensure_two_operand_post(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitTile *tile, MVMint8 reg[2]) {
+ MVMint8 out = tile->values[0];
+ if (out != reg[0]) {
+ /* insert a copy afterwards */
+ | mov Rq(out), Rq(reg[0]);
}
}
+
+MVM_JIT_TILE_DECL(add_reg) {
+ MVMint8 reg[2];
+ ensure_two_operand_pre(tc, compiler, tile, reg);
+ | add Rq(reg[0]), Rq(reg[1]);
+ ensure_two_operand_post(tc, compiler, tile, reg);
+}
+
MVM_JIT_TILE_DECL(add_const) {
MVMint8 out = tile->values[0];
MVMint8 in1 = tile->values[1];
@@ -362,15 +388,10 @@ MVM_JIT_TILE_DECL(add_load_idx) {
MVM_JIT_TILE_DECL(and_reg) {
- MVMint8 out = tile->values[0];
- MVMint8 in1 = tile->values[1];
- MVMint8 in2 = tile->values[2];
- if (out == in2) {
- | and Rq(out), Rq(in2);
- } else {
- | mov Rq(out), Rq(in1);
- | and Rq(out), Rq(in2);
- }
+ MVMint8 reg[2];
+ ensure_two_operand_pre(tc, compiler, tile, reg);
+ | and Rq(reg[0]), Rq(reg[1]);
+ ensure_two_operand_post(tc, compiler, tile, reg);
}
MVM_JIT_TILE_DECL(and_const) {
@@ -380,7 +401,8 @@ MVM_JIT_TILE_DECL(and_const) {
MVMint32 sz = tile->args[1];
if (out == in1) {
if (sz == 8 && !fits_in_32_bit(val)) {
- MVM_oops(tc, "Scratch register NYI");
+ | mov64 rax, val;
+ | and Rq(in1), rax;
} else {
| and Rq(in1), val;
}
@@ -452,15 +474,10 @@ MVM_JIT_TILE_DECL(and_load_idx) {
MVM_JIT_TILE_DECL(sub_reg) {
- MVMint8 out = tile->values[0];
- MVMint8 in1 = tile->values[1];
- MVMint8 in2 = tile->values[2];
- if (out == in2) {
- | sub Rq(out), Rq(in2);
- } else {
- | mov Rq(out), Rq(in1);
- | sub Rq(out), Rq(in2);
- }
+ MVMint8 reg[2];
+ ensure_two_operand_pre(tc, compiler, tile, reg);
+ | sub Rq(reg[0]), Rq(reg[1]);
+ ensure_two_operand_post(tc, compiler, tile, reg);
}
MVM_JIT_TILE_DECL(sub_const) {
@@ -470,14 +487,16 @@ MVM_JIT_TILE_DECL(sub_const) {
MVMint32 sz = tile->args[1];
if (out == in1) {
if (sz == 8 && !fits_in_32_bit(val)) {
- MVM_oops(tc, "Scratch register NYI");
+ | mov64 rax, val;
+ | sub Rq(in1), rax;
} else {
| sub Rq(in1), val;
}
} else {
if (sz == 8 && !fits_in_32_bit(val)) {
- | mov64 Rq(out), val;
- | sub Rq(out), Rq(in1);
+ | mov64 rax, val;
+ | mov Rq(out), Rq(in1);
+ | sub Rq(out), rax;
} else {
| mov Rq(out), Rq(in1);
| sub Rq(out), val;

0 comments on commit 349b360

Please sign in to comment.