mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
6f109d8a2d
Refactor FnDecl and FnSig non-type fields into a new wrapper type #### Why this Refactor? This PR is part of an initial cleanup for the [arg splat experiment](https://github.com/rust-lang/rust/issues/153629), but it's a useful refactor by itself. It refactors the non-type fields of `FnDecl`, `FnSig`, and `FnHeader` into a new packed wrapper types, based on this comment in the `splat` experiment PR: https://github.com/rust-lang/rust/pull/153697#discussion_r3004637413 It also refactors some common `FnSig` creation settings into their own methods. I did this instead of creating a struct with defaults. #### Relationship to `splat` Experiment I don't think we can use functional struct updates (`..default()`) to create `FnDecl` and `FnSig`, because we need the bit-packing for the `splat` experiment. Bit-packing will avoid breaking "type is small" assertions for commonly used types when `splat` is added. This PR packs these types: - ExternAbi: enum + `unwind` variants (38) -> 6 bits - ImplicitSelfKind: enum variants (5) -> 3 bits - lifetime_elision_allowed, safety, c_variadic: bool -> 1 bit #### Minor Changes Fixes some typos, and applies rustfmt to clippy files that got skipped somehow.
stdarch-gen-arm generator guide
Running the generator
Run: cargo +nightly run --bin=stdarch-gen-arm -- crates/stdarch-gen-arm/spec crates/core_arch/src
NOTE: If you are running this from rust-lang/rust, you must be in the library/stdarch
working directory.
Input/Output
Input files (intrinsic YAML definitions)
crates/stdarch-gen-arm/spec/<feature>/*.spec.yml
Output files
- Generated intrinsics:
crates/core_arch/src/<arch>/<feature>/generated.rs
- Generated load/store tests:
crates/core_arch/src/<arch>/<feature>/ld_st_tests_<arch>.rs- Only generated when
test: { load: <idx> }ortest: { store: <idx> }is set for SVE/SVE2 intrinsics.
.spec.yml file anatomy
---
Configs
---
Variable definitions
---
Intrinsic definitions
---
- If you're new to YAML syntax, consider reviewing some of the less obvious syntax and features.
- For example, mapping an attribute to a sequence can be done in two different ways:
attribute: [item_a, item_b, item_c]
or
attribute:
- item_a
- item_b
- item_c
Configs
- Mappings defining top-level settings applied to all intrinsics:
arch_cfgs- Sequence of mappings specifying
arch_name,target_feature(sequence), andllvm_prefix.
- Sequence of mappings specifying
uses_neon_types(Optional)- A boolean specifying whether to emit NEON type imports in generated code.
auto_big_endian(Optional)- A boolean specifying whether to auto-generate big-endian shuffles when possible.
auto_llvm_sign_conversion(Optional)- A boolean specifying whether to auto-convert LLVM wrapper args to signed types.
Variable definitions
- Defines YAML anchors/variables to avoid repetition.
- Commonly used for stability attributes, cfgs and target features.
Intrinsic definitions
Example
- name: "vtst{neon_type[0].no}"
doc: "Signed compare bitwise Test bits nonzero"
arguments: ["a: {neon_type[0]}", "b: {neon_type[0]}"]
return_type: "{neon_type[1]}"
attr:
- FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [cmtst]]}]]
- FnCall: [stable, ['feature = "neon_intrinsics"', 'since = "1.59.0"']]
safety: safe
types:
- [int64x1_t, uint64x1_t, 'i64x1', 'i64x1::new(0)']
- [int64x2_t, uint64x2_t, 'i64x2', 'i64x2::new(0, 0)']
- [poly64x1_t, uint64x1_t, 'i64x1', 'i64x1::new(0)']
- [poly64x2_t, uint64x2_t, 'i64x2', 'i64x2::new(0, 0)']
compose:
- Let: [c, "{neon_type[0]}", {FnCall: [simd_and, [a, b]]}]
- Let: [d, "{type[2]}", "{type[3]}"]
- FnCall: [simd_ne, [c, {FnCall: [transmute, [d]]}]]
Explanation of fields
name- The name of the intrinsic
- Often built from a base name followed by a type suffix
doc(Optional)- A string explaining the purpose of the intrinsic
static_defs(Optional)- A sequence of const generics of the format
"const <NAME>: <type>"
- A sequence of const generics of the format
arguments- A sequence of strings in the format
"<argname>: <argtype>"
- A sequence of strings in the format
return_type(Optional)- A string specifying the return type. If omitted, the intrinsic returns
().
- A string specifying the return type. If omitted, the intrinsic returns
attr(Optional)- A sequence of items defining the attributes to be applied to the intrinsic. Often stability attributes, target features, or
assert_instrtests. At least one ofattrorassert_instrmust be set.
- A sequence of items defining the attributes to be applied to the intrinsic. Often stability attributes, target features, or
target_features(Optional)- A sequence of target features to enable for this intrinsic (merged with any global
arch_cfgssettings).
- A sequence of target features to enable for this intrinsic (merged with any global
assert_instr(Optional)- A sequence of strings expected to be found in the assembly. Required if
attris not set.
- A sequence of strings expected to be found in the assembly. Required if
safety(Optional)- Use
safe, or mapunsafe:to a sequence of unsafety comments:custom: "<string>"uninitializedpointer_offset,pointer_offset_vnum, ordereference(optionally qualified withpredicated,predicated_non_faulting, orpredicated_first_faulting)unpredictable_on_faultnon_temporalneonno_provenance: "<string>"
- Use
substitutions(Optional)- Mappings of custom wildcard names to either
MatchSizeorMatchKindexpressions
- Mappings of custom wildcard names to either
types- A sequence or sequence of sequences specifying the types to use when producing each intrinsic variant. These sequences can then be indexed by wildcards.
constraints(Optional)- A sequence of mappings. Each specifies a variable and a constraint. The available mappings are:
- Assert a variable's value exists in a sequence of i32's
- Usage:
{ variable: <name>, any_values: [<i32>,...] }
- Usage:
- Assert a variable's value exists in a range (inclusive)
- Usage:
{ variable: <name>, range: [<i32>, <i32>] }
- Usage:
- Assert a variable's value exists in a range via a match (inclusive)
- Usage:
{ variable: <name>, range: <MatchSize returning [i32,i32]> }
- Usage:
- Assert a variable's value does not exceed the number of elements in a SVE type
<type>.- Usage:
{ variable: <name>, sve_max_elems_type: <type> }
- Usage:
- Assert a variable's value does not exceed the number of elements in a vector type
<type>.- Usage:
{ variable: <name>, vec_max_elems_type: <type> }
- Usage:
predication_methods(Optional)- Configuration for predicate-form variants. Only used when the intrinsic name includes an
_m*_wildcard (e.g.,{_mx},{_mxz}). zeroing_method: Required when requesting_z; either{ drop: <arg> }to remove an argument and replace it with a zero initialiser, or{ select: <predicate_var> }to select zeros into a predicate.dont_care_method: How_xshould be implemented (inferred,as_zeroing, oras_merging).
- Configuration for predicate-form variants. Only used when the intrinsic name includes an
compose- A sequence of expressions that make up the body of the intrinsic
big_endian_inverse(Optional)- A boolean, default false. If true, generates two implementations of each intrinsic variant, one for each endianness, and attempts to automatically generate the required bit swizzles
visibility(Optional)- Function visibility. One of
public(default) orprivate.
- Function visibility. One of
n_variant_op(Optional)- Enables generation of an
_nvariant when the intrinsic name includes the{_n}wildcard. Set to the operand name that should be splattered for the_nform.
- Enables generation of an
test(Optional)- When set, load/store tests are automatically generated.
- A mapping of either
loadorstoreto a number that indexestypesto specify the type that the test should be addressing in memory.
Expressions
Common
Let- Defines a variable
- Usage:
Let: [<variable>, <type(optional)>, <expression>]
Const- Defines a const
- Usage:
Const: [<variable>, <type>, <expression>]
Assign- Performs variable assignment
- Usage:
Assign: [<variable>, <expression>]
FnCall- Performs a function call
- Usage:
FnCall: [<function pointer: expression>, [<argument: expression>, ... ], [<turbofish argument: expression>, ...](optional), <unsafe wrapper(optional): bool>]
MacroCall- Performs a macro call
- Usage:
MacroCall: [<macro name>, <token stream>]
MethodCall- Performs a method call
- Usage:
MethodCall: [<object: expression>, <method name>, [<argument: expression>, ... ]]
LLVMLink- Creates an LLVM link and stores the function's name in the wildcard
{llvm_link}for later use in subsequent expressions. - If left unset, the arguments and return type inherit from the intrinsic's signature by default. The links will also be set automatically if unset.
- Usage:
- Creates an LLVM link and stores the function's name in the wildcard
LLVMLink:
name: <name>
arguments: [<expression>, ... ](optional)
return_type: <return type>(optional)
links: (optional)
- link: <link>
arch: <arch>
- ...
Identifier- Emits a symbol. Prepend with a
$to treat it as a scope variable, which engages variable tracking and enables inference. For example,my_function_namefor a generic symbol or$my_variablefor a variable. - Usage
Identifier: [<symbol name>, <Variable|Symbol>]
- Emits a symbol. Prepend with a
CastAs- Casts an expression to an unchecked type
- Usage:
CastAs: [<expression>, <type>]
MatchSize- Allows for conditional generation depending on the size of a specified type
- Usage:
MatchSize:
- <type>
- default: <expression>
byte(optional): <expression>
halfword(optional): <expression>
doubleword(optional): <expression>
MatchKind- Allows for conditional generation depending on the kind of a specified type
MatchKind:
- <type>
- default: <expression>
float(optional): <expression>
unsigned(optional): <expression>
Rarely Used
IntConstant- Constant signed integer expression
- Usage:
IntConstant: <i32>
FloatConstant- Constant floating-point expression
- Usage:
FloatConstant: <f32>
BoolConstant- Constant boolean expression
- Usage:
BoolConstant: <bool>
Array- An array of expressions
- Usage:
Array: [<expression>, ...]
Multiply- Simply
* - Usage:
Multiply: [<expression>, <expression>]
- Simply
Xor- Simply
^ - Usage:
Xor: [<expression>, <expression>]
- Simply
ConvertConst- Converts the specified constant to the specified type's kind
- Usage:
ConvertConst: [<type>, <i32>]
Type- Yields the given type in the Rust representation
- Usage:
Type: [<type>]
Wildstrings
- Wildstrings let you take advantage of wildcards.
- For example, they are often used in intrinsic names
name: "vtst{neon_type[0].no}" - As shown above, wildcards are identified by the surrounding curly brackets.
- Double curly brackets can be used to escape wildcard functionality if you need literal curly brackets in the generated intrinsic.
Wildcards
Wildcards are heavily used in the spec. They let you write generalised definitions for a group of intrinsics that generate multiple variants. The wildcard itself is replaced with the relevant string in each variant.
Ignoring endianness, for each row in the types field of an intrinsic in the spec, a variant of the intrinsic will be generated. That row's contents can be indexed by the wildcards. Below is the behaviour of each wildcard.
type[<index: usize>]- Replaced in each variant with the value in the indexed position in the relevant row of the
typesfield. - For unnested sequences of
types(i.e.,typesis a sequence where each element is a single item, not another sequence), the square brackets can be omitted. Simply:type
- Replaced in each variant with the value in the indexed position in the relevant row of the
neon_type[<index: usize>]- Extends the behaviour of
typewith some NEON-specific features and inference. - Tuples: This wildcard can also be written as
neon_type_x<n>wherenis in the set{2,3,4}. This generates then-tuple variant of the (inferred) NEON type. - Suffixes: These modify the behaviour of the wildcard from simple substitution.
no- normal behaviour. Tries to do as much work as it can for you, inferring when to emit:- Regular type-size suffixes:
_s8,_u16,_f32, ... qvariants for double-width (128b) vector types:q_s8,q_u16,q_f32, ..._x<n>variants for tuple vector types:_s8_x2,_u32_x3,_f64_x4, ...- As well as any combination of the above:
q_s16_x16...
- Regular type-size suffixes:
- Most of the other suffixes modify the normal behaviour by disabling features or adding new ones. (See table below)
- Extends the behaviour of
sve_type[<index: usize>]- Similar to
neon_type, but without the suffixes.
- Similar to
size[<index: usize>]- The size (in bits) of the indexed type.
size_minus_one[<index: usize>]- Emits the size (in bits) of the indexed type minus one.
size_literal[<index: usize>]- The literal representation of the indexed type.
b: byte,h: halfword,w: word, ord: double.
type_kind[<index: usize>]- The literal representation of the indexed type's kind.
f: float,s: signed,u: unsigned,p: polynomial,b: boolean.
size_in_bytes_log2[<index: usize>]- Log2 of the size of the indexed type in bytes.
predicate[<index: usize>]- SVE predicate vector type inferred from the indexed type.
max_predicate- The same as predicate, but uses the largest type in the relevant
typessequence/row.
- The same as predicate, but uses the largest type in the relevant
_n- Emits the current N-variant suffix when
n_variant_opis configured.
- Emits the current N-variant suffix when
<wildcard> as <type>- If
<wildcard>evaluates to a vector, it produces a vector of the same shape, but with<type>as the base type.
- If
llvm_link- If the
LLVMLinkmapping has been set for an intrinsic, this will give the name of the link.
- If the
_m*- Predicate form masks. Use wildcards such as
{_mx}or{_mxz}to expand merging/don't-care/zeroing variants according to the mask.
- Predicate form masks. Use wildcards such as
<custom>- You may simply call upon wildcards defined under
substitutions.
- You may simply call upon wildcards defined under
neon_type suffixes
| suffix | implication |
|---|---|
.no |
Normal |
.noq |
Never include qs |
.nox |
Never include _x<n>s |
.N |
Include _n_, e.g., _n_s8 |
.noq_N |
Include _n_, but never qs |
.dup |
Include _dup_, e.g., _dup_s8 |
.dup_nox |
Include _dup_ but never _x<n>s |
.lane |
Include _lane_, e.g., _lane_s8 |
.lane_nox |
Include _lane_, but never _x<n>s |
.rot90 |
Include _rot90_, e.g., _rot90_s8 |
.rot180 |
Include _rot180_, e.g., _rot180_s8 |
.rot270 |
Include _rot270_, e.g., _rot270_s8 |
.rot90_lane |
Include _rot90_lane_ |
.rot180_lane |
Include _rot180_lane_ |
.rot270_lane |
Include _rot270_lane_ |
.rot90_laneq |
Include _rot90_laneq_ |
.rot180_laneq |
Include _rot180_laneq_ |
.rot270_laneq |
Include _rot270_laneq_ |
.base |
Produce only the size, e.g., 8, 16 |
.u |
Produce the type's unsigned equivalent |
.laneq_nox |
Include _laneq_, but never _x<n>s |
.tuple |
Produce only the size of the tuple, e.g., 3 |
.base_byte_size |
Produce only the size in bytes. |