Skip to content

Commit 43d8615

Browse files
committed
Fix incorrect alignment checks with C ext
According to the riscv-spec-v2.2 Chapter 12 page 67 [1], under the C extension, jump-related instructions should not trigger any misaligned instruction address exceptions. However, the current implementation checks whether the instruction address is aligned to 16-bit, which is incorrect and could potentially cause a performance hit. This patch eliminates unnecessary misalignment checks for jump instructions when the C extension is enabled, aligning the behavior with the expected specification. Link: https://riscv.org/wp-content/uploads/2017/05/riscv-spec-v2.2.pdf [1]
1 parent cfa1c9f commit 43d8615

File tree

2 files changed

+63
-61
lines changed

2 files changed

+63
-61
lines changed

src/emulate.c

+13-13
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,17 @@ extern struct target_ops gdbstub_ops;
3838
#define IF_imm(i, v) (i->imm == v)
3939

4040
/* RISC-V exception code list */
41-
#define RV_EXCEPTION_LIST \
42-
_(insn_misaligned, 0) /* Instruction address misaligned */ \
43-
_(illegal_insn, 2) /* Illegal instruction */ \
44-
_(breakpoint, 3) /* Breakpoint */ \
45-
_(load_misaligned, 4) /* Load address misaligned */ \
46-
_(store_misaligned, 6) /* Store/AMO address misaligned */ \
41+
/* clang-format off */
42+
#define RV_EXCEPTION_LIST \
43+
IIF(RV32_HAS(EXT_C))(, \
44+
_(insn_misaligned, 0) /* Instruction address misaligned */ \
45+
) \
46+
_(illegal_insn, 2) /* Illegal instruction */ \
47+
_(breakpoint, 3) /* Breakpoint */ \
48+
_(load_misaligned, 4) /* Load address misaligned */ \
49+
_(store_misaligned, 6) /* Store/AMO address misaligned */ \
4750
_(ecall_M, 11) /* Environment call from M-mode */
51+
/* clang-format on */
4852

4953
enum {
5054
#define _(type, code) rv_exception_code##type = code,
@@ -344,16 +348,12 @@ static block_t *block_find(const block_map_t *map, const uint32_t addr)
344348
}
345349
#endif
346350

351+
#if !RV32_HAS(EXT_C)
347352
FORCE_INLINE bool insn_is_misaligned(uint32_t pc)
348353
{
349-
return (pc &
350-
#if RV32_HAS(EXT_C)
351-
0x1
352-
#else
353-
0x3
354-
#endif
355-
);
354+
return pc & 0x3;
356355
}
356+
#endif
357357

358358
/* instruction length information for each RISC-V instruction */
359359
enum {

src/rv32_template.c

+50-48
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,9 @@ RVOP(
142142
if (ir->rd)
143143
rv->X[ir->rd] = pc + 4;
144144
/* check instruction misaligned */
145+
#if !RV32_HAS(EXT_C)
145146
RV_EXC_MISALIGN_HANDLER(pc, insn, false, 0);
147+
#endif
146148
struct rv_insn *taken = ir->branch_taken;
147149
if (taken) {
148150
#if RV32_HAS(JIT)
@@ -213,7 +215,9 @@ RVOP(
213215
if (ir->rd)
214216
rv->X[ir->rd] = pc + 4;
215217
/* check instruction misaligned */
218+
#if !RV32_HAS(EXT_C)
216219
RV_EXC_MISALIGN_HANDLER(pc, insn, false, 0);
220+
#endif
217221
#if !RV32_HAS(JIT)
218222
LOOKUP_OR_UPDATE_BRANCH_HISTORY_TABLE();
219223
#endif
@@ -238,51 +242,52 @@ RVOP(
238242
(type) x cond (type) y
239243
/* clang-format on */
240244

241-
#define BRANCH_FUNC(type, cond) \
242-
const uint32_t pc = PC; \
243-
if (BRANCH_COND(type, rv->X[ir->rs1], rv->X[ir->rs2], cond)) { \
244-
is_branch_taken = false; \
245-
struct rv_insn *untaken = ir->branch_untaken; \
246-
if (!untaken) \
247-
goto nextop; \
248-
IIF(RV32_HAS(JIT)) \
249-
({ \
250-
block_t *block = cache_get(rv->block_cache, PC + 4); \
251-
if (!block) { \
252-
ir->branch_untaken = NULL; \
253-
goto nextop; \
254-
} \
255-
untaken = ir->branch_untaken = block->ir_head; \
256-
if (cache_hot(rv->block_cache, PC + 4)) \
257-
goto nextop; \
258-
}, ); \
259-
PC += 4; \
260-
last_pc = PC; \
261-
MUST_TAIL return untaken->impl(rv, untaken, cycle, PC); \
262-
} \
263-
is_branch_taken = true; \
264-
PC += ir->imm; \
265-
/* check instruction misaligned */ \
266-
RV_EXC_MISALIGN_HANDLER(pc, insn, false, 0); \
267-
struct rv_insn *taken = ir->branch_taken; \
268-
if (taken) { \
269-
IIF(RV32_HAS(JIT)) \
270-
({ \
271-
block_t *block = cache_get(rv->block_cache, PC); \
272-
if (!block) { \
273-
ir->branch_taken = NULL; \
274-
goto end_insn; \
275-
} \
276-
taken = ir->branch_taken = block->ir_head; \
277-
if (cache_hot(rv->block_cache, PC)) \
278-
goto end_insn; \
279-
}, ); \
280-
last_pc = PC; \
281-
MUST_TAIL return taken->impl(rv, taken, cycle, PC); \
282-
} \
283-
end_insn: \
284-
rv->csr_cycle = cycle; \
285-
rv->PC = PC; \
245+
#define BRANCH_FUNC(type, cond) \
246+
IIF(RV32_HAS(EXT_C))(, const uint32_t pc = PC;); \
247+
if (BRANCH_COND(type, rv->X[ir->rs1], rv->X[ir->rs2], cond)) { \
248+
is_branch_taken = false; \
249+
struct rv_insn *untaken = ir->branch_untaken; \
250+
if (!untaken) \
251+
goto nextop; \
252+
IIF(RV32_HAS(JIT)) \
253+
({ \
254+
block_t *block = cache_get(rv->block_cache, PC + 4); \
255+
if (!block) { \
256+
ir->branch_untaken = NULL; \
257+
goto nextop; \
258+
} \
259+
untaken = ir->branch_untaken = block->ir_head; \
260+
if (cache_hot(rv->block_cache, PC + 4)) \
261+
goto nextop; \
262+
}, ); \
263+
PC += 4; \
264+
last_pc = PC; \
265+
MUST_TAIL return untaken->impl(rv, untaken, cycle, PC); \
266+
} \
267+
is_branch_taken = true; \
268+
PC += ir->imm; \
269+
/* check instruction misaligned */ \
270+
IIF(RV32_HAS(EXT_C)) \
271+
(, RV_EXC_MISALIGN_HANDLER(pc, insn, false, 0);) struct rv_insn *taken = \
272+
ir->branch_taken; \
273+
if (taken) { \
274+
IIF(RV32_HAS(JIT)) \
275+
({ \
276+
block_t *block = cache_get(rv->block_cache, PC); \
277+
if (!block) { \
278+
ir->branch_taken = NULL; \
279+
goto end_insn; \
280+
} \
281+
taken = ir->branch_taken = block->ir_head; \
282+
if (cache_hot(rv->block_cache, PC)) \
283+
goto end_insn; \
284+
}, ); \
285+
last_pc = PC; \
286+
MUST_TAIL return taken->impl(rv, taken, cycle, PC); \
287+
} \
288+
end_insn: \
289+
rv->csr_cycle = cycle; \
290+
rv->PC = PC; \
286291
return true;
287292

288293
/* In RV32I and RV64I, if the branch is taken, set pc = pc + offset, where
@@ -1815,7 +1820,6 @@ RVOP(
18151820
{
18161821
rv->X[rv_reg_ra] = PC + 2;
18171822
PC += ir->imm;
1818-
RV_EXC_MISALIGN_HANDLER(PC, insn, true, 0);
18191823
struct rv_insn *taken = ir->branch_taken;
18201824
if (taken) {
18211825
#if RV32_HAS(JIT)
@@ -1981,7 +1985,6 @@ RVOP(
19811985
cj,
19821986
{
19831987
PC += ir->imm;
1984-
RV_EXC_MISALIGN_HANDLER(PC, insn, true, 0);
19851988
struct rv_insn *taken = ir->branch_taken;
19861989
if (taken) {
19871990
#if RV32_HAS(JIT)
@@ -2224,7 +2227,6 @@ RVOP(
22242227
const int32_t jump_to = rv->X[ir->rs1];
22252228
rv->X[rv_reg_ra] = PC + 2;
22262229
PC = jump_to;
2227-
RV_EXC_MISALIGN_HANDLER(PC, insn, true, 0);
22282230
#if !RV32_HAS(JIT)
22292231
LOOKUP_OR_UPDATE_BRANCH_HISTORY_TABLE();
22302232
#endif

0 commit comments

Comments
 (0)