Skip to content

Commit 63b34fe

Browse files
committed
Unrolled build for #162832 in rollup 163472
Rollup merge of #162832 - folkertdev:complex-mul-div, r=tgross35 add `Div` and `Mul` for `Complex<{float}>` tracking issue: #154023 There are no fallbacks for the libcalls, so Miri will currently fail.
2 parents 80a4f6c + 5931727 commit 63b34fe

4 files changed

Lines changed: 166 additions & 1 deletion

File tree

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
From 20d296e9a8b837e586fcc8fc648d4ab9687a2a47 Mon Sep 17 00:00:00 2001
2+
From: Folkert de Vries <folkert@folkertdev.nl>
3+
Date: Mon, 28 Sep 2026 19:14:22 +0200
4+
Subject: [PATCH] sysroot_tests: Disable complex type tests
5+
6+
---
7+
coretests/tests/num/complex.rs | 2 ++
8+
1 file changed, 2 insertions(+)
9+
10+
diff --git a/coretests/tests/num/complex.rs b/coretests/tests/num/complex.rs
11+
index d73d04b1afc..289c0baec17 100644
12+
--- a/coretests/tests/num/complex.rs
13+
+++ b/coretests/tests/num/complex.rs
14+
@@ -75,6 +75,7 @@ fn complex_negation() {
15+
}
16+
17+
#[test]
18+
+#[cfg_attr(target_os = "windows", ignore = "hits an ABI issue with cranelift on windows")]
19+
fn complex_multiplication() {
20+
#[cfg(target_has_reliable_f16)]
21+
assert_eq!(Complex::new(1.0f16, 2.0) * Complex::new(3.0, 4.0), Complex::new(-5.0, 10.0));
22+
@@ -105,6 +106,7 @@ fn complex_multiplication() {
23+
}
24+
25+
#[test]
26+
+#[cfg_attr(target_os = "windows", ignore = "hits an ABI issue with cranelift on windows")]
27+
fn complex_div() {
28+
#[cfg(target_has_reliable_f16)]
29+
assert_eq!(Complex::new(2.0f16, 11.0) / Complex::new(2.0, 1.0), Complex::new(3.0, 4.0));
30+
--
31+
2.43.0
32+

‎library/core/src/num/complex.rs‎

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use crate::ops::{Add, Neg, Sub};
1+
use crate::num::imp::libm::complex::*;
2+
use crate::ops::{Add, Div, Mul, Neg, Sub};
23

34
/// A complex number.
45
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -91,3 +92,54 @@ impl<T: Sub<Output = T>> Sub<T> for Complex<T> {
9192
Complex::new(self.re - rhs, self.im)
9293
}
9394
}
95+
96+
macro_rules! impl_complex_mul_div {
97+
($ty:ty, $mul:ident, $div:ident) => {
98+
#[unstable(feature = "complex_numbers", issue = "154023")]
99+
impl Mul for Complex<$ty> {
100+
type Output = Self;
101+
102+
#[inline]
103+
fn mul(self, rhs: Self) -> Self::Output {
104+
let Complex { re: a, im: b } = self;
105+
let Complex { re: c, im: d } = rhs;
106+
107+
let ac = a * c;
108+
let bd = b * d;
109+
let ad = a * d;
110+
let bc = b * c;
111+
112+
let z = Complex::new(ac - bd, ad + bc);
113+
114+
// Only call the libcall when both components are NaN.
115+
//
116+
// The naive algorithm would return NaN + NaNi for an input like
117+
// (1 + 0i) * (inf + infi). The libcall instead returns inf + infi.
118+
//
119+
// We duplicate the fast path here so that it can be inlined. We use a libcall
120+
// for the NaN correction to reduce the size of `core`.
121+
if z.re.is_nan() && z.im.is_nan() {
122+
crate::hint::cold_path();
123+
$mul(a, b, c, d)
124+
} else {
125+
z
126+
}
127+
}
128+
}
129+
130+
#[unstable(feature = "complex_numbers", issue = "154023")]
131+
impl Div for Complex<$ty> {
132+
type Output = Self;
133+
134+
#[inline]
135+
fn div(self, rhs: Self) -> Self::Output {
136+
$div(self.re, self.im, rhs.re, rhs.im)
137+
}
138+
}
139+
};
140+
}
141+
142+
impl_complex_mul_div!(f16, __rust_mulhc3, __rust_divhc3);
143+
impl_complex_mul_div!(f32, __mulsc3, __divsc3);
144+
impl_complex_mul_div!(f64, __muldc3, __divdc3);
145+
impl_complex_mul_div!(f128, __rust_multc3, __rust_divtc3);

‎library/core/src/num/imp/libm.rs‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,27 @@ unsafe extern "C" {
7676
pub(crate) safe fn truncf16(x: f16) -> f16;
7777
}
7878

79+
/// These symbols are always provided by compiler-builtins.
80+
pub(crate) mod complex {
81+
use crate::num::Complex;
82+
83+
unsafe extern "C" {
84+
pub(crate) safe fn __mulsc3(a: f32, b: f32, c: f32, d: f32) -> Complex<f32>;
85+
pub(crate) safe fn __muldc3(a: f64, b: f64, c: f64, d: f64) -> Complex<f64>;
86+
87+
pub(crate) safe fn __divsc3(a: f32, b: f32, c: f32, d: f32) -> Complex<f32>;
88+
pub(crate) safe fn __divdc3(a: f64, b: f64, c: f64, d: f64) -> Complex<f64>;
89+
}
90+
91+
unsafe extern "Rust" {
92+
pub(crate) safe fn __rust_mulhc3(a: f16, b: f16, c: f16, d: f16) -> Complex<f16>;
93+
pub(crate) safe fn __rust_multc3(a: f128, b: f128, c: f128, d: f128) -> Complex<f128>;
94+
95+
pub(crate) safe fn __rust_divhc3(a: f16, b: f16, c: f16, d: f16) -> Complex<f16>;
96+
pub(crate) safe fn __rust_divtc3(a: f128, b: f128, c: f128, d: f128) -> Complex<f128>;
97+
}
98+
}
99+
79100
/// These symbols will be available when `std` is available, and on many no-std platforms. However,
80101
/// since this isn't a guarantee, we cannot rely on them for stable implementations.
81102
pub(crate) mod likely_available {

‎library/coretests/tests/num/complex.rs‎

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,63 @@ fn complex_negation() {
7373
assert_eq!(-Complex::new(1.0, -2.0), Complex::new(-1.0, 2.0));
7474
assert_eq!(-Complex::new(1.0, f32::INFINITY), Complex::new(-1.0, f32::NEG_INFINITY),);
7575
}
76+
77+
#[test]
78+
fn complex_multiplication() {
79+
#[cfg(target_has_reliable_f16)]
80+
assert_eq!(Complex::new(1.0f16, 2.0) * Complex::new(3.0, 4.0), Complex::new(-5.0, 10.0));
81+
assert_eq!(Complex::new(1.0f32, 2.0) * Complex::new(3.0, 4.0), Complex::new(-5.0, 10.0));
82+
assert_eq!(Complex::new(1.0f64, 2.0) * Complex::new(3.0, 4.0), Complex::new(-5.0, 10.0));
83+
#[cfg(target_has_reliable_f128)]
84+
assert_eq!(Complex::new(1.0f128, 2.0) * Complex::new(3.0, 4.0), Complex::new(-5.0, 10.0));
85+
86+
// The naive algorithm would return NaN + NaNi for these inputs, but the libcall handles it.
87+
#[cfg(target_has_reliable_f16)]
88+
assert_eq!(
89+
Complex::new(1.0, 0.0) * Complex::new(f16::INFINITY, f16::INFINITY),
90+
Complex::new(f16::INFINITY, f16::INFINITY)
91+
);
92+
assert_eq!(
93+
Complex::new(1.0, 0.0) * Complex::new(f32::INFINITY, f32::INFINITY),
94+
Complex::new(f32::INFINITY, f32::INFINITY)
95+
);
96+
assert_eq!(
97+
Complex::new(1.0, 0.0) * Complex::new(f64::INFINITY, f64::INFINITY),
98+
Complex::new(f64::INFINITY, f64::INFINITY)
99+
);
100+
#[cfg(target_has_reliable_f128)]
101+
assert_eq!(
102+
Complex::new(1.0, 0.0) * Complex::new(f128::INFINITY, f128::INFINITY),
103+
Complex::new(f128::INFINITY, f128::INFINITY)
104+
);
105+
}
106+
107+
#[test]
108+
fn complex_div() {
109+
#[cfg(target_has_reliable_f16)]
110+
assert_eq!(Complex::new(2.0f16, 11.0) / Complex::new(2.0, 1.0), Complex::new(3.0, 4.0));
111+
assert_eq!(Complex::new(2.0f32, 11.0) / Complex::new(2.0, 1.0), Complex::new(3.0, 4.0));
112+
assert_eq!(Complex::new(2.0f64, 11.0) / Complex::new(2.0, 1.0), Complex::new(3.0, 4.0));
113+
#[cfg(target_has_reliable_f128)]
114+
assert_eq!(Complex::new(2.0f128, 11.0) / Complex::new(2.0, 1.0), Complex::new(3.0, 4.0));
115+
116+
// The naive algorithm would return NaN + NaNi for these inputs, but the libcall handles it.
117+
#[cfg(target_has_reliable_f16)]
118+
assert_eq!(
119+
Complex::new(f16::INFINITY, 0.0) / Complex::new(1.0, 1.0),
120+
Complex::new(f16::INFINITY, f16::NEG_INFINITY)
121+
);
122+
assert_eq!(
123+
Complex::new(f32::INFINITY, 0.0) / Complex::new(1.0, 1.0),
124+
Complex::new(f32::INFINITY, f32::NEG_INFINITY)
125+
);
126+
assert_eq!(
127+
Complex::new(f64::INFINITY, 0.0) / Complex::new(1.0, 1.0),
128+
Complex::new(f64::INFINITY, f64::NEG_INFINITY)
129+
);
130+
#[cfg(target_has_reliable_f128)]
131+
assert_eq!(
132+
Complex::new(f128::INFINITY, 0.0) / Complex::new(1.0, 1.0),
133+
Complex::new(f128::INFINITY, f128::NEG_INFINITY)
134+
);
135+
}

0 commit comments

Comments
 (0)