@@ -30,6 +30,7 @@ pub use crate::virtualmem::CodePtr;
30
30
/// Status returned by code generation functions
31
31
#[ derive( PartialEq , Debug ) ]
32
32
enum CodegenStatus {
33
+ SkipNextInsn ,
33
34
KeepCompiling ,
34
35
EndBlock ,
35
36
}
@@ -1197,6 +1198,13 @@ pub fn gen_single_block(
1197
1198
// Move to the next instruction to compile
1198
1199
insn_idx += insn_len ( opcode) as u16 ;
1199
1200
1201
+ // Move past next instruction when instructed
1202
+ if status == Some ( SkipNextInsn ) {
1203
+ let next_pc = unsafe { rb_iseq_pc_at_idx ( iseq, insn_idx. into ( ) ) } ;
1204
+ let next_opcode: usize = unsafe { rb_iseq_opcode_at_pc ( iseq, next_pc) } . try_into ( ) . unwrap ( ) ;
1205
+ insn_idx += insn_len ( next_opcode) as u16 ;
1206
+ }
1207
+
1200
1208
// If the instruction terminates this block
1201
1209
if status == Some ( EndBlock ) {
1202
1210
break ;
@@ -1343,30 +1351,92 @@ fn jit_putobject(asm: &mut Assembler, arg: VALUE) {
1343
1351
fn gen_putobject_int2fix (
1344
1352
jit : & mut JITState ,
1345
1353
asm : & mut Assembler ,
1346
- _ocb : & mut OutlinedCb ,
1354
+ ocb : & mut OutlinedCb ,
1347
1355
) -> Option < CodegenStatus > {
1348
1356
let opcode = jit. opcode ;
1349
1357
let cst_val: usize = if opcode == YARVINSN_putobject_INT2FIX_0_ . as_usize ( ) {
1350
1358
0
1351
1359
} else {
1352
1360
1
1353
1361
} ;
1362
+ let cst_val = VALUE :: fixnum_from_usize ( cst_val) ;
1363
+
1364
+ if let Some ( result) = fused_putobject_opt_ltlt ( jit, asm, cst_val, ocb) {
1365
+ return Some ( result) ;
1366
+ }
1354
1367
1355
- jit_putobject ( asm, VALUE :: fixnum_from_usize ( cst_val) ) ;
1368
+ jit_putobject ( asm, cst_val) ;
1356
1369
Some ( KeepCompiling )
1357
1370
}
1358
1371
1359
1372
fn gen_putobject (
1360
1373
jit : & mut JITState ,
1361
1374
asm : & mut Assembler ,
1362
- _ocb : & mut OutlinedCb ,
1375
+ ocb : & mut OutlinedCb ,
1363
1376
) -> Option < CodegenStatus > {
1364
1377
let arg: VALUE = jit. get_arg ( 0 ) ;
1365
1378
1379
+ if let Some ( result) = fused_putobject_opt_ltlt ( jit, asm, arg, ocb) {
1380
+ return Some ( result) ;
1381
+ }
1382
+
1366
1383
jit_putobject ( asm, arg) ;
1367
1384
Some ( KeepCompiling )
1368
1385
}
1369
1386
1387
+ fn fused_putobject_opt_ltlt (
1388
+ jit : & mut JITState ,
1389
+ asm : & mut Assembler ,
1390
+ constant_object : VALUE ,
1391
+ ocb : & mut OutlinedCb ,
1392
+ ) -> Option < CodegenStatus > {
1393
+ let next_opcode = unsafe { rb_vm_insn_addr2opcode ( jit. pc . add ( insn_len ( jit. opcode ) . as_usize ( ) ) . read ( ) . as_ptr ( ) ) } ;
1394
+ if next_opcode == YARVINSN_opt_ltlt as i32 && constant_object. fixnum_p ( ) {
1395
+ // Untag the fixnum shift amount
1396
+ let shift_amt = constant_object. as_isize ( ) >> 1 ;
1397
+ if shift_amt > 63 || shift_amt < 0 {
1398
+ return None ;
1399
+ }
1400
+ if !jit. at_current_insn ( ) {
1401
+ defer_compilation ( jit, asm, ocb) ;
1402
+ return Some ( EndBlock ) ;
1403
+ }
1404
+
1405
+ let lhs = jit. peek_at_stack ( & asm. ctx , 0 ) ;
1406
+ if !lhs. fixnum_p ( ) {
1407
+ return None ;
1408
+ }
1409
+
1410
+ if !assume_bop_not_redefined ( jit, asm, ocb, INTEGER_REDEFINED_OP_FLAG , BOP_LTLT ) {
1411
+ return None ;
1412
+ }
1413
+
1414
+ asm_comment ! ( asm, "integer left shift with rhs={shift_amt}" ) ;
1415
+ let lhs = asm. stack_opnd ( 0 ) ;
1416
+
1417
+ // Guard that lhs is a fixnum if necessary
1418
+ let lhs_type = asm. ctx . get_opnd_type ( lhs. into ( ) ) ;
1419
+ if lhs_type != Type :: Fixnum {
1420
+ asm_comment ! ( asm, "guard arg0 fixnum" ) ;
1421
+ asm. test ( lhs, Opnd :: UImm ( RUBY_FIXNUM_FLAG as u64 ) ) ;
1422
+
1423
+ jit_chain_guard (
1424
+ JCC_JZ ,
1425
+ jit,
1426
+ asm,
1427
+ ocb,
1428
+ SEND_MAX_DEPTH ,
1429
+ Counter :: guard_send_not_fixnums,
1430
+ ) ;
1431
+ }
1432
+
1433
+ asm. stack_pop ( 1 ) ;
1434
+ fixnum_left_shift_body ( asm, lhs, shift_amt as u64 ) ;
1435
+ return Some ( SkipNextInsn ) ;
1436
+ }
1437
+ return None ;
1438
+ }
1439
+
1370
1440
fn gen_putself (
1371
1441
_jit : & mut JITState ,
1372
1442
asm : & mut Assembler ,
@@ -5073,8 +5143,13 @@ fn jit_rb_int_lshift(
5073
5143
Counter :: lshift_amount_changed,
5074
5144
) ;
5075
5145
5146
+ fixnum_left_shift_body ( asm, lhs, shift_amt as u64 ) ;
5147
+ true
5148
+ }
5149
+
5150
+ fn fixnum_left_shift_body ( asm : & mut Assembler , lhs : Opnd , shift_amt : u64 ) {
5076
5151
let in_val = asm. sub ( lhs, 1 . into ( ) ) ;
5077
- let shift_opnd = Opnd :: UImm ( shift_amt as u64 ) ;
5152
+ let shift_opnd = Opnd :: UImm ( shift_amt) ;
5078
5153
let out_val = asm. lshift ( in_val, shift_opnd) ;
5079
5154
let unshifted = asm. rshift ( out_val, shift_opnd) ;
5080
5155
@@ -5087,7 +5162,6 @@ fn jit_rb_int_lshift(
5087
5162
5088
5163
let ret_opnd = asm. stack_push ( Type :: Fixnum ) ;
5089
5164
asm. mov ( ret_opnd, out_val) ;
5090
- true
5091
5165
}
5092
5166
5093
5167
fn jit_rb_int_rshift (
@@ -10384,57 +10458,6 @@ mod tests {
10384
10458
assert ! ( cb. get_write_pos( ) > 0 ) ;
10385
10459
}
10386
10460
10387
- #[ test]
10388
- fn test_putobject_qtrue ( ) {
10389
- // Test gen_putobject with Qtrue
10390
- let ( mut jit, _context, mut asm, mut cb, mut ocb) = setup_codegen ( ) ;
10391
-
10392
- let mut value_array: [ u64 ; 2 ] = [ 0 , Qtrue . into ( ) ] ;
10393
- let pc: * mut VALUE = & mut value_array as * mut u64 as * mut VALUE ;
10394
- jit. pc = pc;
10395
-
10396
- let status = gen_putobject ( & mut jit, & mut asm, & mut ocb) ;
10397
-
10398
- let tmp_type_top = asm. ctx . get_opnd_type ( StackOpnd ( 0 ) ) ;
10399
-
10400
- assert_eq ! ( status, Some ( KeepCompiling ) ) ;
10401
- assert_eq ! ( tmp_type_top, Type :: True ) ;
10402
- asm. compile ( & mut cb, None ) . unwrap ( ) ;
10403
- assert ! ( cb. get_write_pos( ) > 0 ) ;
10404
- }
10405
-
10406
- #[ test]
10407
- fn test_putobject_fixnum ( ) {
10408
- // Test gen_putobject with a Fixnum to test another conditional branch
10409
- let ( mut jit, _context, mut asm, mut cb, mut ocb) = setup_codegen ( ) ;
10410
-
10411
- // The Fixnum 7 is encoded as 7 * 2 + 1, or 15
10412
- let mut value_array: [ u64 ; 2 ] = [ 0 , 15 ] ;
10413
- let pc: * mut VALUE = & mut value_array as * mut u64 as * mut VALUE ;
10414
- jit. pc = pc;
10415
-
10416
- let status = gen_putobject ( & mut jit, & mut asm, & mut ocb) ;
10417
-
10418
- let tmp_type_top = asm. ctx . get_opnd_type ( StackOpnd ( 0 ) ) ;
10419
-
10420
- assert_eq ! ( status, Some ( KeepCompiling ) ) ;
10421
- assert_eq ! ( tmp_type_top, Type :: Fixnum ) ;
10422
- asm. compile ( & mut cb, None ) . unwrap ( ) ;
10423
- assert ! ( cb. get_write_pos( ) > 0 ) ;
10424
- }
10425
-
10426
- #[ test]
10427
- fn test_int2fix ( ) {
10428
- let ( mut jit, _context, mut asm, _cb, mut ocb) = setup_codegen ( ) ;
10429
- jit. opcode = YARVINSN_putobject_INT2FIX_0_ . as_usize ( ) ;
10430
- let status = gen_putobject_int2fix ( & mut jit, & mut asm, & mut ocb) ;
10431
-
10432
- let tmp_type_top = asm. ctx . get_opnd_type ( StackOpnd ( 0 ) ) ;
10433
-
10434
- // Right now we're not testing the generated machine code to make sure a literal 1 or 0 was pushed. I've checked locally.
10435
- assert_eq ! ( status, Some ( KeepCompiling ) ) ;
10436
- assert_eq ! ( tmp_type_top, Type :: Fixnum ) ;
10437
- }
10438
10461
10439
10462
#[ test]
10440
10463
fn test_putself ( ) {
0 commit comments