Hello,
I found that a built-in function "__builtin_riscv_zicbop_cbo_prefetchi" is
terribly broken so that this is practically unusable. It emits the
"prefetch.i" machine instruction HINT but with no usable arguments.
Contents of a.c:
> void function_to_be_called(void);
>
> void sample(void)
> {
> __builtin_riscv_zicbop_cbo_prefetchi(&function_to_be_called);
> function_to_be_called();
> }
Compiling with the 'Zicbop' extension fails.
> $ riscv64-unknown-elf-gcc -O2 -march=rv64i_zicbop -mabi=lp64 -c a.c
> a.c: In function 'sample':
> a.c:5:42: warning: passing argument 1 of
> '__builtin_riscv_zicbop_cbo_prefetchi' makes integer from pointer without a
> cast [-Wint-conversion]
> 5 | __builtin_riscv_zicbop_cbo_prefetchi(&function_to_be_called);
> | ^~~~~~~~~~~~~~~~~~~~~~
> | |
> | void (*)(void)
> a.c:5:42: note: expected 'long int' but argument is of type 'void (*)(void)'
> a.c:5:5: error: invalid argument to built-in function
> 5 | __builtin_riscv_zicbop_cbo_prefetchi(&function_to_be_called);
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
seems the prototype of this built-in function is...
> int __builtin_riscv_zicbop_cbo_prefetchi(int); // RV32
> long __builtin_riscv_zicbop_cbo_prefetchi(long); // RV64
I started to have a bad feeling about this.
Looking at the test case, following code compiles (sort of).
> void sample(void)
> {
> __builtin_riscv_zicbop_cbo_prefetchi(1); /* integer constant: 0-4
> (inclusive) */
> }
WHAT IS THIS PREFETCHING!?
The answer was obvious (tested with GCC 13.2.0).
> $ riscv64-unknown-elf-gcc -O2 -march=rv64i_zicbop -mabi=lp64 -S a.c
> $ cat a.s
> .file "a.c"
> .option nopic
> .attribute arch, "rv64i2p1_zicbop1p0"
> .attribute unaligned_access, 0
> .attribute stack_align, 16
> .text
> .align 2
> .globl sample
> .type sample, @function
> sample:
> li a5,0
> prefetch.i 0(a5)
> ret
> .size sample, .-sample
> .ident "GCC: (gc891d8dc23e1) 13.2.0"
... none (NULL). Even the prefetching constant (1) is ignored.
It makes no sense whatsoever. This patch set is definitely compatibility-
breaking but necessary to make "prefetch.i" work.
This patch set makes following built-in function.
> void __builtin_riscv_zicbop_prefetch_i(void*);
Did you notice that I renamed the function? There are three reasons:
1. We needed to break the compatibility anyway.
2. To avoid functionality problems.
Co-existing functional and non-functional
__builtin_riscv_zicbop_cbo_prefetchi built-in felt like a nightmare.
3. Although this is also a cache block operation, the instruction
"prefetch.i" does not have the name "cbo" in it
(unlike "__builtin_riscv_zicbom_cbo_clean" corresponding "cbo.clean").
Let's make a working sample (a.c):
> void function_to_be_called(void);
>
> void sample(void)
> {
> __builtin_riscv_zicbop_prefetch_i(&function_to_be_called);
> function_to_be_called();
> }
And take look at the output assembly and its relocations.
> $ riscv64-unknown-elf-gcc -O2 -march=rv64i_zicbop -mabi=lp64 -S a.c
> $ cat a.s
> .file "a.c"
> .option nopic
> .attribute arch, "rv64i2p1_zicbop1p0"
> .attribute unaligned_access, 0
> .attribute stack_align, 16
> .text
> .align 2
> .globl sample
> .type sample, @function
> sample:
> lui a5,%hi(function_to_be_called)
> addi a5,a5,%lo(function_to_be_called)
> prefetch.i 0(a5)
> tail function_to_be_called
> .size sample, .-sample
> .ident "GCC: (GNU) 14.0.0 20230810 (experimental)"
I hope this issue is fixed soon.
Sincerely,
Tsukasa
Tsukasa OI (1):
RISC-V: Make "prefetch.i" built-in usable
gcc/config/riscv/riscv-cmo.def | 4 ++--
gcc/config/riscv/riscv.md | 5 ++---
gcc/doc/extend.texi | 7 +++++++
gcc/testsuite/gcc.target/riscv/cmo-zicbop-1.c | 8 +++++---
gcc/testsuite/gcc.target/riscv/cmo-zicbop-2.c | 10 ++++++----
5 files changed, 22 insertions(+), 12 deletions(-)
base-commit: 9b099a83b45b8fcdfc07d518e05d36ea741b2227
--
2.41.0