GCC/Clang RISCV preprocessor macros and RVABI

2,057 views
Skip to first unread message

Michael Clark

unread,
Nov 3, 2016, 12:49:18 AM11/3/16
to RISC-V SW Dev
Thinking about -march= and -mfloat-abi= 

I see that float support can currently be distinguished from GCC preprocessor macros however the macros are different to the march flags, and there is also no expansion of extensions from the -march flags so we don’t know the value of -march at compile time (use case is library code versus internal access for compiler optimisation)

I wonder whether creating macros for each extension in the -march flag is a good idea? e.g. -march=IMAFDN would result in something like this:

#define _RISCV_EXT_I 1
#define _RISCV_EXT_M 1
#define _RISCV_EXT_A 1
#define _RISCV_EXT_F 1
#define _RISCV_EXT_D 1
#define _RISCV_EXT_N 1

Not sure if this is a good idea?

I was looking to see what other platforms define for -mfloat-abi but I couldn’t find anything definitive. Something like this perhaps?

#define _RISCV_RVABI_HARD 1
#define _RISCV_RVABI_SOFT 1
#define _RISCV_RVABI_SOFTFP 1

The other thought was that once these macros are added, we won’t really be able to change them easily without breaking things. The preprocessor macros become part of the ABI glue at the compiler level, and they will likely be used by optimisations in math, crypto and multimedia libraries. So the question is we have to freeze __riscv_soft_float and __riscv_hard_float so we can depend on these in base libraries for presence of hard float? or is it still okay to break things at the preprocessor level? I know the Base ISA is frozen, but it seems there isn’t any official documentation for RVABI interfaces or compiler macros. So even if we add new macros to further distinguish RVABI and the various extensions we should also keep __riscv_soft_float and __riscv_hard_float

There also needs to be an RVABI header (assuming its called RVABI) that includes the soft float and integer ops for 64-bit on RV32, and potentially even 128-bit on RV64 and RV32. There is no reason why we couldn’t provide optimised intrinsics for 128-bit ops on RV32 and RV64 in RVABI, so that 128-bit integer and QP arithmetic work on all RISC-V targets (perhaps at some later date).

Q. Are the 64-bit ops on RV32 in compiler_rt and libgcc or is this part of some kind of RVABI? I think if we define an RVABI early on then a big compatibility mess of many different ABIs could be avoided. i.e. the first decade of ARM.

This example header is just RISC-V FD, and is just a starting point. I imagine we would need to standardise the ABI for integer ‘M’ and ‘A’ as well as the 64-bit fill in functions for 64-bit arithmetic on RV32:


Is there a page somewhere that lists the matrix of what headers are defined depending on which ABI is selected and what hardware extensions are present. It could be quite useful for a manual.

Model specific tuning will also become important e.g. we want to know if whether mul and shifts are constant time for use in optimisation (strength reductions). Ideally RISC-V library code can detect the -mtune flags via preprocessor headers so not only the compiler can perform these optimisations, but libraries can modify their code based on extension and model. e.g.

-mtune=constant-time-shift
-mtune=constant-time-mul

#define _RISCV_MUL_O1 1
#define _RISCV_SHIFT_O1 1

-mtune=non-constant-time-shift
-mtune=non-constant-time-mul

#undef _RISCV_MUL_O1
#undef _RISCV_SHIFT_O1

Crypto code is definitely going to want to enact different strategies depending on whether mul or shift is constant time.

I was actually looking at disassembly of loop induction variables and noticed that gcc currently emits mul in structure offset calculations for array of structure loops (versus emitting adds). It might be something wrong with the cost model. gcc on x86 emits adds for array of structure loop induction variables. Overflow semantics are the same for add or mul so it doesn’t matter whether the loop bounds check is constant or dynamic. I also notice the mul got strength reduced to shift (mul strength reduced to shift with -O3, mul with -Os versus add on x86).

Perhaps I can put up an (unofficial) rvabi.md file that documents the current macros and interfaces. I think it might require some more reverse engineering.

Michael.


mclark@minty:~/src/riscv-tools$ riscv32-unknown-elf-gcc --version
riscv32-unknown-elf-gcc (GCC) 6.1.0
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

mclark@minty:~/src/riscv-tools$ riscv64-unknown-elf-gcc --version
riscv64-unknown-elf-gcc (GCC) 6.1.0
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

mclark@minty:~/src/riscv-tools$ riscv32-unknown-elf-gcc -dM -E -march=IMAFD -msoft-float - < /dev/null | grep -i RISCV
#define __riscv 1
#define __riscv_atomic 1
#define __RISCVEL 1
#define RISCVEL 1
#define _RISCV_SZPTR 32
#define _RISCV_SZINT 32
#define __riscv_muldiv 1
#define __riscv32 1
#define _RISCV_SZLONG 32
#define __RISCVEL__ 1
#define _RISCV_SIM _ABI32
#define __riscv__ 1
#define _riscv 1
#define __riscv_soft_float 1
mclark@minty:~/src/riscv-tools$ riscv32-unknown-elf-gcc -dM -E -march=IMA -mhard-float - < /dev/null | grep -i RISCV
#define __riscv 1
#define __riscv_hard_float 1
#define __riscv_atomic 1
#define __RISCVEL 1
#define RISCVEL 1
#define __riscv_fdiv 1
#define _RISCV_SZPTR 32
#define _RISCV_SZINT 32
#define __riscv_muldiv 1
#define __riscv32 1
#define _RISCV_SZLONG 32
#define __riscv_fsqrt 1
#define __RISCVEL__ 1
#define _RISCV_SIM _ABI32
#define __riscv__ 1
#define _riscv 1
mclark@minty:~/src/riscv-tools$ riscv32-unknown-elf-gcc -dM -E -march=I -mhard-float - < /dev/null | grep -i RISCV
#define __riscv 1
#define __riscv_hard_float 1
#define __RISCVEL 1
#define RISCVEL 1
#define __riscv_fdiv 1
#define _RISCV_SZPTR 32
#define _RISCV_SZINT 32
#define __riscv32 1
#define _RISCV_SZLONG 32
#define __riscv_fsqrt 1
#define __RISCVEL__ 1
#define _RISCV_SIM _ABI32
#define __riscv__ 1
#define _riscv 1


Palmer Dabbelt

unread,
Nov 3, 2016, 12:40:45 PM11/3/16
to michae...@mac.com, sw-...@groups.riscv.org
I like the idea. I think a good policy would be to have any "-march", "-mabi",
or "-mtune" flag be exposed via a preprocessor macro to user code. This just
didn't quite get implemented all the way through the toolchain before binutils
got up because how we deal with FP ABIs changed right in the middle of our
patchset submission. The use cases I'm thinking of are:

#ifdef THERE_ARE_FP_REGISTERS
fsd f0, 0(sp)
fsd f1, 8(sp)
...
#endif

#ifdef I_CAN_PASS_FP_ARGS_IN_REGISTERS
fmv fa0, f3
#else
mv.x.f a0, x3
#endif

#ifdef INTEGER_MULTIPLY_IS_FAST
mul x4, x3, x2
#else
mv a0, x3
mv a1, x2
call mul
mv x4, a0
#endif

It would be great to try and iron these names out before we get GCC upstream,
since once that lands we'll be stuck with whatever mistakes we've made. I
think something like

_RISCV_ARCH_{I,M,A,F,D}

_RISCV_FLOATABI_{SOFT,SINGLE,DOUBLE,QUAD}

_RISCV_TUNE_{FAST_IMUL}

would be a reasonable naming scheme, since it matches the "-m" flag set. Can
you open either an issue (or pull request) on the riscv/riscv-gcc repo with a
concrete suggestion (or patch set) so we get this done? I think this is a GCC
issue and not a binutils issue, but GCC should be getting sent out soon so it's
important to get this right.

Thanks!

On Wed, 02 Nov 2016 21:48:59 PDT (-0700), michae...@mac.com wrote:
> Thinking about -march= and -mfloat-abi=
>
> I see that float support can currently be distinguished from GCC preprocessor macros however the macros are different to the march flags, and there is also no expansion of extensions from the -march flags so we don’t know the value of -march at compile time (use case is library code versus internal access for compiler optimisation)
>
> I wonder whether creating macros for each extension in the -march flag is a good idea? e.g. -march=IMAFDN would result in something like this:
>
> #define _RISCV_EXT_I 1
> #define _RISCV_EXT_M 1
> #define _RISCV_EXT_A 1
> #define _RISCV_EXT_F 1
> #define _RISCV_EXT_D 1
> #define _RISCV_EXT_N 1
>
> Not sure if this is a good idea?
>
> I was looking to see what other platforms define for -mfloat-abi but I couldn’t find anything definitive. Something like this perhaps?
>
> #define _RISCV_RVABI_HARD 1
> #define _RISCV_RVABI_SOFT 1
> #define _RISCV_RVABI_SOFTFP 1
>
> The other thought was that once these macros are added, we won’t really be able to change them easily without breaking things. The preprocessor macros become part of the ABI glue at the compiler level, and they will likely be used by optimisations in math, crypto and multimedia libraries. So the question is we have to freeze __riscv_soft_float and __riscv_hard_float so we can depend on these in base libraries for presence of hard float? or is it still okay to break things at the preprocessor level? I know the Base ISA is frozen, but it seems there isn’t any official documentation for RVABI interfaces or compiler macros. So even if we add new macros to further distinguish RVABI and the various extensions we should also keep __riscv_soft_float and __riscv_hard_float
>
> There also needs to be an RVABI header (assuming its called RVABI) that includes the soft float and integer ops for 64-bit on RV32, and potentially even 128-bit on RV64 and RV32. There is no reason why we couldn’t provide optimised intrinsics for 128-bit ops on RV32 and RV64 in RVABI, so that 128-bit integer and QP arithmetic work on all RISC-V targets (perhaps at some later date).
>
> Q. Are the 64-bit ops on RV32 in compiler_rt and libgcc or is this part of some kind of RVABI? I think if we define an RVABI early on then a big compatibility mess of many different ABIs could be avoided. i.e. the first decade of ARM.
>
> This example header is just RISC-V FD, and is just a starting point. I imagine we would need to standardise the ABI for integer ‘M’ and ‘A’ as well as the 64-bit fill in functions for 64-bit arithmetic on RV32:
>
> https://gist.github.com/michaeljclark/a9699015de965d7fdb306a54ec4157ba <https://gist.github.com/michaeljclark/a9699015de965d7fdb306a54ec4157ba>
> --
> You received this message because you are subscribed to the Google Groups "RISC-V SW Dev" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to sw-dev+un...@groups.riscv.org.
> To post to this group, send email to sw-...@groups.riscv.org.
> Visit this group at https://groups.google.com/a/groups.riscv.org/group/sw-dev/.
> To view this discussion on the web visit https://groups.google.com/a/groups.riscv.org/d/msgid/sw-dev/A5ECE767-6315-481D-9175-826DA2F070C8%40mac.com.

Andrew Waterman

unread,
Nov 3, 2016, 1:33:54 PM11/3/16
to Palmer Dabbelt, Michael Clark, RISC-V SW Dev
On Thu, Nov 3, 2016 at 9:40 AM, Palmer Dabbelt
<palmer....@eecs.berkeley.edu> wrote:
> I like the idea. I think a good policy would be to have any "-march", "-mabi",
> or "-mtune" flag be exposed via a preprocessor macro to user code. This just
> didn't quite get implemented all the way through the toolchain before binutils
> got up because how we deal with FP ABIs changed right in the middle of our
> patchset submission. The use cases I'm thinking of are:
>
> #ifdef THERE_ARE_FP_REGISTERS
> fsd f0, 0(sp)
> fsd f1, 8(sp)
> ...
> #endif

This is #ifdef __riscv_flen, which I think is fine

>
> #ifdef I_CAN_PASS_FP_ARGS_IN_REGISTERS
> fmv fa0, f3
> #else
> mv.x.f a0, x3
> #endif

This is #ifdef __riscv_float_abi_single/double/quad, which I think is fine

>
> #ifdef INTEGER_MULTIPLY_IS_FAST
> mul x4, x3, x2
> #else
> mv a0, x3
> mv a1, x2
> call mul
> mv x4, a0
> #endif

This is currently #ifdef __riscv_mul
> To view this discussion on the web visit https://groups.google.com/a/groups.riscv.org/d/msgid/sw-dev/581b688b.4ad8420a.406cc.fb57%40mx.google.com.

Palmer Dabbelt

unread,
Nov 3, 2016, 1:35:36 PM11/3/16
to Andrew Waterman, michae...@mac.com, sw-...@groups.riscv.org
OK, so I think we're safe with what we've got.
> To view this discussion on the web visit https://groups.google.com/a/groups.riscv.org/d/msgid/sw-dev/CA%2B%2B6G0Dsi03jEnRpOWc-CTN%2Br6FVa_a4VwHm2zRNaPYW_DK8Kg%40mail.gmail.com.

NitinD.

unread,
Oct 21, 2017, 11:46:12 PM10/21/17
to RISC-V SW Dev, wate...@eecs.berkeley.edu, michae...@mac.com, palmer....@eecs.berkeley.edu
Hi,
 Is there a final list of preprocessor macros for march and abi combinations?
 Could someone please point me to it?

Regards,
Nitin

Michael Clark

unread,
Oct 22, 2017, 2:00:47 AM10/22/17
to NitinD., RISC-V SW Dev, wate...@eecs.berkeley.edu, palmer....@eecs.berkeley.edu
You can find the compiler defined macros by executing the compiler with all combinations of -march and -mabi flags. e.g.

gcc -march=rv64gc -mabi=lp64d -dM -- < /dev/null | grep -i riscv

That’s what I did while working on the musl port.

It would be nice to make a list somewhere outside of the compiler as this will be necessary for LLVM/Clang... unless someone has already done this?

Liviu Ionescu

unread,
Oct 22, 2017, 2:03:15 AM10/22/17
to Michael Clark, NitinD., RISC-V SW Dev, wate...@eecs.berkeley.edu, palmer....@eecs.berkeley.edu


> On 22 Oct 2017, at 09:00, Michael Clark <michae...@mac.com> wrote:
>
> It would be nice to make a list somewhere outside of the compiler

it is not exhaustive, but I found it useful:

https://gnu-mcu-eclipse.github.io/arch/riscv/programmer/#preprocessor-macros


regards,

Liviu


Alex Bradbury

unread,
Oct 25, 2017, 10:35:31 AM10/25/17
to Michael Clark, NitinD., RISC-V SW Dev, Andrew Waterman, Palmer Dabbelt
On 22 October 2017 at 07:00, Michael Clark <michae...@mac.com> wrote:
> You can find the compiler defined macros by executing the compiler with all
> combinations of -march and -mabi flags. e.g.
>
> gcc -march=rv64gc -mabi=lp64d -dM -E - < /dev/null | grep -i riscv
>
> That’s what I did while working on the musl port.
>
> It would be nice to make a list somewhere outside of the compiler as this
> will be necessary for LLVM/Clang... unless someone has already done this?

As it happens, I started work on a document covering "toolchain
conventions" which should cover this:

https://github.com/lowRISC/riscv-toolchain-conventions
https://groups.google.com/a/groups.riscv.org/d/msg/sw-dev/URl_dg-fTuk/wRW78vhLBAAJ

Best,

Alex
Reply all
Reply to author
Forward
0 new messages