Use SmallVec in SwitchTargets

This allows building common SwitchTargets (eg. for `if`s) without
allocation.
This commit is contained in:
Jonas Schievink 2020-10-11 01:14:12 +02:00
parent 432535da2b
commit 9a47f74bfe
5 changed files with 14 additions and 15 deletions

View file

@ -196,7 +196,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
mut bx: Bx, mut bx: Bx,
discr: &mir::Operand<'tcx>, discr: &mir::Operand<'tcx>,
switch_ty: Ty<'tcx>, switch_ty: Ty<'tcx>,
targets: &SwitchTargets<'tcx>, targets: &SwitchTargets,
) { ) {
let discr = self.codegen_operand(&mut bx, &discr); let discr = self.codegen_operand(&mut bx, &discr);
// `switch_ty` is redundant, sanity-check that. // `switch_ty` is redundant, sanity-check that.

View file

@ -1,6 +1,7 @@
use crate::mir::interpret::Scalar; use crate::mir::interpret::Scalar;
use crate::ty::{self, Ty, TyCtxt}; use crate::ty::{self, Ty, TyCtxt};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use smallvec::{smallvec, SmallVec};
use super::{ use super::{
AssertMessage, BasicBlock, InlineAsmOperand, Operand, Place, SourceInfo, Successors, AssertMessage, BasicBlock, InlineAsmOperand, Operand, Place, SourceInfo, Successors,
@ -17,10 +18,10 @@ use std::slice;
pub use super::query::*; pub use super::query::*;
#[derive(Debug, Clone, TyEncodable, TyDecodable, HashStable, PartialEq)] #[derive(Debug, Clone, TyEncodable, TyDecodable, HashStable, PartialEq)]
pub struct SwitchTargets<'tcx> { pub struct SwitchTargets {
/// Possible values. The locations to branch to in each case /// Possible values. The locations to branch to in each case
/// are found in the corresponding indices from the `targets` vector. /// are found in the corresponding indices from the `targets` vector.
values: Cow<'tcx, [u128]>, values: SmallVec<[u128; 1]>,
/// Possible branch sites. The last element of this vector is used /// Possible branch sites. The last element of this vector is used
/// for the otherwise branch, so targets.len() == values.len() + 1 /// for the otherwise branch, so targets.len() == values.len() + 1
@ -34,24 +35,24 @@ pub struct SwitchTargets<'tcx> {
// //
// However weve decided to keep this as-is until we figure a case // However weve decided to keep this as-is until we figure a case
// where some other approach seems to be strictly better than other. // where some other approach seems to be strictly better than other.
targets: Vec<BasicBlock>, targets: SmallVec<[BasicBlock; 2]>,
} }
impl<'tcx> SwitchTargets<'tcx> { impl SwitchTargets {
/// Creates switch targets from an iterator of values and target blocks. /// Creates switch targets from an iterator of values and target blocks.
/// ///
/// The iterator may be empty, in which case the `SwitchInt` instruction is equivalent to /// The iterator may be empty, in which case the `SwitchInt` instruction is equivalent to
/// `goto otherwise;`. /// `goto otherwise;`.
pub fn new(targets: impl Iterator<Item = (u128, BasicBlock)>, otherwise: BasicBlock) -> Self { pub fn new(targets: impl Iterator<Item = (u128, BasicBlock)>, otherwise: BasicBlock) -> Self {
let (values, mut targets): (Vec<_>, Vec<_>) = targets.unzip(); let (values, mut targets): (SmallVec<_>, SmallVec<_>) = targets.unzip();
targets.push(otherwise); targets.push(otherwise);
Self { values: values.into(), targets } Self { values: values.into(), targets }
} }
/// Builds a switch targets definition that jumps to `then` if the tested value equals `value`, /// Builds a switch targets definition that jumps to `then` if the tested value equals `value`,
/// and to `else_` if not. /// and to `else_` if not.
pub fn static_if(value: &'static [u128; 1], then: BasicBlock, else_: BasicBlock) -> Self { pub fn static_if(value: u128, then: BasicBlock, else_: BasicBlock) -> Self {
Self { values: Cow::Borrowed(value), targets: vec![then, else_] } Self { values: smallvec![value], targets: smallvec![then, else_] }
} }
/// Returns the fallback target that is jumped to when none of the values match the operand. /// Returns the fallback target that is jumped to when none of the values match the operand.
@ -113,7 +114,7 @@ pub enum TerminatorKind<'tcx> {
/// FIXME: remove this redundant information. Currently, it is relied on by pretty-printing. /// FIXME: remove this redundant information. Currently, it is relied on by pretty-printing.
switch_ty: Ty<'tcx>, switch_ty: Ty<'tcx>,
targets: SwitchTargets<'tcx>, targets: SwitchTargets,
}, },
/// Indicates that the landing pad is finished and unwinding should /// Indicates that the landing pad is finished and unwinding should
@ -295,7 +296,7 @@ impl<'tcx> TerminatorKind<'tcx> {
TerminatorKind::SwitchInt { TerminatorKind::SwitchInt {
discr: cond, discr: cond,
switch_ty: tcx.types.bool, switch_ty: tcx.types.bool,
targets: SwitchTargets::static_if(&[0], f, t), targets: SwitchTargets::static_if(0, f, t),
} }
} }

View file

@ -514,7 +514,7 @@ impl Direction for Forward {
struct SwitchIntEdgeEffectApplier<'a, D, F> { struct SwitchIntEdgeEffectApplier<'a, D, F> {
exit_state: &'a mut D, exit_state: &'a mut D,
targets: &'a SwitchTargets<'a>, targets: &'a SwitchTargets,
propagate: F, propagate: F,
effects_applied: bool, effects_applied: bool,

View file

@ -227,5 +227,5 @@ struct OptimizationInfo<'tcx> {
/// Either Eq or Ne /// Either Eq or Ne
op: BinOp, op: BinOp,
/// Current targets used in the switch /// Current targets used in the switch
targets: SwitchTargets<'tcx>, targets: SwitchTargets,
} }

View file

@ -760,8 +760,6 @@ where
let elem_size = Place::from(self.new_temp(tcx.types.usize)); let elem_size = Place::from(self.new_temp(tcx.types.usize));
let len = Place::from(self.new_temp(tcx.types.usize)); let len = Place::from(self.new_temp(tcx.types.usize));
static USIZE_SWITCH_ZERO: &[u128; 1] = &[0];
let base_block = BasicBlockData { let base_block = BasicBlockData {
statements: vec![ statements: vec![
self.assign(elem_size, Rvalue::NullaryOp(NullOp::SizeOf, ety)), self.assign(elem_size, Rvalue::NullaryOp(NullOp::SizeOf, ety)),
@ -774,7 +772,7 @@ where
discr: move_(elem_size), discr: move_(elem_size),
switch_ty: tcx.types.usize, switch_ty: tcx.types.usize,
targets: SwitchTargets::static_if( targets: SwitchTargets::static_if(
USIZE_SWITCH_ZERO, 0,
self.drop_loop_pair(ety, false, len), self.drop_loop_pair(ety, false, len),
self.drop_loop_pair(ety, true, len), self.drop_loop_pair(ety, true, len),
), ),