The RISC-V ISA defines fence.i as flushing the icache on the current hart (hardware thread, aka core) and not on any other hart. If the linux kernel moves a process to a different hart in between writes to code, and the following fence.i instruction, then the result is indeterminate. To fix this, we need to add a new kernel interface to flush the icache, which is currently implemented as a VDSO. Since the glibc support has not been contributed yet, we need to fix this now before doing so creates a linux ABI change.
This was tested with a riscv64 linux make check. Since I'm using a user-mode qemu to test, and user-mode qemu doesn't have VDSO support (yet?) that means every testcase that requires an icache flush is failing. This is a temporary problem that we have to live with for now. Otherwise, there are no regressions. Committed. gcc/ * config/riscv/linux.h (ICACHE_FLUSH_FUNC): New. * config/riscv/riscv.md (clear_cache): Use it. --- gcc/config/riscv/linux.h | 2 ++ gcc/config/riscv/riscv.md | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/gcc/config/riscv/linux.h b/gcc/config/riscv/linux.h index 6c7e3c4e819..4b2f7b6e1fd 100644 --- a/gcc/config/riscv/linux.h +++ b/gcc/config/riscv/linux.h @@ -45,6 +45,8 @@ along with GCC; see the file COPYING3. If not see #define LIB_SPEC GNU_USER_TARGET_LIB_SPEC " -latomic " #endif +#define ICACHE_FLUSH_FUNC "__riscv_flush_icache" + #define LINK_SPEC "\ -melf" XLEN_SPEC "lriscv \ %{shared} \ diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index db4fed48e53..dab54ad2738 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -1456,7 +1456,13 @@ (match_operand 1 "pmode_register_operand")] "" { +#ifdef ICACHE_FLUSH_FUNC + emit_library_call (gen_rtx_SYMBOL_REF (Pmode, ICACHE_FLUSH_FUNC), + LCT_NORMAL, VOIDmode, operands[0], Pmode, + operands[1], Pmode, const0_rtx, Pmode); +#else emit_insn (gen_fence_i ()); +#endif DONE; }) -- 2.14.1