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.
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.
11 //! Replaces 128-bit operators with lang item calls
13 use rustc::hir::def_id::DefId;
14 use rustc::middle::lang_items::LangItem;
16 use rustc::ty::{Slice, Ty, TyCtxt, TypeVariants};
17 use rustc_data_structures::indexed_vec::{Idx};
18 use transform::{MirPass, MirSource};
21 pub struct Lower128Bit;
23 impl MirPass for Lower128Bit {
24 fn run_pass<'a, 'tcx>(&self,
25 tcx: TyCtxt<'a, 'tcx, 'tcx>,
27 mir: &mut Mir<'tcx>) {
28 if !tcx.sess.opts.debugging_opts.lower_128bit_ops {
32 self.lower_128bit_ops(tcx, mir);
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();
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)
53 let rhs_override_ty = rhs_kind.ty(tcx);
55 match rhs_override_ty {
58 let local_decl = LocalDecl::new_internal(
59 ty, block.statements[i].source_info.span);
60 Some(local_decls.push(local_decl))
64 let storage_dead = cast_local.map(|local| {
66 source_info: block.statements[i].source_info,
67 kind: StatementKind::StorageDead(local),
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(),
77 let bin_statement = block.statements.pop().unwrap();
78 let (source_info, lvalue, lhs, mut rhs) = match bin_statement {
81 kind: StatementKind::Assign(
83 Rvalue::BinaryOp(_, lhs, rhs))
84 } => (source_info, lvalue, lhs, rhs),
87 kind: StatementKind::Assign(
89 Rvalue::CheckedBinaryOp(_, lhs, rhs))
90 } => (source_info, lvalue, lhs, rhs),
91 _ => bug!("Statement doesn't match pattern any more?"),
94 if let Some(local) = cast_local {
95 block.statements.push(Statement {
96 source_info: source_info,
97 kind: StatementKind::StorageLive(local),
99 block.statements.push(Statement {
100 source_info: source_info,
101 kind: StatementKind::Assign(
102 Lvalue::Local(local),
106 rhs_override_ty.unwrap())),
108 rhs = Operand::Move(Lvalue::Local(local));
111 let call_did = check_lang_item_type(
112 lang_item, &lvalue, &lhs, &rhs, local_decls, tcx);
114 let bb = BasicBlock::new(cur_len + new_blocks.len());
115 new_blocks.push(after_call);
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)),
131 basic_blocks.extend(new_blocks);
135 fn check_lang_item_type<'a, 'tcx, D>(
137 lvalue: &Lvalue<'tcx>,
141 tcx: TyCtxt<'a, 'tcx, 'tcx>)
143 where D: HasLocalDecls<'tcx>
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));
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>
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);
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);
179 #[derive(Copy, Clone)]
187 fn ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Ty<'tcx>> {
189 RhsKind::Unchanged => None,
190 RhsKind::ForceU128 => Some(tcx.types.u128),
191 RhsKind::ForceU32 => Some(tcx.types.u32),
196 fn sign_of_128bit(ty: Ty) -> Option<bool> {
198 TypeVariants::TyInt(syntax::ast::IntTy::I128) => Some(true),
199 TypeVariants::TyUint(syntax::ast::UintTy::U128) => Some(false),
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),
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?"),