From 0d4a3f11e2170c3c35b1faf4bd0ba86c73a56221 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 22 Feb 2022 23:19:57 -0800 Subject: [PATCH 1/5] mir-opt: Replace clone on primitives with copy We can't do it for everything, but it would be nice to at least stop making calls to clone methods in debug from things like derived-clones. --- compiler/rustc_middle/src/mir/mod.rs | 30 +++++++ .../rustc_mir_transform/src/instcombine.rs | 85 ++++++++++++++++++- src/test/codegen/inline-hint.rs | 4 +- .../mir-opt/combine_clone_of_primitives.rs | 19 +++++ ...primitives.{impl#0}-clone.InstCombine.diff | 80 +++++++++++++++++ 5 files changed, 214 insertions(+), 4 deletions(-) create mode 100644 src/test/mir-opt/combine_clone_of_primitives.rs create mode 100644 src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 39d6b1267a593..fc438edc7229e 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1915,6 +1915,27 @@ impl<'tcx> Place<'tcx> { (base, proj) }) } + + /// Generates a new place by appending `more_projections` to the existing ones + /// and interning the result. + pub fn project_deeper(self, more_projections: &[PlaceElem<'tcx>], tcx: TyCtxt<'tcx>) -> Self { + if more_projections.is_empty() { + return self; + } + + let mut v: Vec>; + + let new_projections = if self.projection.is_empty() { + more_projections + } else { + v = Vec::with_capacity(self.projection.len() + more_projections.len()); + v.extend(self.projection); + v.extend(more_projections); + &v + }; + + Place { local: self.local, projection: tcx.intern_place_elems(new_projections) } + } } impl From for Place<'_> { @@ -2187,6 +2208,15 @@ impl<'tcx> Operand<'tcx> { Operand::Copy(_) | Operand::Move(_) => None, } } + + /// Gets the `ty::FnDef` from an operand if it's a constant function item. + /// + /// While this is unlikely in general, it's the normal case of what you'll + /// find as the `func` in a [`TerminatorKind::Call`]. + pub fn const_fn_def(&self) -> Option<(DefId, SubstsRef<'tcx>)> { + let const_ty = self.constant()?.literal.const_for_ty()?.ty(); + if let ty::FnDef(def_id, substs) = *const_ty.kind() { Some((def_id, substs)) } else { None } + } } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_mir_transform/src/instcombine.rs b/compiler/rustc_mir_transform/src/instcombine.rs index 385fcc43496e3..30e55d7e2faeb 100644 --- a/compiler/rustc_mir_transform/src/instcombine.rs +++ b/compiler/rustc_mir_transform/src/instcombine.rs @@ -4,9 +4,9 @@ use crate::MirPass; use rustc_hir::Mutability; use rustc_middle::mir::{ BinOp, Body, Constant, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo, - StatementKind, UnOp, + Statement, StatementKind, Terminator, TerminatorKind, UnOp, }; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TyKind}; pub struct InstCombine; @@ -29,6 +29,11 @@ impl<'tcx> MirPass<'tcx> for InstCombine { _ => {} } } + + ctx.combine_primitive_clone( + &mut block.terminator.as_mut().unwrap(), + &mut block.statements, + ); } } } @@ -130,4 +135,80 @@ impl<'tcx> InstCombineContext<'tcx, '_> { } } } + + fn combine_primitive_clone( + &self, + terminator: &mut Terminator<'tcx>, + statements: &mut Vec>, + ) { + let TerminatorKind::Call { func, args, destination, .. } = &mut terminator.kind + else { return }; + + // It's definitely not a clone if there are multiple arguments + if args.len() != 1 { + return; + } + + let Some((destination_place, destination_block)) = *destination + else { return }; + + // Only bother looking more if it's easy to know what we're calling + let Some((fn_def_id, fn_substs)) = func.const_fn_def() + else { return }; + + // Clone needs one subst, so we can cheaply rule out other stuff + if fn_substs.len() != 1 { + return; + } + + // These types are easily available from locals, so check that before + // doing DefId lookups to figure out what we're actually calling. + let arg_ty = args[0].ty(self.local_decls, self.tcx); + + let ty::Ref(_region, inner_ty, Mutability::Not) = *arg_ty.kind() + else { return }; + + if !is_trivially_pure_copy(self.tcx, inner_ty) { + return; + } + + let trait_def_id = self.tcx.trait_of_item(fn_def_id); + if trait_def_id.is_none() || trait_def_id != self.tcx.lang_items().clone_trait() { + return; + } + + if !self.tcx.consider_optimizing(|| { + format!( + "InstCombine - Call: {:?} SourceInfo: {:?}", + (fn_def_id, fn_substs), + terminator.source_info + ) + }) { + return; + } + + let Some(arg_place) = args.pop().unwrap().place() + else { return }; + + statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(box ( + destination_place, + Rvalue::Use(Operand::Copy( + arg_place.project_deeper(&[ProjectionElem::Deref], self.tcx), + )), + )), + }); + terminator.kind = TerminatorKind::Goto { target: destination_block }; + } +} + +fn is_trivially_pure_copy<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { + use TyKind::*; + match *ty.kind() { + Bool | Char | Int(..) | Uint(..) | Float(..) => true, + Array(element_ty, _len) => is_trivially_pure_copy(tcx, element_ty), + Tuple(field_tys) => field_tys.iter().all(|x| is_trivially_pure_copy(tcx, x)), + _ => false, + } } diff --git a/src/test/codegen/inline-hint.rs b/src/test/codegen/inline-hint.rs index ad41badf38169..d3ea1915a8b19 100644 --- a/src/test/codegen/inline-hint.rs +++ b/src/test/codegen/inline-hint.rs @@ -6,7 +6,7 @@ pub fn f() { let a = A; - let b = (0i32, 1i32, 2i32, 3i32); + let b = (0i32, 1i32, 2i32, 3 as *const i32); let c = || {}; a(String::new(), String::new()); @@ -21,7 +21,7 @@ struct A(String, String); // CHECK-NOT: inlinehint // CHECK-SAME: {{$}} -// CHECK: ; <(i32, i32, i32, i32) as core::clone::Clone>::clone +// CHECK: ; <(i32, i32, i32, *const i{{16|32|64}}) as core::clone::Clone>::clone // CHECK-NEXT: ; Function Attrs: inlinehint // CHECK: ; inline_hint::f::{closure#0} diff --git a/src/test/mir-opt/combine_clone_of_primitives.rs b/src/test/mir-opt/combine_clone_of_primitives.rs new file mode 100644 index 0000000000000..894d9281d5dca --- /dev/null +++ b/src/test/mir-opt/combine_clone_of_primitives.rs @@ -0,0 +1,19 @@ +// compile-flags: -C opt-level=0 -Z inline_mir=no + +// EMIT_MIR combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff + +#[derive(Clone)] +struct MyThing { + v: T, + i: u64, + a: [f32; 3], +} + +fn main() { + let x = MyThing:: { v: 2, i: 3, a: [0.0; 3] }; + let y = x.clone(); + + assert_eq!(y.v, 2); + assert_eq!(y.i, 3); + assert_eq!(y.a, [0.0; 3]); +} diff --git a/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff b/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff new file mode 100644 index 0000000000000..a19b92d908462 --- /dev/null +++ b/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff @@ -0,0 +1,80 @@ +- // MIR for `::clone` before InstCombine ++ // MIR for `::clone` after InstCombine + + fn ::clone(_1: &MyThing) -> MyThing { + debug self => _1; // in scope 0 at $DIR/combine_clone_of_primitives.rs:5:10: 5:15 + let mut _0: MyThing; // return place in scope 0 at $DIR/combine_clone_of_primitives.rs:5:10: 5:15 + let _2: &T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 + let _3: &u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 + let _4: &[f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 + let mut _5: T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 + let mut _6: &T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 + let _7: &T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 + let mut _8: u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 + let mut _9: &u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 + let _10: &u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 + let mut _11: [f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 + let mut _12: &[f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 + let _13: &[f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 + scope 1 { + debug __self_0_0 => _2; // in scope 1 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 + debug __self_0_1 => _3; // in scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 + debug __self_0_2 => _4; // in scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 + } + + bb0: { + _2 = &((*_1).0: T); // scope 0 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 + _3 = &((*_1).1: u64); // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 + _4 = &((*_1).2: [f32; 3]); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 +- _7 = &(*_2); // scope 1 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 +- _6 = &(*_7); // scope 1 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 ++ _7 = _2; // scope 1 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 ++ _6 = _7; // scope 1 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 + _5 = ::clone(move _6) -> bb1; // scope 1 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 + // mir::Constant + // + span: $DIR/combine_clone_of_primitives.rs:7:5: 7:9 + // + literal: Const { ty: for<'r> fn(&'r T) -> T {::clone}, val: Value(Scalar()) } + } + + bb1: { +- _10 = &(*_3); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 +- _9 = &(*_10); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 +- _8 = ::clone(move _9) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 +- // mir::Constant +- // + span: $DIR/combine_clone_of_primitives.rs:8:5: 8:11 +- // + literal: Const { ty: for<'r> fn(&'r u64) -> u64 {::clone}, val: Value(Scalar()) } ++ _10 = _3; // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 ++ _9 = _10; // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 ++ _8 = (*_9); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 ++ goto -> bb2; // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 + } + + bb2: { +- _13 = &(*_4); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 +- _12 = &(*_13); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 +- _11 = <[f32; 3] as Clone>::clone(move _12) -> [return: bb3, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 +- // mir::Constant +- // + span: $DIR/combine_clone_of_primitives.rs:9:5: 9:16 +- // + literal: Const { ty: for<'r> fn(&'r [f32; 3]) -> [f32; 3] {<[f32; 3] as Clone>::clone}, val: Value(Scalar()) } ++ _13 = _4; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 ++ _12 = _13; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 ++ _11 = (*_12); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 ++ goto -> bb3; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 + } + + bb3: { + (_0.0: T) = move _5; // scope 1 at $DIR/combine_clone_of_primitives.rs:5:10: 5:15 + (_0.1: u64) = move _8; // scope 1 at $DIR/combine_clone_of_primitives.rs:5:10: 5:15 + (_0.2: [f32; 3]) = move _11; // scope 1 at $DIR/combine_clone_of_primitives.rs:5:10: 5:15 + return; // scope 0 at $DIR/combine_clone_of_primitives.rs:5:15: 5:15 + } + + bb4 (cleanup): { + drop(_5) -> bb5; // scope 1 at $DIR/combine_clone_of_primitives.rs:5:14: 5:15 + } + + bb5 (cleanup): { + resume; // scope 0 at $DIR/combine_clone_of_primitives.rs:5:10: 5:15 + } + } + From b5a54d8777f00141954527a118715b1a36981b73 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 5 Mar 2022 15:19:57 -0800 Subject: [PATCH 2/5] Move `is_trivially_pure_clone_copy` onto `Ty` instead --- compiler/rustc_middle/src/ty/sty.rs | 51 +++++++++++++++++++ .../rustc_mir_transform/src/instcombine.rs | 14 +---- 2 files changed, 53 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 8b0e7794f92ac..f94fd1e2e6d98 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2371,6 +2371,57 @@ impl<'tcx> Ty<'tcx> { } } } + + /// Fast path helper for primitives which are always `Copy` and which + /// have a side-effect-free `Clone` impl. + /// + /// Returning true means the type is known to be pure and `Copy+Clone`. + /// Returning `false` means nothing -- could be `Copy`, might not be. + /// + /// This is mostly useful for optimizations, as there are the types + /// on which we can replace cloning with dereferencing. + pub fn is_trivially_pure_clone_copy(self) -> bool { + match self.kind() { + ty::Bool | ty::Char | ty::Never => true, + + // These aren't even `Clone` + ty::Str | ty::Slice(..) | ty::Foreign(..) | ty::Dynamic(..) => false, + + ty::Int(..) | ty::Uint(..) | ty::Float(..) => true, + + // The voldemort ZSTs are fine. + ty::FnDef(..) => true, + + ty::Array(element_ty, _len) => element_ty.is_trivially_pure_clone_copy(), + + // A 100-tuple isn't "trivial", so doing this only for reasonable sizes. + ty::Tuple(field_tys) => { + field_tys.len() <= 3 && field_tys.iter().all(Self::is_trivially_pure_clone_copy) + } + + // Sometimes traits aren't implemented for every ABI or arity, + // because we can't be generic over everything yet. + ty::FnPtr(..) => false, + + // Definitely absolutely not copy. + ty::Ref(_, _, hir::Mutability::Mut) => false, + + // Thin pointers & thin shared references are pure-clone-copy, but for + // anything with custom metadata it might be more complicated. + ty::Ref(_, _, hir::Mutability::Not) | ty::RawPtr(..) => false, + + ty::Generator(..) | ty::GeneratorWitness(..) => false, + + // Might be, but not "trivial" so just giving the safe answer. + ty::Adt(..) | ty::Closure(..) | ty::Opaque(..) => false, + + ty::Projection(..) | ty::Param(..) | ty::Infer(..) | ty::Error(..) => false, + + ty::Bound(..) | ty::Placeholder(..) => { + bug!("`is_trivially_pure_clone_copy` applied to unexpected type: {:?}", self); + } + } + } } /// Extra information about why we ended up with a particular variance. diff --git a/compiler/rustc_mir_transform/src/instcombine.rs b/compiler/rustc_mir_transform/src/instcombine.rs index 30e55d7e2faeb..d1c4a4b21d0a2 100644 --- a/compiler/rustc_mir_transform/src/instcombine.rs +++ b/compiler/rustc_mir_transform/src/instcombine.rs @@ -6,7 +6,7 @@ use rustc_middle::mir::{ BinOp, Body, Constant, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UnOp, }; -use rustc_middle::ty::{self, Ty, TyCtxt, TyKind}; +use rustc_middle::ty::{self, TyCtxt}; pub struct InstCombine; @@ -168,7 +168,7 @@ impl<'tcx> InstCombineContext<'tcx, '_> { let ty::Ref(_region, inner_ty, Mutability::Not) = *arg_ty.kind() else { return }; - if !is_trivially_pure_copy(self.tcx, inner_ty) { + if !inner_ty.is_trivially_pure_clone_copy() { return; } @@ -202,13 +202,3 @@ impl<'tcx> InstCombineContext<'tcx, '_> { terminator.kind = TerminatorKind::Goto { target: destination_block }; } } - -fn is_trivially_pure_copy<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { - use TyKind::*; - match *ty.kind() { - Bool | Char | Int(..) | Uint(..) | Float(..) => true, - Array(element_ty, _len) => is_trivially_pure_copy(tcx, element_ty), - Tuple(field_tys) => field_tys.iter().all(|x| is_trivially_pure_copy(tcx, x)), - _ => false, - } -} From 54408f096377190a7faf67cb7ef4eda6e1ed4700 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 5 Mar 2022 23:51:10 -0800 Subject: [PATCH 3/5] short-circuit the easy cases in `is_copy_modulo_regions` This change is somewhat extensive, since it affects MIR -- since this is called to determine Copy vs Move -- so any test that's `no_core` needs to actually have the normal `impl`s it uses. --- compiler/rustc_middle/src/ty/util.rs | 2 +- src/test/assembly/sparc-struct-abi.rs | 1 + src/test/assembly/target-feature-multiple.rs | 1 + src/test/codegen/abi-sysv64.rs | 1 + src/test/codegen/abi-x86-interrupt.rs | 1 + src/test/codegen/frame-pointer.rs | 2 +- .../codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs | 8 ++++++++ .../cmse-nonsecure-call/params-on-registers.rs | 1 + .../cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs | 1 + .../cmse-nonsecure-entry/params-on-registers.rs | 1 + .../cmse-nonsecure-entry/params-on-stack.rs | 1 + 11 files changed, 18 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 04e766d16cc49..eb16d305d0a80 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -704,7 +704,7 @@ impl<'tcx> Ty<'tcx> { tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> bool { - tcx_at.is_copy_raw(param_env.and(self)) + self.is_trivially_pure_clone_copy() || tcx_at.is_copy_raw(param_env.and(self)) } /// Checks whether values of this type `T` have a size known at diff --git a/src/test/assembly/sparc-struct-abi.rs b/src/test/assembly/sparc-struct-abi.rs index dd8e6f614df11..6a898b2974a65 100644 --- a/src/test/assembly/sparc-struct-abi.rs +++ b/src/test/assembly/sparc-struct-abi.rs @@ -13,6 +13,7 @@ pub trait Sized {} #[lang = "copy"] pub trait Copy {} +impl Copy for f32 {} #[repr(C)] pub struct Franta { diff --git a/src/test/assembly/target-feature-multiple.rs b/src/test/assembly/target-feature-multiple.rs index 4c2073678b842..18d896e86b215 100644 --- a/src/test/assembly/target-feature-multiple.rs +++ b/src/test/assembly/target-feature-multiple.rs @@ -23,6 +23,7 @@ trait Sized {} #[lang = "copy"] trait Copy {} +impl Copy for u32 {} // Use of these requires target features to be enabled extern "unadjusted" { diff --git a/src/test/codegen/abi-sysv64.rs b/src/test/codegen/abi-sysv64.rs index bb910d573b338..dfc312279083d 100644 --- a/src/test/codegen/abi-sysv64.rs +++ b/src/test/codegen/abi-sysv64.rs @@ -13,6 +13,7 @@ trait Sized {} #[lang = "copy"] trait Copy {} +impl Copy for i64 {} // CHECK: define x86_64_sysvcc i64 @has_sysv64_abi #[no_mangle] diff --git a/src/test/codegen/abi-x86-interrupt.rs b/src/test/codegen/abi-x86-interrupt.rs index 119004d261d60..d612f603e4fea 100644 --- a/src/test/codegen/abi-x86-interrupt.rs +++ b/src/test/codegen/abi-x86-interrupt.rs @@ -13,6 +13,7 @@ trait Sized {} #[lang = "copy"] trait Copy {} +impl Copy for i64 {} // CHECK: define x86_intrcc i64 @has_x86_interrupt_abi #[no_mangle] diff --git a/src/test/codegen/frame-pointer.rs b/src/test/codegen/frame-pointer.rs index 367591dcb9617..f7c02d47939fe 100644 --- a/src/test/codegen/frame-pointer.rs +++ b/src/test/codegen/frame-pointer.rs @@ -17,7 +17,7 @@ trait Sized { } #[lang="copy"] trait Copy { } - +impl Copy for u32 {} // CHECK: define i32 @peach{{.*}}[[PEACH_ATTRS:\#[0-9]+]] { diff --git a/src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs b/src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs index faf81b5ae7605..7f0f678062a64 100644 --- a/src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs +++ b/src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs @@ -10,6 +10,14 @@ trait Sized {} #[lang = "copy"] trait Copy {} +impl Copy for bool {} +impl Copy for i8 {} +impl Copy for u8 {} +impl Copy for i32 {} +impl Copy for i64 {} +impl Copy for u64 {} +impl Copy for f32 {} +impl Copy for f64 {} // CHECK: define void @f_void() #[no_mangle] diff --git a/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-registers.rs b/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-registers.rs index 9e4521df8c34f..bbc039bdf5c7b 100644 --- a/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-registers.rs +++ b/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-registers.rs @@ -7,6 +7,7 @@ pub trait Sized { } #[lang="copy"] pub trait Copy { } +impl Copy for u32 {} extern "rust-intrinsic" { pub fn transmute(e: T) -> U; diff --git a/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs b/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs index d5c67af2b4146..b8112b20a54c6 100644 --- a/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs +++ b/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs @@ -7,6 +7,7 @@ pub trait Sized { } #[lang="copy"] pub trait Copy { } +impl Copy for u32 {} extern "rust-intrinsic" { pub fn transmute(e: T) -> U; diff --git a/src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-registers.rs b/src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-registers.rs index 8cde9ba58b93b..5591a8a5864b5 100644 --- a/src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-registers.rs +++ b/src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-registers.rs @@ -7,6 +7,7 @@ trait Sized { } #[lang="copy"] trait Copy { } +impl Copy for u32 {} #[no_mangle] #[cmse_nonsecure_entry] diff --git a/src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs b/src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs index 9a1b0a38d5eac..39b41dac41f77 100644 --- a/src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs +++ b/src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs @@ -7,6 +7,7 @@ trait Sized { } #[lang="copy"] trait Copy { } +impl Copy for u32 {} #[no_mangle] #[cmse_nonsecure_entry] From 697464a487f8ca8bc0bfadaf4108bb356eb157e0 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 9 Mar 2022 15:50:14 -0800 Subject: [PATCH 4/5] Disable the test on wasm32 Since the expected output has unwind targets --- .../mir-opt/combine_clone_of_primitives.rs | 1 + ...primitives.{impl#0}-clone.InstCombine.diff | 102 +++++++++--------- 2 files changed, 52 insertions(+), 51 deletions(-) diff --git a/src/test/mir-opt/combine_clone_of_primitives.rs b/src/test/mir-opt/combine_clone_of_primitives.rs index 894d9281d5dca..0972d2d68a115 100644 --- a/src/test/mir-opt/combine_clone_of_primitives.rs +++ b/src/test/mir-opt/combine_clone_of_primitives.rs @@ -1,4 +1,5 @@ // compile-flags: -C opt-level=0 -Z inline_mir=no +// ignore-wasm32 compiled with panic=abort by default // EMIT_MIR combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff diff --git a/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff b/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff index a19b92d908462..62e5da4902cb4 100644 --- a/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff +++ b/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff @@ -1,80 +1,80 @@ -- // MIR for `::clone` before InstCombine -+ // MIR for `::clone` after InstCombine +- // MIR for `::clone` before InstCombine ++ // MIR for `::clone` after InstCombine - fn ::clone(_1: &MyThing) -> MyThing { - debug self => _1; // in scope 0 at $DIR/combine_clone_of_primitives.rs:5:10: 5:15 - let mut _0: MyThing; // return place in scope 0 at $DIR/combine_clone_of_primitives.rs:5:10: 5:15 - let _2: &T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 - let _3: &u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 - let _4: &[f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 - let mut _5: T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 - let mut _6: &T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 - let _7: &T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 - let mut _8: u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 - let mut _9: &u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 - let _10: &u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 - let mut _11: [f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 - let mut _12: &[f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 - let _13: &[f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 + fn ::clone(_1: &MyThing) -> MyThing { + debug self => _1; // in scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 + let mut _0: MyThing; // return place in scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 + let _2: &T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 + let _3: &u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 + let _4: &[f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 + let mut _5: T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 + let mut _6: &T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 + let _7: &T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 + let mut _8: u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 + let mut _9: &u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 + let _10: &u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 + let mut _11: [f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 + let mut _12: &[f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 + let _13: &[f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 scope 1 { - debug __self_0_0 => _2; // in scope 1 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 - debug __self_0_1 => _3; // in scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 - debug __self_0_2 => _4; // in scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 + debug __self_0_0 => _2; // in scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 + debug __self_0_1 => _3; // in scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 + debug __self_0_2 => _4; // in scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 } bb0: { - _2 = &((*_1).0: T); // scope 0 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 - _3 = &((*_1).1: u64); // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 - _4 = &((*_1).2: [f32; 3]); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 -- _7 = &(*_2); // scope 1 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 -- _6 = &(*_7); // scope 1 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 -+ _7 = _2; // scope 1 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 -+ _6 = _7; // scope 1 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 - _5 = ::clone(move _6) -> bb1; // scope 1 at $DIR/combine_clone_of_primitives.rs:7:5: 7:9 + _2 = &((*_1).0: T); // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 + _3 = &((*_1).1: u64); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 + _4 = &((*_1).2: [f32; 3]); // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 +- _7 = &(*_2); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 +- _6 = &(*_7); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 ++ _7 = _2; // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 ++ _6 = _7; // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 + _5 = ::clone(move _6) -> bb1; // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 // mir::Constant - // + span: $DIR/combine_clone_of_primitives.rs:7:5: 7:9 + // + span: $DIR/combine_clone_of_primitives.rs:8:5: 8:9 // + literal: Const { ty: for<'r> fn(&'r T) -> T {::clone}, val: Value(Scalar()) } } bb1: { -- _10 = &(*_3); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 -- _9 = &(*_10); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 -- _8 = ::clone(move _9) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 +- _10 = &(*_3); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 +- _9 = &(*_10); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 +- _8 = ::clone(move _9) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 - // mir::Constant -- // + span: $DIR/combine_clone_of_primitives.rs:8:5: 8:11 +- // + span: $DIR/combine_clone_of_primitives.rs:9:5: 9:11 - // + literal: Const { ty: for<'r> fn(&'r u64) -> u64 {::clone}, val: Value(Scalar()) } -+ _10 = _3; // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 -+ _9 = _10; // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 -+ _8 = (*_9); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 -+ goto -> bb2; // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:11 ++ _10 = _3; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 ++ _9 = _10; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 ++ _8 = (*_9); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 ++ goto -> bb2; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 } bb2: { -- _13 = &(*_4); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 -- _12 = &(*_13); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 -- _11 = <[f32; 3] as Clone>::clone(move _12) -> [return: bb3, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 +- _13 = &(*_4); // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 +- _12 = &(*_13); // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 +- _11 = <[f32; 3] as Clone>::clone(move _12) -> [return: bb3, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 - // mir::Constant -- // + span: $DIR/combine_clone_of_primitives.rs:9:5: 9:16 +- // + span: $DIR/combine_clone_of_primitives.rs:10:5: 10:16 - // + literal: Const { ty: for<'r> fn(&'r [f32; 3]) -> [f32; 3] {<[f32; 3] as Clone>::clone}, val: Value(Scalar()) } -+ _13 = _4; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 -+ _12 = _13; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 -+ _11 = (*_12); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 -+ goto -> bb3; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:16 ++ _13 = _4; // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 ++ _12 = _13; // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 ++ _11 = (*_12); // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 ++ goto -> bb3; // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 } bb3: { - (_0.0: T) = move _5; // scope 1 at $DIR/combine_clone_of_primitives.rs:5:10: 5:15 - (_0.1: u64) = move _8; // scope 1 at $DIR/combine_clone_of_primitives.rs:5:10: 5:15 - (_0.2: [f32; 3]) = move _11; // scope 1 at $DIR/combine_clone_of_primitives.rs:5:10: 5:15 - return; // scope 0 at $DIR/combine_clone_of_primitives.rs:5:15: 5:15 + (_0.0: T) = move _5; // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 + (_0.1: u64) = move _8; // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 + (_0.2: [f32; 3]) = move _11; // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 + return; // scope 0 at $DIR/combine_clone_of_primitives.rs:6:15: 6:15 } bb4 (cleanup): { - drop(_5) -> bb5; // scope 1 at $DIR/combine_clone_of_primitives.rs:5:14: 5:15 + drop(_5) -> bb5; // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 } bb5 (cleanup): { - resume; // scope 0 at $DIR/combine_clone_of_primitives.rs:5:10: 5:15 + resume; // scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 } } From 705b8807d531348d05ed3e941b3af695abc24f85 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 10 Mar 2022 01:50:47 -0800 Subject: [PATCH 5/5] The `Clone::clone` call is now a `ConstantKind::Val`, not a `ConstantKind::Ty` --- compiler/rustc_middle/src/mir/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index fc438edc7229e..18c2dd71ad3d0 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2214,7 +2214,7 @@ impl<'tcx> Operand<'tcx> { /// While this is unlikely in general, it's the normal case of what you'll /// find as the `func` in a [`TerminatorKind::Call`]. pub fn const_fn_def(&self) -> Option<(DefId, SubstsRef<'tcx>)> { - let const_ty = self.constant()?.literal.const_for_ty()?.ty(); + let const_ty = self.constant()?.literal.ty(); if let ty::FnDef(def_id, substs) = *const_ty.kind() { Some((def_id, substs)) } else { None } } }