From 4f35c02aa07a30bdaf30301a078da6d590f33063 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 19 May 2025 23:13:17 +0200 Subject: [PATCH] in `intrinsic-test`, format f16 like C --- .../crates/intrinsic-test/src/intrinsic.rs | 13 ++- .../stdarch/crates/intrinsic-test/src/main.rs | 90 +++++++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/library/stdarch/crates/intrinsic-test/src/intrinsic.rs b/library/stdarch/crates/intrinsic-test/src/intrinsic.rs index b96edf185283..4cc27525011f 100644 --- a/library/stdarch/crates/intrinsic-test/src/intrinsic.rs +++ b/library/stdarch/crates/intrinsic-test/src/intrinsic.rs @@ -121,14 +121,25 @@ impl Intrinsic { constraints }; + // the `intrinsic-test` crate compares the output of C and Rust intrinsics. Currently, It uses + // a string representation of the output value to compare. In C, f16 values are currently printed + // as hexadecimal integers. Since https://github.com/rust-lang/rust/pull/127013, rust does print + // them as decimal floating point values. To keep the intrinsics tests working, for now, format + // vectors containing f16 values like C prints them. + let return_value = match self.results.kind() { + TypeKind::Float if self.results.inner_size() == 16 => "debug_f16(__return_value)", + _ => "format_args!(\"{__return_value:.150?}\")", + }; + let indentation2 = indentation.nested(); let indentation3 = indentation2.nested(); + format!( "{indentation}for i in 0..{passes} {{\n\ {indentation2}unsafe {{\n\ {loaded_args}\ {indentation3}let __return_value = {intrinsic_call}{const}({args});\n\ - {indentation3}println!(\"Result {additional}-{{}}: {{:.150?}}\", i + 1, __return_value);\n\ + {indentation3}println!(\"Result {additional}-{{}}: {{:?}}\", i + 1, {return_value});\n\ {indentation2}}}\n\ {indentation}}}", loaded_args = self.arguments.load_values_rust(indentation3), diff --git a/library/stdarch/crates/intrinsic-test/src/main.rs b/library/stdarch/crates/intrinsic-test/src/main.rs index e398db0e905e..cdf9f5bb302e 100644 --- a/library/stdarch/crates/intrinsic-test/src/main.rs +++ b/library/stdarch/crates/intrinsic-test/src/main.rs @@ -190,11 +190,99 @@ fn generate_rust_program(notices: &str, intrinsic: &Intrinsic, target: &str) -> .filter(|i| i.has_constraint()) .collect_vec(); + // Format f16 values (and vectors containing them) in a way that is consistent with C. + let f16_formatting = r#" +/// Used to continue `Debug`ging SIMD types as `MySimd(1, 2, 3, 4)`, as they +/// were before moving to array-based simd. +#[inline] +fn debug_simd_finish( + formatter: &mut core::fmt::Formatter<'_>, + type_name: &str, + array: &[T; N], +) -> core::fmt::Result { + core::fmt::Formatter::debug_tuple_fields_finish( + formatter, + type_name, + &core::array::from_fn::<&dyn core::fmt::Debug, N, _>(|i| &array[i]), + ) +} + +#[repr(transparent)] +struct Hex(T); + +impl core::fmt::Debug for Hex { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + ::fmt(&self.0, f) + } +} + +fn debug_f16(x: T) -> impl core::fmt::Debug { + Hex(x) +} + +trait DebugHexF16 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result; +} + +impl DebugHexF16 for f16 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#06x?}", self.to_bits()) + } +} + +impl DebugHexF16 for float16x4_t { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let array = unsafe { core::mem::transmute::<_, [Hex; 4]>(*self) }; + debug_simd_finish(f, "float16x4_t", &array) + } +} + +impl DebugHexF16 for float16x8_t { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let array = unsafe { core::mem::transmute::<_, [Hex; 8]>(*self) }; + debug_simd_finish(f, "float16x8_t", &array) + } +} + +impl DebugHexF16 for float16x4x2_t { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + debug_simd_finish(f, "float16x4x2_t", &[Hex(self.0), Hex(self.1)]) + } +} +impl DebugHexF16 for float16x4x3_t { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + debug_simd_finish(f, "float16x4x3_t", &[Hex(self.0), Hex(self.1), Hex(self.2)]) + } +} +impl DebugHexF16 for float16x4x4_t { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + debug_simd_finish(f, "float16x4x4_t", &[Hex(self.0), Hex(self.1), Hex(self.2), Hex(self.3)]) + } +} + +impl DebugHexF16 for float16x8x2_t { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + debug_simd_finish(f, "float16x8x2_t", &[Hex(self.0), Hex(self.1)]) + } +} +impl DebugHexF16 for float16x8x3_t { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + debug_simd_finish(f, "float16x8x3_t", &[Hex(self.0), Hex(self.1), Hex(self.2)]) + } +} +impl DebugHexF16 for float16x8x4_t { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + debug_simd_finish(f, "float16x8x4_t", &[Hex(self.0), Hex(self.1), Hex(self.2), Hex(self.3)]) + } +} + "#; + let indentation = Indentation::default(); format!( r#"{notices}#![feature(simd_ffi)] #![feature(link_llvm_intrinsics)] #![feature(f16)] +#![feature(fmt_helpers_for_derive)] #![cfg_attr(target_arch = "arm", feature(stdarch_arm_neon_intrinsics))] #![cfg_attr(target_arch = "arm", feature(stdarch_aarch32_crc32))] #![cfg_attr(any(target_arch = "aarch64", target_arch = "arm64ec"), feature(stdarch_neon_fcma))] @@ -207,6 +295,8 @@ fn generate_rust_program(notices: &str, intrinsic: &Intrinsic, target: &str) -> #![allow(non_upper_case_globals)] use core_arch::arch::{target_arch}::*; +{f16_formatting} + fn main() {{ {arglists} {passes}