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 let debugging_override = tcx.sess.opts.debugging_opts.lower_128bit_ops;
29 let target_default = tcx.sess.host.options.i128_lowering;
30 if !debugging_override.unwrap_or(target_default) {
34 self.lower_128bit_ops(tcx, mir);
39 fn lower_128bit_ops<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &mut Mir<'tcx>) {
40 let mut new_blocks = Vec::new();
41 let cur_len = mir.basic_blocks().len();
43 let (basic_blocks, local_decls) = mir.basic_blocks_and_local_decls_mut();
44 for block in basic_blocks.iter_mut() {
45 for i in (0..block.statements.len()).rev() {
46 let (lang_item, rhs_kind) =
47 if let Some((lang_item, rhs_kind)) =
48 lower_to(&block.statements[i], local_decls, tcx)
55 let rhs_override_ty = rhs_kind.ty(tcx);
57 match rhs_override_ty {
60 let local_decl = LocalDecl::new_internal(
61 ty, block.statements[i].source_info.span);
62 Some(local_decls.push(local_decl))
66 let storage_dead = cast_local.map(|local| {
68 source_info: block.statements[i].source_info,
69 kind: StatementKind::StorageDead(local),
72 let after_call = BasicBlockData {
73 statements: storage_dead.into_iter()
74 .chain(block.statements.drain((i+1)..)).collect(),
75 is_cleanup: block.is_cleanup,
76 terminator: block.terminator.take(),
79 let bin_statement = block.statements.pop().unwrap();
80 let (source_info, place, lhs, mut rhs) = match bin_statement {
83 kind: StatementKind::Assign(
85 Rvalue::BinaryOp(_, lhs, rhs))
86 } => (source_info, place, lhs, rhs),
89 kind: StatementKind::Assign(
91 Rvalue::CheckedBinaryOp(_, lhs, rhs))
92 } => (source_info, place, lhs, rhs),
93 _ => bug!("Statement doesn't match pattern any more?"),
96 if let Some(local) = cast_local {
97 block.statements.push(Statement {
98 source_info: source_info,
99 kind: StatementKind::StorageLive(local),
101 block.statements.push(Statement {
102 source_info: source_info,
103 kind: StatementKind::Assign(
108 rhs_override_ty.unwrap())),
110 rhs = Operand::Move(Place::Local(local));
113 let call_did = check_lang_item_type(
114 lang_item, &place, &lhs, &rhs, local_decls, tcx);
116 let bb = BasicBlock::new(cur_len + new_blocks.len());
117 new_blocks.push(after_call);
122 kind: TerminatorKind::Call {
123 func: Operand::function_handle(tcx, call_did,
124 Slice::empty(), source_info.span),
125 args: vec![lhs, rhs],
126 destination: Some((place, bb)),
133 basic_blocks.extend(new_blocks);
137 fn check_lang_item_type<'a, 'tcx, D>(
143 tcx: TyCtxt<'a, 'tcx, 'tcx>)
145 where D: HasLocalDecls<'tcx>
147 let did = tcx.require_lang_item(lang_item);
148 let poly_sig = tcx.fn_sig(did);
149 let sig = poly_sig.no_late_bound_regions().unwrap();
150 let lhs_ty = lhs.ty(local_decls, tcx);
151 let rhs_ty = rhs.ty(local_decls, tcx);
152 let place_ty = place.ty(local_decls, tcx).to_ty(tcx);
153 let expected = [lhs_ty, rhs_ty, place_ty];
154 assert_eq!(sig.inputs_and_output[..], expected,
155 "lang item {}", tcx.def_symbol_name(did));
159 fn lower_to<'a, 'tcx, D>(statement: &Statement<'tcx>, local_decls: &D, tcx: TyCtxt<'a, 'tcx, 'tcx>)
160 -> Option<(LangItem, RhsKind)>
161 where D: HasLocalDecls<'tcx>
163 match statement.kind {
164 StatementKind::Assign(_, Rvalue::BinaryOp(bin_op, ref lhs, _)) => {
165 let ty = lhs.ty(local_decls, tcx);
166 if let Some(is_signed) = sign_of_128bit(ty) {
167 return item_for_op(bin_op, is_signed);
170 StatementKind::Assign(_, Rvalue::CheckedBinaryOp(bin_op, ref lhs, _)) => {
171 let ty = lhs.ty(local_decls, tcx);
172 if let Some(is_signed) = sign_of_128bit(ty) {
173 return item_for_checked_op(bin_op, is_signed);
181 #[derive(Copy, Clone)]
189 fn ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Ty<'tcx>> {
191 RhsKind::Unchanged => None,
192 RhsKind::ForceU128 => Some(tcx.types.u128),
193 RhsKind::ForceU32 => Some(tcx.types.u32),
198 fn sign_of_128bit(ty: Ty) -> Option<bool> {
200 TypeVariants::TyInt(syntax::ast::IntTy::I128) => Some(true),
201 TypeVariants::TyUint(syntax::ast::UintTy::U128) => Some(false),
206 fn item_for_op(bin_op: BinOp, is_signed: bool) -> Option<(LangItem, RhsKind)> {
207 let i = match (bin_op, is_signed) {
208 (BinOp::Add, true) => (LangItem::I128AddFnLangItem, RhsKind::Unchanged),
209 (BinOp::Add, false) => (LangItem::U128AddFnLangItem, RhsKind::Unchanged),
210 (BinOp::Sub, true) => (LangItem::I128SubFnLangItem, RhsKind::Unchanged),
211 (BinOp::Sub, false) => (LangItem::U128SubFnLangItem, RhsKind::Unchanged),
212 (BinOp::Mul, true) => (LangItem::I128MulFnLangItem, RhsKind::Unchanged),
213 (BinOp::Mul, false) => (LangItem::U128MulFnLangItem, RhsKind::Unchanged),
214 (BinOp::Div, true) => (LangItem::I128DivFnLangItem, RhsKind::Unchanged),
215 (BinOp::Div, false) => (LangItem::U128DivFnLangItem, RhsKind::Unchanged),
216 (BinOp::Rem, true) => (LangItem::I128RemFnLangItem, RhsKind::Unchanged),
217 (BinOp::Rem, false) => (LangItem::U128RemFnLangItem, RhsKind::Unchanged),
218 (BinOp::Shl, true) => (LangItem::I128ShlFnLangItem, RhsKind::ForceU32),
219 (BinOp::Shl, false) => (LangItem::U128ShlFnLangItem, RhsKind::ForceU32),
220 (BinOp::Shr, true) => (LangItem::I128ShrFnLangItem, RhsKind::ForceU32),
221 (BinOp::Shr, false) => (LangItem::U128ShrFnLangItem, RhsKind::ForceU32),
227 fn item_for_checked_op(bin_op: BinOp, is_signed: bool) -> Option<(LangItem, RhsKind)> {
228 let i = match (bin_op, is_signed) {
229 (BinOp::Add, true) => (LangItem::I128AddoFnLangItem, RhsKind::Unchanged),
230 (BinOp::Add, false) => (LangItem::U128AddoFnLangItem, RhsKind::Unchanged),
231 (BinOp::Sub, true) => (LangItem::I128SuboFnLangItem, RhsKind::Unchanged),
232 (BinOp::Sub, false) => (LangItem::U128SuboFnLangItem, RhsKind::Unchanged),
233 (BinOp::Mul, true) => (LangItem::I128MuloFnLangItem, RhsKind::Unchanged),
234 (BinOp::Mul, false) => (LangItem::U128MuloFnLangItem, RhsKind::Unchanged),
235 (BinOp::Shl, true) => (LangItem::I128ShloFnLangItem, RhsKind::ForceU128),
236 (BinOp::Shl, false) => (LangItem::U128ShloFnLangItem, RhsKind::ForceU128),
237 (BinOp::Shr, true) => (LangItem::I128ShroFnLangItem, RhsKind::ForceU128),
238 (BinOp::Shr, false) => (LangItem::U128ShroFnLangItem, RhsKind::ForceU128),
239 _ => bug!("That should be all the checked ones?"),