rust-lang/rust · #162832
add `Div` and `Mul` for `Complex<{float}>`
compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-Disable-complex-type-tests.patchadded32 + / 0 −
@@ -0,0 +1,32 @@+From 20d296e9a8b837e586fcc8fc648d4ab9687a2a47 Mon Sep 17 00:00:00 2001+From: Folkert de Vries <folkert@folkertdev.nl>+Date: Mon, 28 Sep 2026 19:14:22 +0200+Subject: [PATCH] sysroot_tests: Disable complex type tests++---+ coretests/tests/num/complex.rs | 2 +++ 1 file changed, 2 insertions(+)++diff --git a/coretests/tests/num/complex.rs b/coretests/tests/num/complex.rs+index d73d04b1afc..289c0baec17 100644+--- a/coretests/tests/num/complex.rs++++ b/coretests/tests/num/complex.rs+@@ -75,6 +75,7 @@ fn complex_negation() {+ }+ + #[test]++#[cfg_attr(target_os = "windows", ignore = "hits an ABI issue with cranelift on windows")]+ fn complex_multiplication() {+ #[cfg(target_has_reliable_f16)]+ assert_eq!(Complex::new(1.0f16, 2.0) * Complex::new(3.0, 4.0), Complex::new(-5.0, 10.0));+@@ -105,6 +106,7 @@ fn complex_multiplication() {+ }+ + #[test]++#[cfg_attr(target_os = "windows", ignore = "hits an ABI issue with cranelift on windows")]+ fn complex_div() {+ #[cfg(target_has_reliable_f16)]+ assert_eq!(Complex::new(2.0f16, 11.0) / Complex::new(2.0, 1.0), Complex::new(3.0, 4.0));+-- +2.43.0+library/core/src/num/complex.rs53 + / 1 −
@@ -1,4 +1,5 @@-use crate::ops::{Add, Neg, Sub};+use crate::num::imp::libm::complex::*;+use crate::ops::{Add, Div, Mul, Neg, Sub}; /// A complex number. #[derive(Clone, Copy, Debug, PartialEq, Eq)]@@ -91,3 +92,54 @@ impl<T: Sub<Output = T>> Sub<T> for Complex<T> { Complex::new(self.re - rhs, self.im) } }++macro_rules! impl_complex_mul_div {+ ($ty:ty, $mul:ident, $div:ident) => {+ #[unstable(feature = "complex_numbers", issue = "154023")]+ impl Mul for Complex<$ty> {+ type Output = Self;++ #[inline]+ fn mul(self, rhs: Self) -> Self::Output {+ let Complex { re: a, im: b } = self;+ let Complex { re: c, im: d } = rhs;++ let ac = a * c;+ let bd = b * d;+ let ad = a * d;+ let bc = b * c;++ let z = Complex::new(ac - bd, ad + bc);++ // Only call the libcall when both components are NaN.+ //+ // The naive algorithm would return NaN + NaNi for an input like+ // (1 + 0i) * (inf + infi). The libcall instead returns inf + infi.+ //+ // We duplicate the fast path here so that it can be inlined. We use a libcall+ // for the NaN correction to reduce the size of `core`.+ if z.re.is_nan() && z.im.is_nan() {+ crate::hint::cold_path();+ $mul(a, b, c, d)+ } else {+ z+ }+ }+ }++ #[unstable(feature = "complex_numbers", issue = "154023")]+ impl Div for Complex<$ty> {+ type Output = Self;++ #[inline]+ fn div(self, rhs: Self) -> Self::Output {+ $div(self.re, self.im, rhs.re, rhs.im)+ }+ }+ };+}++impl_complex_mul_div!(f16, __rust_mulhc3, __rust_divhc3);+impl_complex_mul_div!(f32, __mulsc3, __divsc3);+impl_complex_mul_div!(f64, __muldc3, __divdc3);+impl_complex_mul_div!(f128, __rust_multc3, __rust_divtc3);library/core/src/num/imp/libm.rs21 + / 0 −
@@ -76,6 +76,27 @@ unsafe extern "C" { pub(crate) safe fn truncf16(x: f16) -> f16; } +/// These symbols are always provided by compiler-builtins.+pub(crate) mod complex {+ use crate::num::Complex;++ unsafe extern "C" {+ pub(crate) safe fn __mulsc3(a: f32, b: f32, c: f32, d: f32) -> Complex<f32>;+ pub(crate) safe fn __muldc3(a: f64, b: f64, c: f64, d: f64) -> Complex<f64>;++ pub(crate) safe fn __divsc3(a: f32, b: f32, c: f32, d: f32) -> Complex<f32>;+ pub(crate) safe fn __divdc3(a: f64, b: f64, c: f64, d: f64) -> Complex<f64>;+ }++ unsafe extern "Rust" {+ pub(crate) safe fn __rust_mulhc3(a: f16, b: f16, c: f16, d: f16) -> Complex<f16>;+ pub(crate) safe fn __rust_multc3(a: f128, b: f128, c: f128, d: f128) -> Complex<f128>;++ pub(crate) safe fn __rust_divhc3(a: f16, b: f16, c: f16, d: f16) -> Complex<f16>;+ pub(crate) safe fn __rust_divtc3(a: f128, b: f128, c: f128, d: f128) -> Complex<f128>;+ }+}+ /// These symbols will be available when `std` is available, and on many no-std platforms. However, /// since this isn't a guarantee, we cannot rely on them for stable implementations. pub(crate) mod likely_available {library/coretests/tests/num/complex.rs60 + / 0 −
@@ -73,3 +73,63 @@ fn complex_negation() { assert_eq!(-Complex::new(1.0, -2.0), Complex::new(-1.0, 2.0)); assert_eq!(-Complex::new(1.0, f32::INFINITY), Complex::new(-1.0, f32::NEG_INFINITY),); }++#[test]+fn complex_multiplication() {+ #[cfg(target_has_reliable_f16)]+ assert_eq!(Complex::new(1.0f16, 2.0) * Complex::new(3.0, 4.0), Complex::new(-5.0, 10.0));+ assert_eq!(Complex::new(1.0f32, 2.0) * Complex::new(3.0, 4.0), Complex::new(-5.0, 10.0));+ assert_eq!(Complex::new(1.0f64, 2.0) * Complex::new(3.0, 4.0), Complex::new(-5.0, 10.0));+ #[cfg(target_has_reliable_f128)]+ assert_eq!(Complex::new(1.0f128, 2.0) * Complex::new(3.0, 4.0), Complex::new(-5.0, 10.0));++ // The naive algorithm would return NaN + NaNi for these inputs, but the libcall handles it.+ #[cfg(target_has_reliable_f16)]+ assert_eq!(+ Complex::new(1.0, 0.0) * Complex::new(f16::INFINITY, f16::INFINITY),+ Complex::new(f16::INFINITY, f16::INFINITY)+ );+ assert_eq!(+ Complex::new(1.0, 0.0) * Complex::new(f32::INFINITY, f32::INFINITY),+ Complex::new(f32::INFINITY, f32::INFINITY)+ );+ assert_eq!(+ Complex::new(1.0, 0.0) * Complex::new(f64::INFINITY, f64::INFINITY),+ Complex::new(f64::INFINITY, f64::INFINITY)+ );+ #[cfg(target_has_reliable_f128)]+ assert_eq!(+ Complex::new(1.0, 0.0) * Complex::new(f128::INFINITY, f128::INFINITY),+ Complex::new(f128::INFINITY, f128::INFINITY)+ );+}++#[test]+fn complex_div() {+ #[cfg(target_has_reliable_f16)]+ assert_eq!(Complex::new(2.0f16, 11.0) / Complex::new(2.0, 1.0), Complex::new(3.0, 4.0));+ assert_eq!(Complex::new(2.0f32, 11.0) / Complex::new(2.0, 1.0), Complex::new(3.0, 4.0));+ assert_eq!(Complex::new(2.0f64, 11.0) / Complex::new(2.0, 1.0), Complex::new(3.0, 4.0));+ #[cfg(target_has_reliable_f128)]+ assert_eq!(Complex::new(2.0f128, 11.0) / Complex::new(2.0, 1.0), Complex::new(3.0, 4.0));++ // The naive algorithm would return NaN + NaNi for these inputs, but the libcall handles it.+ #[cfg(target_has_reliable_f16)]+ assert_eq!(+ Complex::new(f16::INFINITY, 0.0) / Complex::new(1.0, 1.0),+ Complex::new(f16::INFINITY, f16::NEG_INFINITY)+ );+ assert_eq!(+ Complex::new(f32::INFINITY, 0.0) / Complex::new(1.0, 1.0),+ Complex::new(f32::INFINITY, f32::NEG_INFINITY)+ );+ assert_eq!(+ Complex::new(f64::INFINITY, 0.0) / Complex::new(1.0, 1.0),+ Complex::new(f64::INFINITY, f64::NEG_INFINITY)+ );+ #[cfg(target_has_reliable_f128)]+ assert_eq!(+ Complex::new(f128::INFINITY, 0.0) / Complex::new(1.0, 1.0),+ Complex::new(f128::INFINITY, f128::NEG_INFINITY)+ );+}