|
41 | 41 | #endif
|
42 | 42 |
|
43 | 43 | #define WORD_SIZE (4)
|
| 44 | +#define SIGNED_FIT6(x) ((((x) & 0xffffffe0) == 0) || (((x) & 0xffffffe0) == 0xffffffe0)) |
44 | 45 | #define SIGNED_FIT8(x) ((((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80))
|
45 | 46 | #define SIGNED_FIT12(x) ((((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800))
|
46 | 47 | #define SIGNED_FIT18(x) ((((x) & 0xfffe0000) == 0) || (((x) & 0xfffe0000) == 0xfffe0000))
|
@@ -158,13 +159,36 @@ void asm_xtensa_j_label(asm_xtensa_t *as, uint label) {
|
158 | 159 | asm_xtensa_op_j(as, rel);
|
159 | 160 | }
|
160 | 161 |
|
| 162 | +static bool calculate_branch_displacement(asm_xtensa_t *as, uint label, ptrdiff_t *displacement) { |
| 163 | + assert(displacement != NULL && "Displacement pointer is NULL"); |
| 164 | + |
| 165 | + uint32_t label_offset = get_label_dest(as, label); |
| 166 | + *displacement = (ptrdiff_t)(label_offset - as->base.code_offset - 4); |
| 167 | + return (label_offset != (uint32_t)-1) && (*displacement < 0); |
| 168 | +} |
| 169 | + |
161 | 170 | void asm_xtensa_bccz_reg_label(asm_xtensa_t *as, uint cond, uint reg, uint label) {
|
162 |
| - uint32_t dest = get_label_dest(as, label); |
163 |
| - int32_t rel = dest - as->base.code_offset - 4; |
164 |
| - if (as->base.pass == MP_ASM_PASS_EMIT && !SIGNED_FIT12(rel)) { |
| 171 | + ptrdiff_t rel = 0; |
| 172 | + bool can_emit_short_jump = calculate_branch_displacement(as, label, &rel); |
| 173 | + |
| 174 | + if (can_emit_short_jump && SIGNED_FIT12(rel)) { |
| 175 | + // Backwards BCCZ opcodes with an offset that fits in 12 bits can |
| 176 | + // be emitted without any change. |
| 177 | + asm_xtensa_op_bccz(as, cond, reg, rel); |
| 178 | + return; |
| 179 | + } |
| 180 | + |
| 181 | + // Range is effectively extended to 18 bits, as a more complex jump code |
| 182 | + // sequence is emitted. |
| 183 | + if (as->base.pass == MP_ASM_PASS_EMIT && !SIGNED_FIT18(rel - 6)) { |
165 | 184 | mp_raise_msg_varg(&mp_type_RuntimeError, ET_OUT_OF_RANGE, MP_QSTR_bccz);
|
166 | 185 | }
|
167 |
| - asm_xtensa_op_bccz(as, cond, reg, rel); |
| 186 | + |
| 187 | + // ~BCCZ skip ; +0 <- Condition is flipped here (EQ -> NE, etc.) |
| 188 | + // J addr ; +3 |
| 189 | + // skip: ; +6 |
| 190 | + asm_xtensa_op_bccz(as, cond ^ 1, reg, 6 - 4); |
| 191 | + asm_xtensa_op_j(as, rel - 3); |
168 | 192 | }
|
169 | 193 |
|
170 | 194 | void asm_xtensa_bcc_reg_reg_label(asm_xtensa_t *as, uint cond, uint reg1, uint reg2, uint label) {
|
|
0 commit comments