Skip to content

Commit 038ad11

Browse files
Driver provided "intrinsics".
Allows drivers to define functions which are only expanded by the plugin after all type checking, inference, etc etc, ie only once during mono item collection. The form of the interface with the plugins is slightly different than what was proposed in rust-lang#51623. Additionally, signature checking is added.
1 parent bf402f1 commit 038ad11

File tree

35 files changed

+511
-40
lines changed

35 files changed

+511
-40
lines changed

compiler/rustc_codegen_ssa/src/coverageinfo/map.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ impl<'tcx> FunctionCoverage<'tcx> {
5050
}
5151

5252
fn create(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, is_used: bool) -> Self {
53-
let coverageinfo = tcx.coverageinfo(instance.def);
53+
let coverageinfo = tcx.coverageinfo(instance);
5454
debug!(
5555
"FunctionCoverage::create(instance={:?}) has coverageinfo={:?}. is_used={}",
5656
instance, coverageinfo, is_used

compiler/rustc_codegen_ssa/src/mir/block.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -611,9 +611,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
611611
let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize;
612612
let mut llargs = Vec::with_capacity(arg_count);
613613

614+
// Custom intrinsics are treated as-if they were normal functions here.
615+
let is_custom_intrinsic = intrinsic.and_then(|_| instance )
616+
.map(|instance| bx.tcx().custom_intrinsic_mir(instance).is_some() )
617+
.unwrap_or_default();
618+
614619
// Prepare the return value destination
615620
let ret_dest = if let Some((dest, _)) = *destination {
616-
let is_intrinsic = intrinsic.is_some();
621+
let is_intrinsic = intrinsic.is_some() && !is_custom_intrinsic;
617622
self.make_return_dest(&mut bx, dest, &fn_abi.ret, &mut llargs, is_intrinsic)
618623
} else {
619624
ReturnDest::Nothing
@@ -636,6 +641,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
636641
match intrinsic {
637642
None | Some(sym::drop_in_place) => {}
638643
Some(sym::copy_nonoverlapping) => unreachable!(),
644+
Some(_intrinsic) if is_custom_intrinsic => { },
639645
Some(intrinsic) => {
640646
let dest = match ret_dest {
641647
_ if fn_abi.ret.is_indirect() => llargs[0],

compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
3131
bx.add_coverage_counter(instance, id, code_region);
3232
}
3333

34-
let coverageinfo = bx.tcx().coverageinfo(instance.def);
34+
let coverageinfo = bx.tcx().coverageinfo(instance);
3535

3636
let fn_name = bx.get_pgo_func_name_var(instance);
3737
let hash = bx.const_u64(function_source_hash);

compiler/rustc_codegen_ssa/src/mir/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
137137

138138
let llfn = cx.get_fn(instance);
139139

140-
let mir = cx.tcx().instance_mir(instance.def);
140+
let mir = cx.tcx().instance_mir(instance);
141141

142142
let fn_abi = FnAbi::of_instance(cx, instance, &[]);
143143
debug!("fn_abi: {:?}", fn_abi);

compiler/rustc_data_structures/src/sync.rs

+53
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use crate::owning_ref::{Erased, OwningRef};
2121
use std::collections::HashMap;
2222
use std::hash::{BuildHasher, Hash};
2323
use std::ops::{Deref, DerefMut};
24+
use std::sync::{Arc, atomic::AtomicPtr, atomic, };
2425

2526
pub use std::sync::atomic::Ordering;
2627
pub use std::sync::atomic::Ordering::SeqCst;
@@ -598,3 +599,55 @@ impl<T> DerefMut for OneThread<T> {
598599
&mut self.inner
599600
}
600601
}
602+
603+
/// Provides atomic mutability by replacing the value inside this `ArcCell`.
604+
/// Similar to the `crossbeam` structure of the same name.
605+
#[derive(Debug)]
606+
pub struct ArcCell<T>(AtomicPtr<T>);
607+
impl<T> ArcCell<T> {
608+
pub fn new(v: Arc<T>) -> Self {
609+
ArcCell(AtomicPtr::new(Arc::into_raw(v) as *mut _))
610+
}
611+
pub fn get(&self) -> Arc<T> {
612+
let ptr = self.0.load(atomic::Ordering::Acquire);
613+
let arc = unsafe { Arc::from_raw(ptr as *const T) };
614+
let ret = arc.clone();
615+
// don't drop our copy:
616+
::std::mem::forget(arc);
617+
ret
618+
}
619+
/// Update the value, returning the previous value.
620+
pub fn set(&self, v: Arc<T>) -> Arc<T> {
621+
let new = Arc::into_raw(v) as *mut _;
622+
let mut expected = self.0.load(atomic::Ordering::Acquire);
623+
loop {
624+
match self.0.compare_exchange_weak(expected, new,
625+
atomic::Ordering::SeqCst,
626+
atomic::Ordering::Acquire) {
627+
Ok(old) => {
628+
return unsafe { Arc::from_raw(old as *const T) };
629+
},
630+
Err(v) => {
631+
expected = v;
632+
},
633+
}
634+
}
635+
}
636+
}
637+
impl<T> Drop for ArcCell<T> {
638+
fn drop(&mut self) {
639+
let ptr = self.0.load(atomic::Ordering::Acquire);
640+
// drop our copy of the arc:
641+
unsafe { Arc::from_raw(ptr as *const _) };
642+
}
643+
}
644+
impl<T> Clone for ArcCell<T> {
645+
fn clone(&self) -> Self {
646+
ArcCell::new(self.get())
647+
}
648+
}
649+
impl<T> From<Arc<T>> for ArcCell<T> {
650+
fn from(v: Arc<T>) -> Self {
651+
Self::new(v)
652+
}
653+
}

compiler/rustc_middle/src/dep_graph/dep_node.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -285,10 +285,10 @@ pub type DepNode = rustc_query_system::dep_graph::DepNode<DepKind>;
285285
// required that their size stay the same, but we don't want to change
286286
// it inadvertently. This assert just ensures we're aware of any change.
287287
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
288-
static_assert_size!(DepNode, 17);
288+
static_assert_size!(DepNode, 18);
289289

290290
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
291-
static_assert_size!(DepNode, 24);
291+
static_assert_size!(DepNode, 25);
292292

293293
pub trait DepNodeExt: Sized {
294294
/// Construct a DepNode from the given DepKind and DefPathHash. This

compiler/rustc_middle/src/mir/mod.rs

+30
Original file line numberDiff line numberDiff line change
@@ -2900,3 +2900,33 @@ impl Location {
29002900
}
29012901
}
29022902
}
2903+
2904+
pub trait CustomIntrinsicMirGen: Sync + Send + fmt::Debug {
2905+
/// Codegen a plugin-defined intrinsic. This is intended to be used to
2906+
/// "return" values based on the monomorphized and erased types of the
2907+
/// function call. Codegen will codegen the `extra_stmts` and then insert
2908+
/// an unconditional branch to the exit block.
2909+
///
2910+
/// Consider this to be highly unstable; it will likely change without
2911+
/// warning. There is also no spec for this, it is 100% implementation
2912+
/// defined, and may not be implemented at all for some codegen backends.
2913+
///
2914+
/// If the codegen backend is multithreaded, this will be called from
2915+
/// any number of threads, hence `Sync + Send`.
2916+
///
2917+
/// YOU ARE RESPONSIBLE FOR THE SAFETY OF THE EXTRA STATEMENTS.
2918+
/// You have been warned. Good luck, have fun.
2919+
fn mirgen_simple_intrinsic<'tcx>(&self,
2920+
tcx: TyCtxt<'tcx>,
2921+
instance: ty::Instance<'tcx>,
2922+
mir: &mut Body<'tcx>);
2923+
2924+
/// The following are used for typeck-ing:
2925+
2926+
/// The number of generic parameters expected.
2927+
fn generic_parameter_count<'tcx>(&self, tcx: TyCtxt<'tcx>) -> usize;
2928+
/// The types of the input args.
2929+
fn inputs<'tcx>(&self, tcx: TyCtxt<'tcx>) -> &'tcx List<Ty<'tcx>>;
2930+
/// The return type.
2931+
fn output<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
2932+
}

compiler/rustc_middle/src/query/mod.rs

+16-2
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ rustc_queries! {
338338

339339
/// Returns coverage summary info for a function, after executing the `InstrumentCoverage`
340340
/// MIR pass (assuming the -Zinstrument-coverage option is enabled).
341-
query coverageinfo(key: ty::InstanceDef<'tcx>) -> mir::CoverageInfo {
341+
query coverageinfo(key: ty::Instance<'tcx>) -> mir::CoverageInfo {
342342
desc { |tcx| "retrieving coverage info from MIR for `{}`", tcx.def_path_str(key.def_id()) }
343343
storage(ArenaCacheSelector<'tcx>)
344344
}
@@ -363,6 +363,20 @@ rustc_queries! {
363363
storage(ArenaCacheSelector<'tcx>)
364364
cache_on_disk_if { key.is_local() }
365365
}
366+
/// If defined by the driver, returns the extra mir statements to codegen,
367+
/// else returns `None`.
368+
query custom_intrinsic_mirgen(key: DefId) -> Option<Lrc<dyn mir::CustomIntrinsicMirGen>> {
369+
anon
370+
no_hash
371+
372+
desc { |tcx| "asking for the custom MIR generator of `{}`", tcx.def_path_str(key) }
373+
}
374+
/// The monomorphized MIR for a custom intrinsic instance.
375+
query custom_intrinsic_mir(inst: ty::Instance<'tcx>) -> Option<&'tcx mir::Body<'tcx>> {
376+
anon
377+
378+
desc { |tcx| "asking for the custom MIR of `{}`", tcx.def_path_str(inst.def_id()) }
379+
}
366380

367381
/// The `DefId` is the `DefId` of the containing MIR body. Promoteds do not have their own
368382
/// `DefId`. This function returns all promoteds in the specified body. The body references
@@ -782,7 +796,7 @@ rustc_queries! {
782796
}
783797

784798
/// Obtain all the calls into other local functions
785-
query mir_inliner_callees(key: ty::InstanceDef<'tcx>) -> &'tcx [(DefId, SubstsRef<'tcx>)] {
799+
query mir_inliner_callees(key: ty::Instance<'tcx>) -> &'tcx [(DefId, SubstsRef<'tcx>)] {
786800
fatal_cycle
787801
desc { |tcx|
788802
"computing all local function calls in `{}`",

compiler/rustc_middle/src/ty/mod.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -1779,8 +1779,8 @@ impl<'tcx> TyCtxt<'tcx> {
17791779
}
17801780

17811781
/// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair.
1782-
pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> {
1783-
match instance {
1782+
pub fn instance_mir(self, instance: ty::Instance<'tcx>) -> &'tcx Body<'tcx> {
1783+
match instance.def {
17841784
ty::InstanceDef::Item(def) => match self.def_kind(def.did) {
17851785
DefKind::Const
17861786
| DefKind::Static
@@ -1794,14 +1794,20 @@ impl<'tcx> TyCtxt<'tcx> {
17941794
self.optimized_mir(def.did)
17951795
}
17961796
},
1797+
ty::InstanceDef::Intrinsic(..) => {
1798+
if let Some(mir) = self.custom_intrinsic_mir(instance) {
1799+
mir
1800+
} else {
1801+
self.mir_shims(instance.def)
1802+
}
1803+
},
17971804
ty::InstanceDef::VtableShim(..)
17981805
| ty::InstanceDef::ReifyShim(..)
1799-
| ty::InstanceDef::Intrinsic(..)
18001806
| ty::InstanceDef::FnPtrShim(..)
18011807
| ty::InstanceDef::Virtual(..)
18021808
| ty::InstanceDef::ClosureOnceShim { .. }
18031809
| ty::InstanceDef::DropGlue(..)
1804-
| ty::InstanceDef::CloneShim(..) => self.mir_shims(instance),
1810+
| ty::InstanceDef::CloneShim(..) => self.mir_shims(instance.def),
18051811
}
18061812
}
18071813

compiler/rustc_mir/src/const_eval/eval_queries.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
306306
MemoryExtra { can_access_statics: is_static },
307307
);
308308

309-
let res = ecx.load_mir(cid.instance.def, cid.promoted);
309+
let res = ecx.load_mir(cid.instance, cid.promoted);
310310
match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) {
311311
Err(error) => {
312312
let err = ConstEvalErr::new(&ecx, error, None);

compiler/rustc_mir/src/const_eval/machine.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,9 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
203203

204204
fn load_mir(
205205
ecx: &InterpCx<'mir, 'tcx, Self>,
206-
instance: ty::InstanceDef<'tcx>,
206+
instance: ty::Instance<'tcx>,
207207
) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> {
208-
match instance {
208+
match instance.def {
209209
ty::InstanceDef::Item(def) => {
210210
if ecx.tcx.is_ctfe_mir_available(def.did) {
211211
Ok(ecx.tcx.mir_for_ctfe_opt_const_arg(def))
@@ -242,7 +242,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
242242
}
243243
}
244244
// This is a const fn. Call it.
245-
Ok(Some(match ecx.load_mir(instance.def, None) {
245+
Ok(Some(match ecx.load_mir(instance, None) {
246246
Ok(body) => body,
247247
Err(err) => {
248248
if let err_unsup!(NoMirFor(did)) = err.kind() {

compiler/rustc_mir/src/interpret/eval_context.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -485,11 +485,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
485485

486486
pub fn load_mir(
487487
&self,
488-
instance: ty::InstanceDef<'tcx>,
488+
instance: ty::Instance<'tcx>,
489489
promoted: Option<mir::Promoted>,
490490
) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> {
491491
// do not continue if typeck errors occurred (can only occur in local crate)
492-
let def = instance.with_opt_param();
492+
let def = instance.def.with_opt_param();
493493
if let Some(def) = def.as_local() {
494494
if self.tcx.has_typeck_results(def.did) {
495495
if let Some(error_reported) = self.tcx.typeck_opt_const_arg(def).tainted_by_errors {

compiler/rustc_mir/src/interpret/machine.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
142142
/// constants, ...
143143
fn load_mir(
144144
ecx: &InterpCx<'mir, 'tcx, Self>,
145-
instance: ty::InstanceDef<'tcx>,
145+
instance: ty::Instance<'tcx>,
146146
) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> {
147147
Ok(ecx.tcx.instance_mir(instance))
148148
}

compiler/rustc_mir/src/interpret/terminator.rs

+3
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
256256
}
257257
};
258258

259+
let custom = self.tcx.custom_intrinsic_mir(instance);
260+
259261
let get_abi = |this: &Self, instance_ty: Ty<'tcx>| match instance_ty.kind() {
260262
ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(),
261263
ty::Closure(..) => Abi::RustCall,
@@ -355,6 +357,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
355357
// The Rust ABI is special: ZST get skipped.
356358
let rust_abi = match caller_abi {
357359
Abi::Rust | Abi::RustCall => true,
360+
Abi::RustIntrinsic if custom.is_some() => true,
358361
_ => false,
359362
};
360363
// We have two iterators: Where the arguments come from,

compiler/rustc_mir/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ pub fn provide(providers: &mut Providers) {
5252
const_eval::provide(providers);
5353
shim::provide(providers);
5454
transform::provide(providers);
55+
monomorphize::provide(providers);
5556
monomorphize::partitioning::provide(providers);
5657
monomorphize::polymorphize::provide(providers);
5758
providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider;

compiler/rustc_mir/src/monomorphize/collector.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,10 @@ fn visit_instance_use<'tcx>(
907907
if !is_direct_call {
908908
bug!("{:?} being reified", instance);
909909
}
910+
911+
if let Some(_mir) = tcx.custom_intrinsic_mir(instance) {
912+
output.push(create_fn_mono_item(tcx, instance, source));
913+
}
910914
}
911915
ty::InstanceDef::DropGlue(_, None) => {
912916
// Don't need to emit noop drop glue if we are calling directly.
@@ -1374,7 +1378,7 @@ fn collect_neighbours<'tcx>(
13741378
output: &mut Vec<Spanned<MonoItem<'tcx>>>,
13751379
) {
13761380
debug!("collect_neighbours: {:?}", instance.def_id());
1377-
let body = tcx.instance_mir(instance.def);
1381+
let body = tcx.instance_mir(instance);
13781382

13791383
MirNeighborCollector { tcx, body: &body, output, instance }.visit_body(&body);
13801384
}

0 commit comments

Comments
 (0)