@@ -16,6 +16,87 @@ use std::slice;
1616
1717pub use super :: query:: * ;
1818
19+ #[ derive( Debug , Clone , TyEncodable , TyDecodable , HashStable , PartialEq ) ]
20+ pub struct SwitchTargets < ' tcx > {
21+ /// Possible values. The locations to branch to in each case
22+ /// are found in the corresponding indices from the `targets` vector.
23+ values : Cow < ' tcx , [ u128 ] > ,
24+
25+ /// Possible branch sites. The last element of this vector is used
26+ /// for the otherwise branch, so targets.len() == values.len() + 1
27+ /// should hold.
28+ //
29+ // This invariant is quite non-obvious and also could be improved.
30+ // One way to make this invariant is to have something like this instead:
31+ //
32+ // branches: Vec<(ConstInt, BasicBlock)>,
33+ // otherwise: Option<BasicBlock> // exhaustive if None
34+ //
35+ // However we’ve decided to keep this as-is until we figure a case
36+ // where some other approach seems to be strictly better than other.
37+ targets : Vec < BasicBlock > ,
38+ }
39+
40+ impl < ' tcx > SwitchTargets < ' tcx > {
41+ /// Creates switch targets from an iterator of values and target blocks.
42+ ///
43+ /// The iterator may be empty, in which case the `SwitchInt` instruction is equivalent to
44+ /// `goto otherwise;`.
45+ pub fn new ( targets : impl Iterator < Item = ( u128 , BasicBlock ) > , otherwise : BasicBlock ) -> Self {
46+ let ( values, mut targets) : ( Vec < _ > , Vec < _ > ) = targets. unzip ( ) ;
47+ targets. push ( otherwise) ;
48+ Self { values : values. into ( ) , targets }
49+ }
50+
51+ /// Builds a switch targets definition that jumps to `then` if the tested value equals `value`,
52+ /// and to `else_` if not.
53+ pub fn static_if ( value : & ' static [ u128 ; 1 ] , then : BasicBlock , else_ : BasicBlock ) -> Self {
54+ Self { values : Cow :: Borrowed ( value) , targets : vec ! [ then, else_] }
55+ }
56+
57+ /// Returns the fallback target that is jumped to when none of the values match the operand.
58+ pub fn otherwise ( & self ) -> BasicBlock {
59+ * self . targets . last ( ) . unwrap ( )
60+ }
61+
62+ /// Returns an iterator over the switch targets.
63+ ///
64+ /// The iterator will yield tuples containing the value and corresponding target to jump to, not
65+ /// including the `otherwise` fallback target.
66+ ///
67+ /// Note that this may yield 0 elements. Only the `otherwise` branch is mandatory.
68+ pub fn iter ( & self ) -> SwitchTargetsIter < ' _ > {
69+ SwitchTargetsIter { inner : self . values . iter ( ) . zip ( self . targets . iter ( ) ) }
70+ }
71+
72+ /// Returns a slice with all possible jump targets (including the fallback target).
73+ pub fn all_targets ( & self ) -> & [ BasicBlock ] {
74+ & self . targets
75+ }
76+
77+ pub fn all_targets_mut ( & mut self ) -> & mut [ BasicBlock ] {
78+ & mut self . targets
79+ }
80+ }
81+
82+ pub struct SwitchTargetsIter < ' a > {
83+ inner : iter:: Zip < slice:: Iter < ' a , u128 > , slice:: Iter < ' a , BasicBlock > > ,
84+ }
85+
86+ impl < ' a > Iterator for SwitchTargetsIter < ' a > {
87+ type Item = ( u128 , BasicBlock ) ;
88+
89+ fn next ( & mut self ) -> Option < Self :: Item > {
90+ self . inner . next ( ) . map ( |( val, bb) | ( * val, * bb) )
91+ }
92+
93+ fn size_hint ( & self ) -> ( usize , Option < usize > ) {
94+ self . inner . size_hint ( )
95+ }
96+ }
97+
98+ impl < ' a > ExactSizeIterator for SwitchTargetsIter < ' a > { }
99+
19100#[ derive( Clone , TyEncodable , TyDecodable , HashStable , PartialEq ) ]
20101pub enum TerminatorKind < ' tcx > {
21102 /// Block should have one successor in the graph; we jump there.
@@ -32,23 +113,7 @@ pub enum TerminatorKind<'tcx> {
32113 /// FIXME: remove this redundant information. Currently, it is relied on by pretty-printing.
33114 switch_ty : Ty < ' tcx > ,
34115
35- /// Possible values. The locations to branch to in each case
36- /// are found in the corresponding indices from the `targets` vector.
37- values : Cow < ' tcx , [ u128 ] > ,
38-
39- /// Possible branch sites. The last element of this vector is used
40- /// for the otherwise branch, so targets.len() == values.len() + 1
41- /// should hold.
42- //
43- // This invariant is quite non-obvious and also could be improved.
44- // One way to make this invariant is to have something like this instead:
45- //
46- // branches: Vec<(ConstInt, BasicBlock)>,
47- // otherwise: Option<BasicBlock> // exhaustive if None
48- //
49- // However we’ve decided to keep this as-is until we figure a case
50- // where some other approach seems to be strictly better than other.
51- targets : Vec < BasicBlock > ,
116+ targets : SwitchTargets < ' tcx > ,
52117 } ,
53118
54119 /// Indicates that the landing pad is finished and unwinding should
@@ -227,12 +292,10 @@ impl<'tcx> TerminatorKind<'tcx> {
227292 t : BasicBlock ,
228293 f : BasicBlock ,
229294 ) -> TerminatorKind < ' tcx > {
230- static BOOL_SWITCH_FALSE : & [ u128 ] = & [ 0 ] ;
231295 TerminatorKind :: SwitchInt {
232296 discr : cond,
233297 switch_ty : tcx. types . bool ,
234- values : From :: from ( BOOL_SWITCH_FALSE ) ,
235- targets : vec ! [ f, t] ,
298+ targets : SwitchTargets :: static_if ( & [ 0 ] , f, t) ,
236299 }
237300 }
238301
@@ -263,7 +326,7 @@ impl<'tcx> TerminatorKind<'tcx> {
263326 | FalseUnwind { real_target : ref t, unwind : Some ( ref u) } => {
264327 Some ( t) . into_iter ( ) . chain ( slice:: from_ref ( u) )
265328 }
266- SwitchInt { ref targets, .. } => None . into_iter ( ) . chain ( & targets[ ..] ) ,
329+ SwitchInt { ref targets, .. } => None . into_iter ( ) . chain ( & targets. targets [ ..] ) ,
267330 FalseEdge { ref real_target, ref imaginary_target } => {
268331 Some ( real_target) . into_iter ( ) . chain ( slice:: from_ref ( imaginary_target) )
269332 }
@@ -297,7 +360,7 @@ impl<'tcx> TerminatorKind<'tcx> {
297360 | FalseUnwind { real_target : ref mut t, unwind : Some ( ref mut u) } => {
298361 Some ( t) . into_iter ( ) . chain ( slice:: from_mut ( u) )
299362 }
300- SwitchInt { ref mut targets, .. } => None . into_iter ( ) . chain ( & mut targets[ ..] ) ,
363+ SwitchInt { ref mut targets, .. } => None . into_iter ( ) . chain ( & mut targets. targets [ ..] ) ,
301364 FalseEdge { ref mut real_target, ref mut imaginary_target } => {
302365 Some ( real_target) . into_iter ( ) . chain ( slice:: from_mut ( imaginary_target) )
303366 }
@@ -469,11 +532,12 @@ impl<'tcx> TerminatorKind<'tcx> {
469532 match * self {
470533 Return | Resume | Abort | Unreachable | GeneratorDrop => vec ! [ ] ,
471534 Goto { .. } => vec ! [ "" . into( ) ] ,
472- SwitchInt { ref values , switch_ty, .. } => ty:: tls:: with ( |tcx| {
535+ SwitchInt { ref targets , switch_ty, .. } => ty:: tls:: with ( |tcx| {
473536 let param_env = ty:: ParamEnv :: empty ( ) ;
474537 let switch_ty = tcx. lift ( & switch_ty) . unwrap ( ) ;
475538 let size = tcx. layout_of ( param_env. and ( switch_ty) ) . unwrap ( ) . size ;
476- values
539+ targets
540+ . values
477541 . iter ( )
478542 . map ( |& u| {
479543 ty:: Const :: from_scalar ( tcx, Scalar :: from_uint ( u, size) , switch_ty)
0 commit comments