@@ -16,6 +16,87 @@ use std::slice;
16
16
17
17
pub use super :: query:: * ;
18
18
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
+
19
100
#[ derive( Clone , TyEncodable , TyDecodable , HashStable , PartialEq ) ]
20
101
pub enum TerminatorKind < ' tcx > {
21
102
/// Block should have one successor in the graph; we jump there.
@@ -32,23 +113,7 @@ pub enum TerminatorKind<'tcx> {
32
113
/// FIXME: remove this redundant information. Currently, it is relied on by pretty-printing.
33
114
switch_ty : Ty < ' tcx > ,
34
115
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 > ,
52
117
} ,
53
118
54
119
/// Indicates that the landing pad is finished and unwinding should
@@ -227,12 +292,10 @@ impl<'tcx> TerminatorKind<'tcx> {
227
292
t : BasicBlock ,
228
293
f : BasicBlock ,
229
294
) -> TerminatorKind < ' tcx > {
230
- static BOOL_SWITCH_FALSE : & [ u128 ] = & [ 0 ] ;
231
295
TerminatorKind :: SwitchInt {
232
296
discr : cond,
233
297
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) ,
236
299
}
237
300
}
238
301
@@ -263,7 +326,7 @@ impl<'tcx> TerminatorKind<'tcx> {
263
326
| FalseUnwind { real_target : ref t, unwind : Some ( ref u) } => {
264
327
Some ( t) . into_iter ( ) . chain ( slice:: from_ref ( u) )
265
328
}
266
- SwitchInt { ref targets, .. } => None . into_iter ( ) . chain ( & targets[ ..] ) ,
329
+ SwitchInt { ref targets, .. } => None . into_iter ( ) . chain ( & targets. targets [ ..] ) ,
267
330
FalseEdge { ref real_target, ref imaginary_target } => {
268
331
Some ( real_target) . into_iter ( ) . chain ( slice:: from_ref ( imaginary_target) )
269
332
}
@@ -297,7 +360,7 @@ impl<'tcx> TerminatorKind<'tcx> {
297
360
| FalseUnwind { real_target : ref mut t, unwind : Some ( ref mut u) } => {
298
361
Some ( t) . into_iter ( ) . chain ( slice:: from_mut ( u) )
299
362
}
300
- SwitchInt { ref mut targets, .. } => None . into_iter ( ) . chain ( & mut targets[ ..] ) ,
363
+ SwitchInt { ref mut targets, .. } => None . into_iter ( ) . chain ( & mut targets. targets [ ..] ) ,
301
364
FalseEdge { ref mut real_target, ref mut imaginary_target } => {
302
365
Some ( real_target) . into_iter ( ) . chain ( slice:: from_mut ( imaginary_target) )
303
366
}
@@ -469,11 +532,12 @@ impl<'tcx> TerminatorKind<'tcx> {
469
532
match * self {
470
533
Return | Resume | Abort | Unreachable | GeneratorDrop => vec ! [ ] ,
471
534
Goto { .. } => vec ! [ "" . into( ) ] ,
472
- SwitchInt { ref values , switch_ty, .. } => ty:: tls:: with ( |tcx| {
535
+ SwitchInt { ref targets , switch_ty, .. } => ty:: tls:: with ( |tcx| {
473
536
let param_env = ty:: ParamEnv :: empty ( ) ;
474
537
let switch_ty = tcx. lift ( & switch_ty) . unwrap ( ) ;
475
538
let size = tcx. layout_of ( param_env. and ( switch_ty) ) . unwrap ( ) . size ;
476
- values
539
+ targets
540
+ . values
477
541
. iter ( )
478
542
. map ( |& u| {
479
543
ty:: Const :: from_scalar ( tcx, Scalar :: from_uint ( u, size) , switch_ty)
0 commit comments