From 30cef9b40283de88b28f5ba89769f6c4fec72eee Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Mon, 11 Nov 2019 14:32:36 +0000 Subject: [PATCH] Add memoization for const function evaluations When a const function is being evaluated, as long as all its arguments are zero-sized-types (or it has no arguments) then we can trivially memoize the evaluation result using the existing query mechanism. --- src/librustc/mir/interpret/mod.rs | 5 ++++- src/librustc_mir/interpret/terminator.rs | 27 +++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 6c31d54e081c4..d2c97221bf03e 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -123,7 +123,10 @@ use rustc_data_structures::tiny_list::TinyList; use rustc_macros::HashStable; use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian, BigEndian}; -/// Uniquely identifies a specific constant or static. +/// Uniquely identifies one of the following: +/// - A constant +/// - A static +/// - A const fn where all arguments (if any) are zero-sized types #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable, HashStable)] pub struct GlobalId<'tcx> { /// For a constant or static, the `Instance` of the item itself. diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index e10bb85d52df8..e6ccfe885b5be 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -7,7 +7,7 @@ use syntax::source_map::Span; use rustc_target::spec::abi::Abi; use super::{ - InterpResult, PointerArithmetic, + GlobalId, InterpResult, PointerArithmetic, InterpCx, Machine, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal, }; @@ -293,6 +293,31 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } + // If this function is a const function then as an optimisation we can query this + // evaluation immediately. + // + // For the moment we only do this for functions which take no arguments + // (or all arguments are ZSTs) so that we don't memoize too much. + if self.tcx.is_const_fn_raw(instance.def.def_id()) && + args.iter().all(|a| a.layout.is_zst()) + { + let gid = GlobalId { instance, promoted: None }; + let place = self.const_eval_raw(gid)?; + + let dest = match dest { + Some(dest) => dest, + None => throw_ub!(Unreachable) + }; + + self.copy_op(place.into(), dest)?; + + // No stack frame gets pushed, the main loop will just act as if the + // call completed. + self.goto_block(ret)?; + self.dump_place(*dest); + return Ok(()) + } + // We need MIR for this fn let body = match M::find_fn(self, instance, args, dest, ret)? { Some(body) => body,