8000 Merge pull request #225 from Shopify/fixnum-cmp · github/ruby@b53a06f · GitHub
[go: up one dir, main page]

Skip to content

Commit b53a06f

Browse files
authored
Merge pull request #225 from Shopify/fixnum-cmp
OP_SELECT_*
2 parents 5511aa3 + e368e8e commit b53a06f

File tree

2 files changed

+292
-24
lines changed

2 files changed

+292
-24
lines changed

yjit_backend.c

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,11 @@ const char* ir_op_name(int op)
234234
case OP_AND: return "and";
235235
case OP_CALL: return "call";
236236
case OP_CCALL: return "ccall";
237+
case OP_CMOV_GE: return "cmovge";
238+
case OP_CMOV_GT: return "cmovg";
239+
case OP_CMOV_LE: return "cmovle";
240+
case OP_CMOV_LT: return "cmovl";
241+
case OP_CMP: return "cmp";
237242
case OP_COMMENT: return "comment";
238243
case OP_JUMP_EQ: return "jumpeq";
239244
case OP_JUMP_NE: return "jumpne";
@@ -243,10 +248,15 @@ const char* ir_op_name(int op)
243248
case OP_NOT: return "not";
244249
case OP_RET: return "ret";
245250
case OP_RETVAL: return "retval";
251+
case OP_SELECT_GE: return "selectge";
252+
case OP_SELECT_GT: return "selectgt";
253+
case OP_SELECT_LE: return "selectle";
254+
case OP_SELECT_LT: return "selectlt";
246255
case OP_SUB: return "sub";
247256

248257
default:
249258
RUBY_ASSERT(false && "unknown opnd type");
259+
return "unknown";
250260
}
251261
}
252262

@@ -310,6 +320,18 @@ void ir_print_to_dot(jitstate_t *jit)
310320

311321
#define ir_ccall(jit, ...) ir_push_insn(jit, OP_CCALL, __VA_ARGS__)
312322

323+
#define ir_cmov_ge(jit, opnd0, opnd1) \
324+
ir_push_insn(jit, OP_CMOV_GE, opnd0, opnd1)
325+
326+
#define ir_cmov_gt(jit, opnd0, opnd1) \
327+
ir_push_insn(jit, OP_CMOV_GT, opnd0, opnd1)
328+
329+
#define ir_cmov_le(jit, opnd0, opnd1) \
330+
ir_push_insn(jit, OP_CMOV_LE, opnd0, opnd1)
331+
332+
#define ir_cmov_lt(jit, opnd0, opnd1) \
333+
ir_push_insn(jit, OP_CMOV_LT, opnd0, opnd1)
334+
313335
void ir_comment(jitstate_t *jit, ir_opnd_t opnd)
314336
{
315337
ir_push_insn(jit, OP_COMMENT, opnd);
@@ -345,6 +367,12 @@ ir_opnd_t ir_mov(jitstate_t *jit, ir_opnd_t opnd0, ir_opnd_t opnd1)
345367
return ir_push_insn(jit, OP_MOV, opnd0, opnd1);
346368
}
347369

370+
ir_opnd_t ir_cmp(jitstate_t *jit, ir_opnd_t opnd0, ir_opnd_t opnd1)
371+
{
372+
RUBY_ASSERT((opnd0.kind == EIR_INSN_OUT || opnd0.kind == EIR_REG) && "can only cmp with a EIR_INSN_OUT or EIR_REG");
373+
return ir_push_insn(jit, OP_CMP, opnd0, opnd1);
374+
}
375+
348376
#define ir_not(jit, opnd) ir_push_insn(jit, OP_NOT, opnd)
349377

350378
void ir_ret(jitstate_t *jit)
@@ -357,6 +385,18 @@ void ir_retval(jitstate_t *jit, ir_opnd_t opnd)
357385
ir_push_insn(jit, OP_RETVAL, opnd);
358386
}
359387

388+
#define ir_select_ge(jit, opnd0, opnd1, opnd2, opnd3) \
389+
ir_push_insn(jit, OP_SELECT_GE, opnd0, opnd1, opnd2, opnd3)
390+
391+
#define ir_select_gt(jit, opnd0, opnd1, opnd2, opnd3) \
392+
ir_push_insn(jit, OP_SELECT_GT, opnd0, opnd1, opnd2, opnd3)
393+
394+
#define ir_select_le(jit, opnd0, opnd1, opnd2, opnd3) \
395+
ir_push_insn(jit, OP_SELECT_LE, opnd0, opnd1, opnd2, opnd3)
396+
397+
#define ir_select_lt(jit, opnd0, opnd1, opnd2, opnd3) \
398+
ir_push_insn(jit, OP_SELECT_LT, opnd0, opnd1, opnd2, opnd3)
399+
360400
#define ir_sub(jit, opnd0, opnd1) ir_push_insn(jit, OP_SUB, opnd0, opnd1)
361401

362402
/*************************************************/
@@ -379,7 +419,9 @@ int32_t ir_next_scr_reg_idx(int32_t active[NUM_SCR_REGS])
379419
return index;
380420
}
381421
}
422+
382423
RUBY_ASSERT(false && "out of free registers");
424+
return -1;
383425
}
384426

385427
// When we're about to walk through the instructions and perform some kind of
@@ -629,11 +671,67 @@ void ir_alloc_regs(jitstate_t *jit)
629671
rb_darray_append(&jit->insns, call);
630672
break;
631673
}
674+
case OP_SELECT_GE:
675+
case OP_SELECT_GT:
676+
case OP_SELECT_LE:
677+
case OP_SELECT_LT: {
678+
ir_opnd_t left = ir_opnd(insn, 0, allocations);
679+
ir_opnd_t right = ir_opnd(insn, 1, allocations);
680+
681+
ir_opnd_t then_case = ir_opnd(insn, 2, allocations);
682+
ir_opnd_t else_case = ir_opnd(insn, 3, allocations);
683+
684+
// Always allocate a register, since we need a place for the
685+
// cases to live.
686+
int32_t allocated_index = ir_next_scr_reg_idx(active);
687+
ir_opnd_t allocated = SCR_REGS[allocated_index];
688+
689+
allocations[insn_idx] = allocated_index;
690+
active[allocated_index] = last_insn_index;
691+
692+
ir_mov(jit, allocated, left);
693+
ir_cmp(jit, allocated, right);
694+
695+
// Now that the comparison is done, we can safely move the
696+
// else_case operand into the allocated register while
697+
// maintaining the comparison flags.
698+
ir_mov(jit, allocated, else_case);
699+
700+
if (then_case.kind != EIR_REG) {
701+
// Since we don't have as register as the then_case operand,
702+
// we have to first allocate one and then mov the value into
703+
// that register.
704+
int32_t then_allocated_index = ir_next_scr_reg_idx(active);
705+
ir_opnd_t then_allocated = SCR_REGS[then_allocated_index];
706+
707+
active[then_allocated_index] = last_insn_index;
708+
ir_mov(jit, then_allocated, then_case);
709+
then_case = then_allocated;
710+
}
711+
712+
// Now we're going to conditionally move the then_case into the
713+
// allocated register depending on if the comparison flags line
714+
// up to the expected values depending on the current
715+
// instruction.
716+
switch (insn.op) {
717+
case OP_SELECT_GE: ir_cmov_ge(jit, allocated, then_case); break;
718+
case OP_SELECT_GT: ir_cmov_gt(jit, allocated, then_case); break;
719+
case OP_SELECT_LE: ir_cmov_le(jit, allocated, then_case); break;
720+
case OP_SELECT_LT: ir_cmov_lt(jit, allocated, then_case); break;
721+
}
722+
723+
break;
724+
}
632725
}
633726

634727
switch (insn.op) {
635728
// These instructions are just copied over between passes.
636729
case OP_CALL:
730+
case OP_CMOV_GE:
731+
case OP_CMOV_GT:
732+
case OP_CMOV_LE:
733+
case OP_CMOV_LT:
734+
case OP_CMP:
637735
case OP_COMMENT:
638736
case OP_JUMP_OVF:
639737
case OP_LABEL:
@@ -755,6 +853,36 @@ void ir_gen_x86(codeblock_t *cb, jitstate_t *jit)
755853
call(cb, pointer);
756854
break;
757855
}
856+
case OP_CMOV_GE: {
857+
x86opnd_t opnd0 = ir_gen_x86opnd(rb_darray_get(insn->opnds, 0));
858+
x86opnd_t opnd1 = ir_gen_x86opnd(rb_darray_get(insn->opnds, 1));
859+
cmovge(cb, opnd0, opnd1);
860+
break;
861+
}
862+
case OP_CMOV_GT: {
863+
x86opnd_t opnd0 = ir_gen_x86opnd(rb_darray_get(insn->opnds, 0));
864+
x86opnd_t opnd1 = ir_gen_x86opnd(rb_darray_get(insn->opnds, 1));
865+
cmovg(cb, opnd0, opnd1);
866+
break;
867+
}
868+
case OP_CMOV_LE: {
869+
x86opnd_t opnd0 = ir_gen_x86opnd(rb_darray_get(insn->opnds, 0));
870+
x86opnd_t opnd1 = ir_gen_x86opnd(rb_darray_get(insn->opnds, 1));
871+
cmovle(cb, opnd0, opnd1);
872+
break;
873+
}
874+
case OP_CMOV_LT: {
875+
x86opnd_t opnd0 = ir_gen_x86opnd(rb_darray_get(insn->opnds, 0));
876+
x86opnd_t opnd1 = ir_gen_x86opnd(rb_darray_get(insn->opnds, 1));
877+
cmovl(cb, opnd0, opnd1);
878+
break;
879+
}
880+
case OP_CMP: {
881+
x86opnd_t opnd0 = ir_gen_x86opnd(rb_darray_get(insn->opnds, 0));
882+
x86opnd_t opnd1 = ir_gen_x86opnd(rb_darray_get(insn->opnds, 1));
883+
cmp(cb, opnd0, opnd1);
884+
break;
885+
}
758886
case OP_COMMENT:
759887
// Do nothing here until/unless we have a way to consistently
760888
// represent comments in the assembly
@@ -948,6 +1076,38 @@ void test_backend()
9481076
ir_retval(jit, ir_ccall(jit, ir_const_ptr((void *)&ir_test_function_add), ir_imm(3), ir_imm(4)));
9491077
});
9501078

1079+
TEST("select greater than or equal to", 1, {
1080+
ir_retval(jit, ir_select_ge(jit, ir_imm(3), ir_imm(3), ir_imm(1), ir_imm(2)));
1081+
})
1082+
1083+
TEST("select not greater than or equal to", 2, {
1084+
ir_retval(jit, ir_select_ge(jit, ir_imm(3), ir_imm(4), ir_imm(1), ir_imm(2)));
1085+
})
1086+
1087+
TEST("select greater than", 1, {
1088+
ir_retval(jit, ir_select_gt(jit, ir_imm(4), ir_imm(3), ir_imm(1), ir_imm(2)));
1089+
})
1090+
1091+
TEST("select not greater than", 2, {
1092+
ir_retval(jit, ir_select_gt(jit, ir_imm(3), ir_imm(3), ir_imm(1), ir_imm(2)));
1093+
})
1094+
1095+
TEST("select less than or equal to", 1, {
1096+
ir_retval(jit, ir_select_le(jit, ir_imm(3), ir_imm(3), ir_imm(1), ir_imm(2)));
1097+
})
1098+
1099+
TEST("select not less than or equal to", 2, {
1100+
ir_retval(jit, ir_select_le(jit, ir_imm(4), ir_imm(3), ir_imm(1), ir_imm(2)));
1101+
})
1102+
1103+
TEST("select less than", 1, {
1104+
ir_retval(jit, ir_select_lt(jit, ir_imm(3), ir_imm(4), ir_imm(1), ir_imm(2)));
1105+
})
1106+
1107+
TEST("select not less than", 2, {
1108+
ir_retval(jit, ir_select_lt(jit, ir_imm(3), ir_imm(3), ir_imm(1), ir_imm(2)));
1109+
})
1110+
9511111
#undef TEST
9521112
printf("Backend tests done\n");
9531113
}

0 commit comments

Comments
 (0)
0