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 call_did =
45
+ if let Some ( call_did) = lower_to ( & block. statements [ i] , local_decls, tcx) {
46
+ call_did
47
+ } else {
48
+ continue ;
49
+ } ;
50
+
51
+ let after_call = BasicBlockData {
52
+ statements : block. statements . drain ( ( i+1 ) ..) . collect ( ) ,
53
+ is_cleanup : block. is_cleanup ,
54
+ terminator : block. terminator . take ( ) ,
55
+ } ;
56
+
57
+ let bin_statement = block. statements . pop ( ) . unwrap ( ) ;
58
+ let ( source_info, lvalue, lhs, rhs) = match bin_statement {
59
+ Statement {
60
+ source_info,
61
+ kind : StatementKind :: Assign (
62
+ lvalue,
63
+ Rvalue :: BinaryOp ( _, lhs, rhs) )
64
+ } => ( source_info, lvalue, lhs, rhs) ,
65
+ Statement {
66
+ source_info,
67
+ kind : StatementKind :: Assign (
68
+ lvalue,
69
+ Rvalue :: CheckedBinaryOp ( _, lhs, rhs) )
70
+ } => ( source_info, lvalue, lhs, rhs) ,
71
+ _ => bug ! ( "Statement doesn't match pattern any more?" ) ,
72
+ } ;
73
+
74
+ let bb = BasicBlock :: new ( cur_len + new_blocks. len ( ) ) ;
75
+ new_blocks. push ( after_call) ;
76
+
77
+ block. terminator =
78
+ Some ( Terminator {
79
+ source_info,
80
+ kind : TerminatorKind :: Call {
81
+ func : Operand :: function_handle ( tcx, call_did,
82
+ Slice :: empty ( ) , source_info. span ) ,
83
+ args : vec ! [ lhs, rhs] ,
84
+ destination : Some ( ( lvalue, bb) ) ,
85
+ cleanup : None ,
86
+ } ,
87
+ } ) ;
88
+ }
89
+ }
90
+
91
+ basic_blocks. extend ( new_blocks) ;
92
+ }
93
+ }
94
+
95
+ fn lower_to < ' a , ' tcx , D > ( statement : & Statement < ' tcx > , local_decls : & D , tcx : TyCtxt < ' a , ' tcx , ' tcx > )
96
+ -> Option < DefId >
97
+ where D : HasLocalDecls < ' tcx >
98
+ {
99
+ match statement. kind {
100
+ StatementKind :: Assign ( _, Rvalue :: BinaryOp ( bin_op, ref lhs, _) ) => {
101
+ let ty = lhs. ty ( local_decls, tcx) ;
102
+ if let Some ( is_signed) = sign_of_128bit ( & ty) {
103
+ if let Some ( item) = item_for_op ( bin_op, is_signed) {
104
+ return Some ( tcx. require_lang_item ( item) )
105
+ }
106
+ }
107
+ } ,
108
+ StatementKind :: Assign ( _, Rvalue :: CheckedBinaryOp ( bin_op, ref lhs, _) ) => {
109
+ let ty = lhs. ty ( local_decls, tcx) ;
110
+ if let Some ( is_signed) = sign_of_128bit ( & ty) {
111
+ if let Some ( item) = item_for_checked_op ( bin_op, is_signed) {
112
+ return Some ( tcx. require_lang_item ( item) )
113
+ }
114
+ }
115
+ } ,
116
+ _ => { } ,
117
+ }
118
+ None
119
+ }
120
+
121
+ fn sign_of_128bit ( ty : & Ty ) -> Option < bool > {
122
+ match ty. sty {
123
+ TypeVariants :: TyInt ( syntax:: ast:: IntTy :: I128 ) => Some ( true ) ,
124
+ TypeVariants :: TyUint ( syntax:: ast:: UintTy :: U128 ) => Some ( false ) ,
125
+ _ => None ,
126
+ }
127
+ }
128
+
129
+ fn item_for_op ( bin_op : BinOp , is_signed : bool ) -> Option < LangItem > {
130
+ let i = match ( bin_op, is_signed) {
131
+ ( BinOp :: Add , _) => LangItem :: I128AddFnLangItem ,
132
+ ( BinOp :: Sub , _) => LangItem :: I128SubFnLangItem ,
133
+ ( BinOp :: Mul , _) => LangItem :: I128MulFnLangItem ,
134
+ ( BinOp :: Div , true ) => LangItem :: I128DivFnLangItem ,
135
+ ( BinOp :: Div , false ) => LangItem :: U128DivFnLangItem ,
136
+ ( BinOp :: Rem , true ) => LangItem :: I128RemFnLangItem ,
137
+ ( BinOp :: Rem , false ) => LangItem :: U128RemFnLangItem ,
138
+ ( BinOp :: Shl , _) => LangItem :: I128ShlFnLangItem ,
139
+ ( BinOp :: Shr , true ) => LangItem :: I128ShrFnLangItem ,
140
+ ( BinOp :: Shr , false ) => LangItem :: U128ShrFnLangItem ,
141
+ _ => return None ,
142
+ } ;
143
+ Some ( i)
144
+ }
145
+
146
+ fn item_for_checked_op ( bin_op : BinOp , is_signed : bool ) -> Option < LangItem > {
147
+ let i = match ( bin_op, is_signed) {
148
+ ( BinOp :: Add , true ) => LangItem :: I128AddoFnLangItem ,
149
+ ( BinOp :: Add , false ) => LangItem :: U128AddoFnLangItem ,
150
+ ( BinOp :: Sub , true ) => LangItem :: I128SuboFnLangItem ,
151
+ ( BinOp :: Sub , false ) => LangItem :: U128SuboFnLangItem ,
152
+ ( BinOp :: Mul , true ) => LangItem :: I128MuloFnLangItem ,
153
+ ( BinOp :: Mul , false ) => LangItem :: U128MuloFnLangItem ,
154
+ ( BinOp :: Shl , _) => LangItem :: I128ShloFnLangItem ,
155
+ ( BinOp :: Shr , true ) => LangItem :: I128ShroFnLangItem ,
156
+ ( BinOp :: Shr , false ) => LangItem :: U128ShroFnLangItem ,
157
+ _ => return None ,
158
+ } ;
159
+ Some ( i)
160
+ }
0 commit comments