From b4e1a53b7a146fe16fc3347b30700c602110a5f6 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Sun, 28 Jul 2024 12:46:46 +0800 Subject: [PATCH 01/18] Update target-spec metadata for loongarch64 targets --- .../src/spec/targets/loongarch64_unknown_linux_musl.rs | 8 ++++---- .../src/spec/targets/loongarch64_unknown_none.rs | 2 +- .../spec/targets/loongarch64_unknown_none_softfloat.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs index 19b04607f0e0b..f7a6e0bd857f5 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "loongarch64-unknown-linux-musl".into(), metadata: crate::spec::TargetMetadata { - description: Some("LoongArch64 Linux (LP64D ABI) with musl 1.2.3".into()), - tier: Some(3), - host_tools: Some(false), - std: None, // ? + description: Some("LoongArch64 Linux (LP64D ABI) with musl 1.2.5".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs index 744ffff721fe7..9d80b4c901dad 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { Target { llvm_target: "loongarch64-unknown-none".into(), metadata: crate::spec::TargetMetadata { - description: None, + description: Some("Freestanding/bare-metal LoongArch64".into()), tier: Some(2), host_tools: Some(false), std: Some(false), diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs index a382e7a53fbdf..d55611ffee317 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { Target { llvm_target: "loongarch64-unknown-none".into(), metadata: crate::spec::TargetMetadata { - description: None, + description: Some("Freestanding/bare-metal LoongArch64 softfloat".into()), tier: Some(2), host_tools: Some(false), std: Some(false), From 9e05fb67a3360b9faf49b3484e2ac5cec27a6e78 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 23 Jun 2024 16:06:48 +0200 Subject: [PATCH 02/18] Small simplification --- .../rustc_mir_build/src/build/matches/mod.rs | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 6c34978a29c96..f56dad84cdbd1 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1199,6 +1199,17 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { |_| {}, ); } + + /// Visit the leaf candidates in reverse order. + fn visit_leaves_rev<'a>(&'a mut self, mut visit_leaf: impl FnMut(&'a mut Self)) { + traverse_candidate( + self, + &mut (), + &mut move |c, _| visit_leaf(c), + move |c, _| c.subcandidates.iter_mut().rev(), + |_| {}, + ); + } } /// A depth-first traversal of the `Candidate` and all of its recursive @@ -1433,23 +1444,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let otherwise_block = self.match_candidates(match_start_span, scrutinee_span, block, candidates); - // Link each leaf candidate to the `false_edge_start_block` of the next one. - let mut previous_candidate: Option<&mut Candidate<'_, '_>> = None; - for candidate in candidates { - candidate.visit_leaves(|leaf_candidate| { - if let Some(ref mut prev) = previous_candidate { - assert!(leaf_candidate.false_edge_start_block.is_some()); - prev.next_candidate_start_block = leaf_candidate.false_edge_start_block; - } - previous_candidate = Some(leaf_candidate); + // Link each leaf candidate to the `false_edge_start_block` of the next one. In the + // refutable case we also want a false edge to the failure block. + let mut next_candidate_start_block = if refutable { Some(otherwise_block) } else { None }; + for candidate in candidates.iter_mut().rev() { + candidate.visit_leaves_rev(|leaf_candidate| { + leaf_candidate.next_candidate_start_block = next_candidate_start_block; + assert!(leaf_candidate.false_edge_start_block.is_some()); + next_candidate_start_block = leaf_candidate.false_edge_start_block; }); } - if refutable { - // In refutable cases there's always at least one candidate, and we want a false edge to - // the failure block. - previous_candidate.as_mut().unwrap().next_candidate_start_block = Some(otherwise_block) - } else { + if !refutable { // Match checking ensures `otherwise_block` is actually unreachable in irrefutable // cases. let source_info = self.source_info(scrutinee_span); From e2fd9aa33e1887417375e94ec79b39ab4682c8b4 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 23 Jun 2024 15:54:42 +0200 Subject: [PATCH 03/18] Set up false edges in `lower_match_tree` --- .../rustc_mir_build/src/build/matches/mod.rs | 61 ++++---- .../rustc_mir_build/src/build/matches/util.rs | 19 ++- ...se_edges.full_tested_match.built.after.mir | 56 ++++---- ...e_edges.full_tested_match2.built.after.mir | 44 +++--- .../match_false_edges.main.built.after.mir | 92 ++++++------ ....constant_eq.SimplifyCfg-initial.after.mir | 40 +++--- ...joint_ranges.SimplifyCfg-initial.after.mir | 30 ++-- ...ch_match_arms.main.InstrumentCoverage.diff | 44 +++--- ...mment_2.DeduplicateBlocks.panic-abort.diff | 28 ++-- ...ment_2.DeduplicateBlocks.panic-unwind.diff | 28 ++-- ...wise_branch.opt2.EarlyOtherwiseBranch.diff | 14 +- ...wise_branch.opt3.EarlyOtherwiseBranch.diff | 22 +-- ...wise_branch.opt4.EarlyOtherwiseBranch.diff | 22 +-- ...ement_tuple.opt1.EarlyOtherwiseBranch.diff | 14 +- ...ement_tuple.opt2.EarlyOtherwiseBranch.diff | 30 ++-- ...ch_68867.try_sum.EarlyOtherwiseBranch.diff | 124 ++++++++-------- ...nch_noopt.noopt1.EarlyOtherwiseBranch.diff | 26 ++-- ...reading.dfa.JumpThreading.panic-abort.diff | 18 +-- ...eading.dfa.JumpThreading.panic-unwind.diff | 18 +-- tests/mir-opt/jump_threading.rs | 6 +- ...fg-initial.after-ElaborateDrops.after.diff | 132 +++++++++--------- ...fg-initial.after-ElaborateDrops.after.diff | 132 +++++++++--------- ...h_i128_u128.MatchBranchSimplification.diff | 6 +- ...atch_i16_i8.MatchBranchSimplification.diff | 6 +- ...atch_i8_i16.MatchBranchSimplification.diff | 6 +- ..._i16_failed.MatchBranchSimplification.diff | 6 +- ...16_fallback.MatchBranchSimplification.diff | 6 +- ...atch_u8_u16.MatchBranchSimplification.diff | 6 +- ...ut_second_or.SimplifyCfg-initial.after.mir | 30 ++-- ...le_switchint.SimplifyCfg-initial.after.mir | 16 +-- ...tch_const.SingleUseConsts.panic-abort.diff | 8 +- ...ch_const.SingleUseConsts.panic-unwind.diff | 8 +- ...nst_debug.SingleUseConsts.panic-abort.diff | 8 +- ...st_debug.SingleUseConsts.panic-unwind.diff | 8 +- ..._fallthrough.UnreachableEnumBranching.diff | 8 +- ..._fallthrough.UnreachableEnumBranching.diff | 8 +- ....UnreachableEnumBranching.panic-abort.diff | 28 ++-- ...UnreachableEnumBranching.panic-unwind.diff | 28 ++-- ....UnreachableEnumBranching.panic-abort.diff | 12 +- ...UnreachableEnumBranching.panic-unwind.diff | 12 +- ....UnreachableEnumBranching.panic-abort.diff | 12 +- ...UnreachableEnumBranching.panic-unwind.diff | 12 +- ....UnreachableEnumBranching.panic-abort.diff | 12 +- ...UnreachableEnumBranching.panic-unwind.diff | 12 +- ....UnreachableEnumBranching.panic-abort.diff | 14 +- ...UnreachableEnumBranching.panic-unwind.diff | 14 +- ....UnreachableEnumBranching.panic-abort.diff | 32 ++--- ...UnreachableEnumBranching.panic-unwind.diff | 32 ++--- ....UnreachableEnumBranching.panic-abort.diff | 14 +- ...UnreachableEnumBranching.panic-unwind.diff | 14 +- tests/mir-opt/unreachable_enum_branching.rs | 12 +- ....UnreachableEnumBranching.panic-abort.diff | 12 +- ...UnreachableEnumBranching.panic-unwind.diff | 12 +- .../ui/stable-mir-print/basic_function.stdout | 6 +- 54 files changed, 720 insertions(+), 700 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index f56dad84cdbd1..0a55013ae20cd 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1152,8 +1152,6 @@ struct Candidate<'pat, 'tcx> { /// The earliest block that has only candidates >= this one as descendents. Used for false /// edges, see the doc for [`Builder::match_expr`]. false_edge_start_block: Option, - /// The `false_edge_start_block` of the next candidate. - next_candidate_start_block: Option, } impl<'tcx, 'pat> Candidate<'pat, 'tcx> { @@ -1179,7 +1177,6 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { otherwise_block: None, pre_binding_block: None, false_edge_start_block: None, - next_candidate_start_block: None, } } @@ -1444,12 +1441,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let otherwise_block = self.match_candidates(match_start_span, scrutinee_span, block, candidates); - // Link each leaf candidate to the `false_edge_start_block` of the next one. In the - // refutable case we also want a false edge to the failure block. + // Set up false edges so that the borrow-checker cannot make use of the specific CFG we + // generated. We falsely branch from each candidate to the one below it to make it as if we + // were testing match branches one by one in order. In the refutable case we also want a + // false edge to the final failure block. let mut next_candidate_start_block = if refutable { Some(otherwise_block) } else { None }; for candidate in candidates.iter_mut().rev() { + let has_guard = candidate.has_guard; candidate.visit_leaves_rev(|leaf_candidate| { - leaf_candidate.next_candidate_start_block = next_candidate_start_block; + if let Some(next_candidate_start_block) = next_candidate_start_block { + let source_info = self.source_info(leaf_candidate.extra_data.span); + // Falsely branch to `next_candidate_start_block` before reaching pre_binding. + let old_pre_binding = leaf_candidate.pre_binding_block.unwrap(); + let new_pre_binding = self.cfg.start_new_block(); + self.false_edges( + old_pre_binding, + new_pre_binding, + next_candidate_start_block, + source_info, + ); + leaf_candidate.pre_binding_block = Some(new_pre_binding); + if has_guard { + // Falsely branch to `next_candidate_start_block` also if the guard fails. + let new_otherwise = self.cfg.start_new_block(); + let old_otherwise = leaf_candidate.otherwise_block.unwrap(); + self.false_edges( + new_otherwise, + old_otherwise, + next_candidate_start_block, + source_info, + ); + leaf_candidate.otherwise_block = Some(new_otherwise); + } + } assert!(leaf_candidate.false_edge_start_block.is_some()); next_candidate_start_block = leaf_candidate.false_edge_start_block; }); @@ -2302,20 +2326,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug_assert!(candidate.match_pairs.is_empty()); - let candidate_source_info = self.source_info(candidate.extra_data.span); - - let mut block = candidate.pre_binding_block.unwrap(); - - if candidate.next_candidate_start_block.is_some() { - let fresh_block = self.cfg.start_new_block(); - self.false_edges( - block, - fresh_block, - candidate.next_candidate_start_block, - candidate_source_info, - ); - block = fresh_block; - } + let block = candidate.pre_binding_block.unwrap(); if candidate.extra_data.is_never { // This arm has a dummy body, we don't need to generate code for it. `block` is already @@ -2382,16 +2393,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(temp)); } - let otherwise_block = candidate.otherwise_block.unwrap_or_else(|| { - let unreachable = self.cfg.start_new_block(); - self.cfg.terminate(unreachable, source_info, TerminatorKind::Unreachable); - unreachable - }); - self.false_edges( + self.cfg.goto( otherwise_post_guard_block, - otherwise_block, - candidate.next_candidate_start_block, source_info, + candidate.otherwise_block.unwrap(), ); // We want to ensure that the matched candidates are bound diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index c80204c4ad171..1848ab7a20be7 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -18,18 +18,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, from_block: BasicBlock, real_target: BasicBlock, - imaginary_target: Option, + imaginary_target: BasicBlock, source_info: SourceInfo, ) { - match imaginary_target { - Some(target) if target != real_target => { - self.cfg.terminate( - from_block, - source_info, - TerminatorKind::FalseEdge { real_target, imaginary_target: target }, - ); - } - _ => self.cfg.goto(from_block, source_info, real_target), + if imaginary_target != real_target { + self.cfg.terminate( + from_block, + source_info, + TerminatorKind::FalseEdge { real_target, imaginary_target }, + ); + } else { + self.cfg.goto(from_block, source_info, real_target) } } } diff --git a/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir b/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir index 9ebfff18f4830..a93743edfac73 100644 --- a/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir +++ b/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir @@ -37,11 +37,11 @@ fn full_tested_match() -> () { } bb2: { - falseEdge -> [real: bb7, imaginary: bb3]; + falseEdge -> [real: bb8, imaginary: bb3]; } bb3: { - falseEdge -> [real: bb12, imaginary: bb5]; + falseEdge -> [real: bb7, imaginary: bb5]; } bb4: { @@ -50,7 +50,7 @@ fn full_tested_match() -> () { bb5: { _1 = (const 3_i32, const 3_i32); - goto -> bb13; + goto -> bb14; } bb6: { @@ -58,18 +58,33 @@ fn full_tested_match() -> () { } bb7: { + StorageLive(_9); + _9 = ((_2 as Some).0: i32); + StorageLive(_10); + _10 = _9; + _1 = (const 2_i32, move _10); + StorageDead(_10); + StorageDead(_9); + goto -> bb14; + } + + bb8: { StorageLive(_6); _6 = &((_2 as Some).0: i32); _3 = &fake shallow _2; StorageLive(_7); - _7 = guard() -> [return: bb8, unwind: bb15]; + _7 = guard() -> [return: bb10, unwind: bb16]; } - bb8: { - switchInt(move _7) -> [0: bb10, otherwise: bb9]; + bb9: { + goto -> bb3; } - bb9: { + bb10: { + switchInt(move _7) -> [0: bb12, otherwise: bb11]; + } + + bb11: { StorageDead(_7); FakeRead(ForMatchGuard, _3); FakeRead(ForGuardBinding, _6); @@ -81,31 +96,20 @@ fn full_tested_match() -> () { StorageDead(_8); StorageDead(_5); StorageDead(_6); - goto -> bb13; + goto -> bb14; } - bb10: { - goto -> bb11; + bb12: { + goto -> bb13; } - bb11: { + bb13: { StorageDead(_7); StorageDead(_6); - goto -> bb3; - } - - bb12: { - StorageLive(_9); - _9 = ((_2 as Some).0: i32); - StorageLive(_10); - _10 = _9; - _1 = (const 2_i32, move _10); - StorageDead(_10); - StorageDead(_9); - goto -> bb13; + goto -> bb9; } - bb13: { + bb14: { PlaceMention(_1); StorageDead(_2); StorageDead(_1); @@ -113,12 +117,12 @@ fn full_tested_match() -> () { return; } - bb14: { + bb15: { FakeRead(ForMatchedPlace(None), _1); unreachable; } - bb15 (cleanup): { + bb16 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir b/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir index 4d2989ea93ece..0d0ea2be1b005 100644 --- a/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir +++ b/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir @@ -37,7 +37,7 @@ fn full_tested_match2() -> () { } bb2: { - falseEdge -> [real: bb7, imaginary: bb5]; + falseEdge -> [real: bb8, imaginary: bb5]; } bb3: { @@ -48,7 +48,7 @@ fn full_tested_match2() -> () { _1 = (const 2_i32, move _10); StorageDead(_10); StorageDead(_9); - goto -> bb13; + goto -> bb14; } bb4: { @@ -56,7 +56,7 @@ fn full_tested_match2() -> () { } bb5: { - falseEdge -> [real: bb12, imaginary: bb3]; + falseEdge -> [real: bb7, imaginary: bb3]; } bb6: { @@ -64,18 +64,27 @@ fn full_tested_match2() -> () { } bb7: { + _1 = (const 3_i32, const 3_i32); + goto -> bb14; + } + + bb8: { StorageLive(_6); _6 = &((_2 as Some).0: i32); _3 = &fake shallow _2; StorageLive(_7); - _7 = guard() -> [return: bb8, unwind: bb15]; + _7 = guard() -> [return: bb10, unwind: bb16]; } - bb8: { - switchInt(move _7) -> [0: bb10, otherwise: bb9]; + bb9: { + falseEdge -> [real: bb3, imaginary: bb5]; } - bb9: { + bb10: { + switchInt(move _7) -> [0: bb12, otherwise: bb11]; + } + + bb11: { StorageDead(_7); FakeRead(ForMatchGuard, _3); FakeRead(ForGuardBinding, _6); @@ -87,25 +96,20 @@ fn full_tested_match2() -> () { StorageDead(_8); StorageDead(_5); StorageDead(_6); - goto -> bb13; + goto -> bb14; } - bb10: { - goto -> bb11; + bb12: { + goto -> bb13; } - bb11: { + bb13: { StorageDead(_7); StorageDead(_6); - falseEdge -> [real: bb3, imaginary: bb5]; - } - - bb12: { - _1 = (const 3_i32, const 3_i32); - goto -> bb13; + goto -> bb9; } - bb13: { + bb14: { PlaceMention(_1); StorageDead(_2); StorageDead(_1); @@ -113,12 +117,12 @@ fn full_tested_match2() -> () { return; } - bb14: { + bb15: { FakeRead(ForMatchedPlace(None), _1); unreachable; } - bb15 (cleanup): { + bb16 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/match/match_false_edges.main.built.after.mir b/tests/mir-opt/building/match/match_false_edges.main.built.after.mir index 4ed9361070662..87b7e29848f74 100644 --- a/tests/mir-opt/building/match/match_false_edges.main.built.after.mir +++ b/tests/mir-opt/building/match/match_false_edges.main.built.after.mir @@ -43,11 +43,11 @@ fn main() -> () { } bb1: { - falseEdge -> [real: bb14, imaginary: bb4]; + falseEdge -> [real: bb11, imaginary: bb4]; } bb2: { - falseEdge -> [real: bb9, imaginary: bb1]; + falseEdge -> [real: bb12, imaginary: bb1]; } bb3: { @@ -64,11 +64,11 @@ fn main() -> () { _14 = _2; _1 = const 4_i32; StorageDead(_14); - goto -> bb20; + goto -> bb22; } bb6: { - falseEdge -> [real: bb15, imaginary: bb5]; + falseEdge -> [real: bb9, imaginary: bb5]; } bb7: { @@ -81,62 +81,70 @@ fn main() -> () { } bb9: { - StorageLive(_7); - _7 = &((_2 as Some).0: i32); + StorageLive(_11); + _11 = &((_2 as Some).0: i32); _3 = &fake shallow _2; - StorageLive(_8); - _8 = guard() -> [return: bb10, unwind: bb22]; + StorageLive(_12); + StorageLive(_13); + _13 = (*_11); + _12 = guard2(move _13) -> [return: bb18, unwind: bb24]; } bb10: { - switchInt(move _8) -> [0: bb12, otherwise: bb11]; + falseEdge -> [real: bb7, imaginary: bb5]; } bb11: { - StorageDead(_8); - FakeRead(ForMatchGuard, _3); - FakeRead(ForGuardBinding, _7); - StorageLive(_6); - _6 = ((_2 as Some).0: i32); - _1 = const 1_i32; - StorageDead(_6); - StorageDead(_7); - goto -> bb20; + StorageLive(_9); + _9 = _2; + _1 = const 2_i32; + StorageDead(_9); + goto -> bb22; } bb12: { - goto -> bb13; + StorageLive(_7); + _7 = &((_2 as Some).0: i32); + _3 = &fake shallow _2; + StorageLive(_8); + _8 = guard() -> [return: bb14, unwind: bb24]; } bb13: { - StorageDead(_8); - StorageDead(_7); falseEdge -> [real: bb3, imaginary: bb1]; } bb14: { - StorageLive(_9); - _9 = _2; - _1 = const 2_i32; - StorageDead(_9); - goto -> bb20; + switchInt(move _8) -> [0: bb16, otherwise: bb15]; } bb15: { - StorageLive(_11); - _11 = &((_2 as Some).0: i32); - _3 = &fake shallow _2; - StorageLive(_12); - StorageLive(_13); - _13 = (*_11); - _12 = guard2(move _13) -> [return: bb16, unwind: bb22]; + StorageDead(_8); + FakeRead(ForMatchGuard, _3); + FakeRead(ForGuardBinding, _7); + StorageLive(_6); + _6 = ((_2 as Some).0: i32); + _1 = const 1_i32; + StorageDead(_6); + StorageDead(_7); + goto -> bb22; } bb16: { - switchInt(move _12) -> [0: bb18, otherwise: bb17]; + goto -> bb17; } bb17: { + StorageDead(_8); + StorageDead(_7); + goto -> bb13; + } + + bb18: { + switchInt(move _12) -> [0: bb20, otherwise: bb19]; + } + + bb19: { StorageDead(_13); StorageDead(_12); FakeRead(ForMatchGuard, _3); @@ -146,21 +154,21 @@ fn main() -> () { _1 = const 3_i32; StorageDead(_10); StorageDead(_11); - goto -> bb20; + goto -> bb22; } - bb18: { - goto -> bb19; + bb20: { + goto -> bb21; } - bb19: { + bb21: { StorageDead(_13); StorageDead(_12); StorageDead(_11); - falseEdge -> [real: bb7, imaginary: bb5]; + goto -> bb10; } - bb20: { + bb22: { PlaceMention(_1); StorageDead(_2); StorageDead(_1); @@ -168,12 +176,12 @@ fn main() -> () { return; } - bb21: { + bb23: { FakeRead(ForMatchedPlace(None), _1); unreachable; } - bb22 (cleanup): { + bb24 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir index 2b5dbacc2d928..2bce79a3ae799 100644 --- a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir @@ -31,7 +31,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { } bb2: { - falseEdge -> [real: bb12, imaginary: bb5]; + falseEdge -> [real: bb15, imaginary: bb5]; } bb3: { @@ -39,7 +39,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { } bb4: { - falseEdge -> [real: bb16, imaginary: bb1]; + falseEdge -> [real: bb13, imaginary: bb1]; } bb5: { @@ -51,7 +51,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { } bb7: { - falseEdge -> [real: bb15, imaginary: bb3]; + falseEdge -> [real: bb14, imaginary: bb3]; } bb8: { @@ -68,43 +68,43 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { } bb11: { - falseEdge -> [real: bb17, imaginary: bb10]; + falseEdge -> [real: bb12, imaginary: bb10]; } bb12: { - _6 = &fake shallow (_3.0: &str); - _7 = &fake shallow (_3.1: bool); - StorageLive(_10); - _10 = const true; - switchInt(move _10) -> [0: bb14, otherwise: bb13]; + _0 = const 4_u32; + goto -> bb18; } bb13: { - StorageDead(_10); - FakeRead(ForMatchGuard, _6); - FakeRead(ForMatchGuard, _7); - _0 = const 1_u32; + _0 = const 3_u32; goto -> bb18; } bb14: { - StorageDead(_10); - falseEdge -> [real: bb3, imaginary: bb5]; + _0 = const 2_u32; + goto -> bb18; } bb15: { - _0 = const 2_u32; - goto -> bb18; + _6 = &fake shallow (_3.0: &str); + _7 = &fake shallow (_3.1: bool); + StorageLive(_10); + _10 = const true; + switchInt(move _10) -> [0: bb17, otherwise: bb16]; } bb16: { - _0 = const 3_u32; + StorageDead(_10); + FakeRead(ForMatchGuard, _6); + FakeRead(ForMatchGuard, _7); + _0 = const 1_u32; goto -> bb18; } bb17: { - _0 = const 4_u32; - goto -> bb18; + StorageDead(_10); + falseEdge -> [real: bb3, imaginary: bb5]; } bb18: { diff --git a/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir index 07daa3eddfa2c..e521fb4509aa1 100644 --- a/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir @@ -23,7 +23,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 { } bb2: { - falseEdge -> [real: bb9, imaginary: bb3]; + falseEdge -> [real: bb11, imaginary: bb3]; } bb3: { @@ -32,7 +32,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 { } bb4: { - falseEdge -> [real: bb12, imaginary: bb5]; + falseEdge -> [real: bb10, imaginary: bb5]; } bb5: { @@ -40,7 +40,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 { } bb6: { - falseEdge -> [real: bb13, imaginary: bb1]; + falseEdge -> [real: bb9, imaginary: bb1]; } bb7: { @@ -54,32 +54,32 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 { } bb9: { - _3 = &fake shallow _1; - StorageLive(_8); - _8 = _2; - switchInt(move _8) -> [0: bb11, otherwise: bb10]; + _0 = const 2_u32; + goto -> bb14; } bb10: { - StorageDead(_8); - FakeRead(ForMatchGuard, _3); - _0 = const 0_u32; + _0 = const 1_u32; goto -> bb14; } bb11: { - StorageDead(_8); - falseEdge -> [real: bb1, imaginary: bb3]; + _3 = &fake shallow _1; + StorageLive(_8); + _8 = _2; + switchInt(move _8) -> [0: bb13, otherwise: bb12]; } bb12: { - _0 = const 1_u32; + StorageDead(_8); + FakeRead(ForMatchGuard, _3); + _0 = const 0_u32; goto -> bb14; } bb13: { - _0 = const 2_u32; - goto -> bb14; + StorageDead(_8); + falseEdge -> [real: bb1, imaginary: bb3]; } bb14: { diff --git a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff index e60f71f47b1ed..3d791734f4626 100644 --- a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff @@ -55,17 +55,17 @@ bb2: { + Coverage::CounterIncrement(3); - falseEdge -> [real: bb6, imaginary: bb3]; + falseEdge -> [real: bb8, imaginary: bb3]; } bb3: { + Coverage::CounterIncrement(2); - falseEdge -> [real: bb8, imaginary: bb4]; + falseEdge -> [real: bb7, imaginary: bb4]; } bb4: { + Coverage::CounterIncrement(1); - falseEdge -> [real: bb10, imaginary: bb5]; + falseEdge -> [real: bb6, imaginary: bb5]; } bb5: { @@ -78,39 +78,39 @@ } bb6: { - StorageLive(_3); - _3 = ((_1 as D).0: u32); - StorageLive(_4); - _4 = _3; - _0 = consume(move _4) -> [return: bb7, unwind: bb14]; + StorageLive(_7); + _7 = ((_1 as B).0: u32); + StorageLive(_8); + _8 = _7; + _0 = consume(move _8) -> [return: bb11, unwind: bb14]; } bb7: { - StorageDead(_4); - StorageDead(_3); - goto -> bb13; - } - - bb8: { StorageLive(_5); _5 = ((_1 as C).0: u32); StorageLive(_6); _6 = _5; - _0 = consume(move _6) -> [return: bb9, unwind: bb14]; + _0 = consume(move _6) -> [return: bb10, unwind: bb14]; + } + + bb8: { + StorageLive(_3); + _3 = ((_1 as D).0: u32); + StorageLive(_4); + _4 = _3; + _0 = consume(move _4) -> [return: bb9, unwind: bb14]; } bb9: { - StorageDead(_6); - StorageDead(_5); + StorageDead(_4); + StorageDead(_3); goto -> bb13; } bb10: { - StorageLive(_7); - _7 = ((_1 as B).0: u32); - StorageLive(_8); - _8 = _7; - _0 = consume(move _8) -> [return: bb11, unwind: bb14]; + StorageDead(_6); + StorageDead(_5); + goto -> bb13; } bb11: { diff --git a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff index 3a5762e4f3d1e..efb28ba344b2b 100644 --- a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff +++ b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff @@ -33,7 +33,7 @@ _8 = const 3_usize; _9 = Ge(move _7, move _8); - switchInt(move _9) -> [0: bb7, otherwise: bb8]; -+ switchInt(move _9) -> [0: bb10, otherwise: bb7]; ++ switchInt(move _9) -> [0: bb11, otherwise: bb7]; } bb3: { @@ -49,48 +49,48 @@ } bb6: { -- switchInt((*_2)[3 of 4]) -> [47: bb11, otherwise: bb2]; -+ switchInt((*_2)[3 of 4]) -> [47: bb10, otherwise: bb2]; +- switchInt((*_2)[3 of 4]) -> [47: bb13, otherwise: bb2]; ++ switchInt((*_2)[3 of 4]) -> [47: bb11, otherwise: bb2]; } bb7: { - _0 = const false; - goto -> bb14; -+ switchInt((*_2)[0 of 3]) -> [47: bb8, otherwise: bb10]; ++ switchInt((*_2)[0 of 3]) -> [47: bb8, otherwise: bb11]; } bb8: { - switchInt((*_2)[0 of 3]) -> [47: bb9, otherwise: bb7]; -+ switchInt((*_2)[1 of 3]) -> [47: bb9, otherwise: bb10]; ++ switchInt((*_2)[1 of 3]) -> [47: bb9, otherwise: bb11]; } bb9: { - switchInt((*_2)[1 of 3]) -> [47: bb10, otherwise: bb7]; -+ switchInt((*_2)[2 of 3]) -> [47: bb11, 33: bb11, otherwise: bb10]; ++ switchInt((*_2)[2 of 3]) -> [47: bb10, 33: bb10, otherwise: bb11]; } bb10: { -- switchInt((*_2)[2 of 3]) -> [47: bb12, 33: bb13, otherwise: bb7]; +- switchInt((*_2)[2 of 3]) -> [47: bb12, 33: bb11, otherwise: bb7]; - } - - bb11: { - _0 = const false; + _0 = const true; - goto -> bb14; + goto -> bb12; } - bb12: { +- _0 = const true; +- goto -> bb14; +- } +- +- bb13: { + bb11: { - _0 = const true; + _0 = const false; - goto -> bb14; + goto -> bb12; } -- bb13: { -- _0 = const true; -- goto -> bb14; -- } -- - bb14: { + bb12: { StorageDead(_2); diff --git a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff index 21b197d2f270c..c6e2d3a551259 100644 --- a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff +++ b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff @@ -33,7 +33,7 @@ _8 = const 3_usize; _9 = Ge(move _7, move _8); - switchInt(move _9) -> [0: bb7, otherwise: bb8]; -+ switchInt(move _9) -> [0: bb10, otherwise: bb7]; ++ switchInt(move _9) -> [0: bb11, otherwise: bb7]; } bb3: { @@ -49,48 +49,48 @@ } bb6: { -- switchInt((*_2)[3 of 4]) -> [47: bb11, otherwise: bb2]; -+ switchInt((*_2)[3 of 4]) -> [47: bb10, otherwise: bb2]; +- switchInt((*_2)[3 of 4]) -> [47: bb13, otherwise: bb2]; ++ switchInt((*_2)[3 of 4]) -> [47: bb11, otherwise: bb2]; } bb7: { - _0 = const false; - goto -> bb14; -+ switchInt((*_2)[0 of 3]) -> [47: bb8, otherwise: bb10]; ++ switchInt((*_2)[0 of 3]) -> [47: bb8, otherwise: bb11]; } bb8: { - switchInt((*_2)[0 of 3]) -> [47: bb9, otherwise: bb7]; -+ switchInt((*_2)[1 of 3]) -> [47: bb9, otherwise: bb10]; ++ switchInt((*_2)[1 of 3]) -> [47: bb9, otherwise: bb11]; } bb9: { - switchInt((*_2)[1 of 3]) -> [47: bb10, otherwise: bb7]; -+ switchInt((*_2)[2 of 3]) -> [47: bb11, 33: bb11, otherwise: bb10]; ++ switchInt((*_2)[2 of 3]) -> [47: bb10, 33: bb10, otherwise: bb11]; } bb10: { -- switchInt((*_2)[2 of 3]) -> [47: bb12, 33: bb13, otherwise: bb7]; +- switchInt((*_2)[2 of 3]) -> [47: bb12, 33: bb11, otherwise: bb7]; - } - - bb11: { - _0 = const false; + _0 = const true; - goto -> bb14; + goto -> bb12; } - bb12: { +- _0 = const true; +- goto -> bb14; +- } +- +- bb13: { + bb11: { - _0 = const true; + _0 = const false; - goto -> bb14; + goto -> bb12; } -- bb13: { -- _0 = const true; -- goto -> bb14; -- } -- - bb14: { + bb12: { StorageDead(_2); diff --git a/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff index 7776ff0fde794..41ae2fd3af3f4 100644 --- a/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff @@ -38,15 +38,20 @@ bb2: { _6 = discriminant((_3.1: std::option::Option)); - switchInt(move _6) -> [1: bb4, 0: bb1, otherwise: bb7]; + switchInt(move _6) -> [1: bb5, 0: bb1, otherwise: bb7]; } bb3: { _7 = discriminant((_3.1: std::option::Option)); - switchInt(move _7) -> [0: bb5, 1: bb1, otherwise: bb7]; + switchInt(move _7) -> [0: bb4, 1: bb1, otherwise: bb7]; } bb4: { + _0 = const 2_u32; + goto -> bb6; + } + + bb5: { StorageLive(_9); _9 = (((_3.0: std::option::Option) as Some).0: u32); StorageLive(_10); @@ -57,11 +62,6 @@ goto -> bb6; } - bb5: { - _0 = const 2_u32; - goto -> bb6; - } - bb6: { StorageDead(_3); return; diff --git a/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff index b41e952d80f5a..302fd0bfded4b 100644 --- a/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff @@ -49,7 +49,7 @@ bb2: { - _6 = discriminant((_3.1: Option2)); -- switchInt(move _6) -> [0: bb5, otherwise: bb1]; +- switchInt(move _6) -> [0: bb7, otherwise: bb1]; - } - - bb3: { @@ -59,17 +59,11 @@ - - bb4: { - _8 = discriminant((_3.1: Option2)); -- switchInt(move _8) -> [2: bb7, otherwise: bb1]; +- switchInt(move _8) -> [2: bb5, otherwise: bb1]; - } - - bb5: { - StorageLive(_10); - _10 = (((_3.0: Option2) as Some).0: u32); - StorageLive(_11); - _11 = (((_3.1: Option2) as Some).0: bool); - _0 = const 0_u32; - StorageDead(_11); - StorageDead(_10); + _0 = const 3_u32; - goto -> bb8; + goto -> bb5; } @@ -83,7 +77,13 @@ - bb7: { + bb4: { - _0 = const 3_u32; + StorageLive(_10); + _10 = (((_3.0: Option2) as Some).0: u32); + StorageLive(_11); + _11 = (((_3.1: Option2) as Some).0: bool); + _0 = const 0_u32; + StorageDead(_11); + StorageDead(_10); - goto -> bb8; + goto -> bb5; } @@ -101,7 +101,7 @@ + + bb7: { + StorageDead(_13); -+ switchInt(_9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb6]; ++ switchInt(_9) -> [0: bb4, 1: bb3, 2: bb2, otherwise: bb6]; } } diff --git a/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff index 18dea56f4307c..eef4fb3278c1c 100644 --- a/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff @@ -49,7 +49,7 @@ bb2: { - _6 = discriminant((_3.1: Option2)); -- switchInt(move _6) -> [0: bb5, otherwise: bb1]; +- switchInt(move _6) -> [0: bb7, otherwise: bb1]; - } - - bb3: { @@ -59,17 +59,11 @@ - - bb4: { - _8 = discriminant((_3.1: Option2)); -- switchInt(move _8) -> [2: bb7, otherwise: bb1]; +- switchInt(move _8) -> [2: bb5, otherwise: bb1]; - } - - bb5: { - StorageLive(_10); - _10 = (((_3.0: Option2) as Some).0: u32); - StorageLive(_11); - _11 = (((_3.1: Option2) as Some).0: u32); - _0 = const 0_u32; - StorageDead(_11); - StorageDead(_10); + _0 = const 3_u32; - goto -> bb8; + goto -> bb5; } @@ -83,7 +77,13 @@ - bb7: { + bb4: { - _0 = const 3_u32; + StorageLive(_10); + _10 = (((_3.0: Option2) as Some).0: u32); + StorageLive(_11); + _11 = (((_3.1: Option2) as Some).0: u32); + _0 = const 0_u32; + StorageDead(_11); + StorageDead(_10); - goto -> bb8; + goto -> bb5; } @@ -101,7 +101,7 @@ + + bb7: { + StorageDead(_13); -+ switchInt(_9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb6]; ++ switchInt(_9) -> [0: bb4, 1: bb3, 2: bb2, otherwise: bb6]; } } diff --git a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff index 4c3c717b52251..cb03e2697ccd3 100644 --- a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff @@ -52,7 +52,7 @@ bb3: { _8 = discriminant((_4.2: std::option::Option)); - switchInt(move _8) -> [1: bb6, 0: bb1, otherwise: bb9]; + switchInt(move _8) -> [1: bb7, 0: bb1, otherwise: bb9]; } bb4: { @@ -62,10 +62,15 @@ bb5: { _10 = discriminant((_4.2: std::option::Option)); - switchInt(move _10) -> [0: bb7, 1: bb1, otherwise: bb9]; + switchInt(move _10) -> [0: bb6, 1: bb1, otherwise: bb9]; } bb6: { + _0 = const 2_u32; + goto -> bb8; + } + + bb7: { StorageLive(_13); _13 = (((_4.0: std::option::Option) as Some).0: u32); StorageLive(_14); @@ -79,11 +84,6 @@ goto -> bb8; } - bb7: { - _0 = const 2_u32; - goto -> bb8; - } - bb8: { StorageDead(_4); return; diff --git a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff index 0ea7a10baaadc..5634df253a5d0 100644 --- a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff @@ -64,8 +64,8 @@ - - bb3: { _8 = discriminant((_4.2: Option2)); -- switchInt(move _8) -> [0: bb8, otherwise: bb1]; -+ switchInt(move _8) -> [0: bb5, otherwise: bb1]; +- switchInt(move _8) -> [0: bb10, otherwise: bb1]; ++ switchInt(move _8) -> [0: bb7, otherwise: bb1]; } - bb4: { @@ -88,22 +88,13 @@ - bb7: { + bb4: { _12 = discriminant((_4.2: Option2)); -- switchInt(move _12) -> [2: bb10, otherwise: bb1]; -+ switchInt(move _12) -> [2: bb7, otherwise: bb1]; +- switchInt(move _12) -> [2: bb8, otherwise: bb1]; ++ switchInt(move _12) -> [2: bb5, otherwise: bb1]; } - bb8: { + bb5: { - StorageLive(_15); - _15 = (((_4.0: Option2) as Some).0: u32); - StorageLive(_16); - _16 = (((_4.1: Option2) as Some).0: u32); - StorageLive(_17); - _17 = (((_4.2: Option2) as Some).0: u32); - _0 = const 0_u32; - StorageDead(_17); - StorageDead(_16); - StorageDead(_15); + _0 = const 3_u32; - goto -> bb11; + goto -> bb8; } @@ -117,7 +108,16 @@ - bb10: { + bb7: { - _0 = const 3_u32; + StorageLive(_15); + _15 = (((_4.0: Option2) as Some).0: u32); + StorageLive(_16); + _16 = (((_4.1: Option2) as Some).0: u32); + StorageLive(_17); + _17 = (((_4.2: Option2) as Some).0: u32); + _0 = const 0_u32; + StorageDead(_17); + StorageDead(_16); + StorageDead(_15); - goto -> bb11; + goto -> bb8; } diff --git a/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff index de12fe8f120a7..8179d9dd11505 100644 --- a/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff @@ -94,78 +94,56 @@ bb2: { _35 = deref_copy (_4.1: &ViewportPercentageLength); _7 = discriminant((*_35)); - switchInt(move _7) -> [0: bb6, otherwise: bb1]; + switchInt(move _7) -> [0: bb9, otherwise: bb1]; } bb3: { _36 = deref_copy (_4.1: &ViewportPercentageLength); _8 = discriminant((*_36)); - switchInt(move _8) -> [1: bb7, otherwise: bb1]; + switchInt(move _8) -> [1: bb8, otherwise: bb1]; } bb4: { _37 = deref_copy (_4.1: &ViewportPercentageLength); _9 = discriminant((*_37)); - switchInt(move _9) -> [2: bb8, otherwise: bb1]; + switchInt(move _9) -> [2: bb7, otherwise: bb1]; } bb5: { _38 = deref_copy (_4.1: &ViewportPercentageLength); _10 = discriminant((*_38)); - switchInt(move _10) -> [3: bb9, otherwise: bb1]; + switchInt(move _10) -> [3: bb6, otherwise: bb1]; } bb6: { - StorageLive(_12); + StorageLive(_27); _39 = deref_copy (_4.0: &ViewportPercentageLength); - _12 = (((*_39) as Vw).0: f32); - StorageLive(_13); + _27 = (((*_39) as Vmax).0: f32); + StorageLive(_28); _40 = deref_copy (_4.1: &ViewportPercentageLength); - _13 = (((*_40) as Vw).0: f32); - StorageLive(_14); - StorageLive(_15); - _15 = _12; - StorageLive(_16); - _16 = _13; - _14 = Add(move _15, move _16); - StorageDead(_16); - StorageDead(_15); - _3 = ViewportPercentageLength::Vw(move _14); - StorageDead(_14); - StorageDead(_13); - StorageDead(_12); + _28 = (((*_40) as Vmax).0: f32); + StorageLive(_29); + StorageLive(_30); + _30 = _27; + StorageLive(_31); + _31 = _28; + _29 = Add(move _30, move _31); + StorageDead(_31); + StorageDead(_30); + _3 = ViewportPercentageLength::Vmax(move _29); + StorageDead(_29); + StorageDead(_28); + StorageDead(_27); goto -> bb10; } bb7: { - StorageLive(_17); - _41 = deref_copy (_4.0: &ViewportPercentageLength); - _17 = (((*_41) as Vh).0: f32); - StorageLive(_18); - _42 = deref_copy (_4.1: &ViewportPercentageLength); - _18 = (((*_42) as Vh).0: f32); - StorageLive(_19); - StorageLive(_20); - _20 = _17; - StorageLive(_21); - _21 = _18; - _19 = Add(move _20, move _21); - StorageDead(_21); - StorageDead(_20); - _3 = ViewportPercentageLength::Vh(move _19); - StorageDead(_19); - StorageDead(_18); - StorageDead(_17); - goto -> bb10; - } - - bb8: { StorageLive(_22); - _43 = deref_copy (_4.0: &ViewportPercentageLength); - _22 = (((*_43) as Vmin).0: f32); + _41 = deref_copy (_4.0: &ViewportPercentageLength); + _22 = (((*_41) as Vmin).0: f32); StorageLive(_23); - _44 = deref_copy (_4.1: &ViewportPercentageLength); - _23 = (((*_44) as Vmin).0: f32); + _42 = deref_copy (_4.1: &ViewportPercentageLength); + _23 = (((*_42) as Vmin).0: f32); StorageLive(_24); StorageLive(_25); _25 = _22; @@ -181,25 +159,47 @@ goto -> bb10; } + bb8: { + StorageLive(_17); + _43 = deref_copy (_4.0: &ViewportPercentageLength); + _17 = (((*_43) as Vh).0: f32); + StorageLive(_18); + _44 = deref_copy (_4.1: &ViewportPercentageLength); + _18 = (((*_44) as Vh).0: f32); + StorageLive(_19); + StorageLive(_20); + _20 = _17; + StorageLive(_21); + _21 = _18; + _19 = Add(move _20, move _21); + StorageDead(_21); + StorageDead(_20); + _3 = ViewportPercentageLength::Vh(move _19); + StorageDead(_19); + StorageDead(_18); + StorageDead(_17); + goto -> bb10; + } + bb9: { - StorageLive(_27); + StorageLive(_12); _45 = deref_copy (_4.0: &ViewportPercentageLength); - _27 = (((*_45) as Vmax).0: f32); - StorageLive(_28); + _12 = (((*_45) as Vw).0: f32); + StorageLive(_13); _46 = deref_copy (_4.1: &ViewportPercentageLength); - _28 = (((*_46) as Vmax).0: f32); - StorageLive(_29); - StorageLive(_30); - _30 = _27; - StorageLive(_31); - _31 = _28; - _29 = Add(move _30, move _31); - StorageDead(_31); - StorageDead(_30); - _3 = ViewportPercentageLength::Vmax(move _29); - StorageDead(_29); - StorageDead(_28); - StorageDead(_27); + _13 = (((*_46) as Vw).0: f32); + StorageLive(_14); + StorageLive(_15); + _15 = _12; + StorageLive(_16); + _16 = _13; + _14 = Add(move _15, move _16); + StorageDead(_16); + StorageDead(_15); + _3 = ViewportPercentageLength::Vw(move _14); + StorageDead(_14); + StorageDead(_13); + StorageDead(_12); goto -> bb10; } diff --git a/tests/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff index 350e5fe6db579..651b1de4ddd37 100644 --- a/tests/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff @@ -45,12 +45,12 @@ bb2: { _6 = discriminant((_3.1: std::option::Option)); - switchInt(move _6) -> [0: bb6, 1: bb5, otherwise: bb1]; + switchInt(move _6) -> [0: bb6, 1: bb7, otherwise: bb1]; } bb3: { _7 = discriminant((_3.1: std::option::Option)); - switchInt(move _7) -> [0: bb4, 1: bb7, otherwise: bb1]; + switchInt(move _7) -> [0: bb4, 1: bb5, otherwise: bb1]; } bb4: { @@ -59,13 +59,10 @@ } bb5: { - StorageLive(_9); - _9 = (((_3.0: std::option::Option) as Some).0: u32); - StorageLive(_10); - _10 = (((_3.1: std::option::Option) as Some).0: u32); - _0 = const 0_u32; - StorageDead(_10); - StorageDead(_9); + StorageLive(_12); + _12 = (((_3.1: std::option::Option) as Some).0: u32); + _0 = const 2_u32; + StorageDead(_12); goto -> bb8; } @@ -78,10 +75,13 @@ } bb7: { - StorageLive(_12); - _12 = (((_3.1: std::option::Option) as Some).0: u32); - _0 = const 2_u32; - StorageDead(_12); + StorageLive(_9); + _9 = (((_3.0: std::option::Option) as Some).0: u32); + StorageLive(_10); + _10 = (((_3.1: std::option::Option) as Some).0: u32); + _0 = const 0_u32; + StorageDead(_10); + StorageDead(_9); goto -> bb8; } diff --git a/tests/mir-opt/jump_threading.dfa.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.dfa.JumpThreading.panic-abort.diff index bbbfe90691f97..8009721fa5c58 100644 --- a/tests/mir-opt/jump_threading.dfa.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.dfa.JumpThreading.panic-abort.diff @@ -24,7 +24,7 @@ bb1: { _4 = discriminant(_1); - switchInt(move _4) -> [0: bb4, 1: bb5, 2: bb6, 3: bb3, otherwise: bb2]; + switchInt(move _4) -> [0: bb6, 1: bb5, 2: bb4, 3: bb3, otherwise: bb2]; } bb2: { @@ -39,11 +39,11 @@ } bb4: { - StorageLive(_5); - _5 = DFA::B; - _1 = move _5; + StorageLive(_7); + _7 = DFA::D; + _1 = move _7; _3 = const (); - StorageDead(_5); + StorageDead(_7); goto -> bb1; } @@ -57,11 +57,11 @@ } bb6: { - StorageLive(_7); - _7 = DFA::D; - _1 = move _7; + StorageLive(_5); + _5 = DFA::B; + _1 = move _5; _3 = const (); - StorageDead(_7); + StorageDead(_5); goto -> bb1; } } diff --git a/tests/mir-opt/jump_threading.dfa.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.dfa.JumpThreading.panic-unwind.diff index bbbfe90691f97..8009721fa5c58 100644 --- a/tests/mir-opt/jump_threading.dfa.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.dfa.JumpThreading.panic-unwind.diff @@ -24,7 +24,7 @@ bb1: { _4 = discriminant(_1); - switchInt(move _4) -> [0: bb4, 1: bb5, 2: bb6, 3: bb3, otherwise: bb2]; + switchInt(move _4) -> [0: bb6, 1: bb5, 2: bb4, 3: bb3, otherwise: bb2]; } bb2: { @@ -39,11 +39,11 @@ } bb4: { - StorageLive(_5); - _5 = DFA::B; - _1 = move _5; + StorageLive(_7); + _7 = DFA::D; + _1 = move _7; _3 = const (); - StorageDead(_5); + StorageDead(_7); goto -> bb1; } @@ -57,11 +57,11 @@ } bb6: { - StorageLive(_7); - _7 = DFA::D; - _1 = move _7; + StorageLive(_5); + _5 = DFA::B; + _1 = move _5; _3 = const (); - StorageDead(_7); + StorageDead(_5); goto -> bb1; } } diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs index e5d8525dcac13..6486a321e693e 100644 --- a/tests/mir-opt/jump_threading.rs +++ b/tests/mir-opt/jump_threading.rs @@ -93,19 +93,19 @@ fn dfa() { // CHECK: {{_.*}} = DFA::A; // CHECK: goto -> bb1; // CHECK: bb1: { - // CHECK: switchInt({{.*}}) -> [0: bb4, 1: bb5, 2: bb6, 3: bb3, otherwise: bb2]; + // CHECK: switchInt({{.*}}) -> [0: bb6, 1: bb5, 2: bb4, 3: bb3, otherwise: bb2]; // CHECK: bb2: { // CHECK: unreachable; // CHECK: bb3: { // CHECK: return; // CHECK: bb4: { - // CHECK: {{_.*}} = DFA::B; + // CHECK: {{_.*}} = DFA::D; // CHECK: goto -> bb1; // CHECK: bb5: { // CHECK: {{_.*}} = DFA::C; // CHECK: goto -> bb1; // CHECK: bb6: { - // CHECK: {{_.*}} = DFA::D; + // CHECK: {{_.*}} = DFA::B; // CHECK: goto -> bb1; let mut state = DFA::A; loop { diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff index 4f29e5244d7c2..3c4a84bc24368 100644 --- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff +++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff @@ -33,17 +33,17 @@ bb0: { PlaceMention(_2); - switchInt((_2.0: bool)) -> [0: bb2, otherwise: bb1]; -+ switchInt((_2.0: bool)) -> [0: bb5, otherwise: bb1]; ++ switchInt((_2.0: bool)) -> [0: bb6, otherwise: bb1]; } bb1: { - switchInt((_2.1: bool)) -> [0: bb4, otherwise: bb3]; -+ switchInt((_2.1: bool)) -> [0: bb10, otherwise: bb2]; ++ switchInt((_2.1: bool)) -> [0: bb5, otherwise: bb2]; } bb2: { -- falseEdge -> [real: bb8, imaginary: bb1]; -+ switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17]; +- falseEdge -> [real: bb9, imaginary: bb1]; ++ switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb4]; } bb3: { @@ -51,11 +51,11 @@ - } - - bb4: { -- falseEdge -> [real: bb13, imaginary: bb3]; +- falseEdge -> [real: bb8, imaginary: bb3]; - } - - bb5: { -- falseEdge -> [real: bb20, imaginary: bb6]; +- falseEdge -> [real: bb7, imaginary: bb6]; - } - - bb6: { @@ -63,19 +63,37 @@ _15 = (_2.1: bool); StorageLive(_16); _16 = move (_2.2: std::string::String); -- goto -> bb19; -+ goto -> bb16; +- goto -> bb20; ++ goto -> bb17; } - bb7: { + bb4: { - _0 = const 1_i32; -- drop(_7) -> [return: bb18, unwind: bb25]; -+ drop(_7) -> [return: bb15, unwind: bb22]; + StorageLive(_15); + _15 = (_2.1: bool); + StorageLive(_16); + _16 = move (_2.2: std::string::String); +- goto -> bb20; ++ goto -> bb17; } - bb8: { + bb5: { + StorageLive(_6); + _6 = &(_2.0: bool); + StorageLive(_8); + _8 = &(_2.2: std::string::String); +- _3 = &fake shallow (_2.0: bool); +- _4 = &fake shallow (_2.1: bool); + StorageLive(_12); + StorageLive(_13); + _13 = _1; +- switchInt(move _13) -> [0: bb16, otherwise: bb15]; ++ switchInt(move _13) -> [0: bb13, otherwise: bb12]; + } + +- bb9: { ++ bb6: { StorageLive(_6); _6 = &(_2.1: bool); StorageLive(_8); @@ -85,12 +103,19 @@ StorageLive(_9); StorageLive(_10); _10 = _1; -- switchInt(move _10) -> [0: bb10, otherwise: bb9]; -+ switchInt(move _10) -> [0: bb7, otherwise: bb6]; +- switchInt(move _10) -> [0: bb12, otherwise: bb11]; ++ switchInt(move _10) -> [0: bb9, otherwise: bb8]; } -- bb9: { -+ bb6: { +- bb10: { ++ bb7: { + _0 = const 1_i32; +- drop(_7) -> [return: bb19, unwind: bb25]; ++ drop(_7) -> [return: bb16, unwind: bb22]; + } + +- bb11: { ++ bb8: { _0 = const 3_i32; StorageDead(_10); StorageDead(_9); @@ -98,15 +123,15 @@ + goto -> bb20; } -- bb10: { -+ bb7: { +- bb12: { ++ bb9: { _9 = (*_6); -- switchInt(move _9) -> [0: bb12, otherwise: bb11]; -+ switchInt(move _9) -> [0: bb9, otherwise: bb8]; +- switchInt(move _9) -> [0: bb14, otherwise: bb13]; ++ switchInt(move _9) -> [0: bb11, otherwise: bb10]; } -- bb11: { -+ bb8: { +- bb13: { ++ bb10: { StorageDead(_10); StorageDead(_9); - FakeRead(ForMatchGuard, _3); @@ -117,12 +142,12 @@ _5 = (_2.1: bool); StorageLive(_7); _7 = move (_2.2: std::string::String); -- goto -> bb7; -+ goto -> bb4; +- goto -> bb10; ++ goto -> bb7; } -- bb12: { -+ bb9: { +- bb14: { ++ bb11: { StorageDead(_10); StorageDead(_9); StorageDead(_8); @@ -131,23 +156,8 @@ + goto -> bb1; } -- bb13: { -+ bb10: { - StorageLive(_6); - _6 = &(_2.0: bool); - StorageLive(_8); - _8 = &(_2.2: std::string::String); -- _3 = &fake shallow (_2.0: bool); -- _4 = &fake shallow (_2.1: bool); - StorageLive(_12); - StorageLive(_13); - _13 = _1; -- switchInt(move _13) -> [0: bb15, otherwise: bb14]; -+ switchInt(move _13) -> [0: bb12, otherwise: bb11]; - } - -- bb14: { -+ bb11: { +- bb15: { ++ bb12: { _0 = const 3_i32; StorageDead(_13); StorageDead(_12); @@ -155,15 +165,15 @@ + goto -> bb20; } -- bb15: { -+ bb12: { +- bb16: { ++ bb13: { _12 = (*_6); -- switchInt(move _12) -> [0: bb17, otherwise: bb16]; -+ switchInt(move _12) -> [0: bb14, otherwise: bb13]; +- switchInt(move _12) -> [0: bb18, otherwise: bb17]; ++ switchInt(move _12) -> [0: bb15, otherwise: bb14]; } -- bb16: { -+ bb13: { +- bb17: { ++ bb14: { StorageDead(_13); StorageDead(_12); - FakeRead(ForMatchGuard, _3); @@ -174,12 +184,12 @@ _5 = (_2.0: bool); StorageLive(_7); _7 = move (_2.2: std::string::String); -- goto -> bb7; -+ goto -> bb4; +- goto -> bb10; ++ goto -> bb7; } -- bb17: { -+ bb14: { +- bb18: { ++ bb15: { StorageDead(_13); StorageDead(_12); StorageDead(_8); @@ -188,8 +198,8 @@ + goto -> bb2; } -- bb18: { -+ bb15: { +- bb19: { ++ bb16: { StorageDead(_7); StorageDead(_5); StorageDead(_8); @@ -198,23 +208,13 @@ + goto -> bb19; } -- bb19: { -+ bb16: { +- bb20: { ++ bb17: { _0 = const 2_i32; - drop(_16) -> [return: bb21, unwind: bb25]; + drop(_16) -> [return: bb18, unwind: bb22]; } -- bb20: { -+ bb17: { - StorageLive(_15); - _15 = (_2.1: bool); - StorageLive(_16); - _16 = move (_2.2: std::string::String); -- goto -> bb19; -+ goto -> bb16; - } - - bb21: { + bb18: { StorageDead(_16); diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff index 4f29e5244d7c2..3c4a84bc24368 100644 --- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff +++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff @@ -33,17 +33,17 @@ bb0: { PlaceMention(_2); - switchInt((_2.0: bool)) -> [0: bb2, otherwise: bb1]; -+ switchInt((_2.0: bool)) -> [0: bb5, otherwise: bb1]; ++ switchInt((_2.0: bool)) -> [0: bb6, otherwise: bb1]; } bb1: { - switchInt((_2.1: bool)) -> [0: bb4, otherwise: bb3]; -+ switchInt((_2.1: bool)) -> [0: bb10, otherwise: bb2]; ++ switchInt((_2.1: bool)) -> [0: bb5, otherwise: bb2]; } bb2: { -- falseEdge -> [real: bb8, imaginary: bb1]; -+ switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17]; +- falseEdge -> [real: bb9, imaginary: bb1]; ++ switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb4]; } bb3: { @@ -51,11 +51,11 @@ - } - - bb4: { -- falseEdge -> [real: bb13, imaginary: bb3]; +- falseEdge -> [real: bb8, imaginary: bb3]; - } - - bb5: { -- falseEdge -> [real: bb20, imaginary: bb6]; +- falseEdge -> [real: bb7, imaginary: bb6]; - } - - bb6: { @@ -63,19 +63,37 @@ _15 = (_2.1: bool); StorageLive(_16); _16 = move (_2.2: std::string::String); -- goto -> bb19; -+ goto -> bb16; +- goto -> bb20; ++ goto -> bb17; } - bb7: { + bb4: { - _0 = const 1_i32; -- drop(_7) -> [return: bb18, unwind: bb25]; -+ drop(_7) -> [return: bb15, unwind: bb22]; + StorageLive(_15); + _15 = (_2.1: bool); + StorageLive(_16); + _16 = move (_2.2: std::string::String); +- goto -> bb20; ++ goto -> bb17; } - bb8: { + bb5: { + StorageLive(_6); + _6 = &(_2.0: bool); + StorageLive(_8); + _8 = &(_2.2: std::string::String); +- _3 = &fake shallow (_2.0: bool); +- _4 = &fake shallow (_2.1: bool); + StorageLive(_12); + StorageLive(_13); + _13 = _1; +- switchInt(move _13) -> [0: bb16, otherwise: bb15]; ++ switchInt(move _13) -> [0: bb13, otherwise: bb12]; + } + +- bb9: { ++ bb6: { StorageLive(_6); _6 = &(_2.1: bool); StorageLive(_8); @@ -85,12 +103,19 @@ StorageLive(_9); StorageLive(_10); _10 = _1; -- switchInt(move _10) -> [0: bb10, otherwise: bb9]; -+ switchInt(move _10) -> [0: bb7, otherwise: bb6]; +- switchInt(move _10) -> [0: bb12, otherwise: bb11]; ++ switchInt(move _10) -> [0: bb9, otherwise: bb8]; } -- bb9: { -+ bb6: { +- bb10: { ++ bb7: { + _0 = const 1_i32; +- drop(_7) -> [return: bb19, unwind: bb25]; ++ drop(_7) -> [return: bb16, unwind: bb22]; + } + +- bb11: { ++ bb8: { _0 = const 3_i32; StorageDead(_10); StorageDead(_9); @@ -98,15 +123,15 @@ + goto -> bb20; } -- bb10: { -+ bb7: { +- bb12: { ++ bb9: { _9 = (*_6); -- switchInt(move _9) -> [0: bb12, otherwise: bb11]; -+ switchInt(move _9) -> [0: bb9, otherwise: bb8]; +- switchInt(move _9) -> [0: bb14, otherwise: bb13]; ++ switchInt(move _9) -> [0: bb11, otherwise: bb10]; } -- bb11: { -+ bb8: { +- bb13: { ++ bb10: { StorageDead(_10); StorageDead(_9); - FakeRead(ForMatchGuard, _3); @@ -117,12 +142,12 @@ _5 = (_2.1: bool); StorageLive(_7); _7 = move (_2.2: std::string::String); -- goto -> bb7; -+ goto -> bb4; +- goto -> bb10; ++ goto -> bb7; } -- bb12: { -+ bb9: { +- bb14: { ++ bb11: { StorageDead(_10); StorageDead(_9); StorageDead(_8); @@ -131,23 +156,8 @@ + goto -> bb1; } -- bb13: { -+ bb10: { - StorageLive(_6); - _6 = &(_2.0: bool); - StorageLive(_8); - _8 = &(_2.2: std::string::String); -- _3 = &fake shallow (_2.0: bool); -- _4 = &fake shallow (_2.1: bool); - StorageLive(_12); - StorageLive(_13); - _13 = _1; -- switchInt(move _13) -> [0: bb15, otherwise: bb14]; -+ switchInt(move _13) -> [0: bb12, otherwise: bb11]; - } - -- bb14: { -+ bb11: { +- bb15: { ++ bb12: { _0 = const 3_i32; StorageDead(_13); StorageDead(_12); @@ -155,15 +165,15 @@ + goto -> bb20; } -- bb15: { -+ bb12: { +- bb16: { ++ bb13: { _12 = (*_6); -- switchInt(move _12) -> [0: bb17, otherwise: bb16]; -+ switchInt(move _12) -> [0: bb14, otherwise: bb13]; +- switchInt(move _12) -> [0: bb18, otherwise: bb17]; ++ switchInt(move _12) -> [0: bb15, otherwise: bb14]; } -- bb16: { -+ bb13: { +- bb17: { ++ bb14: { StorageDead(_13); StorageDead(_12); - FakeRead(ForMatchGuard, _3); @@ -174,12 +184,12 @@ _5 = (_2.0: bool); StorageLive(_7); _7 = move (_2.2: std::string::String); -- goto -> bb7; -+ goto -> bb4; +- goto -> bb10; ++ goto -> bb7; } -- bb17: { -+ bb14: { +- bb18: { ++ bb15: { StorageDead(_13); StorageDead(_12); StorageDead(_8); @@ -188,8 +198,8 @@ + goto -> bb2; } -- bb18: { -+ bb15: { +- bb19: { ++ bb16: { StorageDead(_7); StorageDead(_5); StorageDead(_8); @@ -198,23 +208,13 @@ + goto -> bb19; } -- bb19: { -+ bb16: { +- bb20: { ++ bb17: { _0 = const 2_i32; - drop(_16) -> [return: bb21, unwind: bb25]; + drop(_16) -> [return: bb18, unwind: bb22]; } -- bb20: { -+ bb17: { - StorageLive(_15); - _15 = (_2.1: bool); - StorageLive(_16); - _16 = move (_2.2: std::string::String); -- goto -> bb19; -+ goto -> bb16; - } - - bb21: { + bb18: { StorageDead(_16); diff --git a/tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff index 1f20349fdece4..dc50ae9547255 100644 --- a/tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff +++ b/tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff @@ -8,7 +8,7 @@ bb0: { _2 = discriminant(_1); - switchInt(move _2) -> [1: bb3, 2: bb4, 3: bb5, 340282366920938463463374607431768211455: bb2, otherwise: bb1]; + switchInt(move _2) -> [1: bb5, 2: bb4, 3: bb3, 340282366920938463463374607431768211455: bb2, otherwise: bb1]; } bb1: { @@ -21,7 +21,7 @@ } bb3: { - _0 = const 1_u128; + _0 = const 3_u128; goto -> bb6; } @@ -31,7 +31,7 @@ } bb5: { - _0 = const 3_u128; + _0 = const 1_u128; goto -> bb6; } diff --git a/tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff index 4b435310916a7..3514914b8ecb0 100644 --- a/tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff +++ b/tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff @@ -8,7 +8,7 @@ bb0: { _2 = discriminant(_1); - switchInt(move _2) -> [65535: bb3, 2: bb4, 65533: bb2, otherwise: bb1]; + switchInt(move _2) -> [65535: bb4, 2: bb3, 65533: bb2, otherwise: bb1]; } bb1: { @@ -21,12 +21,12 @@ } bb3: { - _0 = const -1_i8; + _0 = const 2_i8; goto -> bb5; } bb4: { - _0 = const 2_i8; + _0 = const -1_i8; goto -> bb5; } diff --git a/tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff index 8a390736add15..ff4255ec8cc97 100644 --- a/tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff +++ b/tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff @@ -8,7 +8,7 @@ bb0: { _2 = discriminant(_1); - switchInt(move _2) -> [255: bb3, 2: bb4, 253: bb2, otherwise: bb1]; + switchInt(move _2) -> [255: bb4, 2: bb3, 253: bb2, otherwise: bb1]; } bb1: { @@ -21,12 +21,12 @@ } bb3: { - _0 = const -1_i16; + _0 = const 2_i16; goto -> bb5; } bb4: { - _0 = const 2_i16; + _0 = const -1_i16; goto -> bb5; } diff --git a/tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff index b021779229454..022039ecee629 100644 --- a/tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff +++ b/tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff @@ -8,7 +8,7 @@ bb0: { _2 = discriminant(_1); - switchInt(move _2) -> [255: bb3, 2: bb4, 253: bb2, otherwise: bb1]; + switchInt(move _2) -> [255: bb4, 2: bb3, 253: bb2, otherwise: bb1]; } bb1: { @@ -21,12 +21,12 @@ } bb3: { - _0 = const -1_i16; + _0 = const 2_i16; goto -> bb5; } bb4: { - _0 = const 2_i16; + _0 = const -1_i16; goto -> bb5; } diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff index 8fa497fe89002..5690f17f24f65 100644 --- a/tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff +++ b/tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff @@ -6,7 +6,7 @@ let mut _0: i16; bb0: { - switchInt(_1) -> [1: bb2, 2: bb3, otherwise: bb1]; + switchInt(_1) -> [1: bb3, 2: bb2, otherwise: bb1]; } bb1: { @@ -15,12 +15,12 @@ } bb2: { - _0 = const 1_i16; + _0 = const 2_i16; goto -> bb4; } bb3: { - _0 = const 2_i16; + _0 = const 1_i16; goto -> bb4; } diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff index 043fdb197a3ac..dc9c1c2b97f1f 100644 --- a/tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff +++ b/tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff @@ -8,7 +8,7 @@ bb0: { _2 = discriminant(_1); - switchInt(move _2) -> [1: bb3, 2: bb4, 5: bb2, otherwise: bb1]; + switchInt(move _2) -> [1: bb4, 2: bb3, 5: bb2, otherwise: bb1]; } bb1: { @@ -21,12 +21,12 @@ } bb3: { - _0 = const 1_u16; + _0 = const 2_u16; goto -> bb5; } bb4: { - _0 = const 2_u16; + _0 = const 1_u16; goto -> bb5; } diff --git a/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir b/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir index e357e785e33ee..6c76a72b77577 100644 --- a/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir @@ -39,7 +39,7 @@ fn shortcut_second_or() -> () { } bb5: { - falseEdge -> [real: bb10, imaginary: bb6]; + falseEdge -> [real: bb12, imaginary: bb6]; } bb6: { @@ -47,18 +47,19 @@ fn shortcut_second_or() -> () { } bb7: { - falseEdge -> [real: bb12, imaginary: bb8]; + falseEdge -> [real: bb10, imaginary: bb8]; } bb8: { - falseEdge -> [real: bb13, imaginary: bb3]; + falseEdge -> [real: bb9, imaginary: bb3]; } bb9: { - _0 = const (); - StorageDead(_4); - StorageDead(_3); - goto -> bb14; + StorageLive(_3); + _3 = (_1.0: (i32, i32)); + StorageLive(_4); + _4 = (_1.1: i32); + goto -> bb13; } bb10: { @@ -66,7 +67,7 @@ fn shortcut_second_or() -> () { _3 = (_1.0: (i32, i32)); StorageLive(_4); _4 = (_1.1: i32); - goto -> bb9; + goto -> bb13; } bb11: { @@ -74,7 +75,7 @@ fn shortcut_second_or() -> () { _3 = (_1.0: (i32, i32)); StorageLive(_4); _4 = (_1.1: i32); - goto -> bb9; + goto -> bb13; } bb12: { @@ -82,15 +83,14 @@ fn shortcut_second_or() -> () { _3 = (_1.0: (i32, i32)); StorageLive(_4); _4 = (_1.1: i32); - goto -> bb9; + goto -> bb13; } bb13: { - StorageLive(_3); - _3 = (_1.0: (i32, i32)); - StorageLive(_4); - _4 = (_1.1: i32); - goto -> bb9; + _0 = const (); + StorageDead(_4); + StorageDead(_3); + goto -> bb14; } bb14: { diff --git a/tests/mir-opt/or_pattern.single_switchint.SimplifyCfg-initial.after.mir b/tests/mir-opt/or_pattern.single_switchint.SimplifyCfg-initial.after.mir index eafe95b4a11ea..8b0ef7b29d7be 100644 --- a/tests/mir-opt/or_pattern.single_switchint.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/or_pattern.single_switchint.SimplifyCfg-initial.after.mir @@ -22,7 +22,7 @@ fn single_switchint() -> () { } bb3: { - falseEdge -> [real: bb9, imaginary: bb4]; + falseEdge -> [real: bb12, imaginary: bb4]; } bb4: { @@ -30,11 +30,11 @@ fn single_switchint() -> () { } bb5: { - falseEdge -> [real: bb10, imaginary: bb6]; + falseEdge -> [real: bb11, imaginary: bb6]; } bb6: { - falseEdge -> [real: bb11, imaginary: bb1]; + falseEdge -> [real: bb10, imaginary: bb1]; } bb7: { @@ -43,26 +43,26 @@ fn single_switchint() -> () { } bb8: { - falseEdge -> [real: bb12, imaginary: bb7]; + falseEdge -> [real: bb9, imaginary: bb7]; } bb9: { - _1 = const 1_i32; + _1 = const 4_i32; goto -> bb13; } bb10: { - _1 = const 2_i32; + _1 = const 3_i32; goto -> bb13; } bb11: { - _1 = const 3_i32; + _1 = const 2_i32; goto -> bb13; } bb12: { - _1 = const 4_i32; + _1 = const 1_i32; goto -> bb13; } diff --git a/tests/mir-opt/single_use_consts.match_const.SingleUseConsts.panic-abort.diff b/tests/mir-opt/single_use_consts.match_const.SingleUseConsts.panic-abort.diff index 8d87438a47aec..998b89919d1bd 100644 --- a/tests/mir-opt/single_use_consts.match_const.SingleUseConsts.panic-abort.diff +++ b/tests/mir-opt/single_use_consts.match_const.SingleUseConsts.panic-abort.diff @@ -8,9 +8,9 @@ bb0: { StorageLive(_1); - _1 = const ::ASSOC_INT; -- switchInt(_1) -> [7: bb2, 42: bb3, otherwise: bb1]; +- switchInt(_1) -> [7: bb3, 42: bb2, otherwise: bb1]; + nop; -+ switchInt(const ::ASSOC_INT) -> [7: bb2, 42: bb3, otherwise: bb1]; ++ switchInt(const ::ASSOC_INT) -> [7: bb3, 42: bb2, otherwise: bb1]; } bb1: { @@ -19,12 +19,12 @@ } bb2: { - _0 = const "hello"; + _0 = const "towel"; goto -> bb4; } bb3: { - _0 = const "towel"; + _0 = const "hello"; goto -> bb4; } diff --git a/tests/mir-opt/single_use_consts.match_const.SingleUseConsts.panic-unwind.diff b/tests/mir-opt/single_use_consts.match_const.SingleUseConsts.panic-unwind.diff index 8d87438a47aec..998b89919d1bd 100644 --- a/tests/mir-opt/single_use_consts.match_const.SingleUseConsts.panic-unwind.diff +++ b/tests/mir-opt/single_use_consts.match_const.SingleUseConsts.panic-unwind.diff @@ -8,9 +8,9 @@ bb0: { StorageLive(_1); - _1 = const ::ASSOC_INT; -- switchInt(_1) -> [7: bb2, 42: bb3, otherwise: bb1]; +- switchInt(_1) -> [7: bb3, 42: bb2, otherwise: bb1]; + nop; -+ switchInt(const ::ASSOC_INT) -> [7: bb2, 42: bb3, otherwise: bb1]; ++ switchInt(const ::ASSOC_INT) -> [7: bb3, 42: bb2, otherwise: bb1]; } bb1: { @@ -19,12 +19,12 @@ } bb2: { - _0 = const "hello"; + _0 = const "towel"; goto -> bb4; } bb3: { - _0 = const "towel"; + _0 = const "hello"; goto -> bb4; } diff --git a/tests/mir-opt/single_use_consts.match_const_debug.SingleUseConsts.panic-abort.diff b/tests/mir-opt/single_use_consts.match_const_debug.SingleUseConsts.panic-abort.diff index f192f3feb96e5..30f66ef6b8237 100644 --- a/tests/mir-opt/single_use_consts.match_const_debug.SingleUseConsts.panic-abort.diff +++ b/tests/mir-opt/single_use_consts.match_const_debug.SingleUseConsts.panic-abort.diff @@ -20,8 +20,8 @@ bb1: { StorageDead(_2); -- switchInt(_1) -> [7: bb3, 42: bb4, otherwise: bb2]; -+ switchInt(const ::ASSOC_INT) -> [7: bb3, 42: bb4, otherwise: bb2]; +- switchInt(_1) -> [7: bb4, 42: bb3, otherwise: bb2]; ++ switchInt(const ::ASSOC_INT) -> [7: bb4, 42: bb3, otherwise: bb2]; } bb2: { @@ -30,12 +30,12 @@ } bb3: { - _0 = const "hello"; + _0 = const "towel"; goto -> bb5; } bb4: { - _0 = const "towel"; + _0 = const "hello"; goto -> bb5; } diff --git a/tests/mir-opt/single_use_consts.match_const_debug.SingleUseConsts.panic-unwind.diff b/tests/mir-opt/single_use_consts.match_const_debug.SingleUseConsts.panic-unwind.diff index 261faf415f3bc..ed12ad4b93e89 100644 --- a/tests/mir-opt/single_use_consts.match_const_debug.SingleUseConsts.panic-unwind.diff +++ b/tests/mir-opt/single_use_consts.match_const_debug.SingleUseConsts.panic-unwind.diff @@ -20,8 +20,8 @@ bb1: { StorageDead(_2); -- switchInt(_1) -> [7: bb3, 42: bb4, otherwise: bb2]; -+ switchInt(const ::ASSOC_INT) -> [7: bb3, 42: bb4, otherwise: bb2]; +- switchInt(_1) -> [7: bb4, 42: bb3, otherwise: bb2]; ++ switchInt(const ::ASSOC_INT) -> [7: bb4, 42: bb3, otherwise: bb2]; } bb2: { @@ -30,12 +30,12 @@ } bb3: { - _0 = const "hello"; + _0 = const "towel"; goto -> bb5; } bb4: { - _0 = const "towel"; + _0 = const "hello"; goto -> bb5; } diff --git a/tests/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UnreachableEnumBranching.diff b/tests/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UnreachableEnumBranching.diff index 098b620dfaab7..c0ea9fae7df5b 100644 --- a/tests/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UnreachableEnumBranching.diff +++ b/tests/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UnreachableEnumBranching.diff @@ -8,8 +8,8 @@ bb0: { _2 = discriminant(_1); -- switchInt(move _2) -> [1: bb3, 2: bb2, otherwise: bb1]; -+ switchInt(move _2) -> [1: bb3, 2: bb2, otherwise: bb5]; +- switchInt(move _2) -> [1: bb2, 2: bb3, otherwise: bb1]; ++ switchInt(move _2) -> [1: bb2, 2: bb3, otherwise: bb5]; } bb1: { @@ -18,12 +18,12 @@ } bb2: { - _0 = const 1_u32; + _0 = const 2_u32; goto -> bb4; } bb3: { - _0 = const 2_u32; + _0 = const 1_u32; goto -> bb4; } diff --git a/tests/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UnreachableEnumBranching.diff b/tests/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UnreachableEnumBranching.diff index 995e32b033f24..2082e8046ad0b 100644 --- a/tests/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UnreachableEnumBranching.diff +++ b/tests/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UnreachableEnumBranching.diff @@ -8,8 +8,8 @@ bb0: { _2 = discriminant(_1); -- switchInt(move _2) -> [0: bb2, 1: bb3, otherwise: bb1]; -+ switchInt(move _2) -> [0: bb5, 1: bb3, 2: bb1, otherwise: bb5]; +- switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1]; ++ switchInt(move _2) -> [0: bb5, 1: bb2, 2: bb1, otherwise: bb5]; } bb1: { @@ -18,12 +18,12 @@ } bb2: { - _0 = const 1_u32; + _0 = const 2_u32; goto -> bb4; } bb3: { - _0 = const 2_u32; + _0 = const 1_u32; goto -> bb4; } diff --git a/tests/mir-opt/unreachable_enum_branching.byref.UnreachableEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.byref.UnreachableEnumBranching.panic-abort.diff index e5dab5d52a6b7..ed54a38f70bdb 100644 --- a/tests/mir-opt/unreachable_enum_branching.byref.UnreachableEnumBranching.panic-abort.diff +++ b/tests/mir-opt/unreachable_enum_branching.byref.UnreachableEnumBranching.panic-abort.diff @@ -30,8 +30,8 @@ StorageLive(_4); _4 = &(_1.1: Test3); _5 = discriminant((*_4)); -- switchInt(move _5) -> [0: bb3, 1: bb4, 2: bb5, 3: bb2, otherwise: bb1]; -+ switchInt(move _5) -> [0: bb1, 1: bb1, 2: bb5, 3: bb2, otherwise: bb1]; +- switchInt(move _5) -> [0: bb5, 1: bb4, 2: bb3, 3: bb2, otherwise: bb1]; ++ switchInt(move _5) -> [0: bb1, 1: bb1, 2: bb3, 3: bb2, otherwise: bb1]; } bb1: { @@ -47,7 +47,10 @@ } bb3: { - _3 = const "A(Empty)"; + StorageLive(_7); + _7 = const "C"; + _3 = &(*_7); + StorageDead(_7); goto -> bb6; } @@ -60,10 +63,7 @@ } bb5: { - StorageLive(_7); - _7 = const "C"; - _3 = &(*_7); - StorageDead(_7); + _3 = const "A(Empty)"; goto -> bb6; } @@ -72,8 +72,8 @@ StorageDead(_3); StorageLive(_9); _10 = discriminant((_1.1: Test3)); -- switchInt(move _10) -> [0: bb8, 1: bb9, 2: bb10, 3: bb7, otherwise: bb1]; -+ switchInt(move _10) -> [0: bb1, 1: bb1, 2: bb10, 3: bb7, otherwise: bb1]; +- switchInt(move _10) -> [0: bb10, 1: bb9, 2: bb8, 3: bb7, otherwise: bb1]; ++ switchInt(move _10) -> [0: bb1, 1: bb1, 2: bb8, 3: bb7, otherwise: bb1]; } bb7: { @@ -85,7 +85,10 @@ } bb8: { - _9 = const "A(Empty)"; + StorageLive(_12); + _12 = const "C"; + _9 = &(*_12); + StorageDead(_12); goto -> bb11; } @@ -98,10 +101,7 @@ } bb10: { - StorageLive(_12); - _12 = const "C"; - _9 = &(*_12); - StorageDead(_12); + _9 = const "A(Empty)"; goto -> bb11; } diff --git a/tests/mir-opt/unreachable_enum_branching.byref.UnreachableEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.byref.UnreachableEnumBranching.panic-unwind.diff index e5dab5d52a6b7..ed54a38f70bdb 100644 --- a/tests/mir-opt/unreachable_enum_branching.byref.UnreachableEnumBranching.panic-unwind.diff +++ b/tests/mir-opt/unreachable_enum_branching.byref.UnreachableEnumBranching.panic-unwind.diff @@ -30,8 +30,8 @@ StorageLive(_4); _4 = &(_1.1: Test3); _5 = discriminant((*_4)); -- switchInt(move _5) -> [0: bb3, 1: bb4, 2: bb5, 3: bb2, otherwise: bb1]; -+ switchInt(move _5) -> [0: bb1, 1: bb1, 2: bb5, 3: bb2, otherwise: bb1]; +- switchInt(move _5) -> [0: bb5, 1: bb4, 2: bb3, 3: bb2, otherwise: bb1]; ++ switchInt(move _5) -> [0: bb1, 1: bb1, 2: bb3, 3: bb2, otherwise: bb1]; } bb1: { @@ -47,7 +47,10 @@ } bb3: { - _3 = const "A(Empty)"; + StorageLive(_7); + _7 = const "C"; + _3 = &(*_7); + StorageDead(_7); goto -> bb6; } @@ -60,10 +63,7 @@ } bb5: { - StorageLive(_7); - _7 = const "C"; - _3 = &(*_7); - StorageDead(_7); + _3 = const "A(Empty)"; goto -> bb6; } @@ -72,8 +72,8 @@ StorageDead(_3); StorageLive(_9); _10 = discriminant((_1.1: Test3)); -- switchInt(move _10) -> [0: bb8, 1: bb9, 2: bb10, 3: bb7, otherwise: bb1]; -+ switchInt(move _10) -> [0: bb1, 1: bb1, 2: bb10, 3: bb7, otherwise: bb1]; +- switchInt(move _10) -> [0: bb10, 1: bb9, 2: bb8, 3: bb7, otherwise: bb1]; ++ switchInt(move _10) -> [0: bb1, 1: bb1, 2: bb8, 3: bb7, otherwise: bb1]; } bb7: { @@ -85,7 +85,10 @@ } bb8: { - _9 = const "A(Empty)"; + StorageLive(_12); + _12 = const "C"; + _9 = &(*_12); + StorageDead(_12); goto -> bb11; } @@ -98,10 +101,7 @@ } bb10: { - StorageLive(_12); - _12 = const "C"; - _9 = &(*_12); - StorageDead(_12); + _9 = const "A(Empty)"; goto -> bb11; } diff --git a/tests/mir-opt/unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.panic-abort.diff index 02b9f02f4c0ec..be934ac688bb5 100644 --- a/tests/mir-opt/unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.panic-abort.diff +++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.panic-abort.diff @@ -14,7 +14,7 @@ StorageLive(_2); _2 = Test1::C; _3 = discriminant(_2); -- switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1]; +- switchInt(move _3) -> [0: bb3, 1: bb2, otherwise: bb1]; + switchInt(move _3) -> [0: bb5, 1: bb5, 2: bb1, otherwise: bb5]; } @@ -27,11 +27,6 @@ } bb2: { - _1 = const "A(Empty)"; - goto -> bb4; - } - - bb3: { StorageLive(_4); _4 = const "B(Empty)"; _1 = &(*_4); @@ -39,6 +34,11 @@ goto -> bb4; } + bb3: { + _1 = const "A(Empty)"; + goto -> bb4; + } + bb4: { StorageDead(_2); StorageDead(_1); diff --git a/tests/mir-opt/unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.panic-unwind.diff index 02b9f02f4c0ec..be934ac688bb5 100644 --- a/tests/mir-opt/unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.panic-unwind.diff +++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t1.UnreachableEnumBranching.panic-unwind.diff @@ -14,7 +14,7 @@ StorageLive(_2); _2 = Test1::C; _3 = discriminant(_2); -- switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1]; +- switchInt(move _3) -> [0: bb3, 1: bb2, otherwise: bb1]; + switchInt(move _3) -> [0: bb5, 1: bb5, 2: bb1, otherwise: bb5]; } @@ -27,11 +27,6 @@ } bb2: { - _1 = const "A(Empty)"; - goto -> bb4; - } - - bb3: { StorageLive(_4); _4 = const "B(Empty)"; _1 = &(*_4); @@ -39,6 +34,11 @@ goto -> bb4; } + bb3: { + _1 = const "A(Empty)"; + goto -> bb4; + } + bb4: { StorageDead(_2); StorageDead(_1); diff --git a/tests/mir-opt/unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.panic-abort.diff index d3376442376d3..120061841a02f 100644 --- a/tests/mir-opt/unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.panic-abort.diff +++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.panic-abort.diff @@ -14,7 +14,7 @@ StorageLive(_2); _2 = Test3::C; _3 = discriminant(_2); -- switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1]; +- switchInt(move _3) -> [0: bb3, 1: bb2, otherwise: bb1]; + switchInt(move _3) -> [0: bb5, 1: bb5, otherwise: bb1]; } @@ -27,11 +27,6 @@ } bb2: { - _1 = const "A(Empty)"; - goto -> bb4; - } - - bb3: { StorageLive(_4); _4 = const "B(Empty)"; _1 = &(*_4); @@ -39,6 +34,11 @@ goto -> bb4; } + bb3: { + _1 = const "A(Empty)"; + goto -> bb4; + } + bb4: { StorageDead(_2); StorageDead(_1); diff --git a/tests/mir-opt/unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.panic-unwind.diff index d3376442376d3..120061841a02f 100644 --- a/tests/mir-opt/unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.panic-unwind.diff +++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t3.UnreachableEnumBranching.panic-unwind.diff @@ -14,7 +14,7 @@ StorageLive(_2); _2 = Test3::C; _3 = discriminant(_2); -- switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1]; +- switchInt(move _3) -> [0: bb3, 1: bb2, otherwise: bb1]; + switchInt(move _3) -> [0: bb5, 1: bb5, otherwise: bb1]; } @@ -27,11 +27,6 @@ } bb2: { - _1 = const "A(Empty)"; - goto -> bb4; - } - - bb3: { StorageLive(_4); _4 = const "B(Empty)"; _1 = &(*_4); @@ -39,6 +34,11 @@ goto -> bb4; } + bb3: { + _1 = const "A(Empty)"; + goto -> bb4; + } + bb4: { StorageDead(_2); StorageDead(_1); diff --git a/tests/mir-opt/unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.panic-abort.diff index 8f0d5b7cd99c4..b86814d611938 100644 --- a/tests/mir-opt/unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.panic-abort.diff +++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.panic-abort.diff @@ -14,7 +14,7 @@ StorageLive(_2); _2 = Test4::C; _3 = discriminant(_2); - switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1]; + switchInt(move _3) -> [0: bb3, 1: bb2, otherwise: bb1]; } bb1: { @@ -26,11 +26,6 @@ } bb2: { - _1 = const "A(i32)"; - goto -> bb4; - } - - bb3: { StorageLive(_4); _4 = const "B(i32)"; _1 = &(*_4); @@ -38,6 +33,11 @@ goto -> bb4; } + bb3: { + _1 = const "A(i32)"; + goto -> bb4; + } + bb4: { StorageDead(_2); StorageDead(_1); diff --git a/tests/mir-opt/unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.panic-unwind.diff index 8f0d5b7cd99c4..b86814d611938 100644 --- a/tests/mir-opt/unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.panic-unwind.diff +++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t4.UnreachableEnumBranching.panic-unwind.diff @@ -14,7 +14,7 @@ StorageLive(_2); _2 = Test4::C; _3 = discriminant(_2); - switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1]; + switchInt(move _3) -> [0: bb3, 1: bb2, otherwise: bb1]; } bb1: { @@ -26,11 +26,6 @@ } bb2: { - _1 = const "A(i32)"; - goto -> bb4; - } - - bb3: { StorageLive(_4); _4 = const "B(i32)"; _1 = &(*_4); @@ -38,6 +33,11 @@ goto -> bb4; } + bb3: { + _1 = const "A(i32)"; + goto -> bb4; + } + bb4: { StorageDead(_2); StorageDead(_1); diff --git a/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.panic-abort.diff index b1ecd00858290..424ac6ba651c3 100644 --- a/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.panic-abort.diff +++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.panic-abort.diff @@ -15,8 +15,8 @@ StorageLive(_2); _2 = Test4::C; _3 = discriminant(_2); -- switchInt(move _3) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb1]; -+ switchInt(move _3) -> [0: bb2, 1: bb3, 2: bb4, 3: bb1, otherwise: bb6]; +- switchInt(move _3) -> [0: bb4, 1: bb3, 2: bb2, otherwise: bb1]; ++ switchInt(move _3) -> [0: bb4, 1: bb3, 2: bb2, 3: bb1, otherwise: bb6]; } bb1: { @@ -28,7 +28,10 @@ } bb2: { - _1 = const "A(i32)"; + StorageLive(_5); + _5 = const "C"; + _1 = &(*_5); + StorageDead(_5); goto -> bb5; } @@ -41,10 +44,7 @@ } bb4: { - StorageLive(_5); - _5 = const "C"; - _1 = &(*_5); - StorageDead(_5); + _1 = const "A(i32)"; goto -> bb5; } diff --git a/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.panic-unwind.diff index b1ecd00858290..424ac6ba651c3 100644 --- a/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.panic-unwind.diff +++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default.UnreachableEnumBranching.panic-unwind.diff @@ -15,8 +15,8 @@ StorageLive(_2); _2 = Test4::C; _3 = discriminant(_2); -- switchInt(move _3) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb1]; -+ switchInt(move _3) -> [0: bb2, 1: bb3, 2: bb4, 3: bb1, otherwise: bb6]; +- switchInt(move _3) -> [0: bb4, 1: bb3, 2: bb2, otherwise: bb1]; ++ switchInt(move _3) -> [0: bb4, 1: bb3, 2: bb2, 3: bb1, otherwise: bb6]; } bb1: { @@ -28,7 +28,10 @@ } bb2: { - _1 = const "A(i32)"; + StorageLive(_5); + _5 = const "C"; + _1 = &(*_5); + StorageDead(_5); goto -> bb5; } @@ -41,10 +44,7 @@ } bb4: { - StorageLive(_5); - _5 = const "C"; - _1 = &(*_5); - StorageDead(_5); + _1 = const "A(i32)"; goto -> bb5; } diff --git a/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.panic-abort.diff index 28c6d4fb67599..4cd6d3f56833e 100644 --- a/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.panic-abort.diff +++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.panic-abort.diff @@ -16,8 +16,8 @@ StorageLive(_2); _2 = Test4::C; _3 = discriminant(_2); -- switchInt(move _3) -> [0: bb2, 1: bb5, 2: bb6, otherwise: bb1]; -+ switchInt(move _3) -> [0: bb2, 1: bb5, 2: bb6, 3: bb1, otherwise: bb8]; +- switchInt(move _3) -> [0: bb2, 1: bb4, 2: bb3, otherwise: bb1]; ++ switchInt(move _3) -> [0: bb2, 1: bb4, 2: bb3, 3: bb1, otherwise: bb8]; } bb1: { @@ -29,23 +29,18 @@ } bb2: { - switchInt(((_2 as A).0: i32)) -> [1: bb3, 2: bb4, otherwise: bb1]; + switchInt(((_2 as A).0: i32)) -> [1: bb6, 2: bb5, otherwise: bb1]; } bb3: { - _1 = const "A(1)"; + StorageLive(_6); + _6 = const "C"; + _1 = &(*_6); + StorageDead(_6); goto -> bb7; } bb4: { - StorageLive(_4); - _4 = const "A(2)"; - _1 = &(*_4); - StorageDead(_4); - goto -> bb7; - } - - bb5: { StorageLive(_5); _5 = const "B(i32)"; _1 = &(*_5); @@ -53,11 +48,16 @@ goto -> bb7; } + bb5: { + StorageLive(_4); + _4 = const "A(2)"; + _1 = &(*_4); + StorageDead(_4); + goto -> bb7; + } + bb6: { - StorageLive(_6); - _6 = const "C"; - _1 = &(*_6); - StorageDead(_6); + _1 = const "A(1)"; goto -> bb7; } diff --git a/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.panic-unwind.diff index 28c6d4fb67599..4cd6d3f56833e 100644 --- a/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.panic-unwind.diff +++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t4_unreachable_default_2.UnreachableEnumBranching.panic-unwind.diff @@ -16,8 +16,8 @@ StorageLive(_2); _2 = Test4::C; _3 = discriminant(_2); -- switchInt(move _3) -> [0: bb2, 1: bb5, 2: bb6, otherwise: bb1]; -+ switchInt(move _3) -> [0: bb2, 1: bb5, 2: bb6, 3: bb1, otherwise: bb8]; +- switchInt(move _3) -> [0: bb2, 1: bb4, 2: bb3, otherwise: bb1]; ++ switchInt(move _3) -> [0: bb2, 1: bb4, 2: bb3, 3: bb1, otherwise: bb8]; } bb1: { @@ -29,23 +29,18 @@ } bb2: { - switchInt(((_2 as A).0: i32)) -> [1: bb3, 2: bb4, otherwise: bb1]; + switchInt(((_2 as A).0: i32)) -> [1: bb6, 2: bb5, otherwise: bb1]; } bb3: { - _1 = const "A(1)"; + StorageLive(_6); + _6 = const "C"; + _1 = &(*_6); + StorageDead(_6); goto -> bb7; } bb4: { - StorageLive(_4); - _4 = const "A(2)"; - _1 = &(*_4); - StorageDead(_4); - goto -> bb7; - } - - bb5: { StorageLive(_5); _5 = const "B(i32)"; _1 = &(*_5); @@ -53,11 +48,16 @@ goto -> bb7; } + bb5: { + StorageLive(_4); + _4 = const "A(2)"; + _1 = &(*_4); + StorageDead(_4); + goto -> bb7; + } + bb6: { - StorageLive(_6); - _6 = const "C"; - _1 = &(*_6); - StorageDead(_6); + _1 = const "A(1)"; goto -> bb7; } diff --git a/tests/mir-opt/unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.panic-abort.diff index f36a7efd80d45..2de1f77eeec9e 100644 --- a/tests/mir-opt/unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.panic-abort.diff +++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.panic-abort.diff @@ -15,8 +15,8 @@ StorageLive(_2); _2 = Test5::::C; _3 = discriminant(_2); -- switchInt(move _3) -> [255: bb2, 0: bb3, 5: bb4, otherwise: bb1]; -+ switchInt(move _3) -> [255: bb2, 0: bb3, 5: bb4, 3: bb1, otherwise: bb7]; +- switchInt(move _3) -> [255: bb4, 0: bb3, 5: bb2, otherwise: bb1]; ++ switchInt(move _3) -> [255: bb4, 0: bb3, 5: bb2, 3: bb1, otherwise: bb7]; } bb1: { @@ -28,7 +28,10 @@ } bb2: { - _1 = const "A(T)"; + StorageLive(_5); + _5 = const "C"; + _1 = &(*_5); + StorageDead(_5); goto -> bb5; } @@ -41,10 +44,7 @@ } bb4: { - StorageLive(_5); - _5 = const "C"; - _1 = &(*_5); - StorageDead(_5); + _1 = const "A(T)"; goto -> bb5; } diff --git a/tests/mir-opt/unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.panic-unwind.diff index 20e31c24c84b5..5afb78c58a3c1 100644 --- a/tests/mir-opt/unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.panic-unwind.diff +++ b/tests/mir-opt/unreachable_enum_branching.otherwise_t5_unreachable_default.UnreachableEnumBranching.panic-unwind.diff @@ -15,8 +15,8 @@ StorageLive(_2); _2 = Test5::::C; _3 = discriminant(_2); -- switchInt(move _3) -> [255: bb2, 0: bb3, 5: bb4, otherwise: bb1]; -+ switchInt(move _3) -> [255: bb2, 0: bb3, 5: bb4, 3: bb1, otherwise: bb8]; +- switchInt(move _3) -> [255: bb4, 0: bb3, 5: bb2, otherwise: bb1]; ++ switchInt(move _3) -> [255: bb4, 0: bb3, 5: bb2, 3: bb1, otherwise: bb8]; } bb1: { @@ -28,7 +28,10 @@ } bb2: { - _1 = const "A(T)"; + StorageLive(_5); + _5 = const "C"; + _1 = &(*_5); + StorageDead(_5); goto -> bb5; } @@ -41,10 +44,7 @@ } bb4: { - StorageLive(_5); - _5 = const "C"; - _1 = &(*_5); - StorageDead(_5); + _1 = const "A(T)"; goto -> bb5; } diff --git a/tests/mir-opt/unreachable_enum_branching.rs b/tests/mir-opt/unreachable_enum_branching.rs index 6005dc546dc8b..fac14042b1075 100644 --- a/tests/mir-opt/unreachable_enum_branching.rs +++ b/tests/mir-opt/unreachable_enum_branching.rs @@ -120,7 +120,7 @@ fn otherwise_t3() { fn otherwise_t4_unreachable_default() { // CHECK-LABEL: fn otherwise_t4_unreachable_default( // CHECK: [[discr:_.*]] = discriminant( - // CHECK: switchInt(move [[discr]]) -> [0: bb2, 1: bb3, 2: bb4, 3: bb1, otherwise: [[unreachable:bb.*]]]; + // CHECK: switchInt(move [[discr]]) -> [0: {{bb.*}}, 1: {{bb.*}}, 2: {{bb.*}}, 3: {{bb.*}}, otherwise: [[unreachable:bb.*]]]; // CHECK: [[unreachable]]: { // CHECK-NEXT: unreachable; match Test4::C { @@ -135,7 +135,7 @@ fn otherwise_t4_unreachable_default() { fn otherwise_t4_unreachable_default_2() { // CHECK-LABEL: fn otherwise_t4_unreachable_default_2( // CHECK: [[discr:_.*]] = discriminant( - // CHECK: switchInt(move [[discr]]) -> [0: bb2, 1: bb5, 2: bb6, 3: bb1, otherwise: [[unreachable:bb.*]]]; + // CHECK: switchInt(move [[discr]]) -> [0: {{bb.*}}, 1: {{bb.*}}, 2: {{bb.*}}, 3: {{bb.*}}, otherwise: [[unreachable:bb.*]]]; // CHECK: [[unreachable]]: { // CHECK-NEXT: unreachable; match Test4::C { @@ -151,7 +151,7 @@ fn otherwise_t4_unreachable_default_2() { fn otherwise_t4() { // CHECK-LABEL: fn otherwise_t4( // CHECK: [[discr:_.*]] = discriminant( - // CHECK: switchInt(move [[discr]]) -> [0: bb2, 1: bb3, otherwise: [[unreachable:bb.*]]]; + // CHECK: switchInt(move [[discr]]) -> [0: {{bb.*}}, 1: {{bb.*}}, otherwise: [[unreachable:bb.*]]]; // CHECK: [[unreachable]]: { // CHECK-NOT: unreachable; // CHECK: } @@ -166,7 +166,7 @@ fn otherwise_t4() { fn otherwise_t5_unreachable_default() { // CHECK-LABEL: fn otherwise_t5_unreachable_default( // CHECK: [[discr:_.*]] = discriminant( - // CHECK: switchInt(move [[discr]]) -> [255: bb2, 0: bb3, 5: bb4, 3: bb1, otherwise: [[unreachable:bb.*]]]; + // CHECK: switchInt(move [[discr]]) -> [255: {{bb.*}}, 0: {{bb.*}}, 5: {{bb.*}}, 3: {{bb.*}}, otherwise: [[unreachable:bb.*]]]; // CHECK: [[unreachable]]: { // CHECK-NEXT: unreachable; match Test5::::C { @@ -183,7 +183,7 @@ fn byref() { let plop = Plop { xx: 51, test3: Test3::C }; // CHECK: [[ref_discr:_.*]] = discriminant((* - // CHECK: switchInt(move [[ref_discr]]) -> [0: [[unreachable:bb.*]], 1: [[unreachable]], 2: bb5, 3: bb2, otherwise: [[unreachable]]]; + // CHECK: switchInt(move [[ref_discr]]) -> [0: [[unreachable:bb.*]], 1: [[unreachable]], 2: {{bb.*}}, 3: {{bb.*}}, otherwise: [[unreachable]]]; match &plop.test3 { Test3::A(_) => "A(Empty)", Test3::B(_) => "B(Empty)", @@ -195,7 +195,7 @@ fn byref() { // CHECK-NEXT: unreachable; // CHECK: [[discr:_.*]] = discriminant( - // CHECK: switchInt(move [[discr]]) -> [0: [[unreachable]], 1: [[unreachable]], 2: bb10, 3: bb7, otherwise: [[unreachable]]]; + // CHECK: switchInt(move [[discr]]) -> [0: [[unreachable]], 1: [[unreachable]], 2: {{bb.*}}, 3: {{bb.*}}, otherwise: [[unreachable]]]; match plop.test3 { Test3::A(_) => "A(Empty)", Test3::B(_) => "B(Empty)", diff --git a/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-abort.diff index a85fc0da99232..8aef991493672 100644 --- a/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-abort.diff +++ b/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-abort.diff @@ -14,7 +14,7 @@ StorageLive(_2); _2 = Test1::C; _3 = discriminant(_2); -- switchInt(move _3) -> [0: bb3, 1: bb4, 2: bb2, otherwise: bb1]; +- switchInt(move _3) -> [0: bb4, 1: bb3, 2: bb2, otherwise: bb1]; + switchInt(move _3) -> [0: bb1, 1: bb1, 2: bb2, otherwise: bb1]; } @@ -31,11 +31,6 @@ } bb3: { - _1 = const "A(Empty)"; - goto -> bb5; - } - - bb4: { StorageLive(_4); _4 = const "B(Empty)"; _1 = &(*_4); @@ -43,6 +38,11 @@ goto -> bb5; } + bb4: { + _1 = const "A(Empty)"; + goto -> bb5; + } + bb5: { StorageDead(_2); StorageDead(_1); diff --git a/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-unwind.diff index a85fc0da99232..8aef991493672 100644 --- a/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-unwind.diff +++ b/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-unwind.diff @@ -14,7 +14,7 @@ StorageLive(_2); _2 = Test1::C; _3 = discriminant(_2); -- switchInt(move _3) -> [0: bb3, 1: bb4, 2: bb2, otherwise: bb1]; +- switchInt(move _3) -> [0: bb4, 1: bb3, 2: bb2, otherwise: bb1]; + switchInt(move _3) -> [0: bb1, 1: bb1, 2: bb2, otherwise: bb1]; } @@ -31,11 +31,6 @@ } bb3: { - _1 = const "A(Empty)"; - goto -> bb5; - } - - bb4: { StorageLive(_4); _4 = const "B(Empty)"; _1 = &(*_4); @@ -43,6 +38,11 @@ goto -> bb5; } + bb4: { + _1 = const "A(Empty)"; + goto -> bb5; + } + bb5: { StorageDead(_2); StorageDead(_1); diff --git a/tests/ui/stable-mir-print/basic_function.stdout b/tests/ui/stable-mir-print/basic_function.stdout index 3926c1048f54a..76288c2aa49f2 100644 --- a/tests/ui/stable-mir-print/basic_function.stdout +++ b/tests/ui/stable-mir-print/basic_function.stdout @@ -44,14 +44,14 @@ fn demux(_1: u8) -> u8 { let mut _0: u8; debug input => _1; bb0: { - switchInt(_1) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb1]; + switchInt(_1) -> [0: bb4, 1: bb3, 2: bb2, otherwise: bb1]; } bb1: { _0 = 0_u8; goto -> bb5; } bb2: { - _0 = 10_u8; + _0 = 8_u8; goto -> bb5; } bb3: { @@ -59,7 +59,7 @@ fn demux(_1: u8) -> u8 { goto -> bb5; } bb4: { - _0 = 8_u8; + _0 = 10_u8; goto -> bb5; } bb5: { From cbdacec188b1d2ef18a074784edbe58be826be58 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 23 Jun 2024 17:08:10 +0200 Subject: [PATCH 04/18] Abstract out the candidate manipulation not in the main algorithm --- .../rustc_mir_build/src/build/matches/mod.rs | 317 +++++++++++------- .../rustc_mir_build/src/build/matches/util.rs | 2 +- 2 files changed, 192 insertions(+), 127 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 0a55013ae20cd..78efa53253a3f 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -366,28 +366,37 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let scrutinee_place = unpack!(block = self.lower_scrutinee(block, scrutinee_id, scrutinee_span)); - let mut arm_candidates = self.create_match_candidates(&scrutinee_place, arms); - - let match_has_guard = arm_candidates.iter().any(|(_, candidate)| candidate.has_guard); - let mut candidates = - arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::>(); - - let match_start_span = span.shrink_to_lo().to(scrutinee_span); + let arms = arms.iter().map(|arm| &self.thir[*arm]); + // Assemble the initial list of candidates. These top-level candidates are 1:1 with the + // original match arms, but other parts of match lowering also introduce subcandidates (for + // sub-or-patterns). So inside the algorithm, the candidates list may not correspond to + // match arms directly. + let candidates: Vec<_> = arms + .clone() + .map(|arm| { + let arm_has_guard = arm.guard.is_some(); + let arm_candidate = + Candidate::new(scrutinee_place.clone(), &arm.pattern, arm_has_guard, self); + arm_candidate + }) + .collect(); // The set of places that we are creating fake borrows of. If there are no match guards then // we don't need any fake borrows, so don't track them. + let match_has_guard = candidates.iter().any(|candidate| candidate.has_guard); let fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)> = if match_has_guard { util::collect_fake_borrows(self, &candidates, scrutinee_span, scrutinee_place.base()) } else { Vec::new() }; - self.lower_match_tree( + let match_start_span = span.shrink_to_lo().to(scrutinee_span); + let built_tree = self.lower_match_tree( block, scrutinee_span, &scrutinee_place, match_start_span, - &mut candidates, + candidates, false, ); @@ -395,7 +404,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination, scrutinee_place, scrutinee_span, - arm_candidates, + arms, + built_tree.branches, self.source_info(span), fake_borrow_temps, ) @@ -417,51 +427,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(scrutinee_place_builder) } - /// Create the initial `Candidate`s for a `match` expression. - fn create_match_candidates<'pat>( - &mut self, - scrutinee: &PlaceBuilder<'tcx>, - arms: &'pat [ArmId], - ) -> Vec<(&'pat Arm<'tcx>, Candidate<'pat, 'tcx>)> - where - 'a: 'pat, - { - // Assemble the initial list of candidates. These top-level candidates - // are 1:1 with the original match arms, but other parts of match - // lowering also introduce subcandidates (for subpatterns), and will - // also flatten candidates in some cases. So in general a list of - // candidates does _not_ necessarily correspond to a list of arms. - arms.iter() - .copied() - .map(|arm| { - let arm = &self.thir[arm]; - let arm_has_guard = arm.guard.is_some(); - let arm_candidate = - Candidate::new(scrutinee.clone(), &arm.pattern, arm_has_guard, self); - (arm, arm_candidate) - }) - .collect() - } - /// Lower the bindings, guards and arm bodies of a `match` expression. /// /// The decision tree should have already been created /// (by [Builder::lower_match_tree]). /// /// `outer_source_info` is the SourceInfo for the whole match. - fn lower_match_arms( + fn lower_match_arms<'pat>( &mut self, destination: Place<'tcx>, scrutinee_place_builder: PlaceBuilder<'tcx>, scrutinee_span: Span, - arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>, + arms: impl IntoIterator>, + lowered_branches: impl IntoIterator>, outer_source_info: SourceInfo, fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)>, - ) -> BlockAnd<()> { - let arm_end_blocks: Vec = arm_candidates + ) -> BlockAnd<()> + where + 'tcx: 'pat, + { + let arm_end_blocks: Vec = arms .into_iter() - .map(|(arm, candidate)| { - debug!("lowering arm {:?}\ncandidate = {:?}", arm, candidate); + .zip(lowered_branches) + .map(|(arm, branch)| { + debug!("lowering arm {:?}\ncorresponding branch = {:?}", arm, branch); let arm_source_info = self.source_info(arm.span); let arm_scope = (arm.scope, arm_source_info); @@ -494,7 +483,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let arm_block = this.bind_pattern( outer_source_info, - candidate, + branch, &fake_borrow_temps, scrutinee_span, Some((arm, match_scope)), @@ -548,18 +537,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn bind_pattern( &mut self, outer_source_info: SourceInfo, - candidate: Candidate<'_, 'tcx>, + branch: MatchTreeBranch<'tcx>, fake_borrow_temps: &[(Place<'tcx>, Local, FakeBorrowKind)], scrutinee_span: Span, arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>, emit_storage_live: EmitStorageLive, ) -> BasicBlock { - if candidate.subcandidates.is_empty() { - // Avoid generating another `BasicBlock` when we only have one - // candidate. + if branch.sub_branches.len() == 1 { + let [sub_branch] = branch.sub_branches.try_into().unwrap(); + // Avoid generating another `BasicBlock` when we only have one sub branch. self.bind_and_guard_matched_candidate( - candidate, - &[], + sub_branch, fake_borrow_temps, scrutinee_span, arm_match_scope, @@ -587,35 +575,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // We keep a stack of all of the bindings and type ascriptions // from the parent candidates that we visit, that also need to // be bound for each candidate. - traverse_candidate( - candidate, - &mut Vec::new(), - &mut |leaf_candidate, parent_data| { - if let Some(arm) = arm { - self.clear_top_scope(arm.scope); - } - let binding_end = self.bind_and_guard_matched_candidate( - leaf_candidate, - parent_data, - fake_borrow_temps, - scrutinee_span, - arm_match_scope, - schedule_drops, - emit_storage_live, - ); - if arm.is_none() { - schedule_drops = ScheduleDrops::No; - } - self.cfg.goto(binding_end, outer_source_info, target_block); - }, - |inner_candidate, parent_data| { - parent_data.push(inner_candidate.extra_data); - inner_candidate.subcandidates.into_iter() - }, - |parent_data| { - parent_data.pop(); - }, - ); + for sub_branch in branch.sub_branches { + if let Some(arm) = arm { + self.clear_top_scope(arm.scope); + } + let binding_end = self.bind_and_guard_matched_candidate( + sub_branch, + fake_borrow_temps, + scrutinee_span, + arm_match_scope, + schedule_drops, + emit_storage_live, + ); + if arm.is_none() { + schedule_drops = ScheduleDrops::No; + } + self.cfg.goto(binding_end, outer_source_info, target_block); + } target_block } @@ -761,17 +737,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - self.lower_match_tree( + let built_tree = self.lower_match_tree( block, irrefutable_pat.span, &initializer, irrefutable_pat.span, - &mut [&mut candidate], + vec![candidate], false, ); + let [branch] = built_tree.branches.try_into().unwrap(); + self.bind_pattern( self.source_info(irrefutable_pat.span), - candidate, + branch, &[], irrefutable_pat.span, None, @@ -1417,6 +1395,98 @@ pub(crate) struct ArmHasGuard(pub(crate) bool); /////////////////////////////////////////////////////////////////////////// // Main matching algorithm +/// A sub-branch in the output of match lowering. Match lowering has generated MIR code that will +/// branch to `success_block` when the matched value matches the corresponding pattern. If there is +/// a guard, its failure must continue to `otherwise_block`, which will resume testing patterns. +#[derive(Debug)] +struct MatchTreeSubBranch<'tcx> { + span: Span, + /// The block that is branched to if the corresponding subpattern matches. + success_block: BasicBlock, + /// The block to branch to if this arm had a guard and the guard fails. + otherwise_block: BasicBlock, + /// The bindings to set up in this sub-branch. + bindings: Vec>, + /// The ascriptions to set up in this sub-branch. + ascriptions: Vec>, + /// Whether the sub-branch corresponds to a never pattern. + is_never: bool, +} + +/// A branch in the output of match lowering. +#[derive(Debug)] +struct MatchTreeBranch<'tcx> { + sub_branches: Vec>, +} + +/// The result of generating MIR for a pattern-matching expression. Each input branch/arm/pattern +/// gives rise to an output `MatchTreeBranch`. If one of the patterns matches, we branch to the +/// corresponding `success_block`. If none of the patterns matches, we branch to `otherwise_block`. +/// +/// Each branch is made of one of more sub-branches, corresponding to or-patterns. E.g. +/// ```ignore(illustrative) +/// match foo { +/// (x, false) | (false, x) => {} +/// (true, true) => {} +/// } +/// ``` +/// Here the first arm gives the first `MatchTreeBranch`, which has two sub-branches, one for each +/// alternative of the or-pattern. They are kept separate because each needs to bind `x` to a +/// different place. +#[derive(Debug)] +struct BuiltMatchTree<'tcx> { + branches: Vec>, + otherwise_block: BasicBlock, +} + +impl<'tcx> MatchTreeSubBranch<'tcx> { + fn from_sub_candidate( + candidate: Candidate<'_, 'tcx>, + parent_data: &Vec>, + ) -> Self { + debug_assert!(candidate.match_pairs.is_empty()); + MatchTreeSubBranch { + span: candidate.extra_data.span, + success_block: candidate.pre_binding_block.unwrap(), + otherwise_block: candidate.otherwise_block.unwrap(), + bindings: parent_data + .iter() + .flat_map(|d| &d.bindings) + .chain(&candidate.extra_data.bindings) + .cloned() + .collect(), + ascriptions: parent_data + .iter() + .flat_map(|d| &d.ascriptions) + .cloned() + .chain(candidate.extra_data.ascriptions) + .collect(), + is_never: candidate.extra_data.is_never, + } + } +} + +impl<'tcx> MatchTreeBranch<'tcx> { + fn from_candidate(candidate: Candidate<'_, 'tcx>) -> Self { + let mut sub_branches = Vec::new(); + traverse_candidate( + candidate, + &mut Vec::new(), + &mut |candidate: Candidate<'_, '_>, parent_data: &mut Vec>| { + sub_branches.push(MatchTreeSubBranch::from_sub_candidate(candidate, parent_data)); + }, + |inner_candidate, parent_data| { + parent_data.push(inner_candidate.extra_data); + inner_candidate.subcandidates.into_iter() + }, + |parent_data| { + parent_data.pop(); + }, + ); + MatchTreeBranch { sub_branches } + } +} + impl<'a, 'tcx> Builder<'a, 'tcx> { /// The entrypoint of the matching algorithm. Create the decision tree for the match expression, /// starting from `block`. @@ -1433,13 +1503,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scrutinee_span: Span, scrutinee_place_builder: &PlaceBuilder<'tcx>, match_start_span: Span, - candidates: &mut [&mut Candidate<'pat, 'tcx>], + mut candidates: Vec>, refutable: bool, - ) -> BasicBlock { + ) -> BuiltMatchTree<'tcx> { // This will generate code to test scrutinee_place and branch to the appropriate arm block. - // See the doc comment on `match_candidates` for why we have an otherwise block. + // If none of the arms match, we branch to `otherwise_block`. When lowering a `match` + // expression, exhaustiveness checking ensures that this block is unreachable. + let mut candidate_refs = candidates.iter_mut().collect::>(); let otherwise_block = - self.match_candidates(match_start_span, scrutinee_span, block, candidates); + self.match_candidates(match_start_span, scrutinee_span, block, &mut candidate_refs); // Set up false edges so that the borrow-checker cannot make use of the specific CFG we // generated. We falsely branch from each candidate to the one below it to make it as if we @@ -1509,7 +1581,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.terminate(otherwise_block, source_info, TerminatorKind::Unreachable); } - otherwise_block + BuiltMatchTree { + branches: candidates.into_iter().map(MatchTreeBranch::from_candidate).collect(), + otherwise_block, + } } /// The main match algorithm. It begins with a set of candidates `candidates` and has the job of @@ -2259,17 +2334,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) -> BlockAnd<()> { let expr_span = self.thir[expr_id].span; let scrutinee = unpack!(block = self.lower_scrutinee(block, expr_id, expr_span)); - let mut candidate = Candidate::new(scrutinee.clone(), pat, false, self); - let otherwise_block = self.lower_match_tree( - block, - expr_span, - &scrutinee, - pat.span, - &mut [&mut candidate], - true, - ); + let candidate = Candidate::new(scrutinee.clone(), pat, false, self); + let built_tree = + self.lower_match_tree(block, expr_span, &scrutinee, pat.span, vec![candidate], true); + let [branch] = built_tree.branches.try_into().unwrap(); - self.break_for_else(otherwise_block, self.source_info(expr_span)); + self.break_for_else(built_tree.otherwise_block, self.source_info(expr_span)); match declare_let_bindings { DeclareLetBindings::Yes => { @@ -2291,7 +2361,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let success = self.bind_pattern( self.source_info(pat.span), - candidate, + branch, &[], expr_span, None, @@ -2299,7 +2369,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); // If branch coverage is enabled, record this branch. - self.visit_coverage_conditional_let(pat, success, otherwise_block); + self.visit_coverage_conditional_let(pat, success, built_tree.otherwise_block); success.unit() } @@ -2312,39 +2382,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Note: we do not check earlier that if there is a guard, /// there cannot be move bindings. We avoid a use-after-move by only /// moving the binding once the guard has evaluated to true (see below). - fn bind_and_guard_matched_candidate<'pat>( + fn bind_and_guard_matched_candidate( &mut self, - candidate: Candidate<'pat, 'tcx>, - parent_data: &[PatternExtraData<'tcx>], + sub_branch: MatchTreeSubBranch<'tcx>, fake_borrows: &[(Place<'tcx>, Local, FakeBorrowKind)], scrutinee_span: Span, arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>, schedule_drops: ScheduleDrops, emit_storage_live: EmitStorageLive, ) -> BasicBlock { - debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate); - - debug_assert!(candidate.match_pairs.is_empty()); + debug!("bind_and_guard_matched_candidate(subbranch={:?})", sub_branch); - let block = candidate.pre_binding_block.unwrap(); + let block = sub_branch.success_block; - if candidate.extra_data.is_never { + if sub_branch.is_never { // This arm has a dummy body, we don't need to generate code for it. `block` is already // unreachable (except via false edge). - let source_info = self.source_info(candidate.extra_data.span); + let source_info = self.source_info(sub_branch.span); self.cfg.terminate(block, source_info, TerminatorKind::Unreachable); return self.cfg.start_new_block(); } - let ascriptions = parent_data - .iter() - .flat_map(|d| &d.ascriptions) - .cloned() - .chain(candidate.extra_data.ascriptions); - let bindings = - parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings); - - self.ascribe_types(block, ascriptions); + self.ascribe_types(block, sub_branch.ascriptions); // Lower an instance of the arm guard (if present) for this candidate, // and then perform bindings for the arm body. @@ -2355,9 +2414,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Bindings for guards require some extra handling to automatically // insert implicit references/dereferences. - self.bind_matched_candidate_for_guard(block, schedule_drops, bindings.clone()); + self.bind_matched_candidate_for_guard( + block, + schedule_drops, + sub_branch.bindings.iter(), + ); let guard_frame = GuardFrame { - locals: bindings.clone().map(|b| GuardFrameLocal::new(b.var_id)).collect(), + locals: sub_branch + .bindings + .iter() + .map(|b| GuardFrameLocal::new(b.var_id)) + .collect(), }; debug!("entering guard building context: {:?}", guard_frame); self.guard_context.push(guard_frame); @@ -2393,11 +2460,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(temp)); } - self.cfg.goto( - otherwise_post_guard_block, - source_info, - candidate.otherwise_block.unwrap(), - ); + self.cfg.goto(otherwise_post_guard_block, source_info, sub_branch.otherwise_block); // We want to ensure that the matched candidates are bound // after we have confirmed this candidate *and* any @@ -2425,8 +2488,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // ``` // // and that is clearly not correct. - let by_value_bindings = - bindings.filter(|binding| matches!(binding.binding_mode.0, ByRef::No)); + let by_value_bindings = sub_branch + .bindings + .iter() + .filter(|binding| matches!(binding.binding_mode.0, ByRef::No)); // Read all of the by reference bindings to ensure that the // place they refer to can't be modified by the guard. for binding in by_value_bindings.clone() { @@ -2454,7 +2519,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.bind_matched_candidate_for_arm_body( block, schedule_drops, - bindings, + sub_branch.bindings.iter(), emit_storage_live, ); block diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 1848ab7a20be7..79ee683d63cce 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -70,7 +70,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// a MIR pass run after borrow checking. pub(super) fn collect_fake_borrows<'tcx>( cx: &mut Builder<'_, 'tcx>, - candidates: &[&mut Candidate<'_, 'tcx>], + candidates: &[Candidate<'_, 'tcx>], temp_span: Span, scrutinee_base: PlaceBase, ) -> Vec<(Place<'tcx>, Local, FakeBorrowKind)> { From c7471664b356229cd9aac11f1c0339dcf24863b0 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 23 Jun 2024 17:25:41 +0200 Subject: [PATCH 05/18] Visiting bindings is straightforward now --- .../rustc_mir_build/src/build/matches/mod.rs | 28 +++++----- .../rustc_mir_build/src/build/matches/util.rs | 53 ------------------- 2 files changed, 14 insertions(+), 67 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 78efa53253a3f..267db29ff3d7d 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -17,7 +17,6 @@ use rustc_span::symbol::Symbol; use rustc_span::{BytePos, Pos, Span}; use rustc_target::abi::VariantIdx; use tracing::{debug, instrument}; -use util::visit_bindings; use crate::build::expr::as_place::PlaceBuilder; use crate::build::scope::DropKind; @@ -701,7 +700,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { initializer: PlaceBuilder<'tcx>, set_match_place: bool, ) -> BlockAnd<()> { - let mut candidate = Candidate::new(initializer.clone(), irrefutable_pat, false, self); + let candidate = Candidate::new(initializer.clone(), irrefutable_pat, false, self); + let built_tree = self.lower_match_tree( + block, + irrefutable_pat.span, + &initializer, + irrefutable_pat.span, + vec![candidate], + false, + ); + let [branch] = built_tree.branches.try_into().unwrap(); // For matches and function arguments, the place that is being matched // can be set when creating the variables. But the place for @@ -722,7 +730,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // }; // ``` if let Some(place) = initializer.try_to_place(self) { - visit_bindings(&[&mut candidate], |binding: &Binding<'_>| { + // Because or-alternatives bind the same variables, we only explore the first one. + let first_sub_branch = branch.sub_branches.first().unwrap(); + for binding in &first_sub_branch.bindings { let local = self.var_local_id(binding.var_id, OutsideGuard); if let LocalInfo::User(BindingForm::Var(VarBindingForm { opt_match_place: Some((ref mut match_place, _)), @@ -733,20 +743,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else { bug!("Let binding to non-user variable.") }; - }); + } } } - let built_tree = self.lower_match_tree( - block, - irrefutable_pat.span, - &initializer, - irrefutable_pat.span, - vec![candidate], - false, - ); - let [branch] = built_tree.branches.try_into().unwrap(); - self.bind_pattern( self.source_info(irrefutable_pat.span), branch, diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 79ee683d63cce..d3ba1577edf7b 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -1,5 +1,3 @@ -use std::marker::PhantomData; - use rustc_data_structures::fx::FxIndexMap; use rustc_middle::mir::*; use rustc_middle::ty::Ty; @@ -221,57 +219,6 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { } } -/// Visit all the bindings of these candidates. Because or-alternatives bind the same variables, we -/// only explore the first one of each or-pattern. -pub(super) fn visit_bindings<'tcx>( - candidates: &[&mut Candidate<'_, 'tcx>], - f: impl FnMut(&Binding<'tcx>), -) { - let mut visitor = BindingsVisitor { f, phantom: PhantomData }; - for candidate in candidates.iter() { - visitor.visit_candidate(candidate); - } -} - -pub(super) struct BindingsVisitor<'tcx, F> { - f: F, - phantom: PhantomData<&'tcx ()>, -} - -impl<'tcx, F> BindingsVisitor<'tcx, F> -where - F: FnMut(&Binding<'tcx>), -{ - fn visit_candidate(&mut self, candidate: &Candidate<'_, 'tcx>) { - for binding in &candidate.extra_data.bindings { - (self.f)(binding) - } - for match_pair in &candidate.match_pairs { - self.visit_match_pair(match_pair); - } - } - - fn visit_flat_pat(&mut self, flat_pat: &FlatPat<'_, 'tcx>) { - for binding in &flat_pat.extra_data.bindings { - (self.f)(binding) - } - for match_pair in &flat_pat.match_pairs { - self.visit_match_pair(match_pair); - } - } - - fn visit_match_pair(&mut self, match_pair: &MatchPairTree<'_, 'tcx>) { - if let TestCase::Or { pats, .. } = &match_pair.test_case { - // All the or-alternatives should bind the same locals, so we only visit the first one. - self.visit_flat_pat(&pats[0]) - } else { - for subpair in &match_pair.subpairs { - self.visit_match_pair(subpair); - } - } - } -} - #[must_use] pub(crate) fn ref_pat_borrow_kind(ref_mutability: Mutability) -> BorrowKind { match ref_mutability { From 08bcc0139405fb0592a87488759990d615414f08 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 30 Jun 2024 11:33:43 +0200 Subject: [PATCH 06/18] Entirely hide `Candidate`s from outside `lower_match_tree` --- .../rustc_mir_build/src/build/matches/mod.rs | 98 ++++++++++++------- .../rustc_mir_build/src/build/matches/util.rs | 4 + 2 files changed, 64 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 267db29ff3d7d..cae4aa7bad3d2 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -366,36 +366,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { unpack!(block = self.lower_scrutinee(block, scrutinee_id, scrutinee_span)); let arms = arms.iter().map(|arm| &self.thir[*arm]); - // Assemble the initial list of candidates. These top-level candidates are 1:1 with the - // original match arms, but other parts of match lowering also introduce subcandidates (for - // sub-or-patterns). So inside the algorithm, the candidates list may not correspond to - // match arms directly. - let candidates: Vec<_> = arms + let match_start_span = span.shrink_to_lo().to(scrutinee_span); + let patterns = arms .clone() .map(|arm| { - let arm_has_guard = arm.guard.is_some(); - let arm_candidate = - Candidate::new(scrutinee_place.clone(), &arm.pattern, arm_has_guard, self); - arm_candidate + let has_match_guard = + if arm.guard.is_some() { HasMatchGuard::Yes } else { HasMatchGuard::No }; + (&*arm.pattern, has_match_guard) }) .collect(); - - // The set of places that we are creating fake borrows of. If there are no match guards then - // we don't need any fake borrows, so don't track them. - let match_has_guard = candidates.iter().any(|candidate| candidate.has_guard); - let fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)> = if match_has_guard { - util::collect_fake_borrows(self, &candidates, scrutinee_span, scrutinee_place.base()) - } else { - Vec::new() - }; - - let match_start_span = span.shrink_to_lo().to(scrutinee_span); let built_tree = self.lower_match_tree( block, scrutinee_span, &scrutinee_place, match_start_span, - candidates, + patterns, false, ); @@ -404,9 +389,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scrutinee_place, scrutinee_span, arms, - built_tree.branches, + built_tree, self.source_info(span), - fake_borrow_temps, ) } @@ -438,16 +422,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scrutinee_place_builder: PlaceBuilder<'tcx>, scrutinee_span: Span, arms: impl IntoIterator>, - lowered_branches: impl IntoIterator>, + built_match_tree: BuiltMatchTree<'tcx>, outer_source_info: SourceInfo, - fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)>, ) -> BlockAnd<()> where 'tcx: 'pat, { let arm_end_blocks: Vec = arms .into_iter() - .zip(lowered_branches) + .zip(built_match_tree.branches) .map(|(arm, branch)| { debug!("lowering arm {:?}\ncorresponding branch = {:?}", arm, branch); @@ -483,7 +466,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let arm_block = this.bind_pattern( outer_source_info, branch, - &fake_borrow_temps, + &built_match_tree.fake_borrow_temps, scrutinee_span, Some((arm, match_scope)), EmitStorageLive::Yes, @@ -700,13 +683,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { initializer: PlaceBuilder<'tcx>, set_match_place: bool, ) -> BlockAnd<()> { - let candidate = Candidate::new(initializer.clone(), irrefutable_pat, false, self); let built_tree = self.lower_match_tree( block, irrefutable_pat.span, &initializer, irrefutable_pat.span, - vec![candidate], + vec![(irrefutable_pat, HasMatchGuard::No)], false, ); let [branch] = built_tree.branches.try_into().unwrap(); @@ -1136,12 +1118,15 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { fn new( place: PlaceBuilder<'tcx>, pattern: &'pat Pat<'tcx>, - has_guard: bool, + has_guard: HasMatchGuard, cx: &mut Builder<'_, 'tcx>, ) -> Self { // Use `FlatPat` to build simplified match pairs, then immediately // incorporate them into a new candidate. - Self::from_flat_pat(FlatPat::new(place, pattern, cx), has_guard) + Self::from_flat_pat( + FlatPat::new(place, pattern, cx), + matches!(has_guard, HasMatchGuard::Yes), + ) } /// Incorporates an already-simplified [`FlatPat`] into a new candidate. @@ -1437,6 +1422,10 @@ struct MatchTreeBranch<'tcx> { struct BuiltMatchTree<'tcx> { branches: Vec>, otherwise_block: BasicBlock, + /// If any of the branches had a guard, we collect here the places and locals to fakely borrow + /// to ensure match guards can't modify the values as we match them. For more details, see + /// [`util::collect_fake_borrows`]. + fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)>, } impl<'tcx> MatchTreeSubBranch<'tcx> { @@ -1487,12 +1476,18 @@ impl<'tcx> MatchTreeBranch<'tcx> { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum HasMatchGuard { + Yes, + No, +} + impl<'a, 'tcx> Builder<'a, 'tcx> { /// The entrypoint of the matching algorithm. Create the decision tree for the match expression, /// starting from `block`. /// - /// Modifies `candidates` to store the bindings and type ascriptions for - /// that candidate. + /// `patterns` is a list of patterns, one for each arm. The associated boolean indicates whether + /// the arm has a guard. /// /// `refutable` indicates whether the candidate list is refutable (for `if let` and `let else`) /// or not (for `let` and `match`). In the refutable case we return the block to which we branch @@ -1503,9 +1498,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scrutinee_span: Span, scrutinee_place_builder: &PlaceBuilder<'tcx>, match_start_span: Span, - mut candidates: Vec>, + patterns: Vec<(&'pat Pat<'tcx>, HasMatchGuard)>, refutable: bool, - ) -> BuiltMatchTree<'tcx> { + ) -> BuiltMatchTree<'tcx> + where + 'tcx: 'pat, + { + // Assemble the initial list of candidates. These top-level candidates are 1:1 with the + // input patterns, but other parts of match lowering also introduce subcandidates (for + // sub-or-patterns). So inside the algorithm, the candidates list may not correspond to + // match arms directly. + let mut candidates: Vec> = patterns + .into_iter() + .map(|(pat, has_guard)| { + Candidate::new(scrutinee_place_builder.clone(), pat, has_guard, self) + }) + .collect(); + + let fake_borrow_temps = util::collect_fake_borrows( + self, + &candidates, + scrutinee_span, + scrutinee_place_builder.base(), + ); + // This will generate code to test scrutinee_place and branch to the appropriate arm block. // If none of the arms match, we branch to `otherwise_block`. When lowering a `match` // expression, exhaustiveness checking ensures that this block is unreachable. @@ -1584,6 +1600,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { BuiltMatchTree { branches: candidates.into_iter().map(MatchTreeBranch::from_candidate).collect(), otherwise_block, + fake_borrow_temps, } } @@ -2334,9 +2351,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) -> BlockAnd<()> { let expr_span = self.thir[expr_id].span; let scrutinee = unpack!(block = self.lower_scrutinee(block, expr_id, expr_span)); - let candidate = Candidate::new(scrutinee.clone(), pat, false, self); - let built_tree = - self.lower_match_tree(block, expr_span, &scrutinee, pat.span, vec![candidate], true); + let built_tree = self.lower_match_tree( + block, + expr_span, + &scrutinee, + pat.span, + vec![(pat, HasMatchGuard::No)], + true, + ); let [branch] = built_tree.branches.try_into().unwrap(); self.break_for_else(built_tree.otherwise_block, self.source_info(expr_span)); diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index d3ba1577edf7b..8491b5fe380c7 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -72,6 +72,10 @@ pub(super) fn collect_fake_borrows<'tcx>( temp_span: Span, scrutinee_base: PlaceBase, ) -> Vec<(Place<'tcx>, Local, FakeBorrowKind)> { + if candidates.iter().all(|candidate| !candidate.has_guard) { + // Fake borrows are only used when there is a guard. + return Vec::new(); + } let mut collector = FakeBorrowCollector { cx, scrutinee_base, fake_borrows: FxIndexMap::default() }; for candidate in candidates.iter() { From a75d2f9d384135c5f0f6bd6d26ec2ba9aa76745a Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 24 Jul 2024 22:02:48 +0000 Subject: [PATCH 07/18] Cleanup sys module to match house style --- .../std/src/{sys/anonymous_pipe => pipe}/tests.rs | 1 + library/std/src/sys/anonymous_pipe/mod.rs | 14 +++++--------- library/std/src/sys/anonymous_pipe/unix.rs | 8 ++++---- library/std/src/sys/anonymous_pipe/unsupported.rs | 2 +- library/std/src/sys/anonymous_pipe/windows.rs | 8 ++++---- library/std/src/sys/mod.rs | 1 - 6 files changed, 15 insertions(+), 19 deletions(-) rename library/std/src/{sys/anonymous_pipe => pipe}/tests.rs (90%) diff --git a/library/std/src/sys/anonymous_pipe/tests.rs b/library/std/src/pipe/tests.rs similarity index 90% rename from library/std/src/sys/anonymous_pipe/tests.rs rename to library/std/src/pipe/tests.rs index 865d24ec85596..9c38e10678752 100644 --- a/library/std/src/sys/anonymous_pipe/tests.rs +++ b/library/std/src/pipe/tests.rs @@ -2,6 +2,7 @@ use crate::io::{Read, Write}; use crate::pipe::pipe; #[test] +#[cfg(all(windows, unix, not(miri)))] fn pipe_creation_clone_and_rw() { let (rx, tx) = pipe().unwrap(); diff --git a/library/std/src/sys/anonymous_pipe/mod.rs b/library/std/src/sys/anonymous_pipe/mod.rs index 74875677cf3e7..aa14c8b650d34 100644 --- a/library/std/src/sys/anonymous_pipe/mod.rs +++ b/library/std/src/sys/anonymous_pipe/mod.rs @@ -1,18 +1,14 @@ +#![forbid(unsafe_op_in_unsafe_fn)] + cfg_if::cfg_if! { if #[cfg(unix)] { mod unix; - pub(crate) use unix::{AnonPipe, pipe}; - - #[cfg(all(test, not(miri)))] - mod tests; + pub use unix::{AnonPipe, pipe}; } else if #[cfg(windows)] { mod windows; - pub(crate) use windows::{AnonPipe, pipe}; - - #[cfg(all(test, not(miri)))] - mod tests; + pub use windows::{AnonPipe, pipe}; } else { mod unsupported; - pub(crate) use unsupported::{AnonPipe, pipe}; + pub use unsupported::{AnonPipe, pipe}; } } diff --git a/library/std/src/sys/anonymous_pipe/unix.rs b/library/std/src/sys/anonymous_pipe/unix.rs index 7c0e75208c43c..9168024730e67 100644 --- a/library/std/src/sys/anonymous_pipe/unix.rs +++ b/library/std/src/sys/anonymous_pipe/unix.rs @@ -6,10 +6,10 @@ use crate::sys::fd::FileDesc; use crate::sys::pipe::anon_pipe; use crate::sys_common::{FromInner, IntoInner}; -pub(crate) type AnonPipe = FileDesc; +pub type AnonPipe = FileDesc; #[inline] -pub(crate) fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { +pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { anon_pipe().map(|(rx, wx)| (rx.into_inner(), wx.into_inner())) } @@ -34,7 +34,7 @@ impl From for OwnedFd { #[unstable(feature = "anonymous_pipe", issue = "127154")] impl FromRawFd for PipeReader { unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { - Self(FileDesc::from_raw_fd(raw_fd)) + unsafe { Self(FileDesc::from_raw_fd(raw_fd)) } } } #[unstable(feature = "anonymous_pipe", issue = "127154")] @@ -71,7 +71,7 @@ impl From for OwnedFd { #[unstable(feature = "anonymous_pipe", issue = "127154")] impl FromRawFd for PipeWriter { unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { - Self(FileDesc::from_raw_fd(raw_fd)) + unsafe { Self(FileDesc::from_raw_fd(raw_fd)) } } } #[unstable(feature = "anonymous_pipe", issue = "127154")] diff --git a/library/std/src/sys/anonymous_pipe/unsupported.rs b/library/std/src/sys/anonymous_pipe/unsupported.rs index f3c826d2f8dfb..da04e8e6b25af 100644 --- a/library/std/src/sys/anonymous_pipe/unsupported.rs +++ b/library/std/src/sys/anonymous_pipe/unsupported.rs @@ -4,7 +4,7 @@ use crate::process::Stdio; pub(crate) use crate::sys::pipe::AnonPipe; #[inline] -pub(crate) fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { +pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { Err(io::Error::UNSUPPORTED_PLATFORM) } diff --git a/library/std/src/sys/anonymous_pipe/windows.rs b/library/std/src/sys/anonymous_pipe/windows.rs index 0f746b1082baf..1b63e9a9b920b 100644 --- a/library/std/src/sys/anonymous_pipe/windows.rs +++ b/library/std/src/sys/anonymous_pipe/windows.rs @@ -8,10 +8,10 @@ use crate::sys::handle::Handle; use crate::sys::pipe::unnamed_anon_pipe; use crate::sys_common::{FromInner, IntoInner}; -pub(crate) type AnonPipe = Handle; +pub type AnonPipe = Handle; #[inline] -pub(crate) fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { +pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { unnamed_anon_pipe().map(|(rx, wx)| (rx.into_inner(), wx.into_inner())) } @@ -31,7 +31,7 @@ impl AsRawHandle for PipeReader { #[unstable(feature = "anonymous_pipe", issue = "127154")] impl FromRawHandle for PipeReader { unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { - Self(Handle::from_raw_handle(raw_handle)) + unsafe { Self(Handle::from_raw_handle(raw_handle)) } } } #[unstable(feature = "anonymous_pipe", issue = "127154")] @@ -70,7 +70,7 @@ impl AsRawHandle for PipeWriter { #[unstable(feature = "anonymous_pipe", issue = "127154")] impl FromRawHandle for PipeWriter { unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { - Self(Handle::from_raw_handle(raw_handle)) + unsafe { Self(Handle::from_raw_handle(raw_handle)) } } } #[unstable(feature = "anonymous_pipe", issue = "127154")] diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 202997b749513..a86b3628f249a 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -7,7 +7,6 @@ mod pal; mod personality; -#[unstable(feature = "anonymous_pipe", issue = "127154")] pub mod anonymous_pipe; pub mod backtrace; pub mod cmath; From 9169622027f1dcb702f789076da1b8b98c01a215 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 24 Jul 2024 22:22:09 +0000 Subject: [PATCH 08/18] Move Windows implementation of anon pipe --- library/std/src/sys/anonymous_pipe/windows.rs | 16 ++++++++++++---- library/std/src/sys/pal/windows/pipe.rs | 17 ----------------- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/library/std/src/sys/anonymous_pipe/windows.rs b/library/std/src/sys/anonymous_pipe/windows.rs index 1b63e9a9b920b..a48198f8a812b 100644 --- a/library/std/src/sys/anonymous_pipe/windows.rs +++ b/library/std/src/sys/anonymous_pipe/windows.rs @@ -1,18 +1,26 @@ -use crate::io; use crate::os::windows::io::{ AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle, }; use crate::pipe::{PipeReader, PipeWriter}; use crate::process::Stdio; +use crate::sys::c; use crate::sys::handle::Handle; -use crate::sys::pipe::unnamed_anon_pipe; use crate::sys_common::{FromInner, IntoInner}; +use crate::{io, ptr}; pub type AnonPipe = Handle; -#[inline] pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { - unnamed_anon_pipe().map(|(rx, wx)| (rx.into_inner(), wx.into_inner())) + let mut read_pipe = c::INVALID_HANDLE_VALUE; + let mut write_pipe = c::INVALID_HANDLE_VALUE; + + let ret = unsafe { c::CreatePipe(&mut read_pipe, &mut write_pipe, ptr::null_mut(), 0) }; + + if ret == 0 { + Err(io::Error::last_os_error()) + } else { + unsafe { Ok((Handle::from_raw_handle(read_pipe), Handle::from_raw_handle(write_pipe))) } + } } #[unstable(feature = "anonymous_pipe", issue = "127154")] diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index 9eb19fcf2d7a2..7d1b5aca1d5fe 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -36,23 +36,6 @@ pub struct Pipes { pub theirs: AnonPipe, } -/// Create true unnamed anonymous pipe. -pub fn unnamed_anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { - let mut read_pipe = c::INVALID_HANDLE_VALUE; - let mut write_pipe = c::INVALID_HANDLE_VALUE; - - let ret = unsafe { c::CreatePipe(&mut read_pipe, &mut write_pipe, ptr::null_mut(), 0) }; - - if ret == 0 { - Err(io::Error::last_os_error()) - } else { - Ok(( - AnonPipe::from_inner(unsafe { Handle::from_raw_handle(read_pipe) }), - AnonPipe::from_inner(unsafe { Handle::from_raw_handle(write_pipe) }), - )) - } -} - /// Although this looks similar to `anon_pipe` in the Unix module it's actually /// subtly different. Here we'll return two pipes in the `Pipes` return value, /// but one is intended for "us" where as the other is intended for "someone From c586eb6906f26f458a0081850b58728072e3b51a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 12 Jul 2024 03:54:54 -0400 Subject: [PATCH 09/18] Specify the integer type of the `powi` LLVM intrinsic Since LLVM (4c7f820b2b20, "Update @llvm.powi to handle different int sizes for the exponent"), the size of the integer can be specified for the `powi` intrinsic. Make use of this so it is more obvious that integer size is consistent across all float types. This feature is available since LLVM 13 (October 2021). Based on bootstrap we currently support >= 17.0, so there should be no support problems. --- compiler/rustc_codegen_llvm/src/context.rs | 8 ++++---- compiler/rustc_codegen_llvm/src/intrinsic.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index ea930421b5869..14540d41e7c62 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -775,10 +775,10 @@ impl<'ll> CodegenCx<'ll, '_> { ifn!("llvm.debugtrap", fn() -> void); ifn!("llvm.frameaddress", fn(t_i32) -> ptr); - ifn!("llvm.powi.f16", fn(t_f16, t_i32) -> t_f16); - ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32); - ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64); - ifn!("llvm.powi.f128", fn(t_f128, t_i32) -> t_f128); + ifn!("llvm.powi.f16.i32", fn(t_f16, t_i32) -> t_f16); + ifn!("llvm.powi.f32.i32", fn(t_f32, t_i32) -> t_f32); + ifn!("llvm.powi.f64.i32", fn(t_f64, t_i32) -> t_f64); + ifn!("llvm.powi.f128.i32", fn(t_f128, t_i32) -> t_f128); ifn!("llvm.pow.f16", fn(t_f16, t_f16) -> t_f16); ifn!("llvm.pow.f32", fn(t_f32, t_f32) -> t_f32); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 040de1c7dd715..57d5f6fdf503f 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -35,10 +35,10 @@ fn get_simple_intrinsic<'ll>( sym::sqrtf64 => "llvm.sqrt.f64", sym::sqrtf128 => "llvm.sqrt.f128", - sym::powif16 => "llvm.powi.f16", - sym::powif32 => "llvm.powi.f32", - sym::powif64 => "llvm.powi.f64", - sym::powif128 => "llvm.powi.f128", + sym::powif16 => "llvm.powi.f16.i32", + sym::powif32 => "llvm.powi.f32.i32", + sym::powif64 => "llvm.powi.f64.i32", + sym::powif128 => "llvm.powi.f128.i32", sym::sinf16 => "llvm.sin.f16", sym::sinf32 => "llvm.sin.f32", From b6d05171707c727e1be75ca74d44919695a2641b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 18 Jun 2024 21:39:00 -0500 Subject: [PATCH 10/18] Add math intrinsics for `f16` and `f128` These already exist in the compiler. Expose them in core so we can add their library functions. --- library/core/src/intrinsics.rs | 289 +++++++++++++++++++++++++++++++++ 1 file changed, 289 insertions(+) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 13c7f0855d8f0..f230ca612cfe8 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1528,6 +1528,12 @@ extern "rust-intrinsic" { #[rustc_diagnostic_item = "intrinsics_unaligned_volatile_store"] pub fn unaligned_volatile_store(dst: *mut T, val: T); + /// Returns the square root of an `f16` + /// + /// The stabilized version of this intrinsic is + /// [`f16::sqrt`](../../std/primitive.f16.html#method.sqrt) + #[rustc_nounwind] + pub fn sqrtf16(x: f16) -> f16; /// Returns the square root of an `f32` /// /// The stabilized version of this intrinsic is @@ -1540,6 +1546,12 @@ extern "rust-intrinsic" { /// [`f64::sqrt`](../../std/primitive.f64.html#method.sqrt) #[rustc_nounwind] pub fn sqrtf64(x: f64) -> f64; + /// Returns the square root of an `f128` + /// + /// The stabilized version of this intrinsic is + /// [`f128::sqrt`](../../std/primitive.f128.html#method.sqrt) + #[rustc_nounwind] + pub fn sqrtf128(x: f128) -> f128; /// Raises an `f16` to an integer power. /// @@ -1566,6 +1578,12 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn powif128(a: f128, x: i32) -> f128; + /// Returns the sine of an `f16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::sin`](../../std/primitive.f16.html#method.sin) + #[rustc_nounwind] + pub fn sinf16(x: f16) -> f16; /// Returns the sine of an `f32`. /// /// The stabilized version of this intrinsic is @@ -1578,7 +1596,19 @@ extern "rust-intrinsic" { /// [`f64::sin`](../../std/primitive.f64.html#method.sin) #[rustc_nounwind] pub fn sinf64(x: f64) -> f64; + /// Returns the sine of an `f128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::sin`](../../std/primitive.f128.html#method.sin) + #[rustc_nounwind] + pub fn sinf128(x: f128) -> f128; + /// Returns the cosine of an `f16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::cos`](../../std/primitive.f16.html#method.cos) + #[rustc_nounwind] + pub fn cosf16(x: f16) -> f16; /// Returns the cosine of an `f32`. /// /// The stabilized version of this intrinsic is @@ -1591,7 +1621,19 @@ extern "rust-intrinsic" { /// [`f64::cos`](../../std/primitive.f64.html#method.cos) #[rustc_nounwind] pub fn cosf64(x: f64) -> f64; + /// Returns the cosine of an `f128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::cos`](../../std/primitive.f128.html#method.cos) + #[rustc_nounwind] + pub fn cosf128(x: f128) -> f128; + /// Raises an `f16` to an `f16` power. + /// + /// The stabilized version of this intrinsic is + /// [`f16::powf`](../../std/primitive.f16.html#method.powf) + #[rustc_nounwind] + pub fn powf16(a: f16, x: f16) -> f16; /// Raises an `f32` to an `f32` power. /// /// The stabilized version of this intrinsic is @@ -1604,7 +1646,19 @@ extern "rust-intrinsic" { /// [`f64::powf`](../../std/primitive.f64.html#method.powf) #[rustc_nounwind] pub fn powf64(a: f64, x: f64) -> f64; + /// Raises an `f128` to an `f128` power. + /// + /// The stabilized version of this intrinsic is + /// [`f128::powf`](../../std/primitive.f128.html#method.powf) + #[rustc_nounwind] + pub fn powf128(a: f128, x: f128) -> f128; + /// Returns the exponential of an `f16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::exp`](../../std/primitive.f16.html#method.exp) + #[rustc_nounwind] + pub fn expf16(x: f16) -> f16; /// Returns the exponential of an `f32`. /// /// The stabilized version of this intrinsic is @@ -1617,7 +1671,19 @@ extern "rust-intrinsic" { /// [`f64::exp`](../../std/primitive.f64.html#method.exp) #[rustc_nounwind] pub fn expf64(x: f64) -> f64; + /// Returns the exponential of an `f128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::exp`](../../std/primitive.f128.html#method.exp) + #[rustc_nounwind] + pub fn expf128(x: f128) -> f128; + /// Returns 2 raised to the power of an `f16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::exp2`](../../std/primitive.f16.html#method.exp2) + #[rustc_nounwind] + pub fn exp2f16(x: f16) -> f16; /// Returns 2 raised to the power of an `f32`. /// /// The stabilized version of this intrinsic is @@ -1630,7 +1696,19 @@ extern "rust-intrinsic" { /// [`f64::exp2`](../../std/primitive.f64.html#method.exp2) #[rustc_nounwind] pub fn exp2f64(x: f64) -> f64; + /// Returns 2 raised to the power of an `f128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::exp2`](../../std/primitive.f128.html#method.exp2) + #[rustc_nounwind] + pub fn exp2f128(x: f128) -> f128; + /// Returns the natural logarithm of an `f16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::ln`](../../std/primitive.f16.html#method.ln) + #[rustc_nounwind] + pub fn logf16(x: f16) -> f16; /// Returns the natural logarithm of an `f32`. /// /// The stabilized version of this intrinsic is @@ -1643,7 +1721,19 @@ extern "rust-intrinsic" { /// [`f64::ln`](../../std/primitive.f64.html#method.ln) #[rustc_nounwind] pub fn logf64(x: f64) -> f64; + /// Returns the natural logarithm of an `f128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::ln`](../../std/primitive.f128.html#method.ln) + #[rustc_nounwind] + pub fn logf128(x: f128) -> f128; + /// Returns the base 10 logarithm of an `f16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::log10`](../../std/primitive.f16.html#method.log10) + #[rustc_nounwind] + pub fn log10f16(x: f16) -> f16; /// Returns the base 10 logarithm of an `f32`. /// /// The stabilized version of this intrinsic is @@ -1656,7 +1746,19 @@ extern "rust-intrinsic" { /// [`f64::log10`](../../std/primitive.f64.html#method.log10) #[rustc_nounwind] pub fn log10f64(x: f64) -> f64; + /// Returns the base 10 logarithm of an `f128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::log10`](../../std/primitive.f128.html#method.log10) + #[rustc_nounwind] + pub fn log10f128(x: f128) -> f128; + /// Returns the base 2 logarithm of an `f16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::log2`](../../std/primitive.f16.html#method.log2) + #[rustc_nounwind] + pub fn log2f16(x: f16) -> f16; /// Returns the base 2 logarithm of an `f32`. /// /// The stabilized version of this intrinsic is @@ -1669,7 +1771,19 @@ extern "rust-intrinsic" { /// [`f64::log2`](../../std/primitive.f64.html#method.log2) #[rustc_nounwind] pub fn log2f64(x: f64) -> f64; + /// Returns the base 2 logarithm of an `f128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::log2`](../../std/primitive.f128.html#method.log2) + #[rustc_nounwind] + pub fn log2f128(x: f128) -> f128; + /// Returns `a * b + c` for `f16` values. + /// + /// The stabilized version of this intrinsic is + /// [`f16::mul_add`](../../std/primitive.f16.html#method.mul_add) + #[rustc_nounwind] + pub fn fmaf16(a: f16, b: f16, c: f16) -> f16; /// Returns `a * b + c` for `f32` values. /// /// The stabilized version of this intrinsic is @@ -1682,7 +1796,19 @@ extern "rust-intrinsic" { /// [`f64::mul_add`](../../std/primitive.f64.html#method.mul_add) #[rustc_nounwind] pub fn fmaf64(a: f64, b: f64, c: f64) -> f64; + /// Returns `a * b + c` for `f128` values. + /// + /// The stabilized version of this intrinsic is + /// [`f128::mul_add`](../../std/primitive.f128.html#method.mul_add) + #[rustc_nounwind] + pub fn fmaf128(a: f128, b: f128, c: f128) -> f128; + /// Returns the absolute value of an `f16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::abs`](../../std/primitive.f16.html#method.abs) + #[rustc_nounwind] + pub fn fabsf16(x: f16) -> f16; /// Returns the absolute value of an `f32`. /// /// The stabilized version of this intrinsic is @@ -1695,7 +1821,25 @@ extern "rust-intrinsic" { /// [`f64::abs`](../../std/primitive.f64.html#method.abs) #[rustc_nounwind] pub fn fabsf64(x: f64) -> f64; + /// Returns the absolute value of an `f128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::abs`](../../std/primitive.f128.html#method.abs) + #[rustc_nounwind] + pub fn fabsf128(x: f128) -> f128; + /// Returns the minimum of two `f16` values. + /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// + /// The stabilized version of this intrinsic is + /// [`f16::min`] + #[rustc_safe_intrinsic] + #[rustc_nounwind] + pub fn minnumf16(x: f16, y: f16) -> f16; /// Returns the minimum of two `f32` values. /// /// Note that, unlike most intrinsics, this is safe to call; @@ -1720,6 +1864,31 @@ extern "rust-intrinsic" { #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn minnumf64(x: f64, y: f64) -> f64; + /// Returns the minimum of two `f128` values. + /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// + /// The stabilized version of this intrinsic is + /// [`f128::min`] + #[rustc_safe_intrinsic] + #[rustc_nounwind] + pub fn minnumf128(x: f128, y: f128) -> f128; + + /// Returns the maximum of two `f16` values. + /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// + /// The stabilized version of this intrinsic is + /// [`f16::max`] + #[rustc_safe_intrinsic] + #[rustc_nounwind] + pub fn maxnumf16(x: f16, y: f16) -> f16; /// Returns the maximum of two `f32` values. /// /// Note that, unlike most intrinsics, this is safe to call; @@ -1744,7 +1913,25 @@ extern "rust-intrinsic" { #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn maxnumf64(x: f64, y: f64) -> f64; + /// Returns the maximum of two `f128` values. + /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// + /// The stabilized version of this intrinsic is + /// [`f128::max`] + #[rustc_safe_intrinsic] + #[rustc_nounwind] + pub fn maxnumf128(x: f128, y: f128) -> f128; + /// Copies the sign from `y` to `x` for `f16` values. + /// + /// The stabilized version of this intrinsic is + /// [`f16::copysign`](../../std/primitive.f16.html#method.copysign) + #[rustc_nounwind] + pub fn copysignf16(x: f16, y: f16) -> f16; /// Copies the sign from `y` to `x` for `f32` values. /// /// The stabilized version of this intrinsic is @@ -1757,7 +1944,19 @@ extern "rust-intrinsic" { /// [`f64::copysign`](../../std/primitive.f64.html#method.copysign) #[rustc_nounwind] pub fn copysignf64(x: f64, y: f64) -> f64; + /// Copies the sign from `y` to `x` for `f128` values. + /// + /// The stabilized version of this intrinsic is + /// [`f128::copysign`](../../std/primitive.f128.html#method.copysign) + #[rustc_nounwind] + pub fn copysignf128(x: f128, y: f128) -> f128; + /// Returns the largest integer less than or equal to an `f16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::floor`](../../std/primitive.f16.html#method.floor) + #[rustc_nounwind] + pub fn floorf16(x: f16) -> f16; /// Returns the largest integer less than or equal to an `f32`. /// /// The stabilized version of this intrinsic is @@ -1770,7 +1969,19 @@ extern "rust-intrinsic" { /// [`f64::floor`](../../std/primitive.f64.html#method.floor) #[rustc_nounwind] pub fn floorf64(x: f64) -> f64; + /// Returns the largest integer less than or equal to an `f128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::floor`](../../std/primitive.f128.html#method.floor) + #[rustc_nounwind] + pub fn floorf128(x: f128) -> f128; + /// Returns the smallest integer greater than or equal to an `f16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::ceil`](../../std/primitive.f16.html#method.ceil) + #[rustc_nounwind] + pub fn ceilf16(x: f16) -> f16; /// Returns the smallest integer greater than or equal to an `f32`. /// /// The stabilized version of this intrinsic is @@ -1783,7 +1994,19 @@ extern "rust-intrinsic" { /// [`f64::ceil`](../../std/primitive.f64.html#method.ceil) #[rustc_nounwind] pub fn ceilf64(x: f64) -> f64; + /// Returns the smallest integer greater than or equal to an `f128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::ceil`](../../std/primitive.f128.html#method.ceil) + #[rustc_nounwind] + pub fn ceilf128(x: f128) -> f128; + /// Returns the integer part of an `f16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::trunc`](../../std/primitive.f16.html#method.trunc) + #[rustc_nounwind] + pub fn truncf16(x: f16) -> f16; /// Returns the integer part of an `f32`. /// /// The stabilized version of this intrinsic is @@ -1796,7 +2019,25 @@ extern "rust-intrinsic" { /// [`f64::trunc`](../../std/primitive.f64.html#method.trunc) #[rustc_nounwind] pub fn truncf64(x: f64) -> f64; + /// Returns the integer part of an `f128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::trunc`](../../std/primitive.f128.html#method.trunc) + #[rustc_nounwind] + pub fn truncf128(x: f128) -> f128; + /// Returns the nearest integer to an `f16`. Changing the rounding mode is not possible in Rust, + /// so this rounds half-way cases to the number with an even least significant digit. + /// + /// May raise an inexact floating-point exception if the argument is not an integer. + /// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions + /// cannot actually be utilized from Rust code. + /// In other words, this intrinsic is equivalent in behavior to `nearbyintf16` and `roundevenf16`. + /// + /// The stabilized version of this intrinsic is + /// [`f16::round_ties_even`](../../std/primitive.f16.html#method.round_ties_even) + #[rustc_nounwind] + pub fn rintf16(x: f16) -> f16; /// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust, /// so this rounds half-way cases to the number with an even least significant digit. /// @@ -1821,7 +2062,25 @@ extern "rust-intrinsic" { /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even) #[rustc_nounwind] pub fn rintf64(x: f64) -> f64; + /// Returns the nearest integer to an `f128`. Changing the rounding mode is not possible in Rust, + /// so this rounds half-way cases to the number with an even least significant digit. + /// + /// May raise an inexact floating-point exception if the argument is not an integer. + /// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions + /// cannot actually be utilized from Rust code. + /// In other words, this intrinsic is equivalent in behavior to `nearbyintf128` and `roundevenf128`. + /// + /// The stabilized version of this intrinsic is + /// [`f128::round_ties_even`](../../std/primitive.f128.html#method.round_ties_even) + #[rustc_nounwind] + pub fn rintf128(x: f128) -> f128; + /// Returns the nearest integer to an `f16`. Changing the rounding mode is not possible in Rust, + /// so this rounds half-way cases to the number with an even least significant digit. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + pub fn nearbyintf16(x: f16) -> f16; /// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust, /// so this rounds half-way cases to the number with an even least significant digit. /// @@ -1834,7 +2093,19 @@ extern "rust-intrinsic" { /// This intrinsic does not have a stable counterpart. #[rustc_nounwind] pub fn nearbyintf64(x: f64) -> f64; + /// Returns the nearest integer to an `f128`. Changing the rounding mode is not possible in Rust, + /// so this rounds half-way cases to the number with an even least significant digit. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + pub fn nearbyintf128(x: f128) -> f128; + /// Returns the nearest integer to an `f16`. Rounds half-way cases away from zero. + /// + /// The stabilized version of this intrinsic is + /// [`f16::round`](../../std/primitive.f16.html#method.round) + #[rustc_nounwind] + pub fn roundf16(x: f16) -> f16; /// Returns the nearest integer to an `f32`. Rounds half-way cases away from zero. /// /// The stabilized version of this intrinsic is @@ -1847,7 +2118,19 @@ extern "rust-intrinsic" { /// [`f64::round`](../../std/primitive.f64.html#method.round) #[rustc_nounwind] pub fn roundf64(x: f64) -> f64; + /// Returns the nearest integer to an `f128`. Rounds half-way cases away from zero. + /// + /// The stabilized version of this intrinsic is + /// [`f128::round`](../../std/primitive.f128.html#method.round) + #[rustc_nounwind] + pub fn roundf128(x: f128) -> f128; + /// Returns the nearest integer to an `f16`. Rounds half-way cases to the number + /// with an even least significant digit. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + pub fn roundevenf16(x: f16) -> f16; /// Returns the nearest integer to an `f32`. Rounds half-way cases to the number /// with an even least significant digit. /// @@ -1860,6 +2143,12 @@ extern "rust-intrinsic" { /// This intrinsic does not have a stable counterpart. #[rustc_nounwind] pub fn roundevenf64(x: f64) -> f64; + /// Returns the nearest integer to an `f128`. Rounds half-way cases to the number + /// with an even least significant digit. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + pub fn roundevenf128(x: f128) -> f128; /// Float addition that allows optimizations based on algebraic rules. /// May assume inputs are finite. From 90e63ddebba9b0d5a0b03073508867d7878b90f2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 27 Jun 2024 04:13:25 -0500 Subject: [PATCH 11/18] Add math functions for `f16` and `f128` This adds missing functions for math operations on the new float types. Platform support is pretty spotty at this point, since even platforms with generally good support can be missing math functions. `std/build.rs` is updated to reflect this. --- library/std/build.rs | 37 + library/std/src/f128.rs | 1300 ++++++++++++++++++++++- library/std/src/f128/tests.rs | 450 +++++++- library/std/src/f16.rs | 1296 +++++++++++++++++++++- library/std/src/f16/tests.rs | 444 +++++++- library/std/src/macros.rs | 2 +- library/std/src/sys/cmath.rs | 15 + library/std/src/sys/pal/mod.rs | 12 + library/std/src/sys/pal/unix/android.rs | 10 + 9 files changed, 3474 insertions(+), 92 deletions(-) diff --git a/library/std/build.rs b/library/std/build.rs index c542ba81eedc1..256face7aeff6 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -85,6 +85,11 @@ fn main() { println!("cargo:rustc-check-cfg=cfg(reliable_f16)"); println!("cargo:rustc-check-cfg=cfg(reliable_f128)"); + // This is a step beyond only having the types and basic functions available. Math functions + // aren't consistently available or correct. + println!("cargo:rustc-check-cfg=cfg(reliable_f16_math)"); + println!("cargo:rustc-check-cfg=cfg(reliable_f128_math)"); + let has_reliable_f16 = match (target_arch.as_str(), target_os.as_str()) { // Selection failure until recent LLVM // FIXME(llvm19): can probably be removed at the version bump @@ -128,10 +133,42 @@ fn main() { _ => false, }; + // These are currently empty, but will fill up as some platforms move from completely + // unreliable to reliable basics but unreliable math. + + // LLVM is currenlty adding missing routines, + let has_reliable_f16_math = has_reliable_f16 + && match (target_arch.as_str(), target_os.as_str()) { + // Currently nothing special. Hooray! + // This will change as platforms gain better better support for standard ops but math + // lags behind. + _ => true, + }; + + let has_reliable_f128_math = has_reliable_f128 + && match (target_arch.as_str(), target_os.as_str()) { + // LLVM lowers `fp128` math to `long double` symbols even on platforms where + // `long double` is not IEEE binary128. See + // . + // + // This rules out anything that doesn't have `long double` = `binary128`; <= 32 bits + // (ld is `f64`), anything other than Linux (Windows and MacOS use `f64`), and `x86` + // (ld is 80-bit extended precision). + ("x86_64", _) => false, + (_, "linux") if target_pointer_width == 64 => true, + _ => false, + }; + if has_reliable_f16 { println!("cargo:rustc-cfg=reliable_f16"); } if has_reliable_f128 { println!("cargo:rustc-cfg=reliable_f128"); } + if has_reliable_f16_math { + println!("cargo:rustc-cfg=reliable_f16_math"); + } + if has_reliable_f128_math { + println!("cargo:rustc-cfg=reliable_f128_math"); + } } diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs index a5b00d57cefdd..97a57f2f460e9 100644 --- a/library/std/src/f128.rs +++ b/library/std/src/f128.rs @@ -12,25 +12,180 @@ pub use core::f128::consts; #[cfg(not(test))] use crate::intrinsics; +#[cfg(not(test))] +use crate::sys::cmath; #[cfg(not(test))] impl f128 { - /// Raises a number to an integer power. + /// Returns the largest integer less than or equal to `self`. /// - /// Using this function is generally faster than using `powf`. - /// It might have a different sequence of rounding operations than `powf`, - /// so the results are not guaranteed to agree. + /// This function always returns the precise result. /// - /// # Unspecified precision + /// # Examples /// - /// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and - /// can even differ within the same execution from one invocation to the next. + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let f = 3.7_f128; + /// let g = 3.0_f128; + /// let h = -3.7_f128; + /// + /// assert_eq!(f.floor(), 3.0); + /// assert_eq!(g.floor(), 3.0); + /// assert_eq!(h.floor(), -4.0); + /// # } + /// ``` #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn powi(self, n: i32) -> f128 { - unsafe { intrinsics::powif128(self, n) } + pub fn floor(self) -> f128 { + unsafe { intrinsics::floorf128(self) } + } + + /// Returns the smallest integer greater than or equal to `self`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let f = 3.01_f128; + /// let g = 4.0_f128; + /// + /// assert_eq!(f.ceil(), 4.0); + /// assert_eq!(g.ceil(), 4.0); + /// # } + /// ``` + #[inline] + #[doc(alias = "ceiling")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn ceil(self) -> f128 { + unsafe { intrinsics::ceilf128(self) } + } + + /// Returns the nearest integer to `self`. If a value is half-way between two + /// integers, round away from `0.0`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let f = 3.3_f128; + /// let g = -3.3_f128; + /// let h = -3.7_f128; + /// let i = 3.5_f128; + /// let j = 4.5_f128; + /// + /// assert_eq!(f.round(), 3.0); + /// assert_eq!(g.round(), -3.0); + /// assert_eq!(h.round(), -4.0); + /// assert_eq!(i.round(), 4.0); + /// assert_eq!(j.round(), 5.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn round(self) -> f128 { + unsafe { intrinsics::roundf128(self) } + } + + /// Returns the nearest integer to a number. Rounds half-way cases to the number + /// with an even least significant digit. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let f = 3.3_f128; + /// let g = -3.3_f128; + /// let h = 3.5_f128; + /// let i = 4.5_f128; + /// + /// assert_eq!(f.round_ties_even(), 3.0); + /// assert_eq!(g.round_ties_even(), -3.0); + /// assert_eq!(h.round_ties_even(), 4.0); + /// assert_eq!(i.round_ties_even(), 4.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn round_ties_even(self) -> f128 { + unsafe { intrinsics::rintf128(self) } + } + + /// Returns the integer part of `self`. + /// This means that non-integer numbers are always truncated towards zero. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let f = 3.7_f128; + /// let g = 3.0_f128; + /// let h = -3.7_f128; + /// + /// assert_eq!(f.trunc(), 3.0); + /// assert_eq!(g.trunc(), 3.0); + /// assert_eq!(h.trunc(), -3.0); + /// # } + /// ``` + #[inline] + #[doc(alias = "truncate")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn trunc(self) -> f128 { + unsafe { intrinsics::truncf128(self) } + } + + /// Returns the fractional part of `self`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let x = 3.6_f128; + /// let y = -3.6_f128; + /// let abs_difference_x = (x.fract() - 0.6).abs(); + /// let abs_difference_y = (y.fract() - (-0.6)).abs(); + /// + /// assert!(abs_difference_x <= f128::EPSILON); + /// assert!(abs_difference_y <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn fract(self) -> f128 { + self - self.trunc() } /// Computes the absolute value of `self`. @@ -41,7 +196,7 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #[cfg(reliable_f128)] { // FIXME(f16_f128): reliable_f128 + /// # #[cfg(reliable_f128)] { /// /// let x = 3.5_f128; /// let y = -3.5_f128; @@ -61,4 +216,1129 @@ impl f128 { // We don't do this now because LLVM has lowering bugs for f128 math. Self::from_bits(self.to_bits() & !(1 << 127)) } + + /// Returns a number that represents the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - NaN if the number is NaN + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let f = 3.5_f128; + /// + /// assert_eq!(f.signum(), 1.0); + /// assert_eq!(f128::NEG_INFINITY.signum(), -1.0); + /// + /// assert!(f128::NAN.signum().is_nan()); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn signum(self) -> f128 { + if self.is_nan() { Self::NAN } else { 1.0_f128.copysign(self) } + } + + /// Returns a number composed of the magnitude of `self` and the sign of + /// `sign`. + /// + /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise + /// equal to `-self`. If `self` is a NaN, then a NaN with the sign bit of + /// `sign` is returned. Note, however, that conserving the sign bit on NaN + /// across arithmetical operations is not generally guaranteed. + /// See [explanation of NaN as a special value](primitive@f128) for more info. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let f = 3.5_f128; + /// + /// assert_eq!(f.copysign(0.42), 3.5_f128); + /// assert_eq!(f.copysign(-0.42), -3.5_f128); + /// assert_eq!((-f).copysign(0.42), 3.5_f128); + /// assert_eq!((-f).copysign(-0.42), -3.5_f128); + /// + /// assert!(f128::NAN.copysign(1.0).is_nan()); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn copysign(self, sign: f128) -> f128 { + unsafe { intrinsics::copysignf128(self, sign) } + } + + /// Fused multiply-add. Computes `(self * a) + b` with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` *may* be more performant than an unfused multiply-add if + /// the target architecture has a dedicated `fma` CPU instruction. However, + /// this is not always true, and will be heavily dependant on designing + /// algorithms with specific target hardware in mind. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. It is specified by IEEE 754 as + /// `fusedMultiplyAdd` and guaranteed not to change. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let m = 10.0_f128; + /// let x = 4.0_f128; + /// let b = 60.0_f128; + /// + /// assert_eq!(m.mul_add(x, b), 100.0); + /// assert_eq!(m * x + b, 100.0); + /// + /// let one_plus_eps = 1.0_f128 + f128::EPSILON; + /// let one_minus_eps = 1.0_f128 - f128::EPSILON; + /// let minus_one = -1.0_f128; + /// + /// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps. + /// assert_eq!(one_plus_eps.mul_add(one_minus_eps, minus_one), -f128::EPSILON * f128::EPSILON); + /// // Different rounding with the non-fused multiply and add. + /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn mul_add(self, a: f128, b: f128) -> f128 { + unsafe { intrinsics::fmaf128(self, a, b) } + } + + /// Calculates Euclidean division, the matching method for `rem_euclid`. + /// + /// This computes the integer `n` such that + /// `self = n * rhs + self.rem_euclid(rhs)`. + /// In other words, the result is `self / rhs` rounded to the integer `n` + /// such that `self >= n * rhs`. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let a: f128 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0 + /// assert_eq!((-a).div_euclid(b), -2.0); // -7.0 >= 4.0 * -2.0 + /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0 + /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0 + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn div_euclid(self, rhs: f128) -> f128 { + let q = (self / rhs).trunc(); + if self % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; + } + q + } + + /// Calculates the least nonnegative remainder of `self (mod rhs)`. + /// + /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in + /// most cases. However, due to a floating point round-off error it can + /// result in `r == rhs.abs()`, violating the mathematical definition, if + /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. + /// This result is not an element of the function's codomain, but it is the + /// closest floating point number in the real numbers and thus fulfills the + /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)` + /// approximately. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let a: f128 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.rem_euclid(b), 3.0); + /// assert_eq!((-a).rem_euclid(b), 1.0); + /// assert_eq!(a.rem_euclid(-b), 3.0); + /// assert_eq!((-a).rem_euclid(-b), 1.0); + /// // limitation due to round-off error + /// assert!((-f128::EPSILON).rem_euclid(3.0) != 0.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[doc(alias = "modulo", alias = "mod")] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn rem_euclid(self, rhs: f128) -> f128 { + let r = self % rhs; + if r < 0.0 { r + rhs.abs() } else { r } + } + + /// Raises a number to an integer power. + /// + /// Using this function is generally faster than using `powf`. + /// It might have a different sequence of rounding operations than `powf`, + /// so the results are not guaranteed to agree. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn powi(self, n: i32) -> f128 { + unsafe { intrinsics::powif128(self, n) } + } + + /// Raises a number to a floating point power. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let x = 2.0_f128; + /// let abs_difference = (x.powf(2.0) - (x * x)).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn powf(self, n: f128) -> f128 { + unsafe { intrinsics::powf128(self, n) } + } + + /// Returns the square root of a number. + /// + /// Returns NaN if `self` is a negative number other than `-0.0`. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. It is specified by IEEE 754 as `squareRoot` + /// and guaranteed not to change. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let positive = 4.0_f128; + /// let negative = -4.0_f128; + /// let negative_zero = -0.0_f128; + /// + /// assert_eq!(positive.sqrt(), 2.0); + /// assert!(negative.sqrt().is_nan()); + /// assert!(negative_zero.sqrt() == negative_zero); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn sqrt(self) -> f128 { + unsafe { intrinsics::sqrtf128(self) } + } + + /// Returns `e^(self)`, (the exponential function). + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let one = 1.0f128; + /// // e^1 + /// let e = one.exp(); + /// + /// // ln(e) - 1 == 0 + /// let abs_difference = (e.ln() - 1.0).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn exp(self) -> f128 { + unsafe { intrinsics::expf128(self) } + } + + /// Returns `2^(self)`. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let f = 2.0f128; + /// + /// // 2^2 - 4 == 0 + /// let abs_difference = (f.exp2() - 4.0).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn exp2(self) -> f128 { + unsafe { intrinsics::exp2f128(self) } + } + + /// Returns the natural logarithm of the number. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let one = 1.0f128; + /// // e^1 + /// let e = one.exp(); + /// + /// // ln(e) - 1 == 0 + /// let abs_difference = (e.ln() - 1.0).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn ln(self) -> f128 { + unsafe { intrinsics::logf128(self) } + } + + /// Returns the logarithm of the number with respect to an arbitrary base. + /// + /// The result might not be correctly rounded owing to implementation details; + /// `self.log2()` can produce more accurate results for base 2, and + /// `self.log10()` can produce more accurate results for base 10. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let five = 5.0f128; + /// + /// // log5(5) - 1 == 0 + /// let abs_difference = (five.log(5.0) - 1.0).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn log(self, base: f128) -> f128 { + self.ln() / base.ln() + } + + /// Returns the base 2 logarithm of the number. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let two = 2.0f128; + /// + /// // log2(2) - 1 == 0 + /// let abs_difference = (two.log2() - 1.0).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn log2(self) -> f128 { + crate::sys::log2f128(self) + } + + /// Returns the base 10 logarithm of the number. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let ten = 10.0f128; + /// + /// // log10(10) - 1 == 0 + /// let abs_difference = (ten.log10() - 1.0).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn log10(self) -> f128 { + unsafe { intrinsics::log10f128(self) } + } + + /// Returns the cube root of a number. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// + /// This function currently corresponds to the `cbrtf128` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let x = 8.0f128; + /// + /// // x^(1/3) - 2 == 0 + /// let abs_difference = (x.cbrt() - 2.0).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn cbrt(self) -> f128 { + unsafe { cmath::cbrtf128(self) } + } + + /// Compute the distance between the origin and a point (`x`, `y`) on the + /// Euclidean plane. Equivalently, compute the length of the hypotenuse of a + /// right-angle triangle with other sides having length `x.abs()` and + /// `y.abs()`. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// + /// This function currently corresponds to the `hypotf128` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let x = 2.0f128; + /// let y = 3.0f128; + /// + /// // sqrt(x^2 + y^2) + /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn hypot(self, other: f128) -> f128 { + unsafe { cmath::hypotf128(self, other) } + } + + /// Computes the sine of a number (in radians). + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let x = std::f128::consts::FRAC_PI_2; + /// + /// let abs_difference = (x.sin() - 1.0).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn sin(self) -> f128 { + unsafe { intrinsics::sinf128(self) } + } + + /// Computes the cosine of a number (in radians). + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let x = 2.0 * std::f128::consts::PI; + /// + /// let abs_difference = (x.cos() - 1.0).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn cos(self) -> f128 { + unsafe { intrinsics::cosf128(self) } + } + + /// Computes the tangent of a number (in radians). + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `tanf128` from libc on Unix and + /// Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let x = std::f128::consts::FRAC_PI_4; + /// let abs_difference = (x.tan() - 1.0).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn tan(self) -> f128 { + unsafe { cmath::tanf128(self) } + } + + /// Computes the arcsine of a number. Return value is in radians in + /// the range [-pi/2, pi/2] or NaN if the number is outside the range + /// [-1, 1]. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `asinf128` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let f = std::f128::consts::FRAC_PI_2; + /// + /// // asin(sin(pi/2)) + /// let abs_difference = (f.sin().asin() - std::f128::consts::FRAC_PI_2).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[doc(alias = "arcsin")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn asin(self) -> f128 { + unsafe { cmath::asinf128(self) } + } + + /// Computes the arccosine of a number. Return value is in radians in + /// the range [0, pi] or NaN if the number is outside the range + /// [-1, 1]. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `acosf128` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let f = std::f128::consts::FRAC_PI_4; + /// + /// // acos(cos(pi/4)) + /// let abs_difference = (f.cos().acos() - std::f128::consts::FRAC_PI_4).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[doc(alias = "arccos")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn acos(self) -> f128 { + unsafe { cmath::acosf128(self) } + } + + /// Computes the arctangent of a number. Return value is in radians in the + /// range [-pi/2, pi/2]; + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `atanf128` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let f = 1.0f128; + /// + /// // atan(tan(1)) + /// let abs_difference = (f.tan().atan() - 1.0).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[doc(alias = "arctan")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn atan(self) -> f128 { + unsafe { cmath::atanf128(self) } + } + + /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. + /// + /// * `x = 0`, `y = 0`: `0` + /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` + /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` + /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `atan2f128` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// // Positive angles measured counter-clockwise + /// // from positive x axis + /// // -pi/4 radians (45 deg clockwise) + /// let x1 = 3.0f128; + /// let y1 = -3.0f128; + /// + /// // 3pi/4 radians (135 deg counter-clockwise) + /// let x2 = -3.0f128; + /// let y2 = 3.0f128; + /// + /// let abs_difference_1 = (y1.atan2(x1) - (-std::f128::consts::FRAC_PI_4)).abs(); + /// let abs_difference_2 = (y2.atan2(x2) - (3.0 * std::f128::consts::FRAC_PI_4)).abs(); + /// + /// assert!(abs_difference_1 <= f128::EPSILON); + /// assert!(abs_difference_2 <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn atan2(self, other: f128) -> f128 { + unsafe { cmath::atan2f128(self, other) } + } + + /// Simultaneously computes the sine and cosine of the number, `x`. Returns + /// `(sin(x), cos(x))`. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `(f128::sin(x), + /// f128::cos(x))`. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let x = std::f128::consts::FRAC_PI_4; + /// let f = x.sin_cos(); + /// + /// let abs_difference_0 = (f.0 - x.sin()).abs(); + /// let abs_difference_1 = (f.1 - x.cos()).abs(); + /// + /// assert!(abs_difference_0 <= f128::EPSILON); + /// assert!(abs_difference_1 <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[doc(alias = "sincos")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + pub fn sin_cos(self) -> (f128, f128) { + (self.sin(), self.cos()) + } + + /// Returns `e^(self) - 1` in a way that is accurate even if the + /// number is close to zero. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `expm1f128` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let x = 1e-8_f128; + /// + /// // for very small x, e^x is approximately 1 + x + x^2 / 2 + /// let approx = x + x * x / 2.0; + /// let abs_difference = (x.exp_m1() - approx).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn exp_m1(self) -> f128 { + unsafe { cmath::expm1f128(self) } + } + + /// Returns `ln(1+n)` (natural logarithm) more accurately than if + /// the operations were performed separately. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `log1pf128` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let x = 1e-8_f128; + /// + /// // for very small x, ln(1 + x) is approximately x - x^2 / 2 + /// let approx = x - x * x / 2.0; + /// let abs_difference = (x.ln_1p() - approx).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// # } + /// ``` + #[inline] + #[doc(alias = "log1p")] + #[must_use = "method returns a new number and does not mutate the original value"] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + pub fn ln_1p(self) -> f128 { + unsafe { cmath::log1pf128(self) } + } + + /// Hyperbolic sine function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `sinhf128` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let e = std::f128::consts::E; + /// let x = 1.0f128; + /// + /// let f = x.sinh(); + /// // Solving sinh() at 1 gives `(e^2-1)/(2e)` + /// let g = ((e * e) - 1.0) / (2.0 * e); + /// let abs_difference = (f - g).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn sinh(self) -> f128 { + unsafe { cmath::sinhf128(self) } + } + + /// Hyperbolic cosine function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `coshf128` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let e = std::f128::consts::E; + /// let x = 1.0f128; + /// let f = x.cosh(); + /// // Solving cosh() at 1 gives this result + /// let g = ((e * e) + 1.0) / (2.0 * e); + /// let abs_difference = (f - g).abs(); + /// + /// // Same result + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn cosh(self) -> f128 { + unsafe { cmath::coshf128(self) } + } + + /// Hyperbolic tangent function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `tanhf128` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let e = std::f128::consts::E; + /// let x = 1.0f128; + /// + /// let f = x.tanh(); + /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))` + /// let g = (1.0 - e.powi(-2)) / (1.0 + e.powi(-2)); + /// let abs_difference = (f - g).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn tanh(self) -> f128 { + unsafe { cmath::tanhf128(self) } + } + + /// Inverse hyperbolic sine function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let x = 1.0f128; + /// let f = x.sinh().asinh(); + /// + /// let abs_difference = (f - x).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[doc(alias = "arcsinh")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn asinh(self) -> f128 { + let ax = self.abs(); + let ix = 1.0 / ax; + (ax + (ax / (Self::hypot(1.0, ix) + ix))).ln_1p().copysign(self) + } + + /// Inverse hyperbolic cosine function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let x = 1.0f128; + /// let f = x.cosh().acosh(); + /// + /// let abs_difference = (f - x).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[doc(alias = "arccosh")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn acosh(self) -> f128 { + if self < 1.0 { + Self::NAN + } else { + (self + ((self - 1.0).sqrt() * (self + 1.0).sqrt())).ln() + } + } + + /// Inverse hyperbolic tangent function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let e = std::f128::consts::E; + /// let f = e.tanh().atanh(); + /// + /// let abs_difference = (f - e).abs(); + /// + /// assert!(abs_difference <= 1e-5); + /// # } + /// ``` + #[inline] + #[doc(alias = "arctanh")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn atanh(self) -> f128 { + 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() + } + + /// Gamma function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `tgammaf128` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// #![feature(float_gamma)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let x = 5.0f128; + /// + /// let abs_difference = (x.gamma() - 24.0).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn gamma(self) -> f128 { + unsafe { cmath::tgammaf128(self) } + } + + /// Natural logarithm of the absolute value of the gamma function + /// + /// The integer part of the tuple indicates the sign of the gamma function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `lgammaf128_r` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// #![feature(float_gamma)] + /// # #[cfg(reliable_f128_math)] { + /// + /// let x = 2.0f128; + /// + /// let abs_difference = (x.ln_gamma().0 - 0.0).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn ln_gamma(self) -> (f128, i32) { + let mut signgamp: i32 = 0; + let x = unsafe { cmath::lgammaf128_r(self, &mut signgamp) }; + (x, signgamp) + } } diff --git a/library/std/src/f128/tests.rs b/library/std/src/f128/tests.rs index 162c8dbad81a1..df806a639f620 100644 --- a/library/std/src/f128/tests.rs +++ b/library/std/src/f128/tests.rs @@ -4,6 +4,21 @@ use crate::f128::consts; use crate::num::{FpCategory as Fp, *}; +// Note these tolerances make sense around zero, but not for more extreme exponents. + +/// For operations that are near exact, usually not involving math of different +/// signs. +const TOL_PRECISE: f128 = 1e-28; + +/// Default tolerances. Works for values that should be near precise but not exact. Roughly +/// the precision carried by `100 * 100`. +const TOL: f128 = 1e-12; + +/// Tolerances for math that is allowed to be imprecise, usually due to multiple chained +/// operations. +#[cfg(reliable_f128_math)] +const TOL_IMPR: f128 = 1e-10; + /// Smallest number const TINY_BITS: u128 = 0x1; @@ -191,9 +206,100 @@ fn test_classify() { assert_eq!(1e-4932f128.classify(), Fp::Subnormal); } -// FIXME(f16_f128): add missing math functions when available +#[test] +#[cfg(reliable_f128_math)] +fn test_floor() { + assert_approx_eq!(1.0f128.floor(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.3f128.floor(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.5f128.floor(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.7f128.floor(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(0.0f128.floor(), 0.0f128, TOL_PRECISE); + assert_approx_eq!((-0.0f128).floor(), -0.0f128, TOL_PRECISE); + assert_approx_eq!((-1.0f128).floor(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.3f128).floor(), -2.0f128, TOL_PRECISE); + assert_approx_eq!((-1.5f128).floor(), -2.0f128, TOL_PRECISE); + assert_approx_eq!((-1.7f128).floor(), -2.0f128, TOL_PRECISE); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_ceil() { + assert_approx_eq!(1.0f128.ceil(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.3f128.ceil(), 2.0f128, TOL_PRECISE); + assert_approx_eq!(1.5f128.ceil(), 2.0f128, TOL_PRECISE); + assert_approx_eq!(1.7f128.ceil(), 2.0f128, TOL_PRECISE); + assert_approx_eq!(0.0f128.ceil(), 0.0f128, TOL_PRECISE); + assert_approx_eq!((-0.0f128).ceil(), -0.0f128, TOL_PRECISE); + assert_approx_eq!((-1.0f128).ceil(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.3f128).ceil(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.5f128).ceil(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.7f128).ceil(), -1.0f128, TOL_PRECISE); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_round() { + assert_approx_eq!(2.5f128.round(), 3.0f128, TOL_PRECISE); + assert_approx_eq!(1.0f128.round(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.3f128.round(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.5f128.round(), 2.0f128, TOL_PRECISE); + assert_approx_eq!(1.7f128.round(), 2.0f128, TOL_PRECISE); + assert_approx_eq!(0.0f128.round(), 0.0f128, TOL_PRECISE); + assert_approx_eq!((-0.0f128).round(), -0.0f128, TOL_PRECISE); + assert_approx_eq!((-1.0f128).round(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.3f128).round(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.5f128).round(), -2.0f128, TOL_PRECISE); + assert_approx_eq!((-1.7f128).round(), -2.0f128, TOL_PRECISE); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_round_ties_even() { + assert_approx_eq!(2.5f128.round_ties_even(), 2.0f128, TOL_PRECISE); + assert_approx_eq!(1.0f128.round_ties_even(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.3f128.round_ties_even(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.5f128.round_ties_even(), 2.0f128, TOL_PRECISE); + assert_approx_eq!(1.7f128.round_ties_even(), 2.0f128, TOL_PRECISE); + assert_approx_eq!(0.0f128.round_ties_even(), 0.0f128, TOL_PRECISE); + assert_approx_eq!((-0.0f128).round_ties_even(), -0.0f128, TOL_PRECISE); + assert_approx_eq!((-1.0f128).round_ties_even(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.3f128).round_ties_even(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.5f128).round_ties_even(), -2.0f128, TOL_PRECISE); + assert_approx_eq!((-1.7f128).round_ties_even(), -2.0f128, TOL_PRECISE); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_trunc() { + assert_approx_eq!(1.0f128.trunc(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.3f128.trunc(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.5f128.trunc(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.7f128.trunc(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(0.0f128.trunc(), 0.0f128, TOL_PRECISE); + assert_approx_eq!((-0.0f128).trunc(), -0.0f128, TOL_PRECISE); + assert_approx_eq!((-1.0f128).trunc(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.3f128).trunc(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.5f128).trunc(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.7f128).trunc(), -1.0f128, TOL_PRECISE); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_fract() { + assert_approx_eq!(1.0f128.fract(), 0.0f128, TOL_PRECISE); + assert_approx_eq!(1.3f128.fract(), 0.3f128, TOL_PRECISE); + assert_approx_eq!(1.5f128.fract(), 0.5f128, TOL_PRECISE); + assert_approx_eq!(1.7f128.fract(), 0.7f128, TOL_PRECISE); + assert_approx_eq!(0.0f128.fract(), 0.0f128, TOL_PRECISE); + assert_approx_eq!((-0.0f128).fract(), -0.0f128, TOL_PRECISE); + assert_approx_eq!((-1.0f128).fract(), -0.0f128, TOL_PRECISE); + assert_approx_eq!((-1.3f128).fract(), -0.3f128, TOL_PRECISE); + assert_approx_eq!((-1.5f128).fract(), -0.5f128, TOL_PRECISE); + assert_approx_eq!((-1.7f128).fract(), -0.7f128, TOL_PRECISE); +} #[test] +#[cfg(reliable_f128_math)] fn test_abs() { assert_eq!(f128::INFINITY.abs(), f128::INFINITY); assert_eq!(1f128.abs(), 1f128); @@ -293,6 +399,24 @@ fn test_next_down() { } #[test] +#[cfg(reliable_f128_math)] +fn test_mul_add() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + assert_approx_eq!(12.3f128.mul_add(4.5, 6.7), 62.05, TOL_PRECISE); + assert_approx_eq!((-12.3f128).mul_add(-4.5, -6.7), 48.65, TOL_PRECISE); + assert_approx_eq!(0.0f128.mul_add(8.9, 1.2), 1.2, TOL_PRECISE); + assert_approx_eq!(3.4f128.mul_add(-0.0, 5.6), 5.6, TOL_PRECISE); + assert!(nan.mul_add(7.8, 9.0).is_nan()); + assert_eq!(inf.mul_add(7.8, 9.0), inf); + assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); + assert_eq!(8.9f128.mul_add(inf, 3.2), inf); + assert_eq!((-3.2f128).mul_add(2.4, neg_inf), neg_inf); +} + +#[test] +#[cfg(reliable_f16_math)] fn test_recip() { let nan: f128 = f128::NAN; let inf: f128 = f128::INFINITY; @@ -301,11 +425,161 @@ fn test_recip() { assert_eq!(2.0f128.recip(), 0.5); assert_eq!((-0.4f128).recip(), -2.5); assert_eq!(0.0f128.recip(), inf); + assert_approx_eq!( + f128::MAX.recip(), + 8.40525785778023376565669454330438228902076605e-4933, + 1e-4900 + ); assert!(nan.recip().is_nan()); assert_eq!(inf.recip(), 0.0); assert_eq!(neg_inf.recip(), 0.0); } +// Many math functions allow for less accurate results, so the next tolerance up is used + +#[test] +#[cfg(reliable_f128_math)] +fn test_powi() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + assert_eq!(1.0f128.powi(1), 1.0); + assert_approx_eq!((-3.1f128).powi(2), 9.6100000000000005506706202140776519387, TOL); + assert_approx_eq!(5.9f128.powi(-2), 0.028727377190462507313100483690639638451, TOL); + assert_eq!(8.3f128.powi(0), 1.0); + assert!(nan.powi(2).is_nan()); + assert_eq!(inf.powi(3), inf); + assert_eq!(neg_inf.powi(2), inf); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_powf() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + assert_eq!(1.0f128.powf(1.0), 1.0); + assert_approx_eq!(3.4f128.powf(4.5), 246.40818323761892815995637964326426756, TOL_IMPR); + assert_approx_eq!(2.7f128.powf(-3.2), 0.041652009108526178281070304373500889273, TOL_IMPR); + assert_approx_eq!((-3.1f128).powf(2.0), 9.6100000000000005506706202140776519387, TOL_IMPR); + assert_approx_eq!(5.9f128.powf(-2.0), 0.028727377190462507313100483690639638451, TOL_IMPR); + assert_eq!(8.3f128.powf(0.0), 1.0); + assert!(nan.powf(2.0).is_nan()); + assert_eq!(inf.powf(2.0), inf); + assert_eq!(neg_inf.powf(3.0), neg_inf); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_sqrt_domain() { + assert!(f128::NAN.sqrt().is_nan()); + assert!(f128::NEG_INFINITY.sqrt().is_nan()); + assert!((-1.0f128).sqrt().is_nan()); + assert_eq!((-0.0f128).sqrt(), -0.0); + assert_eq!(0.0f128.sqrt(), 0.0); + assert_eq!(1.0f128.sqrt(), 1.0); + assert_eq!(f128::INFINITY.sqrt(), f128::INFINITY); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_exp() { + assert_eq!(1.0, 0.0f128.exp()); + assert_approx_eq!(consts::E, 1.0f128.exp(), TOL); + assert_approx_eq!(148.41315910257660342111558004055227962348775, 5.0f128.exp(), TOL); + + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + let nan: f128 = f128::NAN; + assert_eq!(inf, inf.exp()); + assert_eq!(0.0, neg_inf.exp()); + assert!(nan.exp().is_nan()); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_exp2() { + assert_eq!(32.0, 5.0f128.exp2()); + assert_eq!(1.0, 0.0f128.exp2()); + + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + let nan: f128 = f128::NAN; + assert_eq!(inf, inf.exp2()); + assert_eq!(0.0, neg_inf.exp2()); + assert!(nan.exp2().is_nan()); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_ln() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + assert_approx_eq!(1.0f128.exp().ln(), 1.0, TOL); + assert!(nan.ln().is_nan()); + assert_eq!(inf.ln(), inf); + assert!(neg_inf.ln().is_nan()); + assert!((-2.3f128).ln().is_nan()); + assert_eq!((-0.0f128).ln(), neg_inf); + assert_eq!(0.0f128.ln(), neg_inf); + assert_approx_eq!(4.0f128.ln(), 1.3862943611198906188344642429163531366, TOL); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_log() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + assert_eq!(10.0f128.log(10.0), 1.0); + assert_approx_eq!(2.3f128.log(3.5), 0.66485771361478710036766645911922010272, TOL); + assert_eq!(1.0f128.exp().log(1.0f128.exp()), 1.0); + assert!(1.0f128.log(1.0).is_nan()); + assert!(1.0f128.log(-13.9).is_nan()); + assert!(nan.log(2.3).is_nan()); + assert_eq!(inf.log(10.0), inf); + assert!(neg_inf.log(8.8).is_nan()); + assert!((-2.3f128).log(0.1).is_nan()); + assert_eq!((-0.0f128).log(2.0), neg_inf); + assert_eq!(0.0f128.log(7.0), neg_inf); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_log2() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + assert_approx_eq!(10.0f128.log2(), 3.32192809488736234787031942948939017, TOL); + assert_approx_eq!(2.3f128.log2(), 1.2016338611696504130002982471978765921, TOL); + assert_approx_eq!(1.0f128.exp().log2(), 1.4426950408889634073599246810018921381, TOL); + assert!(nan.log2().is_nan()); + assert_eq!(inf.log2(), inf); + assert!(neg_inf.log2().is_nan()); + assert!((-2.3f128).log2().is_nan()); + assert_eq!((-0.0f128).log2(), neg_inf); + assert_eq!(0.0f128.log2(), neg_inf); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_log10() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + assert_eq!(10.0f128.log10(), 1.0); + assert_approx_eq!(2.3f128.log10(), 0.36172783601759284532595218865859309898, TOL); + assert_approx_eq!(1.0f128.exp().log10(), 0.43429448190325182765112891891660508222, TOL); + assert_eq!(1.0f128.log10(), 0.0); + assert!(nan.log10().is_nan()); + assert_eq!(inf.log10(), inf); + assert!(neg_inf.log10().is_nan()); + assert!((-2.3f128).log10().is_nan()); + assert_eq!((-0.0f128).log10(), neg_inf); + assert_eq!(0.0f128.log10(), neg_inf); +} + #[test] fn test_to_degrees() { let pi: f128 = consts::PI; @@ -313,8 +587,8 @@ fn test_to_degrees() { let inf: f128 = f128::INFINITY; let neg_inf: f128 = f128::NEG_INFINITY; assert_eq!(0.0f128.to_degrees(), 0.0); - assert_approx_eq!((-5.8f128).to_degrees(), -332.315521); - assert_eq!(pi.to_degrees(), 180.0); + assert_approx_eq!((-5.8f128).to_degrees(), -332.31552117587745090765431723855668471, TOL); + assert_approx_eq!(pi.to_degrees(), 180.0, TOL); assert!(nan.to_degrees().is_nan()); assert_eq!(inf.to_degrees(), inf); assert_eq!(neg_inf.to_degrees(), neg_inf); @@ -328,19 +602,122 @@ fn test_to_radians() { let inf: f128 = f128::INFINITY; let neg_inf: f128 = f128::NEG_INFINITY; assert_eq!(0.0f128.to_radians(), 0.0); - assert_approx_eq!(154.6f128.to_radians(), 2.698279); - assert_approx_eq!((-332.31f128).to_radians(), -5.799903); + assert_approx_eq!(154.6f128.to_radians(), 2.6982790235832334267135442069489767804, TOL); + assert_approx_eq!((-332.31f128).to_radians(), -5.7999036373023566567593094812182763013, TOL); // check approx rather than exact because round trip for pi doesn't fall on an exactly // representable value (unlike `f32` and `f64`). - assert_approx_eq!(180.0f128.to_radians(), pi); + assert_approx_eq!(180.0f128.to_radians(), pi, TOL_PRECISE); assert!(nan.to_radians().is_nan()); assert_eq!(inf.to_radians(), inf); assert_eq!(neg_inf.to_radians(), neg_inf); } +#[test] +#[cfg(reliable_f128_math)] +fn test_asinh() { + // Lower accuracy results are allowed, use increased tolerances + assert_eq!(0.0f128.asinh(), 0.0f128); + assert_eq!((-0.0f128).asinh(), -0.0f128); + + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + let nan: f128 = f128::NAN; + assert_eq!(inf.asinh(), inf); + assert_eq!(neg_inf.asinh(), neg_inf); + assert!(nan.asinh().is_nan()); + assert!((-0.0f128).asinh().is_sign_negative()); + + // issue 63271 + assert_approx_eq!(2.0f128.asinh(), 1.443635475178810342493276740273105f128, TOL_IMPR); + assert_approx_eq!((-2.0f128).asinh(), -1.443635475178810342493276740273105f128, TOL_IMPR); + // regression test for the catastrophic cancellation fixed in 72486 + assert_approx_eq!( + (-67452098.07139316f128).asinh(), + -18.720075426274544393985484294000831757220, + TOL_IMPR + ); + + // test for low accuracy from issue 104548 + assert_approx_eq!(60.0f128, 60.0f128.sinh().asinh(), TOL_IMPR); + // mul needed for approximate comparison to be meaningful + assert_approx_eq!(1.0f128, 1e-15f128.sinh().asinh() * 1e15f128, TOL_IMPR); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_acosh() { + assert_eq!(1.0f128.acosh(), 0.0f128); + assert!(0.999f128.acosh().is_nan()); + + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + let nan: f128 = f128::NAN; + assert_eq!(inf.acosh(), inf); + assert!(neg_inf.acosh().is_nan()); + assert!(nan.acosh().is_nan()); + assert_approx_eq!(2.0f128.acosh(), 1.31695789692481670862504634730796844f128, TOL_IMPR); + assert_approx_eq!(3.0f128.acosh(), 1.76274717403908605046521864995958461f128, TOL_IMPR); + + // test for low accuracy from issue 104548 + assert_approx_eq!(60.0f128, 60.0f128.cosh().acosh(), TOL_IMPR); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_atanh() { + assert_eq!(0.0f128.atanh(), 0.0f128); + assert_eq!((-0.0f128).atanh(), -0.0f128); + + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + let nan: f128 = f128::NAN; + assert_eq!(1.0f128.atanh(), inf); + assert_eq!((-1.0f128).atanh(), neg_inf); + assert!(2f128.atanh().atanh().is_nan()); + assert!((-2f128).atanh().atanh().is_nan()); + assert!(inf.atanh().is_nan()); + assert!(neg_inf.atanh().is_nan()); + assert!(nan.atanh().is_nan()); + assert_approx_eq!(0.5f128.atanh(), 0.54930614433405484569762261846126285f128, TOL_IMPR); + assert_approx_eq!((-0.5f128).atanh(), -0.54930614433405484569762261846126285f128, TOL_IMPR); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_gamma() { + // precision can differ among platforms + assert_approx_eq!(1.0f128.gamma(), 1.0f128, TOL_IMPR); + assert_approx_eq!(2.0f128.gamma(), 1.0f128, TOL_IMPR); + assert_approx_eq!(3.0f128.gamma(), 2.0f128, TOL_IMPR); + assert_approx_eq!(4.0f128.gamma(), 6.0f128, TOL_IMPR); + assert_approx_eq!(5.0f128.gamma(), 24.0f128, TOL_IMPR); + assert_approx_eq!(0.5f128.gamma(), consts::PI.sqrt(), TOL_IMPR); + assert_approx_eq!((-0.5f128).gamma(), -2.0 * consts::PI.sqrt(), TOL_IMPR); + assert_eq!(0.0f128.gamma(), f128::INFINITY); + assert_eq!((-0.0f128).gamma(), f128::NEG_INFINITY); + assert!((-1.0f128).gamma().is_nan()); + assert!((-2.0f128).gamma().is_nan()); + assert!(f128::NAN.gamma().is_nan()); + assert!(f128::NEG_INFINITY.gamma().is_nan()); + assert_eq!(f128::INFINITY.gamma(), f128::INFINITY); + assert_eq!(1760.9f128.gamma(), f128::INFINITY); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_ln_gamma() { + assert_approx_eq!(1.0f128.ln_gamma().0, 0.0f128, TOL_IMPR); + assert_eq!(1.0f128.ln_gamma().1, 1); + assert_approx_eq!(2.0f128.ln_gamma().0, 0.0f128, TOL_IMPR); + assert_eq!(2.0f128.ln_gamma().1, 1); + assert_approx_eq!(3.0f128.ln_gamma().0, 2.0f128.ln(), TOL_IMPR); + assert_eq!(3.0f128.ln_gamma().1, 1); + assert_approx_eq!((-0.5f128).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln(), TOL_IMPR); + assert_eq!((-0.5f128).ln_gamma().1, -1); +} + #[test] fn test_real_consts() { - // FIXME(f16_f128): add math tests when available use super::consts; let pi: f128 = consts::PI; @@ -351,29 +728,34 @@ fn test_real_consts() { let frac_pi_8: f128 = consts::FRAC_PI_8; let frac_1_pi: f128 = consts::FRAC_1_PI; let frac_2_pi: f128 = consts::FRAC_2_PI; - // let frac_2_sqrtpi: f128 = consts::FRAC_2_SQRT_PI; - // let sqrt2: f128 = consts::SQRT_2; - // let frac_1_sqrt2: f128 = consts::FRAC_1_SQRT_2; - // let e: f128 = consts::E; - // let log2_e: f128 = consts::LOG2_E; - // let log10_e: f128 = consts::LOG10_E; - // let ln_2: f128 = consts::LN_2; - // let ln_10: f128 = consts::LN_10; - - assert_approx_eq!(frac_pi_2, pi / 2f128); - assert_approx_eq!(frac_pi_3, pi / 3f128); - assert_approx_eq!(frac_pi_4, pi / 4f128); - assert_approx_eq!(frac_pi_6, pi / 6f128); - assert_approx_eq!(frac_pi_8, pi / 8f128); - assert_approx_eq!(frac_1_pi, 1f128 / pi); - assert_approx_eq!(frac_2_pi, 2f128 / pi); - // assert_approx_eq!(frac_2_sqrtpi, 2f128 / pi.sqrt()); - // assert_approx_eq!(sqrt2, 2f128.sqrt()); - // assert_approx_eq!(frac_1_sqrt2, 1f128 / 2f128.sqrt()); - // assert_approx_eq!(log2_e, e.log2()); - // assert_approx_eq!(log10_e, e.log10()); - // assert_approx_eq!(ln_2, 2f128.ln()); - // assert_approx_eq!(ln_10, 10f128.ln()); + + assert_approx_eq!(frac_pi_2, pi / 2f128, TOL_PRECISE); + assert_approx_eq!(frac_pi_3, pi / 3f128, TOL_PRECISE); + assert_approx_eq!(frac_pi_4, pi / 4f128, TOL_PRECISE); + assert_approx_eq!(frac_pi_6, pi / 6f128, TOL_PRECISE); + assert_approx_eq!(frac_pi_8, pi / 8f128, TOL_PRECISE); + assert_approx_eq!(frac_1_pi, 1f128 / pi, TOL_PRECISE); + assert_approx_eq!(frac_2_pi, 2f128 / pi, TOL_PRECISE); + + #[cfg(reliable_f128_math)] + { + let frac_2_sqrtpi: f128 = consts::FRAC_2_SQRT_PI; + let sqrt2: f128 = consts::SQRT_2; + let frac_1_sqrt2: f128 = consts::FRAC_1_SQRT_2; + let e: f128 = consts::E; + let log2_e: f128 = consts::LOG2_E; + let log10_e: f128 = consts::LOG10_E; + let ln_2: f128 = consts::LN_2; + let ln_10: f128 = consts::LN_10; + + assert_approx_eq!(frac_2_sqrtpi, 2f128 / pi.sqrt(), TOL_PRECISE); + assert_approx_eq!(sqrt2, 2f128.sqrt(), TOL_PRECISE); + assert_approx_eq!(frac_1_sqrt2, 1f128 / 2f128.sqrt(), TOL_PRECISE); + assert_approx_eq!(log2_e, e.log2(), TOL_PRECISE); + assert_approx_eq!(log10_e, e.log10(), TOL_PRECISE); + assert_approx_eq!(ln_2, 2f128.ln(), TOL_PRECISE); + assert_approx_eq!(ln_10, 10f128.ln(), TOL_PRECISE); + } } #[test] @@ -382,10 +764,10 @@ fn test_float_bits_conv() { assert_eq!((12.5f128).to_bits(), 0x40029000000000000000000000000000); assert_eq!((1337f128).to_bits(), 0x40094e40000000000000000000000000); assert_eq!((-14.25f128).to_bits(), 0xc002c800000000000000000000000000); - assert_approx_eq!(f128::from_bits(0x3fff0000000000000000000000000000), 1.0); - assert_approx_eq!(f128::from_bits(0x40029000000000000000000000000000), 12.5); - assert_approx_eq!(f128::from_bits(0x40094e40000000000000000000000000), 1337.0); - assert_approx_eq!(f128::from_bits(0xc002c800000000000000000000000000), -14.25); + assert_approx_eq!(f128::from_bits(0x3fff0000000000000000000000000000), 1.0, TOL_PRECISE); + assert_approx_eq!(f128::from_bits(0x40029000000000000000000000000000), 12.5, TOL_PRECISE); + assert_approx_eq!(f128::from_bits(0x40094e40000000000000000000000000), 1337.0, TOL_PRECISE); + assert_approx_eq!(f128::from_bits(0xc002c800000000000000000000000000), -14.25, TOL_PRECISE); // Check that NaNs roundtrip their bits regardless of signaling-ness // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs index e3024defed734..55877316e5b98 100644 --- a/library/std/src/f16.rs +++ b/library/std/src/f16.rs @@ -12,25 +12,180 @@ pub use core::f16::consts; #[cfg(not(test))] use crate::intrinsics; +#[cfg(not(test))] +use crate::sys::cmath; #[cfg(not(test))] impl f16 { - /// Raises a number to an integer power. + /// Returns the largest integer less than or equal to `self`. /// - /// Using this function is generally faster than using `powf`. - /// It might have a different sequence of rounding operations than `powf`, - /// so the results are not guaranteed to agree. + /// This function always returns the precise result. /// - /// # Unspecified precision + /// # Examples /// - /// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and - /// can even differ within the same execution from one invocation to the next. + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let f = 3.7_f16; + /// let g = 3.0_f16; + /// let h = -3.7_f16; + /// + /// assert_eq!(f.floor(), 3.0); + /// assert_eq!(g.floor(), 3.0); + /// assert_eq!(h.floor(), -4.0); + /// # } + /// ``` #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn powi(self, n: i32) -> f16 { - unsafe { intrinsics::powif16(self, n) } + pub fn floor(self) -> f16 { + unsafe { intrinsics::floorf16(self) } + } + + /// Returns the smallest integer greater than or equal to `self`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let f = 3.01_f16; + /// let g = 4.0_f16; + /// + /// assert_eq!(f.ceil(), 4.0); + /// assert_eq!(g.ceil(), 4.0); + /// # } + /// ``` + #[inline] + #[doc(alias = "ceiling")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn ceil(self) -> f16 { + unsafe { intrinsics::ceilf16(self) } + } + + /// Returns the nearest integer to `self`. If a value is half-way between two + /// integers, round away from `0.0`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let f = 3.3_f16; + /// let g = -3.3_f16; + /// let h = -3.7_f16; + /// let i = 3.5_f16; + /// let j = 4.5_f16; + /// + /// assert_eq!(f.round(), 3.0); + /// assert_eq!(g.round(), -3.0); + /// assert_eq!(h.round(), -4.0); + /// assert_eq!(i.round(), 4.0); + /// assert_eq!(j.round(), 5.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn round(self) -> f16 { + unsafe { intrinsics::roundf16(self) } + } + + /// Returns the nearest integer to a number. Rounds half-way cases to the number + /// with an even least significant digit. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let f = 3.3_f16; + /// let g = -3.3_f16; + /// let h = 3.5_f16; + /// let i = 4.5_f16; + /// + /// assert_eq!(f.round_ties_even(), 3.0); + /// assert_eq!(g.round_ties_even(), -3.0); + /// assert_eq!(h.round_ties_even(), 4.0); + /// assert_eq!(i.round_ties_even(), 4.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn round_ties_even(self) -> f16 { + unsafe { intrinsics::rintf16(self) } + } + + /// Returns the integer part of `self`. + /// This means that non-integer numbers are always truncated towards zero. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let f = 3.7_f16; + /// let g = 3.0_f16; + /// let h = -3.7_f16; + /// + /// assert_eq!(f.trunc(), 3.0); + /// assert_eq!(g.trunc(), 3.0); + /// assert_eq!(h.trunc(), -3.0); + /// # } + /// ``` + #[inline] + #[doc(alias = "truncate")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn trunc(self) -> f16 { + unsafe { intrinsics::truncf16(self) } + } + + /// Returns the fractional part of `self`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let x = 3.6_f16; + /// let y = -3.6_f16; + /// let abs_difference_x = (x.fract() - 0.6).abs(); + /// let abs_difference_y = (y.fract() - (-0.6)).abs(); + /// + /// assert!(abs_difference_x <= f16::EPSILON); + /// assert!(abs_difference_y <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn fract(self) -> f16 { + self - self.trunc() } /// Computes the absolute value of `self`. @@ -60,4 +215,1127 @@ impl f16 { // FIXME(f16_f128): replace with `intrinsics::fabsf16` when available Self::from_bits(self.to_bits() & !(1 << 15)) } + + /// Returns a number that represents the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - NaN if the number is NaN + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let f = 3.5_f16; + /// + /// assert_eq!(f.signum(), 1.0); + /// assert_eq!(f16::NEG_INFINITY.signum(), -1.0); + /// + /// assert!(f16::NAN.signum().is_nan()); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn signum(self) -> f16 { + if self.is_nan() { Self::NAN } else { 1.0_f16.copysign(self) } + } + + /// Returns a number composed of the magnitude of `self` and the sign of + /// `sign`. + /// + /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise + /// equal to `-self`. If `self` is a NaN, then a NaN with the sign bit of + /// `sign` is returned. Note, however, that conserving the sign bit on NaN + /// across arithmetical operations is not generally guaranteed. + /// See [explanation of NaN as a special value](primitive@f16) for more info. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let f = 3.5_f16; + /// + /// assert_eq!(f.copysign(0.42), 3.5_f16); + /// assert_eq!(f.copysign(-0.42), -3.5_f16); + /// assert_eq!((-f).copysign(0.42), 3.5_f16); + /// assert_eq!((-f).copysign(-0.42), -3.5_f16); + /// + /// assert!(f16::NAN.copysign(1.0).is_nan()); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn copysign(self, sign: f16) -> f16 { + unsafe { intrinsics::copysignf16(self, sign) } + } + + /// Fused multiply-add. Computes `(self * a) + b` with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` *may* be more performant than an unfused multiply-add if + /// the target architecture has a dedicated `fma` CPU instruction. However, + /// this is not always true, and will be heavily dependant on designing + /// algorithms with specific target hardware in mind. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. It is specified by IEEE 754 as + /// `fusedMultiplyAdd` and guaranteed not to change. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let m = 10.0_f16; + /// let x = 4.0_f16; + /// let b = 60.0_f16; + /// + /// assert_eq!(m.mul_add(x, b), 100.0); + /// assert_eq!(m * x + b, 100.0); + /// + /// let one_plus_eps = 1.0_f16 + f16::EPSILON; + /// let one_minus_eps = 1.0_f16 - f16::EPSILON; + /// let minus_one = -1.0_f16; + /// + /// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps. + /// assert_eq!(one_plus_eps.mul_add(one_minus_eps, minus_one), -f16::EPSILON * f16::EPSILON); + /// // Different rounding with the non-fused multiply and add. + /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn mul_add(self, a: f16, b: f16) -> f16 { + unsafe { intrinsics::fmaf16(self, a, b) } + } + + /// Calculates Euclidean division, the matching method for `rem_euclid`. + /// + /// This computes the integer `n` such that + /// `self = n * rhs + self.rem_euclid(rhs)`. + /// In other words, the result is `self / rhs` rounded to the integer `n` + /// such that `self >= n * rhs`. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let a: f16 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0 + /// assert_eq!((-a).div_euclid(b), -2.0); // -7.0 >= 4.0 * -2.0 + /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0 + /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0 + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn div_euclid(self, rhs: f16) -> f16 { + let q = (self / rhs).trunc(); + if self % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; + } + q + } + + /// Calculates the least nonnegative remainder of `self (mod rhs)`. + /// + /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in + /// most cases. However, due to a floating point round-off error it can + /// result in `r == rhs.abs()`, violating the mathematical definition, if + /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. + /// This result is not an element of the function's codomain, but it is the + /// closest floating point number in the real numbers and thus fulfills the + /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)` + /// approximately. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let a: f16 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.rem_euclid(b), 3.0); + /// assert_eq!((-a).rem_euclid(b), 1.0); + /// assert_eq!(a.rem_euclid(-b), 3.0); + /// assert_eq!((-a).rem_euclid(-b), 1.0); + /// // limitation due to round-off error + /// assert!((-f16::EPSILON).rem_euclid(3.0) != 0.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[doc(alias = "modulo", alias = "mod")] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn rem_euclid(self, rhs: f16) -> f16 { + let r = self % rhs; + if r < 0.0 { r + rhs.abs() } else { r } + } + + /// Raises a number to an integer power. + /// + /// Using this function is generally faster than using `powf`. + /// It might have a different sequence of rounding operations than `powf`, + /// so the results are not guaranteed to agree. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn powi(self, n: i32) -> f16 { + unsafe { intrinsics::powif16(self, n) } + } + + /// Raises a number to a floating point power. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let x = 2.0_f16; + /// let abs_difference = (x.powf(2.0) - (x * x)).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn powf(self, n: f16) -> f16 { + unsafe { intrinsics::powf16(self, n) } + } + + /// Returns the square root of a number. + /// + /// Returns NaN if `self` is a negative number other than `-0.0`. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. It is specified by IEEE 754 as `squareRoot` + /// and guaranteed not to change. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let positive = 4.0_f16; + /// let negative = -4.0_f16; + /// let negative_zero = -0.0_f16; + /// + /// assert_eq!(positive.sqrt(), 2.0); + /// assert!(negative.sqrt().is_nan()); + /// assert!(negative_zero.sqrt() == negative_zero); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn sqrt(self) -> f16 { + unsafe { intrinsics::sqrtf16(self) } + } + + /// Returns `e^(self)`, (the exponential function). + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let one = 1.0f16; + /// // e^1 + /// let e = one.exp(); + /// + /// // ln(e) - 1 == 0 + /// let abs_difference = (e.ln() - 1.0).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn exp(self) -> f16 { + unsafe { intrinsics::expf16(self) } + } + + /// Returns `2^(self)`. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let f = 2.0f16; + /// + /// // 2^2 - 4 == 0 + /// let abs_difference = (f.exp2() - 4.0).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn exp2(self) -> f16 { + unsafe { intrinsics::exp2f16(self) } + } + + /// Returns the natural logarithm of the number. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let one = 1.0f16; + /// // e^1 + /// let e = one.exp(); + /// + /// // ln(e) - 1 == 0 + /// let abs_difference = (e.ln() - 1.0).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn ln(self) -> f16 { + unsafe { intrinsics::logf16(self) } + } + + /// Returns the logarithm of the number with respect to an arbitrary base. + /// + /// The result might not be correctly rounded owing to implementation details; + /// `self.log2()` can produce more accurate results for base 2, and + /// `self.log10()` can produce more accurate results for base 10. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let five = 5.0f16; + /// + /// // log5(5) - 1 == 0 + /// let abs_difference = (five.log(5.0) - 1.0).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn log(self, base: f16) -> f16 { + self.ln() / base.ln() + } + + /// Returns the base 2 logarithm of the number. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let two = 2.0f16; + /// + /// // log2(2) - 1 == 0 + /// let abs_difference = (two.log2() - 1.0).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn log2(self) -> f16 { + crate::sys::log2f16(self) + } + + /// Returns the base 10 logarithm of the number. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let ten = 10.0f16; + /// + /// // log10(10) - 1 == 0 + /// let abs_difference = (ten.log10() - 1.0).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn log10(self) -> f16 { + unsafe { intrinsics::log10f16(self) } + } + + /// Returns the cube root of a number. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `cbrtf` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let x = 8.0f16; + /// + /// // x^(1/3) - 2 == 0 + /// let abs_difference = (x.cbrt() - 2.0).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn cbrt(self) -> f16 { + (unsafe { cmath::cbrtf(self as f32) }) as f16 + } + + /// Compute the distance between the origin and a point (`x`, `y`) on the + /// Euclidean plane. Equivalently, compute the length of the hypotenuse of a + /// right-angle triangle with other sides having length `x.abs()` and + /// `y.abs()`. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `hypotf` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let x = 2.0f16; + /// let y = 3.0f16; + /// + /// // sqrt(x^2 + y^2) + /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn hypot(self, other: f16) -> f16 { + (unsafe { cmath::hypotf(self as f32, other as f32) }) as f16 + } + + /// Computes the sine of a number (in radians). + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let x = std::f16::consts::FRAC_PI_2; + /// + /// let abs_difference = (x.sin() - 1.0).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn sin(self) -> f16 { + unsafe { intrinsics::sinf16(self) } + } + + /// Computes the cosine of a number (in radians). + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let x = 2.0 * std::f16::consts::PI; + /// + /// let abs_difference = (x.cos() - 1.0).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn cos(self) -> f16 { + unsafe { intrinsics::cosf16(self) } + } + + /// Computes the tangent of a number (in radians). + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `tanf` from libc on Unix and + /// Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let x = std::f16::consts::FRAC_PI_4; + /// let abs_difference = (x.tan() - 1.0).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn tan(self) -> f16 { + (unsafe { cmath::tanf(self as f32) }) as f16 + } + + /// Computes the arcsine of a number. Return value is in radians in + /// the range [-pi/2, pi/2] or NaN if the number is outside the range + /// [-1, 1]. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `asinf` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let f = std::f16::consts::FRAC_PI_2; + /// + /// // asin(sin(pi/2)) + /// let abs_difference = (f.sin().asin() - std::f16::consts::FRAC_PI_2).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[doc(alias = "arcsin")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn asin(self) -> f16 { + (unsafe { cmath::asinf(self as f32) }) as f16 + } + + /// Computes the arccosine of a number. Return value is in radians in + /// the range [0, pi] or NaN if the number is outside the range + /// [-1, 1]. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `acosf` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let f = std::f16::consts::FRAC_PI_4; + /// + /// // acos(cos(pi/4)) + /// let abs_difference = (f.cos().acos() - std::f16::consts::FRAC_PI_4).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[doc(alias = "arccos")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn acos(self) -> f16 { + (unsafe { cmath::acosf(self as f32) }) as f16 + } + + /// Computes the arctangent of a number. Return value is in radians in the + /// range [-pi/2, pi/2]; + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `atanf` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let f = 1.0f16; + /// + /// // atan(tan(1)) + /// let abs_difference = (f.tan().atan() - 1.0).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[doc(alias = "arctan")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn atan(self) -> f16 { + (unsafe { cmath::atanf(self as f32) }) as f16 + } + + /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. + /// + /// * `x = 0`, `y = 0`: `0` + /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` + /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` + /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `atan2f` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// // Positive angles measured counter-clockwise + /// // from positive x axis + /// // -pi/4 radians (45 deg clockwise) + /// let x1 = 3.0f16; + /// let y1 = -3.0f16; + /// + /// // 3pi/4 radians (135 deg counter-clockwise) + /// let x2 = -3.0f16; + /// let y2 = 3.0f16; + /// + /// let abs_difference_1 = (y1.atan2(x1) - (-std::f16::consts::FRAC_PI_4)).abs(); + /// let abs_difference_2 = (y2.atan2(x2) - (3.0 * std::f16::consts::FRAC_PI_4)).abs(); + /// + /// assert!(abs_difference_1 <= f16::EPSILON); + /// assert!(abs_difference_2 <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn atan2(self, other: f16) -> f16 { + (unsafe { cmath::atan2f(self as f32, other as f32) }) as f16 + } + + /// Simultaneously computes the sine and cosine of the number, `x`. Returns + /// `(sin(x), cos(x))`. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `(f16::sin(x), + /// f16::cos(x))`. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let x = std::f16::consts::FRAC_PI_4; + /// let f = x.sin_cos(); + /// + /// let abs_difference_0 = (f.0 - x.sin()).abs(); + /// let abs_difference_1 = (f.1 - x.cos()).abs(); + /// + /// assert!(abs_difference_0 <= f16::EPSILON); + /// assert!(abs_difference_1 <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[doc(alias = "sincos")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + pub fn sin_cos(self) -> (f16, f16) { + (self.sin(), self.cos()) + } + + /// Returns `e^(self) - 1` in a way that is accurate even if the + /// number is close to zero. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `expm1f` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let x = 1e-4_f16; + /// + /// // for very small x, e^x is approximately 1 + x + x^2 / 2 + /// let approx = x + x * x / 2.0; + /// let abs_difference = (x.exp_m1() - approx).abs(); + /// + /// assert!(abs_difference < 1e-4); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn exp_m1(self) -> f16 { + (unsafe { cmath::expm1f(self as f32) }) as f16 + } + + /// Returns `ln(1+n)` (natural logarithm) more accurately than if + /// the operations were performed separately. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `log1pf` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let x = 1e-4_f16; + /// + /// // for very small x, ln(1 + x) is approximately x - x^2 / 2 + /// let approx = x - x * x / 2.0; + /// let abs_difference = (x.ln_1p() - approx).abs(); + /// + /// assert!(abs_difference < 1e-4); + /// # } + /// ``` + #[inline] + #[doc(alias = "log1p")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn ln_1p(self) -> f16 { + (unsafe { cmath::log1pf(self as f32) }) as f16 + } + + /// Hyperbolic sine function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `sinhf` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let e = std::f16::consts::E; + /// let x = 1.0f16; + /// + /// let f = x.sinh(); + /// // Solving sinh() at 1 gives `(e^2-1)/(2e)` + /// let g = ((e * e) - 1.0) / (2.0 * e); + /// let abs_difference = (f - g).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn sinh(self) -> f16 { + (unsafe { cmath::sinhf(self as f32) }) as f16 + } + + /// Hyperbolic cosine function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `coshf` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let e = std::f16::consts::E; + /// let x = 1.0f16; + /// let f = x.cosh(); + /// // Solving cosh() at 1 gives this result + /// let g = ((e * e) + 1.0) / (2.0 * e); + /// let abs_difference = (f - g).abs(); + /// + /// // Same result + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn cosh(self) -> f16 { + (unsafe { cmath::coshf(self as f32) }) as f16 + } + + /// Hyperbolic tangent function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `tanhf` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let e = std::f16::consts::E; + /// let x = 1.0f16; + /// + /// let f = x.tanh(); + /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))` + /// let g = (1.0 - e.powi(-2)) / (1.0 + e.powi(-2)); + /// let abs_difference = (f - g).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn tanh(self) -> f16 { + (unsafe { cmath::tanhf(self as f32) }) as f16 + } + + /// Inverse hyperbolic sine function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let x = 1.0f16; + /// let f = x.sinh().asinh(); + /// + /// let abs_difference = (f - x).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[doc(alias = "arcsinh")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn asinh(self) -> f16 { + let ax = self.abs(); + let ix = 1.0 / ax; + (ax + (ax / (Self::hypot(1.0, ix) + ix))).ln_1p().copysign(self) + } + + /// Inverse hyperbolic cosine function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let x = 1.0f16; + /// let f = x.cosh().acosh(); + /// + /// let abs_difference = (f - x).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[doc(alias = "arccosh")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn acosh(self) -> f16 { + if self < 1.0 { + Self::NAN + } else { + (self + ((self - 1.0).sqrt() * (self + 1.0).sqrt())).ln() + } + } + + /// Inverse hyperbolic tangent function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let e = std::f16::consts::E; + /// let f = e.tanh().atanh(); + /// + /// let abs_difference = (f - e).abs(); + /// + /// assert!(abs_difference <= 0.01); + /// # } + /// ``` + #[inline] + #[doc(alias = "arctanh")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn atanh(self) -> f16 { + 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() + } + + /// Gamma function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `tgammaf` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// #![feature(float_gamma)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let x = 5.0f16; + /// + /// let abs_difference = (x.gamma() - 24.0).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn gamma(self) -> f16 { + (unsafe { cmath::tgammaf(self as f32) }) as f16 + } + + /// Natural logarithm of the absolute value of the gamma function + /// + /// The integer part of the tuple indicates the sign of the gamma function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `lgamma_r` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// #![feature(float_gamma)] + /// # #[cfg(reliable_f16_math)] { + /// + /// let x = 2.0f16; + /// + /// let abs_difference = (x.ln_gamma().0 - 0.0).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn ln_gamma(self) -> (f16, i32) { + let mut signgamp: i32 = 0; + let x = (unsafe { cmath::lgammaf_r(self as f32, &mut signgamp) }) as f16; + (x, signgamp) + } } diff --git a/library/std/src/f16/tests.rs b/library/std/src/f16/tests.rs index f73bdf68e8295..f0ef807dac141 100644 --- a/library/std/src/f16/tests.rs +++ b/library/std/src/f16/tests.rs @@ -4,11 +4,21 @@ use crate::f16::consts; use crate::num::{FpCategory as Fp, *}; -// We run out of precision pretty quickly with f16 -// const F16_APPROX_L1: f16 = 0.001; -const F16_APPROX_L2: f16 = 0.01; -// const F16_APPROX_L3: f16 = 0.1; -const F16_APPROX_L4: f16 = 0.5; +/// Tolerance for results on the order of 10.0e-2; +#[cfg(reliable_f16_math)] +const TOL_N2: f16 = 0.0001; + +/// Tolerance for results on the order of 10.0e+0 +#[cfg(reliable_f16_math)] +const TOL_0: f16 = 0.01; + +/// Tolerance for results on the order of 10.0e+2 +#[cfg(reliable_f16_math)] +const TOL_P2: f16 = 0.5; + +/// Tolerance for results on the order of 10.0e+4 +#[cfg(reliable_f16_math)] +const TOL_P4: f16 = 10.0; /// Smallest number const TINY_BITS: u16 = 0x1; @@ -197,9 +207,100 @@ fn test_classify() { assert_eq!(1e-5f16.classify(), Fp::Subnormal); } -// FIXME(f16_f128): add missing math functions when available +#[test] +#[cfg(reliable_f16_math)] +fn test_floor() { + assert_approx_eq!(1.0f16.floor(), 1.0f16, TOL_0); + assert_approx_eq!(1.3f16.floor(), 1.0f16, TOL_0); + assert_approx_eq!(1.5f16.floor(), 1.0f16, TOL_0); + assert_approx_eq!(1.7f16.floor(), 1.0f16, TOL_0); + assert_approx_eq!(0.0f16.floor(), 0.0f16, TOL_0); + assert_approx_eq!((-0.0f16).floor(), -0.0f16, TOL_0); + assert_approx_eq!((-1.0f16).floor(), -1.0f16, TOL_0); + assert_approx_eq!((-1.3f16).floor(), -2.0f16, TOL_0); + assert_approx_eq!((-1.5f16).floor(), -2.0f16, TOL_0); + assert_approx_eq!((-1.7f16).floor(), -2.0f16, TOL_0); +} + +#[test] +#[cfg(reliable_f16_math)] +fn test_ceil() { + assert_approx_eq!(1.0f16.ceil(), 1.0f16, TOL_0); + assert_approx_eq!(1.3f16.ceil(), 2.0f16, TOL_0); + assert_approx_eq!(1.5f16.ceil(), 2.0f16, TOL_0); + assert_approx_eq!(1.7f16.ceil(), 2.0f16, TOL_0); + assert_approx_eq!(0.0f16.ceil(), 0.0f16, TOL_0); + assert_approx_eq!((-0.0f16).ceil(), -0.0f16, TOL_0); + assert_approx_eq!((-1.0f16).ceil(), -1.0f16, TOL_0); + assert_approx_eq!((-1.3f16).ceil(), -1.0f16, TOL_0); + assert_approx_eq!((-1.5f16).ceil(), -1.0f16, TOL_0); + assert_approx_eq!((-1.7f16).ceil(), -1.0f16, TOL_0); +} + +#[test] +#[cfg(reliable_f16_math)] +fn test_round() { + assert_approx_eq!(2.5f16.round(), 3.0f16, TOL_0); + assert_approx_eq!(1.0f16.round(), 1.0f16, TOL_0); + assert_approx_eq!(1.3f16.round(), 1.0f16, TOL_0); + assert_approx_eq!(1.5f16.round(), 2.0f16, TOL_0); + assert_approx_eq!(1.7f16.round(), 2.0f16, TOL_0); + assert_approx_eq!(0.0f16.round(), 0.0f16, TOL_0); + assert_approx_eq!((-0.0f16).round(), -0.0f16, TOL_0); + assert_approx_eq!((-1.0f16).round(), -1.0f16, TOL_0); + assert_approx_eq!((-1.3f16).round(), -1.0f16, TOL_0); + assert_approx_eq!((-1.5f16).round(), -2.0f16, TOL_0); + assert_approx_eq!((-1.7f16).round(), -2.0f16, TOL_0); +} + +#[test] +#[cfg(reliable_f16_math)] +fn test_round_ties_even() { + assert_approx_eq!(2.5f16.round_ties_even(), 2.0f16, TOL_0); + assert_approx_eq!(1.0f16.round_ties_even(), 1.0f16, TOL_0); + assert_approx_eq!(1.3f16.round_ties_even(), 1.0f16, TOL_0); + assert_approx_eq!(1.5f16.round_ties_even(), 2.0f16, TOL_0); + assert_approx_eq!(1.7f16.round_ties_even(), 2.0f16, TOL_0); + assert_approx_eq!(0.0f16.round_ties_even(), 0.0f16, TOL_0); + assert_approx_eq!((-0.0f16).round_ties_even(), -0.0f16, TOL_0); + assert_approx_eq!((-1.0f16).round_ties_even(), -1.0f16, TOL_0); + assert_approx_eq!((-1.3f16).round_ties_even(), -1.0f16, TOL_0); + assert_approx_eq!((-1.5f16).round_ties_even(), -2.0f16, TOL_0); + assert_approx_eq!((-1.7f16).round_ties_even(), -2.0f16, TOL_0); +} #[test] +#[cfg(reliable_f16_math)] +fn test_trunc() { + assert_approx_eq!(1.0f16.trunc(), 1.0f16, TOL_0); + assert_approx_eq!(1.3f16.trunc(), 1.0f16, TOL_0); + assert_approx_eq!(1.5f16.trunc(), 1.0f16, TOL_0); + assert_approx_eq!(1.7f16.trunc(), 1.0f16, TOL_0); + assert_approx_eq!(0.0f16.trunc(), 0.0f16, TOL_0); + assert_approx_eq!((-0.0f16).trunc(), -0.0f16, TOL_0); + assert_approx_eq!((-1.0f16).trunc(), -1.0f16, TOL_0); + assert_approx_eq!((-1.3f16).trunc(), -1.0f16, TOL_0); + assert_approx_eq!((-1.5f16).trunc(), -1.0f16, TOL_0); + assert_approx_eq!((-1.7f16).trunc(), -1.0f16, TOL_0); +} + +#[test] +#[cfg(reliable_f16_math)] +fn test_fract() { + assert_approx_eq!(1.0f16.fract(), 0.0f16, TOL_0); + assert_approx_eq!(1.3f16.fract(), 0.3f16, TOL_0); + assert_approx_eq!(1.5f16.fract(), 0.5f16, TOL_0); + assert_approx_eq!(1.7f16.fract(), 0.7f16, TOL_0); + assert_approx_eq!(0.0f16.fract(), 0.0f16, TOL_0); + assert_approx_eq!((-0.0f16).fract(), -0.0f16, TOL_0); + assert_approx_eq!((-1.0f16).fract(), -0.0f16, TOL_0); + assert_approx_eq!((-1.3f16).fract(), -0.3f16, TOL_0); + assert_approx_eq!((-1.5f16).fract(), -0.5f16, TOL_0); + assert_approx_eq!((-1.7f16).fract(), -0.7f16, TOL_0); +} + +#[test] +#[cfg(reliable_f16_math)] fn test_abs() { assert_eq!(f16::INFINITY.abs(), f16::INFINITY); assert_eq!(1f16.abs(), 1f16); @@ -299,6 +400,24 @@ fn test_next_down() { } #[test] +#[cfg(reliable_f16_math)] +fn test_mul_add() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + assert_approx_eq!(12.3f16.mul_add(4.5, 6.7), 62.05, TOL_P2); + assert_approx_eq!((-12.3f16).mul_add(-4.5, -6.7), 48.65, TOL_P2); + assert_approx_eq!(0.0f16.mul_add(8.9, 1.2), 1.2, TOL_0); + assert_approx_eq!(3.4f16.mul_add(-0.0, 5.6), 5.6, TOL_0); + assert!(nan.mul_add(7.8, 9.0).is_nan()); + assert_eq!(inf.mul_add(7.8, 9.0), inf); + assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); + assert_eq!(8.9f16.mul_add(inf, 3.2), inf); + assert_eq!((-3.2f16).mul_add(2.4, neg_inf), neg_inf); +} + +#[test] +#[cfg(reliable_f16_math)] fn test_recip() { let nan: f16 = f16::NAN; let inf: f16 = f16::INFINITY; @@ -307,11 +426,157 @@ fn test_recip() { assert_eq!(2.0f16.recip(), 0.5); assert_eq!((-0.4f16).recip(), -2.5); assert_eq!(0.0f16.recip(), inf); + assert_approx_eq!(f16::MAX.recip(), 1.526624e-5f16, 1e-4); assert!(nan.recip().is_nan()); assert_eq!(inf.recip(), 0.0); assert_eq!(neg_inf.recip(), 0.0); } +#[test] +#[cfg(reliable_f16_math)] +fn test_powi() { + // FIXME(llvm19): LLVM misoptimizes `powi.f16` + // + // let nan: f16 = f16::NAN; + // let inf: f16 = f16::INFINITY; + // let neg_inf: f16 = f16::NEG_INFINITY; + // assert_eq!(1.0f16.powi(1), 1.0); + // assert_approx_eq!((-3.1f16).powi(2), 9.61, TOL_0); + // assert_approx_eq!(5.9f16.powi(-2), 0.028727, TOL_N2); + // assert_eq!(8.3f16.powi(0), 1.0); + // assert!(nan.powi(2).is_nan()); + // assert_eq!(inf.powi(3), inf); + // assert_eq!(neg_inf.powi(2), inf); +} + +#[test] +#[cfg(reliable_f16_math)] +fn test_powf() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + assert_eq!(1.0f16.powf(1.0), 1.0); + assert_approx_eq!(3.4f16.powf(4.5), 246.408183, TOL_P2); + assert_approx_eq!(2.7f16.powf(-3.2), 0.041652, TOL_N2); + assert_approx_eq!((-3.1f16).powf(2.0), 9.61, TOL_P2); + assert_approx_eq!(5.9f16.powf(-2.0), 0.028727, TOL_N2); + assert_eq!(8.3f16.powf(0.0), 1.0); + assert!(nan.powf(2.0).is_nan()); + assert_eq!(inf.powf(2.0), inf); + assert_eq!(neg_inf.powf(3.0), neg_inf); +} + +#[test] +#[cfg(reliable_f16_math)] +fn test_sqrt_domain() { + assert!(f16::NAN.sqrt().is_nan()); + assert!(f16::NEG_INFINITY.sqrt().is_nan()); + assert!((-1.0f16).sqrt().is_nan()); + assert_eq!((-0.0f16).sqrt(), -0.0); + assert_eq!(0.0f16.sqrt(), 0.0); + assert_eq!(1.0f16.sqrt(), 1.0); + assert_eq!(f16::INFINITY.sqrt(), f16::INFINITY); +} + +#[test] +#[cfg(reliable_f16_math)] +fn test_exp() { + assert_eq!(1.0, 0.0f16.exp()); + assert_approx_eq!(2.718282, 1.0f16.exp(), TOL_0); + assert_approx_eq!(148.413159, 5.0f16.exp(), TOL_0); + + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + let nan: f16 = f16::NAN; + assert_eq!(inf, inf.exp()); + assert_eq!(0.0, neg_inf.exp()); + assert!(nan.exp().is_nan()); +} + +#[test] +#[cfg(reliable_f16_math)] +fn test_exp2() { + assert_eq!(32.0, 5.0f16.exp2()); + assert_eq!(1.0, 0.0f16.exp2()); + + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + let nan: f16 = f16::NAN; + assert_eq!(inf, inf.exp2()); + assert_eq!(0.0, neg_inf.exp2()); + assert!(nan.exp2().is_nan()); +} + +#[test] +#[cfg(reliable_f16_math)] +fn test_ln() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + assert_approx_eq!(1.0f16.exp().ln(), 1.0, TOL_0); + assert!(nan.ln().is_nan()); + assert_eq!(inf.ln(), inf); + assert!(neg_inf.ln().is_nan()); + assert!((-2.3f16).ln().is_nan()); + assert_eq!((-0.0f16).ln(), neg_inf); + assert_eq!(0.0f16.ln(), neg_inf); + assert_approx_eq!(4.0f16.ln(), 1.386294, TOL_0); +} + +#[test] +#[cfg(reliable_f16_math)] +fn test_log() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + assert_eq!(10.0f16.log(10.0), 1.0); + assert_approx_eq!(2.3f16.log(3.5), 0.664858, TOL_0); + assert_eq!(1.0f16.exp().log(1.0f16.exp()), 1.0); + assert!(1.0f16.log(1.0).is_nan()); + assert!(1.0f16.log(-13.9).is_nan()); + assert!(nan.log(2.3).is_nan()); + assert_eq!(inf.log(10.0), inf); + assert!(neg_inf.log(8.8).is_nan()); + assert!((-2.3f16).log(0.1).is_nan()); + assert_eq!((-0.0f16).log(2.0), neg_inf); + assert_eq!(0.0f16.log(7.0), neg_inf); +} + +#[test] +#[cfg(reliable_f16_math)] +fn test_log2() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + assert_approx_eq!(10.0f16.log2(), 3.321928, TOL_0); + assert_approx_eq!(2.3f16.log2(), 1.201634, TOL_0); + assert_approx_eq!(1.0f16.exp().log2(), 1.442695, TOL_0); + assert!(nan.log2().is_nan()); + assert_eq!(inf.log2(), inf); + assert!(neg_inf.log2().is_nan()); + assert!((-2.3f16).log2().is_nan()); + assert_eq!((-0.0f16).log2(), neg_inf); + assert_eq!(0.0f16.log2(), neg_inf); +} + +#[test] +#[cfg(reliable_f16_math)] +fn test_log10() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + assert_eq!(10.0f16.log10(), 1.0); + assert_approx_eq!(2.3f16.log10(), 0.361728, TOL_0); + assert_approx_eq!(1.0f16.exp().log10(), 0.434294, TOL_0); + assert_eq!(1.0f16.log10(), 0.0); + assert!(nan.log10().is_nan()); + assert_eq!(inf.log10(), inf); + assert!(neg_inf.log10().is_nan()); + assert!((-2.3f16).log10().is_nan()); + assert_eq!((-0.0f16).log10(), neg_inf); + assert_eq!(0.0f16.log10(), neg_inf); +} + #[test] fn test_to_degrees() { let pi: f16 = consts::PI; @@ -319,8 +584,8 @@ fn test_to_degrees() { let inf: f16 = f16::INFINITY; let neg_inf: f16 = f16::NEG_INFINITY; assert_eq!(0.0f16.to_degrees(), 0.0); - assert_approx_eq!((-5.8f16).to_degrees(), -332.315521); - assert_approx_eq!(pi.to_degrees(), 180.0, F16_APPROX_L4); + assert_approx_eq!((-5.8f16).to_degrees(), -332.315521, TOL_P2); + assert_approx_eq!(pi.to_degrees(), 180.0, TOL_P2); assert!(nan.to_degrees().is_nan()); assert_eq!(inf.to_degrees(), inf); assert_eq!(neg_inf.to_degrees(), neg_inf); @@ -334,14 +599,112 @@ fn test_to_radians() { let inf: f16 = f16::INFINITY; let neg_inf: f16 = f16::NEG_INFINITY; assert_eq!(0.0f16.to_radians(), 0.0); - assert_approx_eq!(154.6f16.to_radians(), 2.698279); - assert_approx_eq!((-332.31f16).to_radians(), -5.799903); - assert_approx_eq!(180.0f16.to_radians(), pi, F16_APPROX_L2); + assert_approx_eq!(154.6f16.to_radians(), 2.698279, TOL_0); + assert_approx_eq!((-332.31f16).to_radians(), -5.799903, TOL_0); + assert_approx_eq!(180.0f16.to_radians(), pi, TOL_0); assert!(nan.to_radians().is_nan()); assert_eq!(inf.to_radians(), inf); assert_eq!(neg_inf.to_radians(), neg_inf); } +#[test] +#[cfg(reliable_f16_math)] +fn test_asinh() { + assert_eq!(0.0f16.asinh(), 0.0f16); + assert_eq!((-0.0f16).asinh(), -0.0f16); + + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + let nan: f16 = f16::NAN; + assert_eq!(inf.asinh(), inf); + assert_eq!(neg_inf.asinh(), neg_inf); + assert!(nan.asinh().is_nan()); + assert!((-0.0f16).asinh().is_sign_negative()); + // issue 63271 + assert_approx_eq!(2.0f16.asinh(), 1.443635475178810342493276740273105f16, TOL_0); + assert_approx_eq!((-2.0f16).asinh(), -1.443635475178810342493276740273105f16, TOL_0); + // regression test for the catastrophic cancellation fixed in 72486 + assert_approx_eq!((-200.0f16).asinh(), -5.991470797049389, TOL_0); + + // test for low accuracy from issue 104548 + assert_approx_eq!(10.0f16, 10.0f16.sinh().asinh(), TOL_0); + // mul needed for approximate comparison to be meaningful + assert_approx_eq!(1.0f16, 1e-3f16.sinh().asinh() * 1e3f16, TOL_0); +} + +#[test] +#[cfg(reliable_f16_math)] +fn test_acosh() { + assert_eq!(1.0f16.acosh(), 0.0f16); + assert!(0.999f16.acosh().is_nan()); + + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + let nan: f16 = f16::NAN; + assert_eq!(inf.acosh(), inf); + assert!(neg_inf.acosh().is_nan()); + assert!(nan.acosh().is_nan()); + assert_approx_eq!(2.0f16.acosh(), 1.31695789692481670862504634730796844f16, TOL_0); + assert_approx_eq!(3.0f16.acosh(), 1.76274717403908605046521864995958461f16, TOL_0); + + // test for low accuracy from issue 104548 + assert_approx_eq!(10.0f16, 10.0f16.cosh().acosh(), TOL_P2); +} + +#[test] +#[cfg(reliable_f16_math)] +fn test_atanh() { + assert_eq!(0.0f16.atanh(), 0.0f16); + assert_eq!((-0.0f16).atanh(), -0.0f16); + + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + let nan: f16 = f16::NAN; + assert_eq!(1.0f16.atanh(), inf); + assert_eq!((-1.0f16).atanh(), neg_inf); + assert!(2f16.atanh().atanh().is_nan()); + assert!((-2f16).atanh().atanh().is_nan()); + assert!(inf.atanh().is_nan()); + assert!(neg_inf.atanh().is_nan()); + assert!(nan.atanh().is_nan()); + assert_approx_eq!(0.5f16.atanh(), 0.54930614433405484569762261846126285f16, TOL_0); + assert_approx_eq!((-0.5f16).atanh(), -0.54930614433405484569762261846126285f16, TOL_0); +} + +#[test] +#[cfg(reliable_f16_math)] +fn test_gamma() { + // precision can differ among platforms + assert_approx_eq!(1.0f16.gamma(), 1.0f16, TOL_0); + assert_approx_eq!(2.0f16.gamma(), 1.0f16, TOL_0); + assert_approx_eq!(3.0f16.gamma(), 2.0f16, TOL_0); + assert_approx_eq!(4.0f16.gamma(), 6.0f16, TOL_0); + assert_approx_eq!(5.0f16.gamma(), 24.0f16, TOL_0); + assert_approx_eq!(0.5f16.gamma(), consts::PI.sqrt(), TOL_0); + assert_approx_eq!((-0.5f16).gamma(), -2.0 * consts::PI.sqrt(), TOL_0); + assert_eq!(0.0f16.gamma(), f16::INFINITY); + assert_eq!((-0.0f16).gamma(), f16::NEG_INFINITY); + assert!((-1.0f16).gamma().is_nan()); + assert!((-2.0f16).gamma().is_nan()); + assert!(f16::NAN.gamma().is_nan()); + assert!(f16::NEG_INFINITY.gamma().is_nan()); + assert_eq!(f16::INFINITY.gamma(), f16::INFINITY); + assert_eq!(171.71f16.gamma(), f16::INFINITY); +} + +#[test] +#[cfg(reliable_f16_math)] +fn test_ln_gamma() { + assert_approx_eq!(1.0f16.ln_gamma().0, 0.0f16, TOL_0); + assert_eq!(1.0f16.ln_gamma().1, 1); + assert_approx_eq!(2.0f16.ln_gamma().0, 0.0f16, TOL_0); + assert_eq!(2.0f16.ln_gamma().1, 1); + assert_approx_eq!(3.0f16.ln_gamma().0, 2.0f16.ln(), TOL_0); + assert_eq!(3.0f16.ln_gamma().1, 1); + assert_approx_eq!((-0.5f16).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln(), TOL_0); + assert_eq!((-0.5f16).ln_gamma().1, -1); +} + #[test] fn test_real_consts() { // FIXME(f16_f128): add math tests when available @@ -355,29 +718,34 @@ fn test_real_consts() { let frac_pi_8: f16 = consts::FRAC_PI_8; let frac_1_pi: f16 = consts::FRAC_1_PI; let frac_2_pi: f16 = consts::FRAC_2_PI; - // let frac_2_sqrtpi: f16 = consts::FRAC_2_SQRT_PI; - // let sqrt2: f16 = consts::SQRT_2; - // let frac_1_sqrt2: f16 = consts::FRAC_1_SQRT_2; - // let e: f16 = consts::E; - // let log2_e: f16 = consts::LOG2_E; - // let log10_e: f16 = consts::LOG10_E; - // let ln_2: f16 = consts::LN_2; - // let ln_10: f16 = consts::LN_10; - - assert_approx_eq!(frac_pi_2, pi / 2f16); - assert_approx_eq!(frac_pi_3, pi / 3f16); - assert_approx_eq!(frac_pi_4, pi / 4f16); - assert_approx_eq!(frac_pi_6, pi / 6f16); - assert_approx_eq!(frac_pi_8, pi / 8f16); - assert_approx_eq!(frac_1_pi, 1f16 / pi); - assert_approx_eq!(frac_2_pi, 2f16 / pi); - // assert_approx_eq!(frac_2_sqrtpi, 2f16 / pi.sqrt()); - // assert_approx_eq!(sqrt2, 2f16.sqrt()); - // assert_approx_eq!(frac_1_sqrt2, 1f16 / 2f16.sqrt()); - // assert_approx_eq!(log2_e, e.log2()); - // assert_approx_eq!(log10_e, e.log10()); - // assert_approx_eq!(ln_2, 2f16.ln()); - // assert_approx_eq!(ln_10, 10f16.ln()); + + assert_approx_eq!(frac_pi_2, pi / 2f16, TOL_0); + assert_approx_eq!(frac_pi_3, pi / 3f16, TOL_0); + assert_approx_eq!(frac_pi_4, pi / 4f16, TOL_0); + assert_approx_eq!(frac_pi_6, pi / 6f16, TOL_0); + assert_approx_eq!(frac_pi_8, pi / 8f16, TOL_0); + assert_approx_eq!(frac_1_pi, 1f16 / pi, TOL_0); + assert_approx_eq!(frac_2_pi, 2f16 / pi, TOL_0); + + #[cfg(reliable_f16_math)] + { + let frac_2_sqrtpi: f16 = consts::FRAC_2_SQRT_PI; + let sqrt2: f16 = consts::SQRT_2; + let frac_1_sqrt2: f16 = consts::FRAC_1_SQRT_2; + let e: f16 = consts::E; + let log2_e: f16 = consts::LOG2_E; + let log10_e: f16 = consts::LOG10_E; + let ln_2: f16 = consts::LN_2; + let ln_10: f16 = consts::LN_10; + + assert_approx_eq!(frac_2_sqrtpi, 2f16 / pi.sqrt(), TOL_0); + assert_approx_eq!(sqrt2, 2f16.sqrt(), TOL_0); + assert_approx_eq!(frac_1_sqrt2, 1f16 / 2f16.sqrt(), TOL_0); + assert_approx_eq!(log2_e, e.log2(), TOL_0); + assert_approx_eq!(log10_e, e.log10(), TOL_0); + assert_approx_eq!(ln_2, 2f16.ln(), TOL_0); + assert_approx_eq!(ln_10, 10f16.ln(), TOL_0); + } } #[test] @@ -386,10 +754,10 @@ fn test_float_bits_conv() { assert_eq!((12.5f16).to_bits(), 0x4a40); assert_eq!((1337f16).to_bits(), 0x6539); assert_eq!((-14.25f16).to_bits(), 0xcb20); - assert_approx_eq!(f16::from_bits(0x3c00), 1.0); - assert_approx_eq!(f16::from_bits(0x4a40), 12.5); - assert_approx_eq!(f16::from_bits(0x6539), 1337.0); - assert_approx_eq!(f16::from_bits(0xcb20), -14.25); + assert_approx_eq!(f16::from_bits(0x3c00), 1.0, TOL_0); + assert_approx_eq!(f16::from_bits(0x4a40), 12.5, TOL_0); + assert_approx_eq!(f16::from_bits(0x6539), 1337.0, TOL_P4); + assert_approx_eq!(f16::from_bits(0xcb20), -14.25, TOL_0); // Check that NaNs roundtrip their bits regardless of signaling-ness let masked_nan1 = f16::NAN.to_bits() ^ NAN_MASK1; diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index ba519afc62b07..1b0d7f3dbf2c9 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -382,7 +382,7 @@ macro_rules! assert_approx_eq { let diff = (*a - *b).abs(); assert!( diff < $lim, - "{a:?} is not approximately equal to {b:?} (threshold {lim:?}, actual {diff:?})", + "{a:?} is not approximately equal to {b:?} (threshold {lim:?}, difference {diff:?})", lim = $lim ); }}; diff --git a/library/std/src/sys/cmath.rs b/library/std/src/sys/cmath.rs index 99df503b82de2..2997e908fa1b2 100644 --- a/library/std/src/sys/cmath.rs +++ b/library/std/src/sys/cmath.rs @@ -28,6 +28,21 @@ extern "C" { pub fn lgamma_r(n: f64, s: &mut i32) -> f64; pub fn lgammaf_r(n: f32, s: &mut i32) -> f32; + pub fn acosf128(n: f128) -> f128; + pub fn asinf128(n: f128) -> f128; + pub fn atanf128(n: f128) -> f128; + pub fn atan2f128(a: f128, b: f128) -> f128; + pub fn cbrtf128(n: f128) -> f128; + pub fn coshf128(n: f128) -> f128; + pub fn expm1f128(n: f128) -> f128; + pub fn hypotf128(x: f128, y: f128) -> f128; + pub fn log1pf128(n: f128) -> f128; + pub fn sinhf128(n: f128) -> f128; + pub fn tanf128(n: f128) -> f128; + pub fn tanhf128(n: f128) -> f128; + pub fn tgammaf128(n: f128) -> f128; + pub fn lgammaf128_r(n: f128, s: &mut i32) -> f128; + cfg_if::cfg_if! { if #[cfg(not(all(target_os = "windows", target_env = "msvc", target_arch = "x86")))] { pub fn acosf(n: f32) -> f32; diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs index df0176244489a..48de5bab8776a 100644 --- a/library/std/src/sys/pal/mod.rs +++ b/library/std/src/sys/pal/mod.rs @@ -79,9 +79,16 @@ cfg_if::cfg_if! { #[cfg(not(test))] cfg_if::cfg_if! { if #[cfg(target_os = "android")] { + pub use self::android::log2f16; pub use self::android::log2f32; pub use self::android::log2f64; + pub use self::android::log2f128; } else { + #[inline] + pub fn log2f16(n: f16) -> f16 { + unsafe { crate::intrinsics::log2f16(n) } + } + #[inline] pub fn log2f32(n: f32) -> f32 { unsafe { crate::intrinsics::log2f32(n) } @@ -91,6 +98,11 @@ cfg_if::cfg_if! { pub fn log2f64(n: f64) -> f64 { unsafe { crate::intrinsics::log2f64(n) } } + + #[inline] + pub fn log2f128(n: f128) -> f128 { + unsafe { crate::intrinsics::log2f128(n) } + } } } diff --git a/library/std/src/sys/pal/unix/android.rs b/library/std/src/sys/pal/unix/android.rs index 0f704994f550a..62b82c567eec2 100644 --- a/library/std/src/sys/pal/unix/android.rs +++ b/library/std/src/sys/pal/unix/android.rs @@ -45,6 +45,11 @@ use super::weak::weak; // // log_2(x) = ln(x) * log_2(e) +#[cfg(not(test))] +pub fn log2f16(f: f16) -> f16 { + f.ln() * crate::f16::consts::LOG2_E +} + #[cfg(not(test))] pub fn log2f32(f: f32) -> f32 { f.ln() * crate::f32::consts::LOG2_E @@ -55,6 +60,11 @@ pub fn log2f64(f: f64) -> f64 { f.ln() * crate::f64::consts::LOG2_E } +#[cfg(not(test))] +pub fn log2f128(f: f128) -> f128 { + f.ln() * crate::f128::consts::LOG2_E +} + // Back in the day [1] the `signal` function was just an inline wrapper // around `bsd_signal`, but starting in API level android-20 the `signal` // symbols was introduced [2]. Finally, in android-21 the API `bsd_signal` was From a4657ddd4d935f748f14fd535610dce332bdfa10 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 17 Jul 2024 16:17:09 -0400 Subject: [PATCH 12/18] Add `core` functions for `f16` and `f128` that require math routines `min`, `max`, and similar functions require external math routines. Add these under the same gates as `std` math functions (`reliable_f16_math` and `reliable_f128_math`). --- library/core/src/num/f128.rs | 176 ++++++++++++++++++++++++++++++++++ library/core/src/num/f16.rs | 171 +++++++++++++++++++++++++++++++++ library/std/src/f128/tests.rs | 28 +++++- library/std/src/f16/tests.rs | 28 +++++- 4 files changed, 401 insertions(+), 2 deletions(-) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 6a24748fd9e87..cfe3a20df532e 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -686,6 +686,182 @@ impl f128 { self * RADS_PER_DEG } + /// Returns the maximum of the two numbers, ignoring NaN. + /// + /// If one of the arguments is NaN, then the other argument is returned. + /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs; + /// this function handles all NaNs the same way and avoids maxNum's problems with associativity. + /// This also matches the behavior of libm’s fmax. + /// + /// ``` + /// #![feature(f128)] + /// # // Using aarch64 because `reliable_f128_math` is needed + /// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] { + /// + /// let x = 1.0f128; + /// let y = 2.0f128; + /// + /// assert_eq!(x.max(y), y); + /// # } + /// ``` + #[inline] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "this returns the result of the comparison, without modifying either input"] + pub fn max(self, other: f128) -> f128 { + intrinsics::maxnumf128(self, other) + } + + /// Returns the minimum of the two numbers, ignoring NaN. + /// + /// If one of the arguments is NaN, then the other argument is returned. + /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs; + /// this function handles all NaNs the same way and avoids minNum's problems with associativity. + /// This also matches the behavior of libm’s fmin. + /// + /// ``` + /// #![feature(f128)] + /// # // Using aarch64 because `reliable_f128_math` is needed + /// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] { + /// + /// let x = 1.0f128; + /// let y = 2.0f128; + /// + /// assert_eq!(x.min(y), x); + /// # } + /// ``` + #[inline] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "this returns the result of the comparison, without modifying either input"] + pub fn min(self, other: f128) -> f128 { + intrinsics::minnumf128(self, other) + } + + /// Returns the maximum of the two numbers, propagating NaN. + /// + /// This returns NaN when *either* argument is NaN, as opposed to + /// [`f128::max`] which only returns NaN when *both* arguments are NaN. + /// + /// ``` + /// #![feature(f128)] + /// #![feature(float_minimum_maximum)] + /// # // Using aarch64 because `reliable_f128_math` is needed + /// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] { + /// + /// let x = 1.0f128; + /// let y = 2.0f128; + /// + /// assert_eq!(x.maximum(y), y); + /// assert!(x.maximum(f128::NAN).is_nan()); + /// # } + /// ``` + /// + /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater + /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0. + /// Note that this follows the semantics specified in IEEE 754-2019. + /// + /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN + /// operand is conserved; see [explanation of NaN as a special value](f128) for more info. + #[inline] + #[unstable(feature = "f128", issue = "116909")] + // #[unstable(feature = "float_minimum_maximum", issue = "91079")] + #[must_use = "this returns the result of the comparison, without modifying either input"] + pub fn maximum(self, other: f128) -> f128 { + if self > other { + self + } else if other > self { + other + } else if self == other { + if self.is_sign_positive() && other.is_sign_negative() { self } else { other } + } else { + self + other + } + } + + /// Returns the minimum of the two numbers, propagating NaN. + /// + /// This returns NaN when *either* argument is NaN, as opposed to + /// [`f128::min`] which only returns NaN when *both* arguments are NaN. + /// + /// ``` + /// #![feature(f128)] + /// #![feature(float_minimum_maximum)] + /// # // Using aarch64 because `reliable_f128_math` is needed + /// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] { + /// + /// let x = 1.0f128; + /// let y = 2.0f128; + /// + /// assert_eq!(x.minimum(y), x); + /// assert!(x.minimum(f128::NAN).is_nan()); + /// # } + /// ``` + /// + /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser + /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0. + /// Note that this follows the semantics specified in IEEE 754-2019. + /// + /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN + /// operand is conserved; see [explanation of NaN as a special value](f128) for more info. + #[inline] + #[unstable(feature = "f128", issue = "116909")] + // #[unstable(feature = "float_minimum_maximum", issue = "91079")] + #[must_use = "this returns the result of the comparison, without modifying either input"] + pub fn minimum(self, other: f128) -> f128 { + if self < other { + self + } else if other < self { + other + } else if self == other { + if self.is_sign_negative() && other.is_sign_positive() { self } else { other } + } else { + // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + self + other + } + } + + /// Calculates the middle point of `self` and `rhs`. + /// + /// This returns NaN when *either* argument is NaN or if a combination of + /// +inf and -inf is provided as arguments. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// #![feature(num_midpoint)] + /// # // Using aarch64 because `reliable_f128_math` is needed + /// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] { + /// + /// assert_eq!(1f128.midpoint(4.0), 2.5); + /// assert_eq!((-5.5f128).midpoint(8.0), 1.25); + /// # } + /// ``` + #[inline] + #[unstable(feature = "f128", issue = "116909")] + // #[unstable(feature = "num_midpoint", issue = "110840")] + pub fn midpoint(self, other: f128) -> f128 { + const LO: f128 = f128::MIN_POSITIVE * 2.; + const HI: f128 = f128::MAX / 2.; + + let (a, b) = (self, other); + let abs_a = a.abs_private(); + let abs_b = b.abs_private(); + + if abs_a <= HI && abs_b <= HI { + // Overflow is impossible + (a + b) / 2. + } else if abs_a < LO { + // Not safe to halve a + a + (b / 2.) + } else if abs_b < LO { + // Not safe to halve b + (a / 2.) + b + } else { + // Not safe to halve a and b + (a / 2.) + (b / 2.) + } + } + /// Rounds toward zero and converts to any primitive integer type, /// assuming that the value is finite and fits in that type. /// diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 054897b3c96bc..8947bf0d84826 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -720,6 +720,177 @@ impl f16 { self * RADS_PER_DEG } + /// Returns the maximum of the two numbers, ignoring NaN. + /// + /// If one of the arguments is NaN, then the other argument is returned. + /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs; + /// this function handles all NaNs the same way and avoids maxNum's problems with associativity. + /// This also matches the behavior of libm’s fmax. + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// + /// let x = 1.0f16; + /// let y = 2.0f16; + /// + /// assert_eq!(x.max(y), y); + /// # } + /// ``` + #[inline] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "this returns the result of the comparison, without modifying either input"] + pub fn max(self, other: f16) -> f16 { + intrinsics::maxnumf16(self, other) + } + + /// Returns the minimum of the two numbers, ignoring NaN. + /// + /// If one of the arguments is NaN, then the other argument is returned. + /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs; + /// this function handles all NaNs the same way and avoids minNum's problems with associativity. + /// This also matches the behavior of libm’s fmin. + /// + /// ``` + /// #![feature(f16)] + /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// + /// let x = 1.0f16; + /// let y = 2.0f16; + /// + /// assert_eq!(x.min(y), x); + /// # } + /// ``` + #[inline] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "this returns the result of the comparison, without modifying either input"] + pub fn min(self, other: f16) -> f16 { + intrinsics::minnumf16(self, other) + } + + /// Returns the maximum of the two numbers, propagating NaN. + /// + /// This returns NaN when *either* argument is NaN, as opposed to + /// [`f16::max`] which only returns NaN when *both* arguments are NaN. + /// + /// ``` + /// #![feature(f16)] + /// #![feature(float_minimum_maximum)] + /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// + /// let x = 1.0f16; + /// let y = 2.0f16; + /// + /// assert_eq!(x.maximum(y), y); + /// assert!(x.maximum(f16::NAN).is_nan()); + /// # } + /// ``` + /// + /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater + /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0. + /// Note that this follows the semantics specified in IEEE 754-2019. + /// + /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN + /// operand is conserved; see [explanation of NaN as a special value](f16) for more info. + #[inline] + #[unstable(feature = "f16", issue = "116909")] + // #[unstable(feature = "float_minimum_maximum", issue = "91079")] + #[must_use = "this returns the result of the comparison, without modifying either input"] + pub fn maximum(self, other: f16) -> f16 { + if self > other { + self + } else if other > self { + other + } else if self == other { + if self.is_sign_positive() && other.is_sign_negative() { self } else { other } + } else { + self + other + } + } + + /// Returns the minimum of the two numbers, propagating NaN. + /// + /// This returns NaN when *either* argument is NaN, as opposed to + /// [`f16::min`] which only returns NaN when *both* arguments are NaN. + /// + /// ``` + /// #![feature(f16)] + /// #![feature(float_minimum_maximum)] + /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// + /// let x = 1.0f16; + /// let y = 2.0f16; + /// + /// assert_eq!(x.minimum(y), x); + /// assert!(x.minimum(f16::NAN).is_nan()); + /// # } + /// ``` + /// + /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser + /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0. + /// Note that this follows the semantics specified in IEEE 754-2019. + /// + /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN + /// operand is conserved; see [explanation of NaN as a special value](f16) for more info. + #[inline] + #[unstable(feature = "f16", issue = "116909")] + // #[unstable(feature = "float_minimum_maximum", issue = "91079")] + #[must_use = "this returns the result of the comparison, without modifying either input"] + pub fn minimum(self, other: f16) -> f16 { + if self < other { + self + } else if other < self { + other + } else if self == other { + if self.is_sign_negative() && other.is_sign_positive() { self } else { other } + } else { + // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + self + other + } + } + + /// Calculates the middle point of `self` and `rhs`. + /// + /// This returns NaN when *either* argument is NaN or if a combination of + /// +inf and -inf is provided as arguments. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// #![feature(num_midpoint)] + /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// + /// assert_eq!(1f16.midpoint(4.0), 2.5); + /// assert_eq!((-5.5f16).midpoint(8.0), 1.25); + /// # } + /// ``` + #[inline] + #[unstable(feature = "f16", issue = "116909")] + // #[unstable(feature = "num_midpoint", issue = "110840")] + pub fn midpoint(self, other: f16) -> f16 { + const LO: f16 = f16::MIN_POSITIVE * 2.; + const HI: f16 = f16::MAX / 2.; + + let (a, b) = (self, other); + let abs_a = a.abs_private(); + let abs_b = b.abs_private(); + + if abs_a <= HI && abs_b <= HI { + // Overflow is impossible + (a + b) / 2. + } else if abs_a < LO { + // Not safe to halve a + a + (b / 2.) + } else if abs_b < LO { + // Not safe to halve b + (a / 2.) + b + } else { + // Not safe to halve a and b + (a / 2.) + (b / 2.) + } + } + /// Rounds toward zero and converts to any primitive integer type, /// assuming that the value is finite and fits in that type. /// diff --git a/library/std/src/f128/tests.rs b/library/std/src/f128/tests.rs index df806a639f620..7051c051bf723 100644 --- a/library/std/src/f128/tests.rs +++ b/library/std/src/f128/tests.rs @@ -56,7 +56,33 @@ fn test_num_f128() { test_num(10f128, 2f128); } -// FIXME(f16_f128): add min and max tests when available +#[test] +#[cfg(reliable_f128_math)] +fn test_min_nan() { + assert_eq!(f128::NAN.min(2.0), 2.0); + assert_eq!(2.0f128.min(f128::NAN), 2.0); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_max_nan() { + assert_eq!(f128::NAN.max(2.0), 2.0); + assert_eq!(2.0f128.max(f128::NAN), 2.0); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_minimum() { + assert!(f128::NAN.minimum(2.0).is_nan()); + assert!(2.0f128.minimum(f128::NAN).is_nan()); +} + +#[test] +#[cfg(reliable_f128_math)] +fn test_maximum() { + assert!(f128::NAN.maximum(2.0).is_nan()); + assert!(2.0f128.maximum(f128::NAN).is_nan()); +} #[test] fn test_nan() { diff --git a/library/std/src/f16/tests.rs b/library/std/src/f16/tests.rs index f0ef807dac141..50504e7ffd94f 100644 --- a/library/std/src/f16/tests.rs +++ b/library/std/src/f16/tests.rs @@ -57,7 +57,33 @@ fn test_num_f16() { test_num(10f16, 2f16); } -// FIXME(f16_f128): add min and max tests when available +#[test] +#[cfg(reliable_f16_math)] +fn test_min_nan() { + assert_eq!(f16::NAN.min(2.0), 2.0); + assert_eq!(2.0f16.min(f16::NAN), 2.0); +} + +#[test] +#[cfg(reliable_f16_math)] +fn test_max_nan() { + assert_eq!(f16::NAN.max(2.0), 2.0); + assert_eq!(2.0f16.max(f16::NAN), 2.0); +} + +#[test] +#[cfg(reliable_f16_math)] +fn test_minimum() { + assert!(f16::NAN.minimum(2.0).is_nan()); + assert!(2.0f16.minimum(f16::NAN).is_nan()); +} + +#[test] +#[cfg(reliable_f16_math)] +fn test_maximum() { + assert!(f16::NAN.maximum(2.0).is_nan()); + assert!(2.0f16.maximum(f16::NAN).is_nan()); +} #[test] fn test_nan() { From e1d23c9fa2714177196ca3e43f751d4cdc634915 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 17 Jul 2024 20:45:13 -0400 Subject: [PATCH 13/18] Update comments for `{f16, f32, f64, f128}::midpoint` Clarify what makes some operations not safe, and correct comment in the default branch ("not safe" -> "safe"). --- library/core/src/num/f128.rs | 6 +++--- library/core/src/num/f16.rs | 6 +++--- library/core/src/num/f32.rs | 6 +++--- library/core/src/num/f64.rs | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index cfe3a20df532e..0c04f47fe7df1 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -851,13 +851,13 @@ impl f128 { // Overflow is impossible (a + b) / 2. } else if abs_a < LO { - // Not safe to halve a + // Not safe to halve `a` (would underflow) a + (b / 2.) } else if abs_b < LO { - // Not safe to halve b + // Not safe to halve `b` (would underflow) (a / 2.) + b } else { - // Not safe to halve a and b + // Safe to halve `a` and `b` (a / 2.) + (b / 2.) } } diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 8947bf0d84826..e5b1148e19215 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -880,13 +880,13 @@ impl f16 { // Overflow is impossible (a + b) / 2. } else if abs_a < LO { - // Not safe to halve a + // Not safe to halve `a` (would underflow) a + (b / 2.) } else if abs_b < LO { - // Not safe to halve b + // Not safe to halve `b` (would underflow) (a / 2.) + b } else { - // Not safe to halve a and b + // Safe to halve `a` and `b` (a / 2.) + (b / 2.) } } diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 08d863f17caf7..e65c982b17227 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1070,13 +1070,13 @@ impl f32 { // Overflow is impossible (a + b) / 2. } else if abs_a < LO { - // Not safe to halve a + // Not safe to halve `a` (would underflow) a + (b / 2.) } else if abs_b < LO { - // Not safe to halve b + // Not safe to halve `b` (would underflow) (a / 2.) + b } else { - // Not safe to halve a and b + // Safe to halve `a` and `b` (a / 2.) + (b / 2.) } } diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 5d33eea6d011f..b27d47b07d544 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1064,13 +1064,13 @@ impl f64 { // Overflow is impossible (a + b) / 2. } else if abs_a < LO { - // Not safe to halve a + // Not safe to halve `a` (would underflow) a + (b / 2.) } else if abs_b < LO { - // Not safe to halve b + // Not safe to halve `b` (would underflow) (a / 2.) + b } else { - // Not safe to halve a and b + // Safe to halve `a` and `b` (a / 2.) + (b / 2.) } } From d64bbb127ac920d6058d8f308d0c6670ff07dac7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 30 Jul 2024 18:11:46 -0400 Subject: [PATCH 14/18] Add a disclaimer about x86 `f128` math functions Due to a LLVM bug, `f128` math functions link successfully but LLVM chooses the wrong symbols (`long double` symbols rather than those for binary128). Since this is a notable problem that may surprise a number of users, add a note about it. Link: https://github.com/llvm/llvm-project/issues/44744 --- library/core/src/primitive_docs.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 5989bcbcc5201..09ebef89fb0c2 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1244,6 +1244,9 @@ mod prim_f64 {} /// actually implement it. For x86-64 and AArch64, ISA support is not even specified, /// so it will always be a software implementation significantly slower than `f64`. /// +/// _Note: `f128` support is incomplete. Many platforms will not be able to link math functions. On +/// x86 in particular, these functions do link but their results are always incorrect._ +/// /// *[See also the `std::f128::consts` module](crate::f128::consts).* /// /// [wikipedia]: https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format From f6f587e7ea7ce26418fdaca7dd05faff8c68fc9d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 11 Apr 2024 14:10:34 -0400 Subject: [PATCH 15/18] Introduce REDUNDANT_IMPORTS lint --- compiler/rustc_lint/messages.ftl | 8 +-- compiler/rustc_lint_defs/src/builtin.rs | 26 ++++++++++ compiler/rustc_resolve/src/imports.rs | 8 ++- compiler/rustc_resolve/src/lib.rs | 4 +- .../redundant-import-extern-prelude.rs | 7 +-- .../redundant-import-extern-prelude.stderr | 14 +++++ .../redundant-import-issue-121915-2015.rs | 5 +- .../redundant-import-issue-121915-2015.stderr | 17 ++++++ .../redundant-import-lang-prelude-attr.rs | 7 +-- .../redundant-import-lang-prelude-attr.stderr | 14 +++++ .../imports/redundant-import-lang-prelude.rs | 7 +-- .../redundant-import-lang-prelude.stderr | 14 +++++ .../ui/imports/suggest-remove-issue-121315.rs | 11 ++-- .../suggest-remove-issue-121315.stderr | 52 +++++++++++++++++-- tests/ui/lint/unused/issue-59896.rs | 5 +- tests/ui/lint/unused/issue-59896.stderr | 17 ++++++ .../use-redundant-glob-parent.rs | 4 +- .../use-redundant-glob-parent.stderr | 17 ++++++ .../lint/use-redundant/use-redundant-glob.rs | 4 +- .../use-redundant/use-redundant-glob.stderr | 16 ++++++ .../use-redundant-issue-71450.rs | 5 +- .../use-redundant-issue-71450.stderr | 17 ++++++ .../use-redundant-prelude-rust-2015.rs | 14 ++--- .../use-redundant-prelude-rust-2015.stderr | 44 ++++++++++++++++ .../use-redundant-prelude-rust-2021.rs | 8 ++- .../use-redundant-prelude-rust-2021.stderr | 26 ++++++++++ tests/ui/lint/use-redundant/use-redundant.rs | 4 +- .../lint/use-redundant/use-redundant.stderr | 19 ++++++- 28 files changed, 332 insertions(+), 62 deletions(-) create mode 100644 tests/ui/imports/redundant-import-extern-prelude.stderr create mode 100644 tests/ui/imports/redundant-import-issue-121915-2015.stderr create mode 100644 tests/ui/imports/redundant-import-lang-prelude-attr.stderr create mode 100644 tests/ui/imports/redundant-import-lang-prelude.stderr create mode 100644 tests/ui/lint/unused/issue-59896.stderr create mode 100644 tests/ui/lint/use-redundant/use-redundant-glob-parent.stderr create mode 100644 tests/ui/lint/use-redundant/use-redundant-glob.stderr create mode 100644 tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr create mode 100644 tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr create mode 100644 tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 987dbf6db630a..7e4feb0a82716 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -700,10 +700,10 @@ lint_reason_must_be_string_literal = reason must be a string literal lint_reason_must_come_last = reason in lint attribute must come last lint_redundant_import = the item `{$ident}` is imported redundantly - .label_imported_here = the item `{ident}` is already imported here - .label_defined_here = the item `{ident}` is already defined here - .label_imported_prelude = the item `{ident}` is already imported by the extern prelude - .label_defined_prelude = the item `{ident}` is already defined by the extern prelude + .label_imported_here = the item `{$ident}` is already imported here + .label_defined_here = the item `{$ident}` is already defined here + .label_imported_prelude = the item `{$ident}` is already imported by the extern prelude + .label_defined_prelude = the item `{$ident}` is already defined by the extern prelude lint_redundant_import_visibility = glob import doesn't reexport anything with visibility `{$import_vis}` because no imported item is public enough .note = the most public imported item is `{$max_vis}` diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 246b516076461..3fdfb327c70cc 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -82,6 +82,7 @@ declare_lint_pass! { PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, PTR_CAST_ADD_AUTO_TO_OBJECT, PUB_USE_OF_PRIVATE_EXTERN_CRATE, + REDUNDANT_IMPORTS, REDUNDANT_LIFETIMES, REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT_REACHABLE, @@ -426,6 +427,31 @@ declare_lint! { "imports that are never used" } +declare_lint! { + /// The `redundant_imports` lint detects imports that are redundant due to being + /// imported already; either through a previous import, or being present in + /// the prelude. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(redundant_imports)] + /// use std::option::Option::None; + /// fn foo() -> Option { None } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Redundant imports are unnecessary and can be removed to simplify code. + /// If you intended to re-export the item to make it available outside of the + /// module, add a visibility modifier like `pub`. + pub REDUNDANT_IMPORTS, + Allow, + "imports that are redundant due to being imported already" +} + declare_lint! { /// The `must_not_suspend` lint guards against values that shouldn't be held across suspend points /// (`.await`) diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index f76fa62a0094f..0fa5cde9424b5 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -14,7 +14,7 @@ use rustc_middle::metadata::{ModChild, Reexport}; use rustc_middle::{span_bug, ty}; use rustc_session::lint::builtin::{ AMBIGUOUS_GLOB_REEXPORTS, HIDDEN_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, - UNUSED_IMPORTS, + REDUNDANT_IMPORTS, UNUSED_IMPORTS, }; use rustc_session::lint::BuiltinLintDiag; use rustc_span::edit_distance::find_best_match_for_name; @@ -1387,14 +1387,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let mut redundant_spans: Vec<_> = redundant_span.present_items().collect(); redundant_spans.sort(); redundant_spans.dedup(); - /* FIXME(unused_imports): Add this back as a new lint - self.lint_buffer.buffer_lint_with_diagnostic( - UNUSED_IMPORTS, + self.lint_buffer.buffer_lint( + REDUNDANT_IMPORTS, id, import.span, BuiltinLintDiag::RedundantImport(redundant_spans, source), ); - */ return true; } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 6aca0545e64de..a42083b9dea35 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -178,8 +178,8 @@ enum ImplTraitContext { /// Used for tracking import use types which will be used for redundant import checking. /// ### Used::Scope Example -/// ```rust,ignore (redundant_imports) -/// #![deny(unused_imports)] +/// ```rust,compile_fail +/// #![deny(redundant_imports)] /// use std::mem::drop; /// fn main() { /// let s = Box::new(32); diff --git a/tests/ui/imports/redundant-import-extern-prelude.rs b/tests/ui/imports/redundant-import-extern-prelude.rs index f1de06417aa5d..0064eaa931882 100644 --- a/tests/ui/imports/redundant-import-extern-prelude.rs +++ b/tests/ui/imports/redundant-import-extern-prelude.rs @@ -1,16 +1,17 @@ -//@ check-pass // Check that we detect imports that are redundant due to the extern prelude // and that we emit a reasonable diagnostic. // issue: rust-lang/rust#121915 +//~^^^ NOTE the item `aux_issue_121915` is already defined by the extern prelude // See also the discussion in . //@ compile-flags: --extern aux_issue_121915 --edition 2018 //@ aux-build: aux-issue-121915.rs -#[deny(unused_imports)] +#[deny(redundant_imports)] +//~^ NOTE the lint level is defined here fn main() { use aux_issue_121915; - //FIXME(unused_imports): ~^ ERROR the item `aux_issue_121915` is imported redundantly + //~^ ERROR the item `aux_issue_121915` is imported redundantly aux_issue_121915::item(); } diff --git a/tests/ui/imports/redundant-import-extern-prelude.stderr b/tests/ui/imports/redundant-import-extern-prelude.stderr new file mode 100644 index 0000000000000..6d2518c1284b6 --- /dev/null +++ b/tests/ui/imports/redundant-import-extern-prelude.stderr @@ -0,0 +1,14 @@ +error: the item `aux_issue_121915` is imported redundantly + --> $DIR/redundant-import-extern-prelude.rs:14:9 + | +LL | use aux_issue_121915; + | ^^^^^^^^^^^^^^^^ the item `aux_issue_121915` is already defined by the extern prelude + | +note: the lint level is defined here + --> $DIR/redundant-import-extern-prelude.rs:11:8 + | +LL | #[deny(redundant_imports)] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/imports/redundant-import-issue-121915-2015.rs b/tests/ui/imports/redundant-import-issue-121915-2015.rs index be3b8209ada99..dc499bc40b616 100644 --- a/tests/ui/imports/redundant-import-issue-121915-2015.rs +++ b/tests/ui/imports/redundant-import-issue-121915-2015.rs @@ -1,12 +1,11 @@ -//@ check-pass //@ compile-flags: --extern aux_issue_121915 --edition 2015 //@ aux-build: aux-issue-121915.rs extern crate aux_issue_121915; -#[deny(unused_imports)] +#[deny(redundant_imports)] fn main() { use aux_issue_121915; - //FIXME(unused_imports): ~^ ERROR the item `aux_issue_121915` is imported redundantly + //~^ ERROR the item `aux_issue_121915` is imported redundantly aux_issue_121915::item(); } diff --git a/tests/ui/imports/redundant-import-issue-121915-2015.stderr b/tests/ui/imports/redundant-import-issue-121915-2015.stderr new file mode 100644 index 0000000000000..f4e9f604896ab --- /dev/null +++ b/tests/ui/imports/redundant-import-issue-121915-2015.stderr @@ -0,0 +1,17 @@ +error: the item `aux_issue_121915` is imported redundantly + --> $DIR/redundant-import-issue-121915-2015.rs:8:9 + | +LL | extern crate aux_issue_121915; + | ------------------------------ the item `aux_issue_121915` is already imported here +... +LL | use aux_issue_121915; + | ^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/redundant-import-issue-121915-2015.rs:6:8 + | +LL | #[deny(redundant_imports)] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/imports/redundant-import-lang-prelude-attr.rs b/tests/ui/imports/redundant-import-lang-prelude-attr.rs index 59cd570f44c25..f7ee91880bad5 100644 --- a/tests/ui/imports/redundant-import-lang-prelude-attr.rs +++ b/tests/ui/imports/redundant-import-lang-prelude-attr.rs @@ -1,6 +1,6 @@ -//@ check-pass // Check that we detect imports (of built-in attributes) that are redundant due to // the language prelude and that we emit a reasonable diagnostic. +//~^^ NOTE the item `allow` is already defined by the extern prelude // Note that we use the term "extern prelude" in the label even though "language prelude" // would be more correct. However, it's not worth special-casing this. @@ -9,9 +9,10 @@ //@ edition: 2018 -#![deny(unused_imports)] +#![deny(redundant_imports)] +//~^ NOTE the lint level is defined here -use allow; //FIXME(unused_imports): ~ ERROR the item `allow` is imported redundantly +use allow; //~ ERROR the item `allow` is imported redundantly #[allow(unused)] fn main() {} diff --git a/tests/ui/imports/redundant-import-lang-prelude-attr.stderr b/tests/ui/imports/redundant-import-lang-prelude-attr.stderr new file mode 100644 index 0000000000000..f0016f5fab41f --- /dev/null +++ b/tests/ui/imports/redundant-import-lang-prelude-attr.stderr @@ -0,0 +1,14 @@ +error: the item `allow` is imported redundantly + --> $DIR/redundant-import-lang-prelude-attr.rs:15:5 + | +LL | use allow; + | ^^^^^ the item `allow` is already defined by the extern prelude + | +note: the lint level is defined here + --> $DIR/redundant-import-lang-prelude-attr.rs:12:9 + | +LL | #![deny(redundant_imports)] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/imports/redundant-import-lang-prelude.rs b/tests/ui/imports/redundant-import-lang-prelude.rs index 53d3b70996342..3f95ffbe02e7e 100644 --- a/tests/ui/imports/redundant-import-lang-prelude.rs +++ b/tests/ui/imports/redundant-import-lang-prelude.rs @@ -1,16 +1,17 @@ -//@ check-pass // Check that we detect imports that are redundant due to the language prelude // and that we emit a reasonable diagnostic. +//~^^ NOTE the item `u8` is already defined by the extern prelude // Note that we use the term "extern prelude" in the label even though "language prelude" // would be more correct. However, it's not worth special-casing this. // See also the discussion in . -#![deny(unused_imports)] +#![deny(redundant_imports)] +//~^ NOTE the lint level is defined here use std::primitive::u8; -//FIXME(unused_imports): ~^ ERROR the item `u8` is imported redundantly +//~^ ERROR the item `u8` is imported redundantly const _: u8 = 0; diff --git a/tests/ui/imports/redundant-import-lang-prelude.stderr b/tests/ui/imports/redundant-import-lang-prelude.stderr new file mode 100644 index 0000000000000..4fd576397812e --- /dev/null +++ b/tests/ui/imports/redundant-import-lang-prelude.stderr @@ -0,0 +1,14 @@ +error: the item `u8` is imported redundantly + --> $DIR/redundant-import-lang-prelude.rs:13:5 + | +LL | use std::primitive::u8; + | ^^^^^^^^^^^^^^^^^^ the item `u8` is already defined by the extern prelude + | +note: the lint level is defined here + --> $DIR/redundant-import-lang-prelude.rs:10:9 + | +LL | #![deny(redundant_imports)] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/imports/suggest-remove-issue-121315.rs b/tests/ui/imports/suggest-remove-issue-121315.rs index 2bb82833a5bc3..ee3ceb6e3a380 100644 --- a/tests/ui/imports/suggest-remove-issue-121315.rs +++ b/tests/ui/imports/suggest-remove-issue-121315.rs @@ -1,20 +1,19 @@ //@ compile-flags: --edition 2021 - -#![deny(unused_imports)] +#![deny(unused_imports, redundant_imports)] #![allow(dead_code)] fn test0() { // Test remove FlatUnused use std::convert::TryFrom; - //FIXME(unused_imports): ~^ ERROR the item `TryFrom` is imported redundantly + //~^ ERROR the item `TryFrom` is imported redundantly let _ = u32::try_from(5i32); } fn test1() { // FIXME(yukang) Test remove NestedFullUnused use std::convert::{TryFrom, TryInto}; - //FIXME(unused_imports): ~^ ERROR the item `TryFrom` is imported redundantly - //FIXME(unused_imports): ~| ERROR the item `TryInto` is imported redundantly + //~^ ERROR the item `TryFrom` is imported redundantly + //~| ERROR the item `TryInto` is imported redundantly let _ = u32::try_from(5i32); let _a: i32 = u32::try_into(5u32).unwrap(); @@ -24,7 +23,7 @@ fn test2() { // FIXME(yukang): Test remove both redundant and unused use std::convert::{AsMut, Into}; //~^ ERROR unused import: `AsMut` - //FIXME(unused_imports): ~| ERROR the item `Into` is imported redundantly + //~| ERROR the item `Into` is imported redundantly let _a: u32 = (5u8).into(); } diff --git a/tests/ui/imports/suggest-remove-issue-121315.stderr b/tests/ui/imports/suggest-remove-issue-121315.stderr index 5701514e1bd6e..5d0bf9bea6a94 100644 --- a/tests/ui/imports/suggest-remove-issue-121315.stderr +++ b/tests/ui/imports/suggest-remove-issue-121315.stderr @@ -1,20 +1,62 @@ +error: the item `TryFrom` is imported redundantly + --> $DIR/suggest-remove-issue-121315.rs:7:9 + | +LL | use std::convert::TryFrom; + | ^^^^^^^^^^^^^^^^^^^^^ + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL + | + = note: the item `TryFrom` is already defined here + | +note: the lint level is defined here + --> $DIR/suggest-remove-issue-121315.rs:2:25 + | +LL | #![deny(unused_imports, redundant_imports)] + | ^^^^^^^^^^^^^^^^^ + +error: the item `TryFrom` is imported redundantly + --> $DIR/suggest-remove-issue-121315.rs:14:24 + | +LL | use std::convert::{TryFrom, TryInto}; + | ^^^^^^^ + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL + | + = note: the item `TryFrom` is already defined here + +error: the item `TryInto` is imported redundantly + --> $DIR/suggest-remove-issue-121315.rs:14:33 + | +LL | use std::convert::{TryFrom, TryInto}; + | ^^^^^^^ + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL + | + = note: the item `TryInto` is already defined here + error: unused import: `AsMut` - --> $DIR/suggest-remove-issue-121315.rs:25:24 + --> $DIR/suggest-remove-issue-121315.rs:24:24 | LL | use std::convert::{AsMut, Into}; | ^^^^^ | note: the lint level is defined here - --> $DIR/suggest-remove-issue-121315.rs:3:9 + --> $DIR/suggest-remove-issue-121315.rs:2:9 | -LL | #![deny(unused_imports)] +LL | #![deny(unused_imports, redundant_imports)] | ^^^^^^^^^^^^^^ +error: the item `Into` is imported redundantly + --> $DIR/suggest-remove-issue-121315.rs:24:31 + | +LL | use std::convert::{AsMut, Into}; + | ^^^^ + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL + | + = note: the item `Into` is already defined here + error: unused import: `From` - --> $DIR/suggest-remove-issue-121315.rs:34:24 + --> $DIR/suggest-remove-issue-121315.rs:33:24 | LL | use std::convert::{From, Infallible}; | ^^^^ -error: aborting due to 2 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/lint/unused/issue-59896.rs b/tests/ui/lint/unused/issue-59896.rs index a98017524f550..5624e7f02fb43 100644 --- a/tests/ui/lint/unused/issue-59896.rs +++ b/tests/ui/lint/unused/issue-59896.rs @@ -1,10 +1,9 @@ -//@ check-pass -#![deny(unused_imports)] +#![deny(redundant_imports)] struct S; fn main() { - use S; //FIXME(unused_imports): ~ ERROR the item `S` is imported redundantly + use S; //~ ERROR the item `S` is imported redundantly let _s = S; } diff --git a/tests/ui/lint/unused/issue-59896.stderr b/tests/ui/lint/unused/issue-59896.stderr new file mode 100644 index 0000000000000..363a6419d9c85 --- /dev/null +++ b/tests/ui/lint/unused/issue-59896.stderr @@ -0,0 +1,17 @@ +error: the item `S` is imported redundantly + --> $DIR/issue-59896.rs:6:9 + | +LL | struct S; + | --------- the item `S` is already defined here +... +LL | use S; + | ^ + | +note: the lint level is defined here + --> $DIR/issue-59896.rs:1:9 + | +LL | #![deny(redundant_imports)] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/use-redundant/use-redundant-glob-parent.rs b/tests/ui/lint/use-redundant/use-redundant-glob-parent.rs index 797e57f48e9d2..c8c413dccd3f2 100644 --- a/tests/ui/lint/use-redundant/use-redundant-glob-parent.rs +++ b/tests/ui/lint/use-redundant/use-redundant-glob-parent.rs @@ -1,5 +1,5 @@ //@ check-pass -#![warn(unused_imports)] +#![warn(redundant_imports)] pub mod bar { pub struct Foo(pub Bar); @@ -9,7 +9,7 @@ pub mod bar { use bar::*; pub fn warning() -> Foo { - use bar::Foo; //FIXME(unused_imports): ~ WARNING imported redundantly + use bar::Foo; //~ WARNING imported redundantly Foo(Bar('a')) } diff --git a/tests/ui/lint/use-redundant/use-redundant-glob-parent.stderr b/tests/ui/lint/use-redundant/use-redundant-glob-parent.stderr new file mode 100644 index 0000000000000..3b06b2df67454 --- /dev/null +++ b/tests/ui/lint/use-redundant/use-redundant-glob-parent.stderr @@ -0,0 +1,17 @@ +warning: the item `Foo` is imported redundantly + --> $DIR/use-redundant-glob-parent.rs:12:9 + | +LL | use bar::*; + | ------ the item `Foo` is already imported here +... +LL | use bar::Foo; + | ^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/use-redundant-glob-parent.rs:2:9 + | +LL | #![warn(redundant_imports)] + | ^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/lint/use-redundant/use-redundant-glob.rs b/tests/ui/lint/use-redundant/use-redundant-glob.rs index e5835be89d841..52383d4ceffc3 100644 --- a/tests/ui/lint/use-redundant/use-redundant-glob.rs +++ b/tests/ui/lint/use-redundant/use-redundant-glob.rs @@ -1,5 +1,5 @@ //@ check-pass -#![warn(unused_imports)] +#![warn(redundant_imports)] pub mod bar { pub struct Foo(pub Bar); @@ -8,7 +8,7 @@ pub mod bar { pub fn warning() -> bar::Foo { use bar::*; - use bar::Foo; //FIXME(unused_imports): ~ WARNING imported redundantly + use bar::Foo; //~ WARNING imported redundantly Foo(Bar('a')) } diff --git a/tests/ui/lint/use-redundant/use-redundant-glob.stderr b/tests/ui/lint/use-redundant/use-redundant-glob.stderr new file mode 100644 index 0000000000000..47b2ce54bb733 --- /dev/null +++ b/tests/ui/lint/use-redundant/use-redundant-glob.stderr @@ -0,0 +1,16 @@ +warning: the item `Foo` is imported redundantly + --> $DIR/use-redundant-glob.rs:11:9 + | +LL | use bar::*; + | ------ the item `Foo` is already imported here +LL | use bar::Foo; + | ^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/use-redundant-glob.rs:2:9 + | +LL | #![warn(redundant_imports)] + | ^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/lint/use-redundant/use-redundant-issue-71450.rs b/tests/ui/lint/use-redundant/use-redundant-issue-71450.rs index 2db3435d46dbd..6a3ffa4522ae2 100644 --- a/tests/ui/lint/use-redundant/use-redundant-issue-71450.rs +++ b/tests/ui/lint/use-redundant/use-redundant-issue-71450.rs @@ -1,6 +1,6 @@ //@ check-pass -#![warn(unused_imports)] +#![warn(redundant_imports)] mod foo { use std::fmt; @@ -23,8 +23,7 @@ mod foo { fn main() { { - use std::string::String; - //FIXME(unused_imports): ~^ WARNING the item `String` is imported redundantly + use std::string::String; //~ WARNING the item `String` is imported redundantly // 'String' from 'std::string::String'. let s = String::new(); println!("{}", s); diff --git a/tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr b/tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr new file mode 100644 index 0000000000000..c14ab9e11e0fc --- /dev/null +++ b/tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr @@ -0,0 +1,17 @@ +warning: the item `String` is imported redundantly + --> $DIR/use-redundant-issue-71450.rs:26:13 + | +LL | use std::string::String; + | ^^^^^^^^^^^^^^^^^^^ + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL + | + = note: the item `String` is already defined here + | +note: the lint level is defined here + --> $DIR/use-redundant-issue-71450.rs:3:9 + | +LL | #![warn(redundant_imports)] + | ^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs index 62f50c8a0df90..6abe3602abee7 100644 --- a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs +++ b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs @@ -1,16 +1,12 @@ //@ check-pass -#![warn(unused_imports)] +#![warn(redundant_imports)] -use std::option::Option::Some; -//FIXME(unused_imports): ~^ WARNING the item `Some` is imported redundantly -use std::option::Option::None; -//FIXME(unused_imports): ~ WARNING the item `None` is imported redundantly +use std::option::Option::Some;//~ WARNING the item `Some` is imported redundantly +use std::option::Option::None; //~ WARNING the item `None` is imported redundantly -use std::result::Result::Ok; -//FIXME(unused_imports): ~^ WARNING the item `Ok` is imported redundantly -use std::result::Result::Err; -//FIXME(unused_imports): ~^ WARNING the item `Err` is imported redundantly +use std::result::Result::Ok;//~ WARNING the item `Ok` is imported redundantly +use std::result::Result::Err;//~ WARNING the item `Err` is imported redundantly use std::convert::{TryFrom, TryInto}; fn main() { diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr new file mode 100644 index 0000000000000..2b0e16a87dc06 --- /dev/null +++ b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr @@ -0,0 +1,44 @@ +warning: the item `Some` is imported redundantly + --> $DIR/use-redundant-prelude-rust-2015.rs:5:5 + | +LL | use std::option::Option::Some; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL + | + = note: the item `Some` is already defined here + | +note: the lint level is defined here + --> $DIR/use-redundant-prelude-rust-2015.rs:2:9 + | +LL | #![warn(redundant_imports)] + | ^^^^^^^^^^^^^^^^^ + +warning: the item `None` is imported redundantly + --> $DIR/use-redundant-prelude-rust-2015.rs:6:5 + | +LL | use std::option::Option::None; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL + | + = note: the item `None` is already defined here + +warning: the item `Ok` is imported redundantly + --> $DIR/use-redundant-prelude-rust-2015.rs:8:5 + | +LL | use std::result::Result::Ok; + | ^^^^^^^^^^^^^^^^^^^^^^^ + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL + | + = note: the item `Ok` is already defined here + +warning: the item `Err` is imported redundantly + --> $DIR/use-redundant-prelude-rust-2015.rs:9:5 + | +LL | use std::result::Result::Err; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL + | + = note: the item `Err` is already defined here + +warning: 4 warnings emitted + diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs index 1baa1ac1b8cd3..236ee032b677b 100644 --- a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs +++ b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs @@ -1,11 +1,9 @@ //@ check-pass //@ edition:2021 -#![warn(unused_imports)] +#![warn(redundant_imports)] -use std::convert::TryFrom; -//FIXME(unused_imports): ~^ WARNING the item `TryFrom` is imported redundantly -use std::convert::TryInto; -//FIXME(unused_imports): ~^ WARNING the item `TryInto` is imported redundantly +use std::convert::TryFrom;//~ WARNING the item `TryFrom` is imported redundantly +use std::convert::TryInto;//~ WARNING the item `TryInto` is imported redundantly fn main() { let _e: Result = 8u8.try_into(); diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr new file mode 100644 index 0000000000000..526771c597aa7 --- /dev/null +++ b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.stderr @@ -0,0 +1,26 @@ +warning: the item `TryFrom` is imported redundantly + --> $DIR/use-redundant-prelude-rust-2021.rs:5:5 + | +LL | use std::convert::TryFrom; + | ^^^^^^^^^^^^^^^^^^^^^ + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL + | + = note: the item `TryFrom` is already defined here + | +note: the lint level is defined here + --> $DIR/use-redundant-prelude-rust-2021.rs:3:9 + | +LL | #![warn(redundant_imports)] + | ^^^^^^^^^^^^^^^^^ + +warning: the item `TryInto` is imported redundantly + --> $DIR/use-redundant-prelude-rust-2021.rs:6:5 + | +LL | use std::convert::TryInto; + | ^^^^^^^^^^^^^^^^^^^^^ + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL + | + = note: the item `TryInto` is already defined here + +warning: 2 warnings emitted + diff --git a/tests/ui/lint/use-redundant/use-redundant.rs b/tests/ui/lint/use-redundant/use-redundant.rs index 9e4902af34b7d..0efed378f988b 100644 --- a/tests/ui/lint/use-redundant/use-redundant.rs +++ b/tests/ui/lint/use-redundant/use-redundant.rs @@ -1,5 +1,5 @@ //@ check-pass -#![warn(unused_imports)] +#![warn(unused_imports, redundant_imports)] use crate::foo::Bar; @@ -18,7 +18,7 @@ use m1::*; //~ WARNING unused import use m2::*; //~ WARNING unused import fn main() { - use crate::foo::Bar; //FIXME(unused_imports): ~ WARNING imported redundantly + use crate::foo::Bar; //~ WARNING imported redundantly let _a: Bar = 3; baz(); diff --git a/tests/ui/lint/use-redundant/use-redundant.stderr b/tests/ui/lint/use-redundant/use-redundant.stderr index 224e841123748..76846a1dca98d 100644 --- a/tests/ui/lint/use-redundant/use-redundant.stderr +++ b/tests/ui/lint/use-redundant/use-redundant.stderr @@ -7,7 +7,7 @@ LL | use m1::*; note: the lint level is defined here --> $DIR/use-redundant.rs:2:9 | -LL | #![warn(unused_imports)] +LL | #![warn(unused_imports, redundant_imports)] | ^^^^^^^^^^^^^^ warning: unused import: `m2::*` @@ -16,5 +16,20 @@ warning: unused import: `m2::*` LL | use m2::*; | ^^^^^ -warning: 2 warnings emitted +warning: the item `Bar` is imported redundantly + --> $DIR/use-redundant.rs:21:9 + | +LL | use crate::foo::Bar; + | --------------- the item `Bar` is already imported here +... +LL | use crate::foo::Bar; + | ^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/use-redundant.rs:2:25 + | +LL | #![warn(unused_imports, redundant_imports)] + | ^^^^^^^^^^^^^^^^^ + +warning: 3 warnings emitted From e84a7d91b7b618fe5bb8d3c0face3384c768fb2c Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 31 Jul 2024 13:45:14 +0000 Subject: [PATCH 16/18] Remove unneeded `pub(crate)` --- library/std/src/sys/anonymous_pipe/unsupported.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/anonymous_pipe/unsupported.rs b/library/std/src/sys/anonymous_pipe/unsupported.rs index da04e8e6b25af..dd51e70315e96 100644 --- a/library/std/src/sys/anonymous_pipe/unsupported.rs +++ b/library/std/src/sys/anonymous_pipe/unsupported.rs @@ -1,7 +1,7 @@ use crate::io; use crate::pipe::{PipeReader, PipeWriter}; use crate::process::Stdio; -pub(crate) use crate::sys::pipe::AnonPipe; +pub use crate::sys::pipe::AnonPipe; #[inline] pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { From 62d4998753ecf0f88105733b03152ef94deaee71 Mon Sep 17 00:00:00 2001 From: B I Mohammed Abbas Date: Wed, 31 Jul 2024 19:28:18 +0530 Subject: [PATCH 17/18] Add VxWorks platfrom support documents --- src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 12 ++--- src/doc/rustc/src/platform-support/vxworks.md | 51 +++++++++++++++++++ 3 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 src/doc/rustc/src/platform-support/vxworks.md diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 292b6032f8493..08460af15d4c7 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -74,6 +74,7 @@ - [*-unknown-openbsd](platform-support/openbsd.md) - [*-unknown-redox](platform-support/redox.md) - [\*-unknown-uefi](platform-support/unknown-uefi.md) + - [\*-wrs-vxworks](platform-support/vxworks.md) - [wasm32-wasip1](platform-support/wasm32-wasip1.md) - [wasm32-wasip1-threads](platform-support/wasm32-wasip1-threads.md) - [wasm32-wasip2](platform-support/wasm32-wasip2.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 0c7f4e7bf1b43..cbb338f481172 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -263,7 +263,7 @@ target | std | host | notes [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD [`aarch64-unknown-redox`](platform-support/redox.md) | ✓ | | ARM64 Redox OS `aarch64-uwp-windows-msvc` | ✓ | | -`aarch64-wrs-vxworks` | ? | | +[`aarch64-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | ARM64 VxWorks OS `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI) `aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian) [`aarch64_be-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD (big-endian) @@ -281,7 +281,7 @@ target | std | host | notes [`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | Armv7-A Linux with uClibc, hardfloat `armv7-unknown-freebsd` | ✓ | ✓ | Armv7-A FreeBSD [`armv7-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv7-A NetBSD w/hard-float -`armv7-wrs-vxworks-eabihf` | ? | | Armv7-A for VxWorks +[`armv7-wrs-vxworks-eabihf`](platform-support/vxworks.md) | ? | | Armv7-A for VxWorks [`armv7a-kmc-solid_asp3-eabi`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3 [`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3, hardfloat [`armv7a-none-eabihf`](platform-support/arm-none-eabi.md) | * | | Bare Armv7-A, hardfloat @@ -307,7 +307,7 @@ target | std | host | notes `i686-uwp-windows-gnu` | ✓ | | [^x86_32-floats-return-ABI] `i686-uwp-windows-msvc` | ✓ | | [^x86_32-floats-return-ABI] [`i686-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ | | 32-bit Windows 7 support [^x86_32-floats-return-ABI] -`i686-wrs-vxworks` | ? | | [^x86_32-floats-return-ABI] +[`i686-wrs-vxworks`](platform-support/vxworks.md) | ? | | [^x86_32-floats-return-ABI] [`m68k-unknown-linux-gnu`](platform-support/m68k-unknown-linux-gnu.md) | ? | | Motorola 680x0 Linux `mips-unknown-linux-gnu` | ✓ | ✓ | MIPS Linux (kernel 4.4, glibc 2.23) `mips-unknown-linux-musl` | ✓ | | MIPS Linux with musl 1.2.3 @@ -333,8 +333,8 @@ target | std | host | notes `powerpc-unknown-linux-musl` | ? | | PowerPC Linux with musl 1.2.3 [`powerpc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD 32-bit powerpc systems [`powerpc-unknown-openbsd`](platform-support/powerpc-unknown-openbsd.md) | * | | -`powerpc-wrs-vxworks-spe` | ? | | -`powerpc-wrs-vxworks` | ? | | +[`powerpc-wrs-vxworks-spe`](platform-support/vxworks.md) | ? | | +[`powerpc-wrs-vxworks`](platform-support/vxworks.md) | ? | | `powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2) `powerpc64le-unknown-freebsd` | | | PPC64LE FreeBSD `powerpc-unknown-freebsd` | | | PowerPC FreeBSD @@ -383,7 +383,7 @@ target | std | host | notes `x86_64-uwp-windows-gnu` | ✓ | | `x86_64-uwp-windows-msvc` | ✓ | | [`x86_64-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ | | 64-bit Windows 7 support -`x86_64-wrs-vxworks` | ? | | +[`x86_64-wrs-vxworks`](platform-support/vxworks.md) | ? | | [`x86_64h-apple-darwin`](platform-support/x86_64h-apple-darwin.md) | ✓ | ✓ | macOS with late-gen Intel (at least Haswell) [`x86_64-unknown-linux-none`](platform-support/x86_64-unknown-linux-none.md) | * | | 64-bit Linux with no libc [`xtensa-esp32-none-elf`](platform-support/xtensa.md) | * | | Xtensa ESP32 diff --git a/src/doc/rustc/src/platform-support/vxworks.md b/src/doc/rustc/src/platform-support/vxworks.md new file mode 100644 index 0000000000000..c0a818558e0bf --- /dev/null +++ b/src/doc/rustc/src/platform-support/vxworks.md @@ -0,0 +1,51 @@ +# `*-wrs-vxworks` + +**Tier: 3** + +Targets for the VxWorks operating +system. + +Target triplets available: + +- `x86_64-wrs-vxworks` +- `aarch64-wrs-vxworks` +- `i686-wrs-vxworks` +- `armv7-wrs-vxworks-eabihf` +- `powerpc-wrs-vxworks` +- `powerpc-wrs-vxworks-spe` + +## Target maintainers + +- B I Mohammed Abbas ([@biabbas](https://github.com/biabbas)) + +## Requirements + +Rust for each target can be cross-compiled with its specific target vsb configuration. Std support is added but not yet fully tested. + +## Building the target + +You can build Rust with support for the targets by adding it to the `target` list in `config.toml`. In addition the workbench and wr-cc have to configured and activated. + +```toml +[build] +build-stage = 1 +target = [ + "", + "x86_64-wrs-vxworks", + "aarch64-wrs-vxworks", + "i686-wrs-vxworks", + "armv7-wrs-vxworks-eabihf", + "powerpc-wrs-vxworks", + "powerpc-wrs-vxworks-spe", +] +``` + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for VxWorks. + +The easiest way to build and test programs for VxWorks is to use the shipped rustc and cargo in VxWorks workbench, following the official windriver guidelines. + +## Cross-compilation toolchains and C code + +The target supports C code. Pre-compiled C toolchains can be found in provided VxWorks workbench. From f6c4110b9d0afdc1b20962fa06dc3d90df768ec5 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 31 Jul 2024 17:38:40 +0300 Subject: [PATCH 18/18] improve bootstrap to allow selecting llvm tools individually Everything works as before, + now bootstrap allows for individually selecting LLVM tools (e.g., `x dist opt llvm-dis`) to include in the dist artifact. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/dist.rs | 37 ++++++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 967ddbc0d3483..58f86aa996dd1 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2122,8 +2122,13 @@ impl Step for LlvmTools { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let default = should_build_extended_tool(run.builder, "llvm-tools"); - // FIXME: allow using the names of the tools themselves? - run.alias("llvm-tools").default_condition(default) + + let mut run = run.alias("llvm-tools"); + for tool in LLVM_TOOLS { + run = run.alias(tool); + } + + run.default_condition(default) } fn make_run(run: RunConfig<'_>) { @@ -2131,6 +2136,32 @@ impl Step for LlvmTools { } fn run(self, builder: &Builder<'_>) -> Option { + fn tools_to_install(paths: &[PathBuf]) -> Vec<&'static str> { + let mut tools = vec![]; + + for path in paths { + let path = path.to_str().unwrap(); + + // Include all tools if path is 'llvm-tools'. + if path == "llvm-tools" { + return LLVM_TOOLS.to_owned(); + } + + for tool in LLVM_TOOLS { + if path == *tool { + tools.push(*tool); + } + } + } + + // If no specific tool is requested, include all tools. + if tools.is_empty() { + tools = LLVM_TOOLS.to_owned(); + } + + tools + } + let target = self.target; /* run only if llvm-config isn't used */ @@ -2151,7 +2182,7 @@ impl Step for LlvmTools { // Prepare the image directory let src_bindir = builder.llvm_out(target).join("bin"); let dst_bindir = format!("lib/rustlib/{}/bin", target.triple); - for tool in LLVM_TOOLS { + for tool in tools_to_install(&builder.paths) { let exe = src_bindir.join(exe(tool, target)); tarball.add_file(&exe, &dst_bindir, 0o755); }