From bab79c3a2d155f178481451cb76e150f7b83b0ce Mon Sep 17 00:00:00 2001 From: George Wort Date: Mon, 8 Jan 2024 14:56:19 +0000 Subject: [PATCH] Add the NEON-SVE Bridge intrinsics This allows Neon and SVE types to be converted between, often allowing the same register to be used for the different types. --- crates/core_arch/src/aarch64/sve/sve.rs | 384 ++++++++++++++++++++++ crates/core_arch/src/aarch64/sve/types.rs | 6 + crates/stdarch-gen2/spec/sve/sve.spec.yml | 46 +++ crates/stdarch-gen2/src/intrinsic.rs | 14 +- 4 files changed, 448 insertions(+), 2 deletions(-) diff --git a/crates/core_arch/src/aarch64/sve/sve.rs b/crates/core_arch/src/aarch64/sve/sve.rs index bd02cc50d4..a8fb247230 100644 --- a/crates/core_arch/src/aarch64/sve/sve.rs +++ b/crates/core_arch/src/aarch64/sve/sve.rs @@ -9792,6 +9792,146 @@ pub fn svdup_n_u64_x(pg: svbool_t, op: u64) -> svuint64_t { pub fn svdup_n_u64_z(pg: svbool_t, op: u64) -> svuint64_t { svdup_n_u64_m(svdup_n_u64(0), pg, op) } +#[doc = "Broadcast the 128 bit NEON vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svdup_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svdup_neonq_f32(data: float32x4_t) -> svfloat32_t { + extern "C" { + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.experimental.vector.insert.nxv4f32.v4f32" + )] + fn _svdup_neonq_f32(op0: svfloat32_t, op1: float32x4_t, idx: i64) -> svfloat32_t; + } + unsafe { + let op = _svdup_neonq_f32(simd_reinterpret(()), data, 0); + svdupq_lane_f32(op, 0) + } +} +#[doc = "Broadcast the 128 bit NEON vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svdup_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svdup_neonq_f64(data: float64x2_t) -> svfloat64_t { + extern "C" { + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.experimental.vector.insert.nxv2f64.v2f64" + )] + fn _svdup_neonq_f64(op0: svfloat64_t, op1: float64x2_t, idx: i64) -> svfloat64_t; + } + unsafe { + let op = _svdup_neonq_f64(simd_reinterpret(()), data, 0); + svdupq_lane_f64(op, 0) + } +} +#[doc = "Broadcast the 128 bit NEON vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svdup_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svdup_neonq_s8(data: int8x16_t) -> svint8_t { + extern "C" { + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.experimental.vector.insert.nxv16i8.v16i8" + )] + fn _svdup_neonq_s8(op0: svint8_t, op1: int8x16_t, idx: i64) -> svint8_t; + } + unsafe { + let op = _svdup_neonq_s8(simd_reinterpret(()), data, 0); + svdupq_lane_s8(op, 0) + } +} +#[doc = "Broadcast the 128 bit NEON vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svdup_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svdup_neonq_s16(data: int16x8_t) -> svint16_t { + extern "C" { + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.experimental.vector.insert.nxv8i16.v8i16" + )] + fn _svdup_neonq_s16(op0: svint16_t, op1: int16x8_t, idx: i64) -> svint16_t; + } + unsafe { + let op = _svdup_neonq_s16(simd_reinterpret(()), data, 0); + svdupq_lane_s16(op, 0) + } +} +#[doc = "Broadcast the 128 bit NEON vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svdup_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svdup_neonq_s32(data: int32x4_t) -> svint32_t { + extern "C" { + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.experimental.vector.insert.nxv4i32.v4i32" + )] + fn _svdup_neonq_s32(op0: svint32_t, op1: int32x4_t, idx: i64) -> svint32_t; + } + unsafe { + let op = _svdup_neonq_s32(simd_reinterpret(()), data, 0); + svdupq_lane_s32(op, 0) + } +} +#[doc = "Broadcast the 128 bit NEON vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svdup_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svdup_neonq_s64(data: int64x2_t) -> svint64_t { + extern "C" { + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.experimental.vector.insert.nxv2i64.v2i64" + )] + fn _svdup_neonq_s64(op0: svint64_t, op1: int64x2_t, idx: i64) -> svint64_t; + } + unsafe { + let op = _svdup_neonq_s64(simd_reinterpret(()), data, 0); + svdupq_lane_s64(op, 0) + } +} +#[doc = "Broadcast the 128 bit NEON vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svdup_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svdup_neonq_u8(data: uint8x16_t) -> svuint8_t { + unsafe { svdup_neonq_s8(data.as_signed()).as_unsigned() } +} +#[doc = "Broadcast the 128 bit NEON vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svdup_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svdup_neonq_u16(data: uint16x8_t) -> svuint16_t { + unsafe { svdup_neonq_s16(data.as_signed()).as_unsigned() } +} +#[doc = "Broadcast the 128 bit NEON vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svdup_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svdup_neonq_u32(data: uint32x4_t) -> svuint32_t { + unsafe { svdup_neonq_s32(data.as_signed()).as_unsigned() } +} +#[doc = "Broadcast the 128 bit NEON vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svdup_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svdup_neonq_u64(data: uint64x2_t) -> svuint64_t { + unsafe { svdup_neonq_s64(data.as_signed()).as_unsigned() } +} #[doc = "Broadcast a quadword of scalars"] #[doc = ""] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/svdupq_lane[_f32])"] @@ -11714,6 +11854,128 @@ pub fn svget4_u64(tuple: svuint64x4_t) -> svuint64_t { static_assert_range!(IMM_INDEX, 0, 3); unsafe { svget4_s64::(tuple.as_signed()).as_unsigned() } } +#[doc = "Get the first 128 bits of SVE vector as a Neon vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svget_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svget_neonq_f32(data: svfloat32_t) -> float32x4_t { + extern "C" { + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.experimental.vector.extract.v4f32.nxv4f32" + )] + fn _svget_neonq_f32(op0: svfloat32_t, idx: i64) -> float32x4_t; + } + unsafe { _svget_neonq_f32(data, 0) } +} +#[doc = "Get the first 128 bits of SVE vector as a Neon vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svget_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svget_neonq_f64(data: svfloat64_t) -> float64x2_t { + extern "C" { + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.experimental.vector.extract.v2f64.nxv2f64" + )] + fn _svget_neonq_f64(op0: svfloat64_t, idx: i64) -> float64x2_t; + } + unsafe { _svget_neonq_f64(data, 0) } +} +#[doc = "Get the first 128 bits of SVE vector as a Neon vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svget_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svget_neonq_s8(data: svint8_t) -> int8x16_t { + extern "C" { + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.experimental.vector.extract.v16i8.nxv16i8" + )] + fn _svget_neonq_s8(op0: svint8_t, idx: i64) -> int8x16_t; + } + unsafe { _svget_neonq_s8(data, 0) } +} +#[doc = "Get the first 128 bits of SVE vector as a Neon vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svget_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svget_neonq_s16(data: svint16_t) -> int16x8_t { + extern "C" { + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.experimental.vector.extract.v8i16.nxv8i16" + )] + fn _svget_neonq_s16(op0: svint16_t, idx: i64) -> int16x8_t; + } + unsafe { _svget_neonq_s16(data, 0) } +} +#[doc = "Get the first 128 bits of SVE vector as a Neon vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svget_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svget_neonq_s32(data: svint32_t) -> int32x4_t { + extern "C" { + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.experimental.vector.extract.v4i32.nxv4i32" + )] + fn _svget_neonq_s32(op0: svint32_t, idx: i64) -> int32x4_t; + } + unsafe { _svget_neonq_s32(data, 0) } +} +#[doc = "Get the first 128 bits of SVE vector as a Neon vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svget_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svget_neonq_s64(data: svint64_t) -> int64x2_t { + extern "C" { + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.experimental.vector.extract.v2i64.nxv2i64" + )] + fn _svget_neonq_s64(op0: svint64_t, idx: i64) -> int64x2_t; + } + unsafe { _svget_neonq_s64(data, 0) } +} +#[doc = "Get the first 128 bits of SVE vector as a Neon vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svget_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svget_neonq_u8(data: svuint8_t) -> uint8x16_t { + unsafe { svget_neonq_s8(data.as_signed()).as_unsigned() } +} +#[doc = "Get the first 128 bits of SVE vector as a Neon vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svget_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svget_neonq_u16(data: svuint16_t) -> uint16x8_t { + unsafe { svget_neonq_s16(data.as_signed()).as_unsigned() } +} +#[doc = "Get the first 128 bits of SVE vector as a Neon vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svget_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svget_neonq_u32(data: svuint32_t) -> uint32x4_t { + unsafe { svget_neonq_s32(data.as_signed()).as_unsigned() } +} +#[doc = "Get the first 128 bits of SVE vector as a Neon vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svget_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svget_neonq_u64(data: svuint64_t) -> uint64x2_t { + unsafe { svget_neonq_s64(data.as_signed()).as_unsigned() } +} #[doc = "Create linear series"] #[doc = ""] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/svindex_s8)"] @@ -37718,6 +37980,128 @@ pub fn svset4_u64(tuple: svuint64x4_t, x: svuint64_t) -> s static_assert_range!(IMM_INDEX, 0, 3); unsafe { svset4_s64::(tuple.as_signed(), x.as_signed()).as_unsigned() } } +#[doc = "Set the first 128 bits of SVE vector to Neon vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svset_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svset_neonq_f32(sve_data: svfloat32_t, neon_data: float32x4_t) -> svfloat32_t { + extern "C" { + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.experimental.vector.insert.nxv4f32.v4f32" + )] + fn _svset_neonq_f32(op0: svfloat32_t, op1: float32x4_t, idx: i64) -> svfloat32_t; + } + unsafe { _svset_neonq_f32(sve_data, neon_data, 0) } +} +#[doc = "Set the first 128 bits of SVE vector to Neon vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svset_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svset_neonq_f64(sve_data: svfloat64_t, neon_data: float64x2_t) -> svfloat64_t { + extern "C" { + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.experimental.vector.insert.nxv2f64.v2f64" + )] + fn _svset_neonq_f64(op0: svfloat64_t, op1: float64x2_t, idx: i64) -> svfloat64_t; + } + unsafe { _svset_neonq_f64(sve_data, neon_data, 0) } +} +#[doc = "Set the first 128 bits of SVE vector to Neon vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svset_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svset_neonq_s8(sve_data: svint8_t, neon_data: int8x16_t) -> svint8_t { + extern "C" { + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.experimental.vector.insert.nxv16i8.v16i8" + )] + fn _svset_neonq_s8(op0: svint8_t, op1: int8x16_t, idx: i64) -> svint8_t; + } + unsafe { _svset_neonq_s8(sve_data, neon_data, 0) } +} +#[doc = "Set the first 128 bits of SVE vector to Neon vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svset_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svset_neonq_s16(sve_data: svint16_t, neon_data: int16x8_t) -> svint16_t { + extern "C" { + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.experimental.vector.insert.nxv8i16.v8i16" + )] + fn _svset_neonq_s16(op0: svint16_t, op1: int16x8_t, idx: i64) -> svint16_t; + } + unsafe { _svset_neonq_s16(sve_data, neon_data, 0) } +} +#[doc = "Set the first 128 bits of SVE vector to Neon vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svset_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svset_neonq_s32(sve_data: svint32_t, neon_data: int32x4_t) -> svint32_t { + extern "C" { + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.experimental.vector.insert.nxv4i32.v4i32" + )] + fn _svset_neonq_s32(op0: svint32_t, op1: int32x4_t, idx: i64) -> svint32_t; + } + unsafe { _svset_neonq_s32(sve_data, neon_data, 0) } +} +#[doc = "Set the first 128 bits of SVE vector to Neon vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svset_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svset_neonq_s64(sve_data: svint64_t, neon_data: int64x2_t) -> svint64_t { + extern "C" { + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.experimental.vector.insert.nxv2i64.v2i64" + )] + fn _svset_neonq_s64(op0: svint64_t, op1: int64x2_t, idx: i64) -> svint64_t; + } + unsafe { _svset_neonq_s64(sve_data, neon_data, 0) } +} +#[doc = "Set the first 128 bits of SVE vector to Neon vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svset_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svset_neonq_u8(sve_data: svuint8_t, neon_data: uint8x16_t) -> svuint8_t { + unsafe { svset_neonq_s8(sve_data.as_signed(), neon_data.as_signed()).as_unsigned() } +} +#[doc = "Set the first 128 bits of SVE vector to Neon vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svset_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svset_neonq_u16(sve_data: svuint16_t, neon_data: uint16x8_t) -> svuint16_t { + unsafe { svset_neonq_s16(sve_data.as_signed(), neon_data.as_signed()).as_unsigned() } +} +#[doc = "Set the first 128 bits of SVE vector to Neon vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svset_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svset_neonq_u32(sve_data: svuint32_t, neon_data: uint32x4_t) -> svuint32_t { + unsafe { svset_neonq_s32(sve_data.as_signed(), neon_data.as_signed()).as_unsigned() } +} +#[doc = "Set the first 128 bits of SVE vector to Neon vector"] +#[doc = ""] +#[doc = "[Arm's documentation](https://arm-software.github.io/acle/main/acle.html#svset_neonq)"] +#[inline] +#[target_feature(enable = "sve")] +pub fn svset_neonq_u64(sve_data: svuint64_t, neon_data: uint64x2_t) -> svuint64_t { + unsafe { svset_neonq_s64(sve_data.as_signed(), neon_data.as_signed()).as_unsigned() } +} #[doc = "Initialize the first-fault register to all-true"] #[doc = ""] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/svsetffr)"] diff --git a/crates/core_arch/src/aarch64/sve/types.rs b/crates/core_arch/src/aarch64/sve/types.rs index e851a0d762..2f566ed5bf 100644 --- a/crates/core_arch/src/aarch64/sve/types.rs +++ b/crates/core_arch/src/aarch64/sve/types.rs @@ -1,5 +1,6 @@ use super::*; #[allow(improper_ctypes)] +use crate::core_arch::arch::aarch64::*; use crate::marker::ConstParamTy; pub(super) trait AsUnsigned { @@ -201,6 +202,11 @@ impl_sign_conversions! { (*mut i16, *mut u16) (*mut i32, *mut u32) (*mut i64, *mut u64) + + (int8x16_t, uint8x16_t) + (int16x8_t, uint16x8_t) + (int32x4_t, uint32x4_t) + (int64x2_t, uint64x2_t) } impl_sign_conversions_sv! { diff --git a/crates/stdarch-gen2/spec/sve/sve.spec.yml b/crates/stdarch-gen2/spec/sve/sve.spec.yml index 7c8aed779b..6abf5f51a1 100644 --- a/crates/stdarch-gen2/spec/sve/sve.spec.yml +++ b/crates/stdarch-gen2/spec/sve/sve.spec.yml @@ -4844,3 +4844,49 @@ intrinsics: n_variant_op: op2 compose: - LLVMLink: { name: "fminnm.{sve_type}" } + + - name: svdup_neonq_{type} + doc: Broadcast the 128 bit NEON vector + url: https://arm-software.github.io/acle/main/acle.html#svdup_neonq + arguments: ["data: {neon_type}"] + return_type: "{sve_type}" + types: [f32, f64, i8, i16, i32, i64, u8, u16, u32, u64] + assert_instr: [] + compose: + - LLVMLink: + name: llvm.experimental.vector.insert.{sve_type}.{neon_type} + arguments: ["op0: {sve_type}", "op1: {neon_type}", "idx: i64"] + - Let: + - op + - FnCall: + - "{llvm_link}" + - - SvUndef + - $data + - 0 + - FnCall: ["svdupq_lane_{type}", [$op, 0]] + + - name: svset_neonq_{type} + doc: Set the first 128 bits of SVE vector to Neon vector + url: https://arm-software.github.io/acle/main/acle.html#svset_neonq + arguments: ["sve_data: {sve_type}", "neon_data: {neon_type}"] + return_type: "{sve_type}" + types: [f32, f64, i8, i16, i32, i64, u8, u16, u32, u64] + assert_instr: [] + compose: + - LLVMLink: + name: llvm.experimental.vector.insert.{sve_type}.{neon_type} + arguments: ["op0: {sve_type}", "op1: {neon_type}", "idx: i64"] + - FnCall: ["{llvm_link}", [$sve_data, $neon_data, 0]] + + - name: svget_neonq_{type} + doc: Get the first 128 bits of SVE vector as a Neon vector + url: https://arm-software.github.io/acle/main/acle.html#svget_neonq + arguments: ["data: {sve_type}"] + return_type: "{neon_type}" + types: [f32, f64, i8, i16, i32, i64, u8, u16, u32, u64] + assert_instr: [] + compose: + - LLVMLink: + name: llvm.experimental.vector.extract.{neon_type}.{sve_type} + arguments: ["op0: {sve_type}", "idx: i64"] + - FnCall: ["{llvm_link}", [$data, 0]] \ No newline at end of file diff --git a/crates/stdarch-gen2/src/intrinsic.rs b/crates/stdarch-gen2/src/intrinsic.rs index d05b71e44d..6659736b96 100644 --- a/crates/stdarch-gen2/src/intrinsic.rs +++ b/crates/stdarch-gen2/src/intrinsic.rs @@ -809,6 +809,8 @@ pub struct Intrinsic { pub visibility: FunctionVisibility, #[serde(default)] pub doc: Option, + #[serde(default)] + pub url: Option, #[serde(flatten)] pub signature: Signature, /// Function sequential composition @@ -1425,9 +1427,17 @@ impl ToTokens for Intrinsic { if let Some(doc) = &self.doc { let mut doc = vec![doc.to_string()]; - + let url: String = self.url.as_ref().map_or_else( + || { + format!( + "https://developer.arm.com/architectures/instruction-sets/intrinsics/{}", + &signature.doc_name() + ) + }, + |url| url.to_string(), + ); doc.push(String::new()); - doc.push(format!("[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/{})", &signature.doc_name())); + doc.push(format!("[Arm's documentation]({})", url)); if safety.has_doc_comments() { doc.push(String::new());