@samitouri / QOSamiQemu / commits / 460549ba10

target/riscv: Support raising misaligned exceptions for vector loads/stores

When the Zicclsm extension is not enabled, raise misaligned load/store exceptions for misaligned accesses from vector load/store instructions. We will skip the host fast-path and fall back to the slow TLB-path to raise misaligned load/store exceptions for the misaligned accesses when Zicclsm extension is disabled. Signed-off-by: Frank Chang <frank.chang@sifive.com> Reviewed-by: Max Chou <max.chou@sifive.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260810055618.1175500-6-frank.chang@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>

Frank Chang committed Aug 10, 2026 at 13:56 UTC 460549ba1088ee9ac5f69c0f5c42c96ebb4d1355
2 files changed +65 -18
target/riscv/tcg/insn_trans/trans_rvv.c.inc
+15 -3
@@ -1191,26 +1191,38 @@ static bool ldst_whole_trans(uint32_t vd, uint32_t rs1, uint32_t nf,
1191 * Use the helper function if either:
1192 * - vstart is not 0.
1193 */
1194 -
1194 bool use_helper_fn = !s->vstart_eq_zero;
1195
1196 if (!use_helper_fn) {
1197 uint32_t size = s->cfg_ptr->vlenb * nf;
1198 TCGv_i64 t8 = tcg_temp_new_i64();
1199 MemOp atomicity = MO_ATOM_NONE;
1200 + MemOp alignment = MO_UNALN;
1201 +
1202 + /*
1203 + * If Zicclsm is disabled, require alignment based on element size.
1204 + * Use MO_ALIGN_* based on log2_esz (0 = MO_UNALN, 1 = MO_ALIGN_2, etc).
1205 + */
1206 + if (!s->cfg_ptr->ext_zicclsm) {
1207 + alignment = log2_esz << MO_ASHIFT;
1208 + }
1209 +
1210 if (log2_esz == 0) {
1211 atomicity = MO_ATOM_NONE;
1212 } else {
1213 atomicity = MO_ATOM_IFALIGN_PAIR;
1214 }
1215 +
1216 for (int i = 0; i < size; i += 8) {
1217 TCGv addr = get_address(s, rs1, i);
1218 if (is_load) {
1209 - tcg_gen_qemu_ld_i64(t8, addr, s->mem_idx, MO_LEUQ | atomicity);
1219 + tcg_gen_qemu_ld_i64(t8, addr, s->mem_idx,
1220 + MO_LEUQ | atomicity | alignment);
1221 tcg_gen_st_i64(t8, tcg_env, vreg_ofs(s, vd) + i);
1222 } else {
1223 tcg_gen_ld_i64(t8, tcg_env, vreg_ofs(s, vd) + i);
1213 - tcg_gen_qemu_st_i64(t8, addr, s->mem_idx, MO_LEUQ | atomicity);
1224 + tcg_gen_qemu_st_i64(t8, addr, s->mem_idx,
1225 + MO_LEUQ | atomicity | alignment);
1226 }
1227 if (i == size - 8) {
1228 tcg_gen_movi_i32(cpu_vstart, 0);
target/riscv/tcg/vector_helper.c
+50 -15
@@ -199,20 +199,34 @@ static inline void vext_set_elem_mask(void *v0, int index,
199 ((uint64_t *)v0)[idx] = deposit64(old, pos, 1, value);
200 }
201
202 +static inline MemOpIdx vext_make_memop_idx(CPURISCVState *env, size_t size)
203 +{
204 + int mmu_idx = riscv_env_mmu_index(env, false);
205 + MemOp memop = size_memop(size) | mo_endian_env(env);
206 +
207 + if (!riscv_cpu_cfg(env)->ext_zicclsm) {
208 + memop |= MO_ALIGN;
209 + }
210 +
211 + return make_memop_idx(memop, mmu_idx);
212 +}
213 +
214 /* elements operations for load and store */
215 typedef void vext_ldst_elem_fn_tlb(CPURISCVState *env, abi_ptr addr,
216 uint32_t idx, void *vd, uintptr_t retaddr);
217 typedef void vext_ldst_elem_fn_host(void *vd, uint32_t idx, void *host);
218
207 -#define GEN_VEXT_LD_ELEM(NAME, ETYPE, H, LDSUF) \
219 +#define GEN_VEXT_TLB_LD_ELEM(NAME, ETYPE, H, LDSUF) \
220 static inline QEMU_ALWAYS_INLINE \
221 void NAME##_tlb(CPURISCVState *env, abi_ptr addr, \
222 uint32_t idx, void *vd, uintptr_t retaddr) \
223 { \
224 ETYPE *cur = ((ETYPE *)vd + H(idx)); \
213 - *cur = cpu_##LDSUF##_data_ra(env, addr, retaddr); \
225 + MemOpIdx oi = vext_make_memop_idx(env, sizeof(ETYPE)); \
226 + *cur = cpu_##LDSUF##_mmu(env, addr, oi, retaddr); \
227 } \
215 - \
228 +
229 +#define GEN_VEXT_HOST_LD_ELEM(NAME, ETYPE, H, LDSUF) \
230 static inline QEMU_ALWAYS_INLINE \
231 void NAME##_host(void *vd, uint32_t idx, void *host) \
232 { \
@@ -220,20 +234,27 @@ void NAME##_host(void *vd, uint32_t idx, void *host) \
234 *cur = (ETYPE)LDSUF##_p(host); \
235 }
236
223 -GEN_VEXT_LD_ELEM(lde_b, uint8_t, H1, ldub)
224 -GEN_VEXT_LD_ELEM(lde_h, uint16_t, H2, lduw_le)
225 -GEN_VEXT_LD_ELEM(lde_w, uint32_t, H4, ldl_le)
226 -GEN_VEXT_LD_ELEM(lde_d, uint64_t, H8, ldq_le)
237 +GEN_VEXT_TLB_LD_ELEM(lde_b, uint8_t, H1, ldb)
238 +GEN_VEXT_TLB_LD_ELEM(lde_h, uint16_t, H2, ldw)
239 +GEN_VEXT_TLB_LD_ELEM(lde_w, uint32_t, H4, ldl)
240 +GEN_VEXT_TLB_LD_ELEM(lde_d, uint64_t, H8, ldq)
241
228 -#define GEN_VEXT_ST_ELEM(NAME, ETYPE, H, STSUF) \
242 +GEN_VEXT_HOST_LD_ELEM(lde_b, uint8_t, H1, ldub)
243 +GEN_VEXT_HOST_LD_ELEM(lde_h, uint16_t, H2, lduw_le)
244 +GEN_VEXT_HOST_LD_ELEM(lde_w, uint32_t, H4, ldl_le)
245 +GEN_VEXT_HOST_LD_ELEM(lde_d, uint64_t, H8, ldq_le)
246 +
247 +#define GEN_VEXT_TLB_ST_ELEM(NAME, ETYPE, H, STSUF) \
248 static inline QEMU_ALWAYS_INLINE \
249 void NAME##_tlb(CPURISCVState *env, abi_ptr addr, \
250 uint32_t idx, void *vd, uintptr_t retaddr) \
251 { \
252 ETYPE data = *((ETYPE *)vd + H(idx)); \
234 - cpu_##STSUF##_data_ra(env, addr, data, retaddr); \
253 + MemOpIdx oi = vext_make_memop_idx(env, sizeof(ETYPE)); \
254 + cpu_##STSUF##_mmu(env, addr, data, oi, retaddr); \
255 } \
236 - \
256 +
257 +#define GEN_VEXT_HOST_ST_ELEM(NAME, ETYPE, H, STSUF) \
258 static inline QEMU_ALWAYS_INLINE \
259 void NAME##_host(void *vd, uint32_t idx, void *host) \
260 { \
@@ -241,10 +262,15 @@ void NAME##_host(void *vd, uint32_t idx, void *host) \
262 STSUF##_p(host, data); \
263 }
264
244 -GEN_VEXT_ST_ELEM(ste_b, uint8_t, H1, stb)
245 -GEN_VEXT_ST_ELEM(ste_h, uint16_t, H2, stw_le)
246 -GEN_VEXT_ST_ELEM(ste_w, uint32_t, H4, stl_le)
247 -GEN_VEXT_ST_ELEM(ste_d, uint64_t, H8, stq_le)
265 +GEN_VEXT_TLB_ST_ELEM(ste_b, uint8_t, H1, stb)
266 +GEN_VEXT_TLB_ST_ELEM(ste_h, uint16_t, H2, stw)
267 +GEN_VEXT_TLB_ST_ELEM(ste_w, uint32_t, H4, stl)
268 +GEN_VEXT_TLB_ST_ELEM(ste_d, uint64_t, H8, stq)
269 +
270 +GEN_VEXT_HOST_ST_ELEM(ste_b, uint8_t, H1, stb)
271 +GEN_VEXT_HOST_ST_ELEM(ste_h, uint16_t, H2, stw_le)
272 +GEN_VEXT_HOST_ST_ELEM(ste_w, uint32_t, H4, stl_le)
273 +GEN_VEXT_HOST_ST_ELEM(ste_d, uint64_t, H8, stq_le)
274
275 static inline QEMU_ALWAYS_INLINE void
276 vext_continuous_ldst_tlb(CPURISCVState *env, vext_ldst_elem_fn_tlb *ldst_tlb,
@@ -398,7 +424,16 @@ vext_page_ldst_us(CPURISCVState *env, void *vd, target_ulong addr,
424 probe_pages(env, addr, size, ra, access_type, mmu_index, &host, &flags,
425 true);
426
401 - if (flags == 0) {
427 + bool misaligned = addr & (esz - 1);
428 +
429 + /*
430 + * Allow the host fast-pash when:
431 + * 1. Page permission/pmp/watchpoint are checked and we have a contigous
432 + * host mapping.
433 + * 2. Zicclsm is enabled or load/store is not a misaligned access.
434 + * Otherwise, we will fall back to the slow TLB-path.
435 + */
436 + if (flags == 0 && (riscv_cpu_cfg(env)->ext_zicclsm || !misaligned)) {
437 if (nf == 1) {
438 vext_continuous_ldst_host(env, ldst_host, vd, evl, env->vstart,
439 host, esz, is_load);