Use SmallVec in SwitchTargets
This allows building common SwitchTargets (eg. for `if`s) without allocation.
This commit is contained in:
parent
432535da2b
commit
9a47f74bfe
5 changed files with 14 additions and 15 deletions
|
@ -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.
|
||||||
|
|
|
@ -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 we’ve decided to keep this as-is until we figure a case
|
// However we’ve 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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
),
|
),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue