@@ -234,6 +234,11 @@ const char* ir_op_name(int op)
234
234
case OP_AND : return "and" ;
235
235
case OP_CALL : return "call" ;
236
236
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" ;
237
242
case OP_COMMENT : return "comment" ;
238
243
case OP_JUMP_EQ : return "jumpeq" ;
239
244
case OP_JUMP_NE : return "jumpne" ;
@@ -243,10 +248,15 @@ const char* ir_op_name(int op)
243
248
case OP_NOT : return "not" ;
244
249
case OP_RET : return "ret" ;
245
250
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" ;
246
255
case OP_SUB : return "sub" ;
247
256
248
257
default :
249
258
RUBY_ASSERT (false && "unknown opnd type" );
259
+ return "unknown" ;
250
260
}
251
261
}
252
262
@@ -310,6 +320,18 @@ void ir_print_to_dot(jitstate_t *jit)
310
320
311
321
#define ir_ccall (jit , ...) ir_push_insn(jit, OP_CCALL, __VA_ARGS__)
312
322
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
+
313
335
void ir_comment (jitstate_t * jit , ir_opnd_t opnd )
314
336
{
315
337
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)
345
367
return ir_push_insn (jit , OP_MOV , opnd0 , opnd1 );
346
368
}
347
369
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
+
348
376
#define ir_not (jit , opnd ) ir_push_insn(jit, OP_NOT, opnd)
349
377
350
378
void ir_ret (jitstate_t * jit )
@@ -357,6 +385,18 @@ void ir_retval(jitstate_t *jit, ir_opnd_t opnd)
357
385
ir_push_insn (jit , OP_RETVAL , opnd );
358
386
}
359
387
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
+
360
400
#define ir_sub (jit , opnd0 , opnd1 ) ir_push_insn(jit, OP_SUB, opnd0, opnd1)
361
401
362
402
/*************************************************/
@@ -379,7 +419,9 @@ int32_t ir_next_scr_reg_idx(int32_t active[NUM_SCR_REGS])
379
419
return index ;
380
420
}
381
421
}
422
+
382
423
RUBY_ASSERT (false && "out of free registers" );
424
+ return -1 ;
383
425
}
384
426
385
427
// 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)
629
671
rb_darray_append (& jit -> insns , call );
630
672
break ;
631
673
}
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
+ }
632
725
}
633
726
634
727
switch (insn .op ) {
635
728
// These instructions are just copied over between passes.
636
729
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 :
637
735
case OP_COMMENT :
638
736
case OP_JUMP_OVF :
639
737
case OP_LABEL :
@@ -755,6 +853,36 @@ void ir_gen_x86(codeblock_t *cb, jitstate_t *jit)
755
853
call (cb , pointer );
756
854
break ;
757
855
}
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
+ }
758
886
case OP_COMMENT :
759
887
// Do nothing here until/unless we have a way to consistently
760
888
// represent comments in the assembly
@@ -948,6 +1076,38 @@ void test_backend()
948
1076
ir_retval (jit , ir_ccall (jit , ir_const_ptr ((void * )& ir_test_function_add ), ir_imm (3 ), ir_imm (4 )));
949
1077
});
950
1078
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
+
951
1111
#undef TEST
952
1112
printf ("Backend tests done\n" );
953
1113
}
0 commit comments