1
+ // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2
+ // file at the top-level directory of this distribution and at
3
+ // http://rust-lang.org/COPYRIGHT.
4
+ //
5
+ // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6
+ // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7
+ // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8
+ // option. This file may not be copied, modified, or distributed
9
+ // except according to those terms.
10
+
11
+ //! Replaces 128-bit operators with lang item calls
12
+
13
+ use rustc:: hir:: def_id:: DefId ;
14
+ use rustc:: middle:: lang_items:: LangItem ;
15
+ use rustc:: mir:: * ;
16
+ use rustc:: ty:: { Slice , Ty , TyCtxt , TypeVariants } ;
17
+ use rustc_data_structures:: indexed_vec:: { Idx } ;
18
+ use transform:: { MirPass , MirSource } ;
19
+ use syntax;
20
+
21
+ pub struct Lower128Bit ;
22
+
23
+ impl MirPass for Lower128Bit {
24
+ fn run_pass < ' a , ' tcx > ( & self ,
25
+ tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
26
+ _src : MirSource ,
27
+ mir : & mut Mir < ' tcx > ) {
28
+ if !tcx. sess . opts . debugging_opts . lower_128bit_ops {
29
+ return
30
+ }
31
+
32
+ self . lower_128bit_ops ( tcx, mir) ;
33
+ }
34
+ }
35
+
36
+ impl Lower128Bit {
37
+ fn lower_128bit_ops < ' a , ' tcx > ( & self , tcx : TyCtxt < ' a , ' tcx , ' tcx > , mir : & mut Mir < ' tcx > ) {
38
+ let mut new_blocks = Vec :: new ( ) ;
39
+ let cur_len = mir. basic_blocks ( ) . len ( ) ;
40
+
41
+ let ( basic_blocks, local_decls) = mir. basic_blocks_and_local_decls_mut ( ) ;
42
+ for block in basic_blocks. iter_mut ( ) {
43
+ for i in ( 0 ..block. statements . len ( ) ) . rev ( ) {
44
+ let ( lang_item, rhs_kind) =
45
+ if let Some ( ( lang_item, rhs_kind) ) =
46
+ lower_to ( & block. statements [ i] , local_decls, tcx)
47
+ {
48
+ ( lang_item, rhs_kind)
49
+ } else {
50
+ continue ;
51
+ } ;
52
+
53
+ let rhs_override_ty = rhs_kind. ty ( tcx) ;
54
+ let cast_local =
55
+ match rhs_override_ty {
56
+ None => None ,
57
+ Some ( ty) => {
58
+ let local_decl = LocalDecl :: new_internal (
59
+ ty, block. statements [ i] . source_info . span ) ;
60
+ Some ( local_decls. push ( local_decl) )
61
+ } ,
62
+ } ;
63
+
64
+ let storage_dead = cast_local. map ( |local| {
65
+ Statement {
66
+ source_info : block. statements [ i] . source_info ,
67
+ kind : StatementKind :: StorageDead ( local) ,
68
+ }
69
+ } ) ;
70
+ let after_call = BasicBlockData {
71
+ statements : storage_dead. into_iter ( )
72
+ . chain ( block. statements . drain ( ( i+1 ) ..) ) . collect ( ) ,
73
+ is_cleanup : block. is_cleanup ,
74
+ terminator : block. terminator . take ( ) ,
75
+ } ;
76
+
77
+ let bin_statement = block. statements . pop ( ) . unwrap ( ) ;
78
+ let ( source_info, lvalue, lhs, mut rhs) = match bin_statement {
79
+ Statement {
80
+ source_info,
81
+ kind : StatementKind :: Assign (
82
+ lvalue,
83
+ Rvalue :: BinaryOp ( _, lhs, rhs) )
84
+ } => ( source_info, lvalue, lhs, rhs) ,
85
+ Statement {
86
+ source_info,
87
+ kind : StatementKind :: Assign (
88
+ lvalue,
89
+ Rvalue :: CheckedBinaryOp ( _, lhs, rhs) )
90
+ } => ( source_info, lvalue, lhs, rhs) ,
91
+ _ => bug ! ( "Statement doesn't match pattern any more?" ) ,
92
+ } ;
93
+
94
+ if let Some ( local) = cast_local {
95
+ block. statements . push ( Statement {
96
+ source_info : source_info,
97
+ kind : StatementKind :: StorageLive ( local) ,
98
+ } ) ;
99
+ block. statements . push ( Statement {
100
+ source_info : source_info,
101
+ kind : StatementKind :: Assign (
102
+ Lvalue :: Local ( local) ,
103
+ Rvalue :: Cast (
104
+ CastKind :: Misc ,
105
+ rhs,
106
+ rhs_override_ty. unwrap ( ) ) ) ,
107
+ } ) ;
108
+ rhs = Operand :: Consume ( Lvalue :: Local ( local) ) ;
109
+ }
110
+
111
+ let call_did = check_lang_item_type (
112
+ lang_item, & lvalue, & lhs, & rhs, local_decls, tcx) ;
113
+
114
+ let bb = BasicBlock :: new ( cur_len + new_blocks. len ( ) ) ;
115
+ new_blocks. push ( after_call) ;
116
+
117
+ block. terminator =
118
+ Some ( Terminator {
119
+ source_info,
120
+ kind : TerminatorKind :: Call {
121
+ func : Operand :: function_handle ( tcx, call_did,
122
+ Slice :: empty ( ) , source_info. span ) ,
123
+ args : vec ! [ lhs, rhs] ,
124
+ destination : Some ( ( lvalue, bb) ) ,
125
+ cleanup : None ,
126
+ } ,
127
+ } ) ;
128
+ }
129
+ }
130
+
131
+ basic_blocks. extend ( new_blocks) ;
132
+ }
133
+ }
134
+
135
+ fn check_lang_item_type < ' a , ' tcx , D > (
136
+ lang_item : LangItem ,
137
+ lvalue : & Lvalue < ' tcx > ,
138
+ lhs : & Operand < ' tcx > ,
139
+ rhs : & Operand < ' tcx > ,
140
+ local_decls : & D ,
141
+ tcx : TyCtxt < ' a , ' tcx , ' tcx > )
142
+ -> DefId
143
+ where D : HasLocalDecls < ' tcx >
144
+ {
145
+ let did = tcx. require_lang_item ( lang_item) ;
146
+ let poly_sig = tcx. fn_sig ( did) ;
147
+ let sig = tcx. no_late_bound_regions ( & poly_sig) . unwrap ( ) ;
148
+ let lhs_ty = lhs. ty ( local_decls, tcx) ;
149
+ let rhs_ty = rhs. ty ( local_decls, tcx) ;
150
+ let lvalue_ty = lvalue. ty ( local_decls, tcx) . to_ty ( tcx) ;
151
+ let expected = [ lhs_ty, rhs_ty, lvalue_ty] ;
152
+ assert_eq ! ( sig. inputs_and_output[ ..] , expected,
153
+ "lang item {}" , tcx. def_symbol_name( did) ) ;
154
+ did
155
+ }
156
+
157
+ fn lower_to < ' a , ' tcx , D > ( statement : & Statement < ' tcx > , local_decls : & D , tcx : TyCtxt < ' a , ' tcx , ' tcx > )
158
+ -> Option < ( LangItem , RhsKind ) >
159
+ where D : HasLocalDecls < ' tcx >
160
+ {
161
+ match statement. kind {
162
+ StatementKind :: Assign ( _, Rvalue :: BinaryOp ( bin_op, ref lhs, _) ) => {
163
+ let ty = lhs. ty ( local_decls, tcx) ;
164
+ if let Some ( is_signed) = sign_of_128bit ( ty) {
165
+ return item_for_op ( bin_op, is_signed) ;
166
+ }
167
+ } ,
168
+ StatementKind :: Assign ( _, Rvalue :: CheckedBinaryOp ( bin_op, ref lhs, _) ) => {
169
+ let ty = lhs. ty ( local_decls, tcx) ;
170
+ if let Some ( is_signed) = sign_of_128bit ( ty) {
171
+ return item_for_checked_op ( bin_op, is_signed) ;
172
+ }
173
+ } ,
174
+ _ => { } ,
175
+ }
176
+ None
177
+ }
178
+
179
+ #[ derive( Copy , Clone ) ]
180
+ enum RhsKind {
181
+ Unchanged ,
182
+ ForceU128 ,
183
+ ForceU32 ,
184
+ }
185
+
186
+ impl RhsKind {
187
+ fn ty < ' a , ' tcx > ( & self , tcx : TyCtxt < ' a , ' tcx , ' tcx > ) -> Option < Ty < ' tcx > > {
188
+ match * self {
189
+ RhsKind :: Unchanged => None ,
190
+ RhsKind :: ForceU128 => Some ( tcx. types . u128 ) ,
191
+ RhsKind :: ForceU32 => Some ( tcx. types . u32 ) ,
192
+ }
193
+ }
194
+ }
195
+
196
+ fn sign_of_128bit ( ty : Ty ) -> Option < bool > {
197
+ match ty. sty {
198
+ TypeVariants :: TyInt ( syntax:: ast:: IntTy :: I128 ) => Some ( true ) ,
199
+ TypeVariants :: TyUint ( syntax:: ast:: UintTy :: U128 ) => Some ( false ) ,
200
+ _ => None ,
201
+ }
202
+ }
203
+
204
+ fn item_for_op ( bin_op : BinOp , is_signed : bool ) -> Option < ( LangItem , RhsKind ) > {
205
+ let i = match ( bin_op, is_signed) {
206
+ ( BinOp :: Add , true ) => ( LangItem :: I128AddFnLangItem , RhsKind :: Unchanged ) ,
207
+ ( BinOp :: Add , false ) => ( LangItem :: U128AddFnLangItem , RhsKind :: Unchanged ) ,
208
+ ( BinOp :: Sub , true ) => ( LangItem :: I128SubFnLangItem , RhsKind :: Unchanged ) ,
209
+ ( BinOp :: Sub , false ) => ( LangItem :: U128SubFnLangItem , RhsKind :: Unchanged ) ,
210
+ ( BinOp :: Mul , true ) => ( LangItem :: I128MulFnLangItem , RhsKind :: Unchanged ) ,
211
+ ( BinOp :: Mul , false ) => ( LangItem :: U128MulFnLangItem , RhsKind :: Unchanged ) ,
212
+ ( BinOp :: Div , true ) => ( LangItem :: I128DivFnLangItem , RhsKind :: Unchanged ) ,
213
+ ( BinOp :: Div , false ) => ( LangItem :: U128DivFnLangItem , RhsKind :: Unchanged ) ,
214
+ ( BinOp :: Rem , true ) => ( LangItem :: I128RemFnLangItem , RhsKind :: Unchanged ) ,
215
+ ( BinOp :: Rem , false ) => ( LangItem :: U128RemFnLangItem , RhsKind :: Unchanged ) ,
216
+ ( BinOp :: Shl , true ) => ( LangItem :: I128ShlFnLangItem , RhsKind :: ForceU32 ) ,
217
+ ( BinOp :: Shl , false ) => ( LangItem :: U128ShlFnLangItem , RhsKind :: ForceU32 ) ,
218
+ ( BinOp :: Shr , true ) => ( LangItem :: I128ShrFnLangItem , RhsKind :: ForceU32 ) ,
219
+ ( BinOp :: Shr , false ) => ( LangItem :: U128ShrFnLangItem , RhsKind :: ForceU32 ) ,
220
+ _ => return None ,
221
+ } ;
222
+ Some ( i)
223
+ }
224
+
225
+ fn item_for_checked_op ( bin_op : BinOp , is_signed : bool ) -> Option < ( LangItem , RhsKind ) > {
226
+ let i = match ( bin_op, is_signed) {
227
+ ( BinOp :: Add , true ) => ( LangItem :: I128AddoFnLangItem , RhsKind :: Unchanged ) ,
228
+ ( BinOp :: Add , false ) => ( LangItem :: U128AddoFnLangItem , RhsKind :: Unchanged ) ,
229
+ ( BinOp :: Sub , true ) => ( LangItem :: I128SuboFnLangItem , RhsKind :: Unchanged ) ,
230
+ ( BinOp :: Sub , false ) => ( LangItem :: U128SuboFnLangItem , RhsKind :: Unchanged ) ,
231
+ ( BinOp :: Mul , true ) => ( LangItem :: I128MuloFnLangItem , RhsKind :: Unchanged ) ,
232
+ ( BinOp :: Mul , false ) => ( LangItem :: U128MuloFnLangItem , RhsKind :: Unchanged ) ,
233
+ ( BinOp :: Shl , true ) => ( LangItem :: I128ShloFnLangItem , RhsKind :: ForceU128 ) ,
234
+ ( BinOp :: Shl , false ) => ( LangItem :: U128ShloFnLangItem , RhsKind :: ForceU128 ) ,
235
+ ( BinOp :: Shr , true ) => ( LangItem :: I128ShroFnLangItem , RhsKind :: ForceU128 ) ,
236
+ ( BinOp :: Shr , false ) => ( LangItem :: U128ShroFnLangItem , RhsKind :: ForceU128 ) ,
237
+ _ => bug ! ( "That should be all the checked ones?" ) ,
238
+ } ;
239
+ Some ( i)
240
+ }
0 commit comments