Skip to content

Latest commit

 

History

History
423 lines (323 loc) · 22 KB

toolchain-conventions.adoc

File metadata and controls

423 lines (323 loc) · 22 KB

Specifying the target ISA with -march

The compiler and assembler both accept the -march flag to specify the target ISA, e.g. rv32imafd. The abbreviation g can be used to represent either IMAFD (when targeting RISC-V ISA specification version 2.2 or earlier) or IMAFD_Zicsr_Zifencei (version 20190608 or later) base and extensions, e.g. -march=rv64g. A target -march which includes floating point instructions implies a hardfloat calling convention, but can be overridden using the -mabi flag (see the next section).

The ISA subset naming conventions and canonical order are described in Chapter ISA Extension Naming Conventions of the RISC-V user-level ISA specification. However, tools do not currently follow this specification (input is case sensitive, …​).

The rule of ISA string become more complicated, due to extension implication rules and more extensions added into RISC-V, the canonical order is non-obvious to humans, so tools should accept the ISA string in non-canonical order to reduce the burden of remembering the canonical order.

Detailed rules for ISA string:

  1. First letter must be i, e or g.

  2. Single-letter may be non-canonical order.

  3. Multi-letter may be non-canonical order.

  4. Multi-letter must be separated by underscore.

  5. Version separator(p) has higher priority than p extension.

Example:

rv32ima_zicsr        # Valid ISA string.
rv32i_zicsr_m        # Valid ISA string.
rv32i_zicsr_ma       # Valid ISA string.
rv32imac             # Valid ISA string.
rv32mai              # Invalid ISA string, first letter must be `i`, `e` or `g`.
rv32i_zicsrzifence   # Valid ISA string, but it will interpreted as rv32
                     # with base extension and `zicsrzifence` extension
                     # rather than `zicsr` and `zifence` extensions.
rv32i2p1             # Valid ISA string, it recognized as `I` extension with
                     # version 2.1 rather than `I` extension with with version
                     # 2.0 and `P` extension with 1.0.

If the 'C' (compressed) instruction set extension is targeted, the compiler will generate compressed instructions where possible.

Note
Single-letter extension with version (e.g. m2p0) is still treated as a single-letter extension, it won’t be treated as a multi-letter extension.
Note
Any output of ISA string like Tag_RISCV_arch must be canonical order.
Note
Cross-tool argument are highly recommended to be passed in canonical order for backward compatibility.

Issues for consideration

  • Whether riscv32 and riscv64 should be accepted as synonyms for rv32 and rv64.

  • Whether the -march string should be parsed case insensitively.

  • Exposing the ability to specify version numbers for a target extension.

  • Specifying non-standard extensions. The ISA specification suggests naming such as rv32gXfirstext_Xsecondext. In GCC or Clang it would be more conventional to give a string such as rv32g+firstext+secondext.

Specifying the target ABI with -mabi

  • ilp32: int, long, pointers are 32-bit. GPRs and the stack are used for parameter passing.

  • ilp32f: int, long, pointers are 32-bit. GPRs, 32-bit FPRs, and the stack are used for parameter passing.

  • ilp32d: int, long, pointers are 32-bit. GPRs, 64-bit FPRs and the stack are used for parameter passing.

  • lp64: long, pointers are 64-bit. GPRs and the the stack are used for parameter passing.

  • lp64f: long, pointers are 64-bit. GPRs, 32-bit FPRs, and the stack are used for parameter passing.

  • lp64d: long, pointers are 64-bit. GPRs, 64-bit FPRs, and the stack are used for parameter passing.

See the RISC-V ELF psABI for more information on these ABIs.

The default value for -mabi is system dependent. For cross-compilation, both -march and -mabi should be specified. An error will be produced for impossible combinations of -march and -mabi such as -march=rv32i and -mabi=ilp32f.

Issues for consideration

  • Should the -mabi string be parsed case insensitively?

  • How should the RV32E ABI be specified? ilp32e?

Specifying the target code model with -mcmodel

The target code model indicates constraints on symbols which the compiler can exploit these constraints to generate more efficient code. Three code models are currently defined for RISC-V:

  • -mcmodel=medlow. The program and its statically defined symbols must lie within a single 2GiB address range, between the absolute addresses -2GiB and +2GiB. lui and addi pairs are used to generate addresses.

  • -mcmodel=medany. The program and its statically defined symbols must lie within a single 4GiB address range. auipc and addi pairs are used to generate addresses.

  • -mcmodel=large. The program and its statically defined symbols can lie within the whole 64-bit address range. auipc, addi and ld are used to generate addresses.

  • Use of any PIC or PIE option (e.g. -fpic, -fPIC, -fpie or -fPIE) will enable the medium position independent code model. This model is similar to the medium any code model, but uses the global offset table (GOT) for non-local symbol addresses.

Note
When PIC or PIE mode enabled the -mcmodel=medlow will be suppressed.

RISC-V psABI has a contain sections to describe the code model:

Disassembler (objdump) behaviour

A RISC-V ELF binary is not currently self-describing, in the sense that it doesn’t contain enough information to determine which variant of the RISC-V architecture is being targeted. GNU objdump will currently attempt disassemble any instruction whose encoding matches one of the standard RV32/RV64GC extensions.

objdump will default to showing pseudoinstructions and ABI register names. The numeric disassembler argument can be used to use architectural register names such as x10, while the no-aliases disassembler argument will ensure only canonical instructions rather than pseudoinstructions or aliases are printed. These arguments are specified using -M, e.g. -M numeric or -M numeric,no-aliases.

Perhaps surprisingly, the disassembler will default to hiding the difference between compressed (16-bit) instructions and their 32-bit equivalent. e.g. c.addi sp, -16 will be printed as addi sp, sp, -16.

Issues for consideration

  • The current GNU objdump behaviour will not provide useful results for cases where non-standard extensions are implemented which reuse some of the standard extension’s encoding space. Making RISC-V ELF files self-describing (as discussed here) would avoid this problem.

  • Would it be useful to have separate flags that control the printing of pseudoinstructions and whether compressed instructions are printed directly or not?

Assembler behaviour

See the RISC-V Assembly Programmer’s Manual for details on the syntax accepted by the assembler.

The assembler will produce compressed instructions whenever possible if the targeted RISC-V variant includes support for the 'C' compressed instruction set.

Issues for consideration

  • There is currently no way to enable support for the 'C' ISA extension, but to disable the automatic 'compression' of instructions.

C/C++ preprocessor definitions

These are now maintained in the RISC-V C API specification.

Specifying stack alignment

The default stack alignment is 16 bytes in RV32I and RV64I, and 4 bytes on RV32E. There is not currently a way to specify an alternative stack alignment, but the -mpreferred-stack-boundary and -mincoming-stack-boundary flags supported by GCC on X86 could be adopted.

Save restore support

The save restore optimization is enabled through the option -msave-restore and reduces the amount of code in the prologue and epilogue by using library functions instead of inline code to save and restore callee saved registers. The library functions are provided in the emulation library and have the following signatures:

  • void __riscv_save_<N>(void)

  • void __riscv_restore_<N>(void)

  • void __riscv_restore_tailcall_<N> (void * tail /* passed in t1 */) (LLVM/compiler-rt only)

<N> is a value between 0 and 12 and corresponds to the number of registers between s0 and s11 that are saved/restored. The return address register ra is always included in the registers saved and restored.

The __riscv_save_<N> functions are called from the prologue, using t0 as the link register to avoid clobbering ra. They allocate stack space for the registers and then save ra and the appropriate number of registers from s0-s11. The __riscv_restore_<N> functions are tail-called from the epilogue. They restore the saved registers, deallocate the stack space for the register, and then perform a return through the restored value of ra.

__riscv_restore_tailcall_<N> are additional entry points used when the epilogue of the called function ends in a tail-call. Unlike __riscv_restore_<N> these are also provided the address of the function which was originally tail-called as an argument, and after restoring registers they make a tail-call through that argument instead of returning. Note that the address of the function to tail-call is provided in register t1, which differs from the normal calling convention.

As of November 2021 the additional tail-call entry points are only implemented in compiler-rt, and calls will only be generated by LLVM when the option -mllvm -save-restore-tailcall is specified.

Conventions for vendor extensions

Support for custom instruction set extensions are an important part of RISC-V, with large encoding spaces reserved of vendor extensions.

However, there are no official guidelines on naming the mnemonics. This section defines guidelines which vendors are expected to follow if upstreaming support for their extensions. Although vendor-provided toolchains are free to make different choices, they are strongly urged to align with these guidelines in order to ensure there is a straightforward path for upstreaming in the future.

Note
Open source toolchain maintainer has final say on accepting vendor extension, comply with this conventions isn’t guarantee upstream will accept.

Vendor extension naming scheme

According to the RISC-V ISA spec, non-standard extensions are named using a single X followed by an alphabetical name and an optional version number.

To make it easier to identify and prevent naming conflict, vendor extensions should start with a vendor name, which could be an abbreviation of the full name.

For example:

  • XVentanaCondOps from Ventana

  • Xsfcflushdlone from SiFive

Assembly mnemonic

In order to avoid confusion between standard extension and other vendor extensions, instruction mnemonics from vendor extensions must have a prefix corresponding to the vendor’s name.

The vendor prefix should be at least two letters long

e.g. sf. for SiFive, vt. for Ventana. No central registration with RISC-V International or elsewhere is required before the prefix is used.

Note
Although no centralized registration is required, vendors should add the vendor prefix to the table IF vendors are interested to upstream their extension to open source toolchain like LLVM or GNU toolchain.

Vendors should also aim to follow the conventions used for naming mnemonics in the ratified base ISA and extensions (e.g. the use of 'w', 'd', 'u', and 's' suffixes).

CSR naming scheme

Vendors may define their own CSRs within the custom read-only CSR address range specified in the RISC-V ISA spec. However, to avoid conflicts, each vendor CSR must include a prefix corresponding to the vendor’s name.

The vendor prefix should match the prefix defined in assembly mnemonics and be separated by a dot, e.g., th.vxrm.

List of vendor prefixes

Table 1. List of vendor prefixes

Vendor

Prefix

URL

Cheriot

ct

https://cheriot.org/

Open Hardware Group

cv

https://www.openhwgroup.org/

Andes

nds

https://www.andestech.com/

SiFive

sf

https://www.sifive.com/

T-Head

th

https://www.t-head.cn/

Tenstorrent

tt

https://www.tenstorrent.com/

Ventana Micro Systems

vt

https://www.ventanamicro.com/

Nuclei

xl

https://nucleisys.com/

Note
Vendor prefixes are case-insensitive.
Note
The Nuclei instruction prefix xl is an abbreviation of "XinLai", which is the Chinese pronunciation of Nuclei(芯来).
Note
OpenHW cores are all branded as CORE-V, hence the prefix.

List of vendor identifiers

Vendor identifiers are dummy symbols used in the corresponding R_RISCV_VENDOR relocation (irrespective of ELF class/XLEN) and must be unique amongst all vendors providing custom relocations. Vendor identifiers may be suffixed with a tag to provide extra relocations for a given vendor.

Table 2. List of vendor identifiers

Vendor

Symbol

Open Hardware Group

COREV

List of vendor extensions

Table 3. List of vendor extensions

Vendor

Name

Version

ISA Document

OpenHW

Xcvalu

1.0.0

CORE-V Instruction Set Extensions

OpenHW

Xcvbi

1.0.0

CORE-V Instruction Set Extensions

OpenHW

Xcvbitmanip

1.0.0

CORE-V Instruction Set Extensions

OpenHW

Xcvelw

1.0.0

CORE-V Instruction Set Extensions

OpenHW

Xcvhwlp

1.0.0

CORE-V Instruction Set Extensions

OpenHW

Xcvmac

1.0.0

CORE-V Instruction Set Extensions

OpenHW

Xcvmem

1.0.0

CORE-V Instruction Set Extensions

OpenHW

Xcvsimd

1.0.0

CORE-V Instruction Set Extensions

SiFive

XSFvqmaccdod

1.0

SiFive Int8 Matrix Multiplication Extensions Specification

SiFive

XSFvqmaccqoq

1.0

SiFive Int8 Matrix Multiplication Extensions Specification

SiFive

XSFvfnrclipxfqf

1.0

FP32-to-int8 Ranged Clip Instructions (Xsfvfnrclipxfqf) Extension Specification

SiFive

Xsfvfwmaccqqq

1.0

Matrix Multiply Accumulate Instruction (Xsfvfwmaccqqq) Extension Specification

SiFive

XSFVCP

1.0

SiFive Vector Coprocessor Interface Software Specification

T-Head

XTheadCmo

1.0

T-Head ISA extension specification

T-Head

XTheadBa

1.0

T-Head ISA extension specification

T-Head

XTheadBb

1.0

T-Head ISA extension specification

T-Head

XTheadBs

1.0

T-Head ISA extension specification

T-Head

XTheadCondMov

1.0

T-Head ISA extension specification

T-Head

XTheadFMemIdx

1.0

T-Head ISA extension specification

T-Head

XTheadFmv

1.0

T-Head ISA extension specification

T-Head

XTheadInt

1.0

T-Head ISA extension specification

T-Head

XTheadMac

1.0

T-Head ISA extension specification

T-Head

XTheadMemPair

1.0

T-Head ISA extension specification

T-Head

XTheadMemIdx

1.0

T-Head ISA extension specification

T-Head

XTheadSync

1.0

T-Head ISA extension specification

T-Head

XTheadVector

1.0

T-Head ISA extension specification

Ventana

XVentanaCondOps

1.0

VTx-family custom instructions

Note
Vendor extension names are case-insensitive, CamelCase is used here for readability.
Note
Additional information on the CORE-V ISA extensions can be found in the CORE-V ISA Extension Naming specification, and in the draft CORE-V Builtin Function specification.

Common Toolchain Command Line Options

This section lists common RISC-V specific toolchain command line options.

-mstrict-align/-mno-strict-align

Indicates that the compiler should not assume that unaligned scalar and unaligned vector memory references are handled by the system.

-mstrict-align: The compiler disallows misaligned memory access.

-mno-strict-align: The compiler allows misaligned memory access.

The compiler’s behavior will follow this order of precedence:

  • Use the setting from -mstrict-align / -mno-strict-align if either option is given, taking the last one specified.

  • Use the setting from -mtune if -mstrict-align / -mno-strict-align is not given.

  • Use the setting from -mcpu if neither of the above options is given.

  • Use the compiler’s default setting if none of the above options are provided.

Note
Non-strict also known as unaligned access or misaligned access
Note
The compiler may generate misaligned access if the program violates the alignment assumption.
Note
This option does not affect inline assembly.

-mscalar-strict-align/-mno-scalar-strict-align/-mvector-strict-align/-mno-vector-strict-align

-mscalar-strict-align/-mno-scalar-strict-align: Similar to -mstrict-align/-mno-strict-align but applied to scalar memory access only.

-mvector-strict-align/-mno-vector-strict-align: Similar to -mstrict-align/-mno-strict-align but applied to vector memory access only.

The precedence among -m[no]-scalar-strict-align, -m[no-]vector-strict-align, and -m[no-]strict-align is determined by the last one specified.

-fcf-protection=[full|branch|return|none]/-fcf-protection

Enable control flow protection. The compiler will insert control flow integrity instructions to protect the program against control flow hijacking attacks.

-fcf-protection is alias to -fcf-protection=full.

  • none: Disable control flow protection.

  • full: Protects all control flow instructions. Branch protection does not require the Zimop extension, but return protection will be enabled only if Zimop is available.

  • branch: Protect branch instructions only by inserting landing pad.

  • return: Protect return instructions only, this require Zimop extension.

-mcf-branch-label-scheme=[unlabeled|func-sig]

Specify the label scheme for the -fcf-protection=branch. The default is value is platform defined.

  • unlabeled: Use simple label scheme, the label is always 0.

  • func-sig: Use function signature as the label, the label is generated by the compiler, the rule is defined in psABI spec.

TODO

  • -mdiv, -mno-div, -mfdiv, -mno-fdiv, -msave-restore, -mno-save-restore, -mexplicit-relocs, -mno-explicit-relocs

Appendix: Exposing a vendor-specific extension across the toolchain

TODO.