cargo run --bin=stdarch-gen-arm -- crates/stdarch-gen-arm/spec$ cargo run --bin=stdarch-gen-arm -- crates/stdarch-gen-arm/spec
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.18s
Running `target/debug/stdarch-gen-arm crates/stdarch-gen-arm/spec`
crates/stdarch-gen-arm/spec/<feature>/*.spec.ymlcrates/core_arch/src/<arch>/<feature>/generated.rscrates/core_arch/src/<arch>/<feature>/ld_st_tests_<arch>.rstest: { load: <idx> } or test: { store: <idx> } is set for SVE/SVE2 intrinsics..spec.yml file anatomy--- Configs --- Variable definitions --- Intrinsic definitions ---
attribute: [item_a, item_b, item_c]
or
attribute: - item_a - item_b - item_c
arch_cfgsarch_name, target_feature (sequence), and llvm_prefix.uses_neon_types(Optional)auto_big_endian(Optional)auto_llvm_sign_conversion(Optional)- 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]]}]]
namedoc (Optional)static_defs (Optional)"const <NAME>: <type>"arguments"<argname>: <argtype>"return_type (Optional)().attr (Optional)assert_instr tests. At least one of attr or assert_instr must be set.target_features (Optional)arch_cfgs settings).assert_instr (Optional)attr is not set.safety (Optional)safe, or map unsafe: to a sequence of unsafety comments:custom: "<string>"uninitializedpointer_offset, pointer_offset_vnum, or dereference (optionally qualified with predicated, predicated_non_faulting, or predicated_first_faulting)unpredictable_on_faultnon_temporalneonno_provenance: "<string>"substitutions (Optional)MatchSize or MatchKind expressionstypesconstraints (Optional){ variable: <name>, any_values: [<i32>,...] }{ variable: <name>, range: [<i32>, <i32>] }{ variable: <name>, range: <MatchSize returning [i32,i32]> }<type>.{ variable: <name>, sve_max_elems_type: <type> }<type>.{ variable: <name>, vec_max_elems_type: <type> }predication_methods (Optional)_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 _x should be implemented (inferred, as_zeroing, or as_merging).composebig_endian_inverse (Optional)visibility (Optional)public (default) or private.n_variant_op (Optional)_n variant when the intrinsic name includes the {_n} wildcard. Set to the operand name that should be splattered for the _n form.test (Optional)load or store to a number that indexes types to specify the type that the test should be addressing in memory.LetLet: [<variable>, <type(optional)>, <expression>]ConstConst: [<variable>, <type>, <expression>]AssignAssign: [<variable>, <expression>]FnCallFnCall: [<function pointer: expression>, [<argument: expression>, ... ], [<turbofish argument: expression>, ...](optional), <unsafe wrapper(optional): bool>]MacroCallMacroCall: [<macro name>, <token stream>]MethodCallMethodCall: [<object: expression>, <method name>, [<argument: expression>, ... ]]LLVMLink{llvm_link} for later use in subsequent expressions.LLVMLink: name: <name> arguments: [<expression>, ... ](optional) return_type: <return type>(optional) links: (optional) - link: <link> arch: <arch> - ...
Identifier$ to treat it as a scope variable, which engages variable tracking and enables inference. For example, my_function_name for a generic symbol or $my_variable for a variable.Identifier: [<symbol name>, <Variable|Symbol>]CastAsCastAs: [<expression>, <type>]MatchSizeMatchSize: - <type> - default: <expression> byte(optional): <expression> halfword(optional): <expression> doubleword(optional): <expression>
MatchKindMatchKind: - <type> - default: <expression> float(optional): <expression> unsigned(optional): <expression>
IntConstantIntConstant: <i32>FloatConstantFloatConstant: <f32>BoolConstantBoolConstant: <bool>ArrayArray: [<expression>, ...]SvUndefundef symbolSvUndefMultiply*Multiply: [<expression>, <expression>]Xor^Xor: [<expression>, <expression>]ConvertConstConvertConst: [<type>, <i32>]TypeType: [<type>]name: "vtst{neon_type[0].no}"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>]types field.types (i.e., types is a sequence where each element is a single item, not another sequence), the square brackets can be omitted. Simply: typeneon_type[<index: usize>]type with some NEON-specific features and inference.neon_type_x<n> where n is in the set {2,3,4}. This generates the n-tuple variant of the (inferred) NEON type.no - normal behaviour. Tries to do as much work as it can for you, inferring when to emit:_s8, _u16, _f32, ...q variants 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, ...q_s16_x16 ...sve_type[<index: usize>]neon_type, but without the suffixes.size[<index: usize>]size_minus_one[<index: usize>]size_literal[<index: usize>]b: byte, h: halfword, w: word, or d: double.type_kind[<index: usize>]f: float, s: signed, u: unsigned, p: polynomial, b: boolean.size_in_bytes_log2[<index: usize>]predicate[<index: usize>]max_predicatetypes sequence/row._nn_variant_op is configured.<wildcard> as <type><wildcard> evaluates to a vector, it produces a vector of the same shape, but with <type> as the base type.llvm_linkLLVMLink mapping has been set for an intrinsic, this will give the name of the link._m*{_mx} or {_mxz} to expand merging/don't-care/zeroing variants according to the mask.<custom>substitutions.| 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. |