@@ -1411,6 +1411,14 @@ dump_interp_ins_data (InterpInst *ins, gint32 ins_offset, const guint16 *data, g
1411
1411
target = ins_offset + * (gint16 * )(data + 1 );
1412
1412
g_string_append_printf (str , " %u, IR_%04x" , * (guint16 * )data , target );
1413
1413
}
1414
+ case MintOpPair2 :
1415
+ g_string_append_printf (str , " %u <- %u, %u <- %u" , data [0 ], data [1 ], data [2 ], data [3 ]);
1416
+ break ;
1417
+ case MintOpPair3 :
1418
+ g_string_append_printf (str , " %u <- %u, %u <- %u, %u <- %u" , data [0 ], data [1 ], data [2 ], data [3 ], data [4 ], data [5 ]);
1419
+ break ;
1420
+ case MintOpPair4 :
1421
+ g_string_append_printf (str , " %u <- %u, %u <- %u, %u <- %u, %u <- %u" , data [0 ], data [1 ], data [2 ], data [3 ], data [4 ], data [5 ], data [6 ], data [7 ]);
1414
1422
break ;
1415
1423
default :
1416
1424
g_string_append_printf (str , "unknown arg type\n" );
@@ -7549,6 +7557,9 @@ emit_compacted_instruction (TransformData *td, guint16* start_ip, InterpInst *in
7549
7557
if (ins -> info .target_bb -> native_offset >= 0 ) {
7550
7558
// Backwards branch. We can already patch it.
7551
7559
* ip ++ = ins -> info .target_bb -> native_offset - br_offset ;
7560
+ } else if (opcode == MINT_BR_S && ins -> info .target_bb == td -> cbb -> next_bb ) {
7561
+ // Ignore branch to the next basic block. Revert the added MINT_BR_S.
7562
+ ip -- ;
7552
7563
} else {
7553
7564
// We don't know the in_offset of the target, add a reloc
7554
7565
Reloc * reloc = (Reloc * )mono_mempool_alloc0 (td -> mempool , sizeof (Reloc ));
@@ -7647,6 +7658,12 @@ emit_compacted_instruction (TransformData *td, guint16* start_ip, InterpInst *in
7647
7658
for (int i = size - 1 ; i < (jit_call2_size - 1 ); i ++ )
7648
7659
* ip ++ = MINT_NIY ;
7649
7660
#endif
7661
+ } else if (opcode >= MINT_MOV_8_2 && opcode <= MINT_MOV_8_4 ) {
7662
+ // This instruction is not marked as operating on any vars, all instruction slots are
7663
+ // actually vas. Resolve their offset
7664
+ int num_vars = mono_interp_oplen [opcode ] - 1 ;
7665
+ for (int i = 0 ; i < num_vars ; i ++ )
7666
+ * ip ++ = td -> locals [ins -> data [i ]].offset ;
7650
7667
} else {
7651
7668
if (mono_interp_op_dregs [opcode ])
7652
7669
* ip ++ = td -> locals [ins -> dreg ].offset ;
@@ -7696,6 +7713,7 @@ generate_compacted_code (TransformData *td)
7696
7713
for (bb = td -> entry_bb ; bb != NULL ; bb = bb -> next_bb ) {
7697
7714
InterpInst * ins = bb -> first_ins ;
7698
7715
bb -> native_offset = ip - td -> new_code ;
7716
+ td -> cbb = bb ;
7699
7717
while (ins ) {
7700
7718
ip = emit_compacted_instruction (td , ip , ins );
7701
7719
ins = ins -> next ;
@@ -7984,7 +8002,7 @@ interp_fold_unop_cond_br (TransformData *td, InterpBasicBlock *cbb, LocalValue *
7984
8002
7985
8003
7986
8004
static InterpInst *
7987
- interp_fold_binop (TransformData * td , LocalValue * local_defs , InterpInst * ins )
8005
+ interp_fold_binop (TransformData * td , LocalValue * local_defs , InterpInst * ins , gboolean * folded )
7988
8006
{
7989
8007
int * local_ref_count = td -> local_ref_count ;
7990
8008
// ins should be a binop, therefore it should have a single dreg and two sregs
@@ -7995,6 +8013,8 @@ interp_fold_binop (TransformData *td, LocalValue *local_defs, InterpInst *ins)
7995
8013
LocalValue * val2 = & local_defs [sreg2 ];
7996
8014
LocalValue result ;
7997
8015
8016
+ * folded = FALSE;
8017
+
7998
8018
if (val1 -> type != LOCAL_VALUE_I4 && val1 -> type != LOCAL_VALUE_I8 )
7999
8019
return ins ;
8000
8020
if (val2 -> type != LOCAL_VALUE_I4 && val2 -> type != LOCAL_VALUE_I8 )
@@ -8066,7 +8086,7 @@ interp_fold_binop (TransformData *td, LocalValue *local_defs, InterpInst *ins)
8066
8086
// with a LDC of the constant. We leave alone the sregs of this instruction, for
8067
8087
// deadce to kill the instructions initializing them.
8068
8088
mono_interp_stats .constant_folds ++ ;
8069
-
8089
+ * folded = TRUE;
8070
8090
if (result .type == LOCAL_VALUE_I4 )
8071
8091
ins = interp_get_ldc_i4_from_const (td , ins , result .i , dreg );
8072
8092
else if (result .type == LOCAL_VALUE_I8 )
@@ -8341,7 +8361,42 @@ interp_cprop (TransformData *td)
8341
8361
} else if (MINT_IS_UNOP_CONDITIONAL_BRANCH (opcode )) {
8342
8362
ins = interp_fold_unop_cond_br (td , bb , local_defs , ins );
8343
8363
} else if (MINT_IS_BINOP (opcode )) {
8344
- ins = interp_fold_binop (td , local_defs , ins );
8364
+ gboolean folded ;
8365
+ ins = interp_fold_binop (td , local_defs , ins , & folded );
8366
+ if (!folded ) {
8367
+ int sreg = -1 ;
8368
+ int mov_op ;
8369
+ if ((opcode == MINT_MUL_I4 || opcode == MINT_DIV_I4 ) &&
8370
+ local_defs [ins -> sregs [1 ]].type == LOCAL_VALUE_I4 &&
8371
+ local_defs [ins -> sregs [1 ]].i == 1 ) {
8372
+ sreg = ins -> sregs [0 ];
8373
+ mov_op = MINT_MOV_4 ;
8374
+ } else if ((opcode == MINT_MUL_I8 || opcode == MINT_DIV_I8 ) &&
8375
+ local_defs [ins -> sregs [1 ]].type == LOCAL_VALUE_I8 &&
8376
+ local_defs [ins -> sregs [1 ]].l == 1 ) {
8377
+ sreg = ins -> sregs [0 ];
8378
+ mov_op = MINT_MOV_8 ;
8379
+ } else if (opcode == MINT_MUL_I4 &&
8380
+ local_defs [ins -> sregs [0 ]].type == LOCAL_VALUE_I4 &&
8381
+ local_defs [ins -> sregs [0 ]].i == 1 ) {
8382
+ sreg = ins -> sregs [1 ];
8383
+ mov_op = MINT_MOV_4 ;
8384
+ } else if (opcode == MINT_MUL_I8 &&
8385
+ local_defs [ins -> sregs [0 ]].type == LOCAL_VALUE_I8 &&
8386
+ local_defs [ins -> sregs [0 ]].l == 1 ) {
8387
+ sreg = ins -> sregs [1 ];
8388
+ mov_op = MINT_MOV_8 ;
8389
+ }
8390
+ if (sreg != -1 ) {
8391
+ ins -> opcode = mov_op ;
8392
+ ins -> sregs [0 ] = sreg ;
8393
+ if (td -> verbose_level ) {
8394
+ g_print ("Replace idempotent binop :\n\t" );
8395
+ dump_interp_inst (ins );
8396
+ }
8397
+ needs_retry = TRUE;
8398
+ }
8399
+ }
8345
8400
} else if (MINT_IS_BINOP_CONDITIONAL_BRANCH (opcode )) {
8346
8401
ins = interp_fold_binop_cond_br (td , bb , local_defs , ins );
8347
8402
} else if (MINT_IS_LDFLD (opcode ) && ins -> data [0 ] == 0 ) {
@@ -9105,7 +9160,11 @@ interp_alloc_offsets (TransformData *td)
9105
9160
if (ins -> flags & INTERP_INST_FLAG_CALL ) {
9106
9161
int * call_args = ins -> info .call_args ;
9107
9162
if (call_args ) {
9163
+ int pair_sregs [MINT_MOV_PAIRS_MAX ];
9164
+ int pair_dregs [MINT_MOV_PAIRS_MAX ];
9165
+ int num_pairs = 0 ;
9108
9166
int var = * call_args ;
9167
+
9109
9168
while (var != -1 ) {
9110
9169
if (td -> locals [var ].flags & INTERP_LOCAL_FLAG_GLOBAL ||
9111
9170
td -> locals [var ].flags & INTERP_LOCAL_FLAG_NO_CALL_ARGS ) {
@@ -9114,17 +9173,27 @@ interp_alloc_offsets (TransformData *td)
9114
9173
int new_var = create_interp_local (td , td -> locals [var ].type );
9115
9174
td -> locals [new_var ].call = ins ;
9116
9175
td -> locals [new_var ].flags |= INTERP_LOCAL_FLAG_CALL_ARGS ;
9117
- int opcode = get_mov_for_type (mint_type (td -> locals [var ].type ), FALSE);
9118
- InterpInst * new_inst = interp_insert_ins_bb (td , bb , ins -> prev , opcode );
9119
- interp_ins_set_dreg (new_inst , new_var );
9120
- interp_ins_set_sreg (new_inst , var );
9121
- if (opcode == MINT_MOV_VT )
9122
- new_inst -> data [0 ] = td -> locals [var ].size ;
9123
- // The arg of the call is no longer global
9124
- * call_args = new_var ;
9125
- // Also update liveness for this instruction
9126
- foreach_local_var (td , new_inst , ins_index , set_var_live_range );
9127
- ins_index ++ ;
9176
+
9177
+ int mt = mint_type (td -> locals [var ].type );
9178
+ if (mt != MINT_TYPE_VT && num_pairs < MINT_MOV_PAIRS_MAX ) {
9179
+ pair_sregs [num_pairs ] = var ;
9180
+ pair_dregs [num_pairs ] = new_var ;
9181
+ num_pairs ++ ;
9182
+ // The arg of the call is no longer global
9183
+ * call_args = new_var ;
9184
+ } else {
9185
+ int opcode = get_mov_for_type (mt , FALSE);
9186
+ InterpInst * new_inst = interp_insert_ins_bb (td , bb , ins -> prev , opcode );
9187
+ interp_ins_set_dreg (new_inst , new_var );
9188
+ interp_ins_set_sreg (new_inst , var );
9189
+ if (opcode == MINT_MOV_VT )
9190
+ new_inst -> data [0 ] = td -> locals [var ].size ;
9191
+ // The arg of the call is no longer global
9192
+ * call_args = new_var ;
9193
+ // Also update liveness for this instruction
9194
+ foreach_local_var (td , new_inst , ins_index , set_var_live_range );
9195
+ ins_index ++ ;
9196
+ }
9128
9197
} else {
9129
9198
// Flag this var as it has special storage on the call args stack
9130
9199
td -> locals [var ].call = ins ;
@@ -9133,6 +9202,30 @@ interp_alloc_offsets (TransformData *td)
9133
9202
call_args ++ ;
9134
9203
var = * call_args ;
9135
9204
}
9205
+ if (num_pairs > 0 ) {
9206
+ int i ;
9207
+ for (i = 0 ; i < num_pairs ; i ++ ) {
9208
+ set_var_live_range (td , pair_sregs [i ], ins_index );
9209
+ set_var_live_range (td , pair_dregs [i ], ins_index );
9210
+ }
9211
+ if (num_pairs == 1 ) {
9212
+ int mt = mint_type (td -> locals [pair_sregs [0 ]].type );
9213
+ int opcode = get_mov_for_type (mt , FALSE);
9214
+ InterpInst * new_inst = interp_insert_ins_bb (td , bb , ins -> prev , opcode );
9215
+ interp_ins_set_dreg (new_inst , pair_dregs [0 ]);
9216
+ interp_ins_set_sreg (new_inst , pair_sregs [0 ]);
9217
+ } else {
9218
+ // Squash together multiple moves to the param area into a single opcode
9219
+ int opcode = MINT_MOV_8_2 + num_pairs - 2 ;
9220
+ InterpInst * new_inst = interp_insert_ins_bb (td , bb , ins -> prev , opcode );
9221
+ int k = 0 ;
9222
+ for (i = 0 ; i < num_pairs ; i ++ ) {
9223
+ new_inst -> data [k ++ ] = pair_dregs [i ];
9224
+ new_inst -> data [k ++ ] = pair_sregs [i ];
9225
+ }
9226
+ }
9227
+ ins_index ++ ;
9228
+ }
9136
9229
}
9137
9230
}
9138
9231
// Set live_start and live_end for every referenced local that is not global
0 commit comments