This is a bit early, but as the Clever-ISA project currently has a functional* toolchain for assembly, and the emulator should be close to complete, I would like to get it looked at for future inclusion in rust.
Clever-ISA is an architecture I have been developing a specfication for since June, 2021. It is a 64-bit CISC architecture, intended to be an x86 substitute. As it applies to rust, the specification prescribes a number of recommendations intended to unify toolchains producing or handling machine code, this intended to describe those recommendations as applied to rust that I would seek approval on when bringing the target formally, which will occur after a fork of rustc is capable of compiling to the target.
*Disclaimer: a fork of GNU binutils does not yet provide an assembler, and https://github.com/LightningCreations/lc-binutils is required for that (and there are some bugs to debug wrt. that, but I expect them to be solved soon).
The Proposal is:
Clever-ISA Target Architecture
All documents in this section reference either a extension specification or a technical document from the https://github.com/Clever-ISA/Clever-ISA repository, in the
specs/ folder from the root. Documents labeled with an
X- prefix refer to an extension which is a normative part of the Clever-ISA specification binding on implementations. Documents labeled with a
D- prefix refer to a technical document that prescribes some forms of interaction with the architecture. Each named document is unique between types, and can be found in markdown form using the name of the document without a prefix within the specs folder. For example,
X-main refers to the document https://github.com/Clever-ISA/Clever-ISA/blob/main/specs/main.md.
The name of the architecture in target tuples is
clever, or alternatively
clever with a version suffix attached, such as
clever1.0, to refer to the target features that should be enabled or disabled. The canonical name
clever should be used in
#[cfg(target_arch)]. Per D-toolchain's target names section, only a published version of the specification should be accepted with an explicit version name.
Per D-toolchain, the list of target features is the same as the named list of extensions, excluding X-main which is always presumed to be available (as all implementations must implement X-main by definition). Each target feature name enables the instructions from the corresponding extension. For example,
-C target-feature="+vector" would enable instructions from the
By their nature, any extension that has been accepted by is not stablized in a public release is both subject to change or removal according to the governance process of Clever-ISA. It is recommended that those extensions be feature-gated for the
#[target_feature] attribute until a version containing them is placed in a feature-freeze status (or at the very least, extension-freeze status when the list of extensions is stablized but the contents are not yet frozen or stable).
The C abi for Clever-ISA is prescribed by D-abi.
extern "C" , primitive types, and the vector type has the ABI prescribed by D-abi.
i128 have alignment 16 on this target.
Wrt. binaries, shared objects, etc. ELF is used. D-abi also prescribes the processor-specific portions for ELF applicable to the target
ABI impact on repr(Rust)/extern "Rust"
While this is non-binding, it is notably unnecessary for
extern "Rust" to pass vector types on Clever-ISA indirectly, as the ABI for these types is well-specified to always use the integer registers.
Intrinsics for clever would be provided by the standard library under
The intrinsics are specified in the Intrinsics Section of D-toolchain, and would have the appropriate signatures adapted for rust. I will not list the exhaustive list for want of a (relatively) short proposal, but I will call out some specific ones with a special signature:
#[target_feature(enable="vector")] extern "platform-intrinsic" unsafe fn __vec_unary<const OP: VecUnaryOp, const ELEM_SIZE: usize, E: Vector>(vec: &mut E); #[target_feature(enable="vector")] extern "platform-intrinsic" unsafe fn __vec_binary<const OP: VecBinaryOp, const ELEM_SIZE: usize, D: VectorOrScalar, S: VectorOrScalar>(a: &mut D, b: S); #[target_feature(enable="vector")] extern "platform-intrinsic" unsafe fn __vec_ternary<const OP: VecTernaryOp, const ELEM_SIZE: usize, D: Vector, S1: VectorOrScalar, S2: VectorOrScalar>(a: &mut D, b: S, c: S);
#[repr(u16)] enums that list each instruction by name and sets the discriminant to the instructions canonical opcode (For example,
VecBinaryOp::Add would have a discriminant of
0x001 - do not use specialization opcodes). The input types to each intrinsic must have at least one Vector type,
__vec8). ELEM_SIZE must be a power of two that is at most the size of the largest vector type.
The vector types defined in the section have alignment equal to the size, except for
__vec256 which is 16-byte aligned.
core::arch::clever should also have a
f16 type (possibly with a different name) for use with 16-bit floating-point intrinsics.
Inline assembly on Clever-ISA uses (exclusively) the generic syntax specified by D-asm, with the directives specified by rust inline-assembly, except that the
.quad directive is deprecated. The canonical reference assembler is
lc-as from the lc-binutils project, but only the subset specified by D-asm is required.
The register classes and register names are as prescribed by D-toolchain, namely:
regwhich refers to a general purpose register (r0-r15), excluding the stack pointer (r7), and the base pointer (r6),
fregwhich refers to a floating-point register (f0-f7),
veclowhich refers to a low-half vector register (v0l-v15l),
vechiwhich refers to a hi-half vector register (v0h-v15h),
vechalfwhich refers to a vector half register, either
vecwhich refers to a vector register pair (v0-v15)
Other than the vector pair registers, there are no overlapping register. A vector pair overlaps with both of its constitutent vector-half registers, but the vector-half registers don't overlap with the others. If a register operand is of clas
vechi, using the
v specifier refers to the vector pair, using the
h specifier refers to the hi half of the vector pair, and using the
l specifier refers to the lo half of the vector pair. Specifiers are not used for any other kind of register, as in-assembly size specifiers are used to refer to smaller portions of a standard register.
Each register, except for the full
vec registers are 64-bit, but can store any value up to 64-bit (note that the entire register is clobbered in this case, as moving into a smaller portion of any register zeroes the higher portion).
The following registers are assumed not to be modified when the option
preserves_flags is specified:
fpcw(unless the function does not have the
fpcw.XOPSSare assumed not the be modified regardless of
preserves_flagssetting unless the
floatextension is not enabled.
mode register, stack pointer (r7), and base pointer (r6), are always assumed not to be modified. Other standard inline-assembly rules also apply.
Edit: Corrected r5 to r15.