From f0cb386c7de34667160b38d016323c4ca18f2ed9 Mon Sep 17 00:00:00 2001 From: Mohammad Omidvar Date: Mon, 20 May 2024 18:11:07 +0000 Subject: [PATCH 1/3] Add intrinsic definition and retrieval APIs --- compiler/rustc_smir/src/rustc_smir/context.rs | 36 ++++++++++++------- compiler/stable_mir/src/compiler_interface.rs | 15 ++++++-- compiler/stable_mir/src/mir/mono.rs | 4 ++- compiler/stable_mir/src/ty.rs | 29 +++++++++++++++ 4 files changed, 68 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index fd31c020f89..7af0aabcaa9 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -23,8 +23,8 @@ use stable_mir::target::{MachineInfo, MachineSize}; use stable_mir::ty::{ AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef, - ForeignItemKind, GenericArgs, LineInfo, PolyFnSig, RigidTy, Span, Ty, TyKind, UintTy, - VariantDef, + ForeignItemKind, GenericArgs, IntrinsicDef, LineInfo, PolyFnSig, RigidTy, Span, Ty, TyKind, + UintTy, VariantDef, }; use stable_mir::{Crate, CrateDef, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, Symbol}; use std::cell::RefCell; @@ -307,6 +307,28 @@ fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig { sig.stable(&mut *tables) } + fn intrinsic(&self, def: DefId) -> Option { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let def_id = def.internal(&mut *tables, tcx); + let intrinsic = tcx.intrinsic_raw(def_id); + intrinsic.map(|_| IntrinsicDef(def)) + } + + fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let def_id = def.0.internal(&mut *tables, tcx); + tcx.intrinsic(def_id).unwrap().name.to_string() + } + + fn intrinsic_must_be_overridden(&self, def: IntrinsicDef) -> bool { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let def_id = def.0.internal(&mut *tables, tcx); + tcx.intrinsic_raw(def_id).unwrap().must_be_overridden + } + fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; @@ -645,16 +667,6 @@ fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol { } } - /// Retrieve the plain intrinsic name of an instance. - /// - /// This assumes that the instance is an intrinsic. - fn intrinsic_name(&self, def: InstanceDef) -> Symbol { - let tables = self.0.borrow_mut(); - let instance = tables.instances[def]; - let intrinsic = tables.tcx.intrinsic(instance.def_id()).unwrap(); - intrinsic.name.to_string() - } - fn ty_layout(&self, ty: Ty) -> Result { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 231d9ba49a3..4dd64228bba 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -13,8 +13,8 @@ use crate::ty::{ AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef, ForeignItemKind, ForeignModule, ForeignModuleDef, GenericArgs, GenericPredicates, Generics, - ImplDef, ImplTrait, LineInfo, PolyFnSig, RigidTy, Span, TraitDecl, TraitDef, Ty, TyKind, - UintTy, VariantDef, + ImplDef, ImplTrait, IntrinsicDef, LineInfo, PolyFnSig, RigidTy, Span, TraitDecl, TraitDef, Ty, + TyKind, UintTy, VariantDef, }; use crate::{ mir, Crate, CrateItem, CrateItems, CrateNum, DefId, Error, Filename, ImplTraitDecls, ItemKind, @@ -88,6 +88,16 @@ pub trait Context { /// Retrieve the function signature for the given generic arguments. fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig; + /// Retrieve the intrinsic definition if the item corresponds one. + fn intrinsic(&self, item: DefId) -> Option; + + /// Retrieve the plain function name of an intrinsic. + fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol; + + /// Returns whether the intrinsic has no meaningful body and all backends + /// need to shim all calls to it. + fn intrinsic_must_be_overridden(&self, def: IntrinsicDef) -> bool; + /// Retrieve the closure signature for the given generic arguments. fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig; @@ -198,7 +208,6 @@ fn resolve_closure( fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option; fn krate(&self, def_id: DefId) -> Crate; fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol; - fn intrinsic_name(&self, def: InstanceDef) -> Symbol; /// Return information about the target machine. fn target_info(&self) -> MachineInfo; diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs index 394038926f6..572f1499c5a 100644 --- a/compiler/stable_mir/src/mir/mono.rs +++ b/compiler/stable_mir/src/mir/mono.rs @@ -106,7 +106,9 @@ pub fn trimmed_name(&self) -> Symbol { /// which is more convenient to match with intrinsic symbols. pub fn intrinsic_name(&self) -> Option { match self.kind { - InstanceKind::Intrinsic => Some(with(|context| context.intrinsic_name(self.def))), + InstanceKind::Intrinsic => { + Some(with(|context| context.intrinsic(self.def.def_id()).unwrap().fn_name())) + } InstanceKind::Item | InstanceKind::Virtual { .. } | InstanceKind::Shim => None, } } diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 56251613840..ab4deac9fd7 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -622,6 +622,35 @@ impl FnDef { pub fn body(&self) -> Option { with(|ctx| ctx.has_body(self.0).then(|| ctx.mir_body(self.0))) } + + /// Get the information of the intrinsic if this function is a definition of one. + pub fn as_intrinsic(&self) -> Option { + with(|cx| cx.intrinsic(self.def_id())) + } + + /// Check if the function is an intrinsic. + #[inline] + pub fn is_intrinsic(&self) -> bool { + self.as_intrinsic().is_some() + } +} + +crate_def! { + pub IntrinsicDef; +} + +impl IntrinsicDef { + /// Returns the plain name of the intrinsic. + /// e.g., `transmute` for `core::intrinsics::transmute`. + pub fn fn_name(&self) -> Symbol { + with(|cx| cx.intrinsic_name(*self)) + } + + /// Returns whether the intrinsic has no meaningful body and all backends + /// need to shim all calls to it. + pub fn must_be_overridden(&self) -> bool { + with(|cx| cx.intrinsic_must_be_overridden(*self)) + } } crate_def! { From 56ad5453f6002aaabdcab6399238a1c93254a134 Mon Sep 17 00:00:00 2001 From: Mohammad Omidvar Date: Mon, 20 May 2024 18:12:06 +0000 Subject: [PATCH 2/3] Extend tests for intrinsic definitions --- .../stable-mir/check_intrinsics.rs | 50 ++++++++++++------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs index 171850b89bb..a9c1f64f812 100644 --- a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs +++ b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs @@ -11,6 +11,7 @@ //@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837 #![feature(rustc_private)] +#![feature(assert_matches)] extern crate rustc_hir; #[macro_use] @@ -23,11 +24,11 @@ use stable_mir::mir::mono::{Instance, InstanceKind}; use stable_mir::mir::visit::{Location, MirVisitor}; use stable_mir::mir::{LocalDecl, Terminator, TerminatorKind}; -use stable_mir::ty::{RigidTy, TyKind}; -use std::collections::HashSet; +use stable_mir::ty::{FnDef, GenericArgs, IntrinsicDef, RigidTy, TyKind}; use std::convert::TryFrom; use std::io::Write; use std::ops::ControlFlow; +use std::assert_matches::assert_matches; /// This function tests that we can correctly get type information from binary operations. fn test_intrinsics() -> ControlFlow<()> { @@ -39,9 +40,10 @@ fn test_intrinsics() -> ControlFlow<()> { visitor.visit_body(&main_body); let calls = visitor.calls; - assert_eq!(calls.len(), 2, "Expected 2 calls, but found: {calls:?}"); - for intrinsic in &calls { - check_intrinsic(intrinsic) + assert_eq!(calls.len(), 3, "Expected 3 calls, but found: {calls:?}"); + for (fn_def, args) in &calls { + check_instance(&Instance::resolve(*fn_def, &args).unwrap()); + check_def(fn_def.as_intrinsic().unwrap()); } ControlFlow::Continue(()) @@ -53,22 +55,35 @@ fn test_intrinsics() -> ControlFlow<()> { /// /// If by any chance this test breaks because you changed how an intrinsic is implemented, please /// update the test to invoke a different intrinsic. -fn check_intrinsic(intrinsic: &Instance) { - assert_eq!(intrinsic.kind, InstanceKind::Intrinsic); - let name = intrinsic.intrinsic_name().unwrap(); - if intrinsic.has_body() { - let Some(body) = intrinsic.body() else { unreachable!("Expected a body") }; +fn check_instance(instance: &Instance) { + assert_eq!(instance.kind, InstanceKind::Intrinsic); + let name = instance.intrinsic_name().unwrap(); + if instance.has_body() { + let Some(body) = instance.body() else { unreachable!("Expected a body") }; assert!(!body.blocks.is_empty()); - assert_eq!(&name, "likely"); + assert_matches!(name.as_str(), "likely" | "vtable_size"); } else { - assert!(intrinsic.body().is_none()); + assert!(instance.body().is_none()); assert_eq!(&name, "size_of_val"); } } +fn check_def(intrinsic: IntrinsicDef) { + let name = intrinsic.fn_name(); + match name.as_str() { + "likely" | "size_of_val" => { + assert!(!intrinsic.must_be_overridden()); + } + "vtable_size" => { + assert!(intrinsic.must_be_overridden()); + } + _ => unreachable!("Unexpected intrinsic: {}", name), + } +} + struct CallsVisitor<'a> { locals: &'a [LocalDecl], - calls: HashSet, + calls: Vec<(FnDef, GenericArgs)>, } impl<'a> MirVisitor for CallsVisitor<'a> { @@ -77,10 +92,10 @@ fn visit_terminator(&mut self, term: &Terminator, _loc: Location) { TerminatorKind::Call { func, .. } => { let TyKind::RigidTy(RigidTy::FnDef(def, args)) = func.ty(self.locals).unwrap().kind() - else { - return; - }; - self.calls.insert(Instance::resolve(def, &args).unwrap()); + else { + return; + }; + self.calls.push((def, args.clone())); } _ => {} } @@ -106,6 +121,7 @@ fn generate_input(path: &str) -> std::io::Result<()> { #![feature(core_intrinsics)] use std::intrinsics::*; pub fn use_intrinsics(init: bool) -> bool {{ + let vtable_sz = unsafe {{ vtable_size(0 as *const ()) }}; let sz = unsafe {{ size_of_val("hi") }}; likely(init && sz == 2) }} From 6743fc7704d28a0be61643b1cada2fd31be132b5 Mon Sep 17 00:00:00 2001 From: Mohammad Omidvar Date: Thu, 23 May 2024 15:35:18 +0000 Subject: [PATCH 3/3] Add conversion from IntrinsicDef to FnDef --- compiler/stable_mir/src/ty.rs | 6 ++++++ tests/ui-fulldeps/stable-mir/check_intrinsics.rs | 16 ++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index ab4deac9fd7..ebfc6e026eb 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -653,6 +653,12 @@ pub fn must_be_overridden(&self) -> bool { } } +impl From for FnDef { + fn from(def: IntrinsicDef) -> Self { + FnDef(def.0) + } +} + crate_def! { pub ClosureDef; } diff --git a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs index a9c1f64f812..7e247ce0c75 100644 --- a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs +++ b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs @@ -24,11 +24,11 @@ use stable_mir::mir::mono::{Instance, InstanceKind}; use stable_mir::mir::visit::{Location, MirVisitor}; use stable_mir::mir::{LocalDecl, Terminator, TerminatorKind}; -use stable_mir::ty::{FnDef, GenericArgs, IntrinsicDef, RigidTy, TyKind}; +use stable_mir::ty::{FnDef, GenericArgs, RigidTy, TyKind}; +use std::assert_matches::assert_matches; use std::convert::TryFrom; use std::io::Write; use std::ops::ControlFlow; -use std::assert_matches::assert_matches; /// This function tests that we can correctly get type information from binary operations. fn test_intrinsics() -> ControlFlow<()> { @@ -41,9 +41,9 @@ fn test_intrinsics() -> ControlFlow<()> { let calls = visitor.calls; assert_eq!(calls.len(), 3, "Expected 3 calls, but found: {calls:?}"); - for (fn_def, args) in &calls { - check_instance(&Instance::resolve(*fn_def, &args).unwrap()); - check_def(fn_def.as_intrinsic().unwrap()); + for (fn_def, args) in calls.into_iter() { + check_instance(&Instance::resolve(fn_def, &args).unwrap()); + check_def(fn_def); } ControlFlow::Continue(()) @@ -68,7 +68,11 @@ fn check_instance(instance: &Instance) { } } -fn check_def(intrinsic: IntrinsicDef) { +fn check_def(fn_def: FnDef) { + assert!(fn_def.is_intrinsic()); + let intrinsic = fn_def.as_intrinsic().unwrap(); + assert_eq!(fn_def, intrinsic.into()); + let name = intrinsic.fn_name(); match name.as_str() { "likely" | "size_of_val" => {