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...
bdw committed Jan 20, 2017
1 parent e6fdb10 commit 349b3605d1a9a943ba71448aeaaf8b6da91ed284
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.