@@ -132,9 +132,9 @@ static void split_immediate(mp_int_t immediate, mp_uint_t *upper, mp_uint_t *low
132
132
133
133
static void load_upper_immediate (asm_rv32_t * state , mp_uint_t rd , mp_uint_t immediate ) {
134
134
// if immediate fits in 17 bits and is ≠ 0:
135
- // c.lui rd, HI(immediate)
135
+ // c.lui rd, HI(immediate)
136
136
// else:
137
- // lui rd, HI(immediate)
137
+ // lui rd, HI(immediate)
138
138
if (FIT_SIGNED (immediate , 17 ) && ((immediate >> 12 ) != 0 )) {
139
139
asm_rv32_opcode_clui (state , rd , immediate );
140
140
} else {
@@ -270,6 +270,14 @@ static void emit_function_epilogue(asm_rv32_t *state, mp_uint_t registers) {
270
270
state -> saved_registers_mask = old_saved_registers_mask ;
271
271
}
272
272
273
+ static bool calculate_displacement_for_label (asm_rv32_t * state , mp_uint_t label , ptrdiff_t * displacement ) {
274
+ assert (displacement != NULL && "Displacement pointer is NULL" );
275
+
276
+ mp_uint_t label_offset = state -> base .label_offsets [label ];
277
+ * displacement = (ptrdiff_t )(label_offset - state -> base .code_offset );
278
+ return (label_offset != (mp_uint_t )- 1 ) && (* displacement < 0 );
279
+ }
280
+
273
281
///////////////////////////////////////////////////////////////////////////////
274
282
275
283
void asm_rv32_entry (asm_rv32_t * state , mp_uint_t locals ) {
@@ -326,10 +334,10 @@ void asm_rv32_emit_call_ind(asm_rv32_t *state, mp_uint_t index) {
326
334
}
327
335
328
336
void asm_rv32_emit_jump_if_reg_eq (asm_rv32_t * state , mp_uint_t rs1 , mp_uint_t rs2 , mp_uint_t label ) {
329
- ptrdiff_t displacement = (ptrdiff_t )(state -> base .label_offsets [label ] - state -> base .code_offset );
337
+ ptrdiff_t displacement = 0 ;
338
+ bool can_emit_short_jump = calculate_displacement_for_label (state , label , & displacement );
330
339
331
- // The least significant bit is ignored anyway.
332
- if (FIT_SIGNED (displacement , 13 )) {
340
+ if (can_emit_short_jump && FIT_SIGNED (displacement , 13 )) {
333
341
// beq rs1, rs2, displacement
334
342
asm_rv32_opcode_beq (state , rs1 , rs2 , displacement );
335
343
return ;
@@ -354,31 +362,24 @@ void asm_rv32_emit_jump_if_reg_eq(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs
354
362
}
355
363
356
364
void asm_rv32_emit_jump_if_reg_nonzero (asm_rv32_t * state , mp_uint_t rs , mp_uint_t label ) {
357
- ptrdiff_t displacement = (ptrdiff_t )(state -> base .label_offsets [label ] - state -> base .code_offset );
365
+ ptrdiff_t displacement = 0 ;
366
+ bool can_emit_short_jump = calculate_displacement_for_label (state , label , & displacement );
358
367
359
- if (FIT_SIGNED (displacement , 9 ) && IS_IN_C_REGISTER_WINDOW (rs )) {
368
+ if (can_emit_short_jump && FIT_SIGNED (displacement , 8 ) && IS_IN_C_REGISTER_WINDOW (rs )) {
360
369
// c.bnez rs', displacement
361
370
asm_rv32_opcode_cbnez (state , MAP_IN_C_REGISTER_WINDOW (rs ), displacement );
362
371
return ;
363
372
}
364
373
365
- // The least significant bit is ignored anyway.
366
- if (FIT_SIGNED (displacement , 13 )) {
374
+ if (can_emit_short_jump && FIT_SIGNED (displacement , 13 )) {
367
375
// bne rs, zero, displacement
368
376
asm_rv32_opcode_bne (state , rs , ASM_RV32_REG_ZERO , displacement );
369
377
return ;
370
378
}
371
379
372
- // Compensate for the initial C.BEQZ/BEQ opcode.
373
- displacement -= IS_IN_C_REGISTER_WINDOW (rs ) ? ASM_HALFWORD_SIZE : ASM_WORD_SIZE ;
374
-
375
- mp_uint_t upper = 0 ;
376
- mp_uint_t lower = 0 ;
377
- split_immediate (displacement , & upper , & lower );
378
-
379
380
// TODO: Can this clobber REG_TEMP[0:2]?
380
381
381
- // if rs1 in C window (the offset always fits) :
382
+ // if rs1 in C window and displacement is negative :
382
383
// c.beqz rs', 10 ; PC + 0
383
384
// auipc temporary, HI(displacement) ; PC + 2
384
385
// jalr zero, temporary, LO(displacement) ; PC + 6
@@ -388,11 +389,20 @@ void asm_rv32_emit_jump_if_reg_nonzero(asm_rv32_t *state, mp_uint_t rs, mp_uint_
388
389
// auipc temporary, HI(displacement) ; PC + 4
389
390
// jalr zero, temporary, LO(displacement) ; PC + 8
390
391
// ... ; PC + 12
391
- if (IS_IN_C_REGISTER_WINDOW (rs )) {
392
+
393
+ if (can_emit_short_jump && IS_IN_C_REGISTER_WINDOW (rs )) {
392
394
asm_rv32_opcode_cbeqz (state , MAP_IN_C_REGISTER_WINDOW (rs ), 10 );
395
+ // Compensate for the C.BEQZ opcode.
396
+ displacement -= ASM_HALFWORD_SIZE ;
393
397
} else {
394
398
asm_rv32_opcode_beq (state , rs , ASM_RV32_REG_ZERO , 12 );
399
+ // Compensate for the BEQ opcode.
400
+ displacement -= ASM_WORD_SIZE ;
395
401
}
402
+
403
+ mp_uint_t upper = 0 ;
404
+ mp_uint_t lower = 0 ;
405
+ split_immediate (displacement , & upper , & lower );
396
406
asm_rv32_opcode_auipc (state , INTERNAL_TEMPORARY , upper );
397
407
asm_rv32_opcode_jalr (state , ASM_RV32_REG_ZERO , INTERNAL_TEMPORARY , lower );
398
408
}
@@ -502,10 +512,10 @@ void asm_rv32_emit_load_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_
502
512
}
503
513
504
514
void asm_rv32_emit_jump (asm_rv32_t * state , mp_uint_t label ) {
505
- ptrdiff_t displacement = (ptrdiff_t )(state -> base .label_offsets [label ] - state -> base .code_offset );
515
+ ptrdiff_t displacement = 0 ;
516
+ bool can_emit_short_jump = calculate_displacement_for_label (state , label , & displacement );
506
517
507
- // The least significant bit is ignored anyway.
508
- if (FIT_SIGNED (displacement , 13 )) {
518
+ if (can_emit_short_jump && FIT_SIGNED (displacement , 12 )) {
509
519
// c.j displacement
510
520
asm_rv32_opcode_cj (state , displacement );
511
521
return ;
@@ -536,12 +546,12 @@ void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint
536
546
mp_uint_t lower = 0 ;
537
547
split_immediate (scaled_offset , & upper , & lower );
538
548
539
- // lui rd , HI(offset) ; Or c.lui if possible
540
- // c.add rd , rs
541
- // sw rd, LO(offset)(rd )
542
- load_upper_immediate (state , rd , upper );
543
- asm_rv32_opcode_cadd (state , rd , rs );
544
- asm_rv32_opcode_sw (state , rd , rd , lower );
549
+ // lui temporary , HI(offset) ; Or c.lui if possible
550
+ // c.add temporary , rs
551
+ // sw rd, LO(offset)(temporary )
552
+ load_upper_immediate (state , INTERNAL_TEMPORARY , upper );
553
+ asm_rv32_opcode_cadd (state , INTERNAL_TEMPORARY , rs );
554
+ asm_rv32_opcode_sw (state , rd , INTERNAL_TEMPORARY , lower );
545
555
}
546
556
547
557
void asm_rv32_emit_mov_reg_pcrel (asm_rv32_t * state , mp_uint_t rd , mp_uint_t label ) {
@@ -550,11 +560,6 @@ void asm_rv32_emit_mov_reg_pcrel(asm_rv32_t *state, mp_uint_t rd, mp_uint_t labe
550
560
mp_uint_t lower = 0 ;
551
561
split_immediate (displacement , & upper , & lower );
552
562
553
- // Compressed instructions are not used even if they may allow for code size
554
- // savings as the code changes size between compute and emit passes
555
- // otherwise. If that happens then the assertion at asmbase.c:93 triggers
556
- // when built in debug mode.
557
-
558
563
// auipc rd, HI(relative)
559
564
// addi rd, rd, LO(relative)
560
565
asm_rv32_opcode_auipc (state , rd , upper );
0 commit comments