Skip to content

Commit

Permalink
Auto merge of #66294 - davidhewitt:const_fn_memoization, r=<try>
Browse files Browse the repository at this point in the history
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.

With thanks to @oli-obk for mentoring me through this at RustFest Barcelona.

r? @oli-obk
  • Loading branch information
bors committed Nov 11, 2019
2 parents 9248b01 + 30cef9b commit 29354cb
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 2 deletions.
5 changes: 4 additions & 1 deletion src/librustc/mir/interpret/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
27 changes: 26 additions & 1 deletion src/librustc_mir/interpret/terminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 29354cb

Please sign in to comment.