Skip to content

Commit 17288e3

Browse files
PaoloS02alistair23
authored andcommitted
optimize the memory probing for vector fault-only-first loads.
Fault-only-first loads in the RISC-V vector extension need to update the vl with the element index that causes an exception. In order to ensure this the emulation of this instruction used to probe the memory covered by the load operation with a loop that iterated over each element so that when a flag was raised it was possible to set the vl to the corresponding element index. This loop was executed every time whether an exception happened or not. This commit removes the per element memory probing from the main execution path and adds a broad memory probing first. If this probing raises any flag that is not a watchpoint flag (that per standard is allowed by this instruction) we proceed with the per element probing to find the index of the element causing the exception and set vl to such index. Signed-off-by: Paolo Savini <[email protected]> Reviewed-by: Daniel Henrique Barboza <[email protected]> Message-ID: <[email protected]> Signed-off-by: Alistair Francis <[email protected]>
1 parent 672cb29 commit 17288e3

File tree

1 file changed

+58
-45
lines changed

1 file changed

+58
-45
lines changed

target/riscv/vector_helper.c

Lines changed: 58 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -633,47 +633,69 @@ vext_ldff(void *vd, void *v0, target_ulong base, CPURISCVState *env,
633633
uint32_t esz = 1 << log2_esz;
634634
uint32_t msize = nf * esz;
635635
uint32_t vma = vext_vma(desc);
636-
target_ulong addr, offset, remain, page_split, elems;
636+
target_ulong addr, addr_probe, addr_i, offset, remain, page_split, elems;
637637
int mmu_index = riscv_env_mmu_index(env, false);
638+
int flags;
639+
void *host;
638640

639641
VSTART_CHECK_EARLY_EXIT(env);
640642

641-
/* probe every access */
642-
for (i = env->vstart; i < env->vl; i++) {
643-
if (!vm && !vext_elem_mask(v0, i)) {
644-
continue;
645-
}
646-
addr = adjust_addr(env, base + i * (nf << log2_esz));
647-
if (i == 0) {
648-
/* Allow fault on first element. */
649-
probe_pages(env, addr, nf << log2_esz, ra, MMU_DATA_LOAD);
650-
} else {
651-
remain = nf << log2_esz;
652-
while (remain > 0) {
653-
void *host;
654-
int flags;
655-
656-
offset = -(addr | TARGET_PAGE_MASK);
657-
658-
/* Probe nonfault on subsequent elements. */
659-
flags = probe_access_flags(env, addr, offset, MMU_DATA_LOAD,
660-
mmu_index, true, &host, 0);
661-
662-
/*
663-
* Stop if invalid (unmapped) or mmio (transaction may fail).
664-
* Do not stop if watchpoint, as the spec says that
665-
* first-fault should continue to access the same
666-
* elements regardless of any watchpoint.
667-
*/
668-
if (flags & ~TLB_WATCHPOINT) {
669-
vl = i;
670-
goto ProbeSuccess;
671-
}
672-
if (remain <= offset) {
673-
break;
643+
addr = base + ((env->vstart * nf) << log2_esz);
644+
page_split = -(addr | TARGET_PAGE_MASK);
645+
/* Get number of elements */
646+
elems = page_split / msize;
647+
if (unlikely(env->vstart + elems >= env->vl)) {
648+
elems = env->vl - env->vstart;
649+
}
650+
651+
/* Check page permission/pmp/watchpoint/etc. */
652+
flags = probe_access_flags(env, adjust_addr(env, addr), elems * msize,
653+
MMU_DATA_LOAD, mmu_index, true, &host, ra);
654+
655+
/* If we are crossing a page check also the second page. */
656+
if (env->vl > elems) {
657+
addr_probe = addr + (elems << log2_esz);
658+
flags |= probe_access_flags(env, adjust_addr(env, addr_probe),
659+
elems * msize, MMU_DATA_LOAD, mmu_index,
660+
true, &host, ra);
661+
}
662+
663+
if (flags & ~TLB_WATCHPOINT) {
664+
/* probe every access */
665+
for (i = env->vstart; i < env->vl; i++) {
666+
if (!vm && !vext_elem_mask(v0, i)) {
667+
continue;
668+
}
669+
addr_i = adjust_addr(env, base + i * (nf << log2_esz));
670+
if (i == 0) {
671+
/* Allow fault on first element. */
672+
probe_pages(env, addr_i, nf << log2_esz, ra, MMU_DATA_LOAD);
673+
} else {
674+
remain = nf << log2_esz;
675+
while (remain > 0) {
676+
offset = -(addr_i | TARGET_PAGE_MASK);
677+
678+
/* Probe nonfault on subsequent elements. */
679+
flags = probe_access_flags(env, addr_i, offset,
680+
MMU_DATA_LOAD, mmu_index, true,
681+
&host, 0);
682+
683+
/*
684+
* Stop if invalid (unmapped) or mmio (transaction may
685+
* fail). Do not stop if watchpoint, as the spec says that
686+
* first-fault should continue to access the same
687+
* elements regardless of any watchpoint.
688+
*/
689+
if (flags & ~TLB_WATCHPOINT) {
690+
vl = i;
691+
goto ProbeSuccess;
692+
}
693+
if (remain <= offset) {
694+
break;
695+
}
696+
remain -= offset;
697+
addr_i = adjust_addr(env, addr_i + offset);
674698
}
675-
remain -= offset;
676-
addr = adjust_addr(env, addr + offset);
677699
}
678700
}
679701
}
@@ -685,15 +707,6 @@ vext_ldff(void *vd, void *v0, target_ulong base, CPURISCVState *env,
685707

686708
if (env->vstart < env->vl) {
687709
if (vm) {
688-
/* Calculate the page range of first page */
689-
addr = base + ((env->vstart * nf) << log2_esz);
690-
page_split = -(addr | TARGET_PAGE_MASK);
691-
/* Get number of elements */
692-
elems = page_split / msize;
693-
if (unlikely(env->vstart + elems >= env->vl)) {
694-
elems = env->vl - env->vstart;
695-
}
696-
697710
/* Load/store elements in the first page */
698711
if (likely(elems)) {
699712
vext_page_ldst_us(env, vd, addr, elems, nf, max_elems,

0 commit comments

Comments
 (0)