1 //! Replaces 128-bit operators with lang item calls
3 use rustc::hir::def_id::DefId;
4 use rustc::middle::lang_items::LangItem;
6 use rustc::ty::{List, Ty, TyCtxt, TyKind};
7 use rustc_data_structures::indexed_vec::{Idx};
8 use crate::transform::{MirPass, MirSource};
10 pub struct Lower128Bit;
12 impl MirPass for Lower128Bit {
13 fn run_pass<'a, 'tcx>(&self,
14 tcx: TyCtxt<'a, 'tcx, 'tcx>,
15 _src: MirSource<'tcx>,
16 mir: &mut Mir<'tcx>) {
17 let debugging_override = tcx.sess.opts.debugging_opts.lower_128bit_ops;
18 let target_default = tcx.sess.host.options.i128_lowering;
19 if !debugging_override.unwrap_or(target_default) {
23 self.lower_128bit_ops(tcx, mir);
28 fn lower_128bit_ops<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &mut Mir<'tcx>) {
29 let mut new_blocks = Vec::new();
30 let cur_len = mir.basic_blocks().len();
32 let (basic_blocks, local_decls) = mir.basic_blocks_and_local_decls_mut();
33 for block in basic_blocks.iter_mut() {
34 for i in (0..block.statements.len()).rev() {
35 let (lang_item, rhs_kind) =
36 if let Some((lang_item, rhs_kind)) =
37 lower_to(&block.statements[i], local_decls, tcx)
44 let rhs_override_ty = rhs_kind.ty(tcx);
46 match rhs_override_ty {
49 let local_decl = LocalDecl::new_internal(
50 ty, block.statements[i].source_info.span);
51 Some(local_decls.push(local_decl))
55 let storage_dead = cast_local.map(|local| {
57 source_info: block.statements[i].source_info,
58 kind: StatementKind::StorageDead(local),
61 let after_call = BasicBlockData {
62 statements: storage_dead.into_iter()
63 .chain(block.statements.drain((i+1)..)).collect(),
64 is_cleanup: block.is_cleanup,
65 terminator: block.terminator.take(),
68 let bin_statement = block.statements.pop().unwrap();
69 let source_info = bin_statement.source_info;
70 let (place, lhs, mut rhs) = match bin_statement.kind {
71 StatementKind::Assign(place, box rvalue) => {
73 Rvalue::BinaryOp(_, lhs, rhs)
74 | Rvalue::CheckedBinaryOp(_, lhs, rhs) => (place, lhs, rhs),
81 if let Some(local) = cast_local {
82 block.statements.push(Statement {
83 source_info: source_info,
84 kind: StatementKind::StorageLive(local),
86 block.statements.push(Statement {
87 source_info: source_info,
88 kind: StatementKind::Assign(
89 Place::Base(PlaceBase::Local(local)),
93 rhs_override_ty.unwrap())),
95 rhs = Operand::Move(Place::Base(PlaceBase::Local(local)));
98 let call_did = check_lang_item_type(
99 lang_item, &place, &lhs, &rhs, local_decls, tcx);
101 let bb = BasicBlock::new(cur_len + new_blocks.len());
102 new_blocks.push(after_call);
107 kind: TerminatorKind::Call {
108 func: Operand::function_handle(tcx, call_did,
109 List::empty(), source_info.span),
110 args: vec![lhs, rhs],
111 destination: Some((place, bb)),
113 from_hir_call: false,
119 basic_blocks.extend(new_blocks);
123 fn check_lang_item_type<'a, 'tcx, D>(
129 tcx: TyCtxt<'a, 'tcx, 'tcx>)
131 where D: HasLocalDecls<'tcx>
133 let did = tcx.require_lang_item(lang_item);
134 let poly_sig = tcx.fn_sig(did);
135 let sig = poly_sig.no_bound_vars().unwrap();
136 let lhs_ty = lhs.ty(local_decls, tcx);
137 let rhs_ty = rhs.ty(local_decls, tcx);
138 let place_ty = place.ty(local_decls, tcx).to_ty(tcx);
139 let expected = [lhs_ty, rhs_ty, place_ty];
140 assert_eq!(sig.inputs_and_output[..], expected,
141 "lang item `{}`", tcx.def_path_str(did));
145 fn lower_to<'a, 'tcx, D>(statement: &Statement<'tcx>, local_decls: &D, tcx: TyCtxt<'a, 'tcx, 'tcx>)
146 -> Option<(LangItem, RhsKind)>
147 where D: HasLocalDecls<'tcx>
149 match statement.kind {
150 StatementKind::Assign(_, box Rvalue::BinaryOp(bin_op, ref lhs, _)) => {
151 let ty = lhs.ty(local_decls, tcx);
152 if let Some(is_signed) = sign_of_128bit(ty) {
153 return item_for_op(bin_op, is_signed);
156 StatementKind::Assign(_, box Rvalue::CheckedBinaryOp(bin_op, ref lhs, _)) => {
157 let ty = lhs.ty(local_decls, tcx);
158 if let Some(is_signed) = sign_of_128bit(ty) {
159 return item_for_checked_op(bin_op, is_signed);
167 #[derive(Copy, Clone)]
175 fn ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Ty<'tcx>> {
177 RhsKind::Unchanged => None,
178 RhsKind::ForceU128 => Some(tcx.types.u128),
179 RhsKind::ForceU32 => Some(tcx.types.u32),
184 fn sign_of_128bit(ty: Ty<'_>) -> Option<bool> {
186 TyKind::Int(syntax::ast::IntTy::I128) => Some(true),
187 TyKind::Uint(syntax::ast::UintTy::U128) => Some(false),
192 fn item_for_op(bin_op: BinOp, is_signed: bool) -> Option<(LangItem, RhsKind)> {
193 let i = match (bin_op, is_signed) {
194 (BinOp::Add, true) => (LangItem::I128AddFnLangItem, RhsKind::Unchanged),
195 (BinOp::Add, false) => (LangItem::U128AddFnLangItem, RhsKind::Unchanged),
196 (BinOp::Sub, true) => (LangItem::I128SubFnLangItem, RhsKind::Unchanged),
197 (BinOp::Sub, false) => (LangItem::U128SubFnLangItem, RhsKind::Unchanged),
198 (BinOp::Mul, true) => (LangItem::I128MulFnLangItem, RhsKind::Unchanged),
199 (BinOp::Mul, false) => (LangItem::U128MulFnLangItem, RhsKind::Unchanged),
200 (BinOp::Div, true) => (LangItem::I128DivFnLangItem, RhsKind::Unchanged),
201 (BinOp::Div, false) => (LangItem::U128DivFnLangItem, RhsKind::Unchanged),
202 (BinOp::Rem, true) => (LangItem::I128RemFnLangItem, RhsKind::Unchanged),
203 (BinOp::Rem, false) => (LangItem::U128RemFnLangItem, RhsKind::Unchanged),
204 (BinOp::Shl, true) => (LangItem::I128ShlFnLangItem, RhsKind::ForceU32),
205 (BinOp::Shl, false) => (LangItem::U128ShlFnLangItem, RhsKind::ForceU32),
206 (BinOp::Shr, true) => (LangItem::I128ShrFnLangItem, RhsKind::ForceU32),
207 (BinOp::Shr, false) => (LangItem::U128ShrFnLangItem, RhsKind::ForceU32),
213 fn item_for_checked_op(bin_op: BinOp, is_signed: bool) -> Option<(LangItem, RhsKind)> {
214 let i = match (bin_op, is_signed) {
215 (BinOp::Add, true) => (LangItem::I128AddoFnLangItem, RhsKind::Unchanged),
216 (BinOp::Add, false) => (LangItem::U128AddoFnLangItem, RhsKind::Unchanged),
217 (BinOp::Sub, true) => (LangItem::I128SuboFnLangItem, RhsKind::Unchanged),
218 (BinOp::Sub, false) => (LangItem::U128SuboFnLangItem, RhsKind::Unchanged),
219 (BinOp::Mul, true) => (LangItem::I128MuloFnLangItem, RhsKind::Unchanged),
220 (BinOp::Mul, false) => (LangItem::U128MuloFnLangItem, RhsKind::Unchanged),
221 (BinOp::Shl, true) => (LangItem::I128ShloFnLangItem, RhsKind::ForceU128),
222 (BinOp::Shl, false) => (LangItem::U128ShloFnLangItem, RhsKind::ForceU128),
223 (BinOp::Shr, true) => (LangItem::I128ShroFnLangItem, RhsKind::ForceU128),
224 (BinOp::Shr, false) => (LangItem::U128ShroFnLangItem, RhsKind::ForceU128),
225 _ => bug!("That should be all the checked ones?"),