]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/transform/lower_128bit.rs
MIR: split Operand::Consume into Copy and Move.
[rust.git] / src / librustc_mir / transform / lower_128bit.rs
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::Move(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 }