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