Auto merge of #46093 - scottmcm:lower-128-mir, r=nagisa
Add a MIR pass to lower 128-bit operators to lang item calls Runs only with `-Z lower_128bit_ops` since it's not hooked into targets yet. This isn't really useful on its own, but the declarations for the lang items need to be in the compiler before compiler-builtins can be updated to define them, so this is part 1 of at least 3. cc https://github.com/rust-lang/rust/issues/45676 @est31 @nagisa
This commit is contained in:
commit
5f44c653cf
@ -310,6 +310,34 @@ language_item_table! {
|
||||
NonZeroItem, "non_zero", non_zero;
|
||||
|
||||
DebugTraitLangItem, "debug_trait", debug_trait;
|
||||
|
||||
// A lang item for each of the 128-bit operators we can optionally lower.
|
||||
I128AddFnLangItem, "i128_add", i128_add_fn;
|
||||
U128AddFnLangItem, "u128_add", u128_add_fn;
|
||||
I128SubFnLangItem, "i128_sub", i128_sub_fn;
|
||||
U128SubFnLangItem, "u128_sub", u128_sub_fn;
|
||||
I128MulFnLangItem, "i128_mul", i128_mul_fn;
|
||||
U128MulFnLangItem, "u128_mul", u128_mul_fn;
|
||||
I128DivFnLangItem, "i128_div", i128_div_fn;
|
||||
U128DivFnLangItem, "u128_div", u128_div_fn;
|
||||
I128RemFnLangItem, "i128_rem", i128_rem_fn;
|
||||
U128RemFnLangItem, "u128_rem", u128_rem_fn;
|
||||
I128ShlFnLangItem, "i128_shl", i128_shl_fn;
|
||||
U128ShlFnLangItem, "u128_shl", u128_shl_fn;
|
||||
I128ShrFnLangItem, "i128_shr", i128_shr_fn;
|
||||
U128ShrFnLangItem, "u128_shr", u128_shr_fn;
|
||||
// And overflow versions for the operators that are checkable.
|
||||
// While MIR calls these Checked*, they return (T,bool), not Option<T>.
|
||||
I128AddoFnLangItem, "i128_addo", i128_addo_fn;
|
||||
U128AddoFnLangItem, "u128_addo", u128_addo_fn;
|
||||
I128SuboFnLangItem, "i128_subo", i128_subo_fn;
|
||||
U128SuboFnLangItem, "u128_subo", u128_subo_fn;
|
||||
I128MuloFnLangItem, "i128_mulo", i128_mulo_fn;
|
||||
U128MuloFnLangItem, "u128_mulo", u128_mulo_fn;
|
||||
I128ShloFnLangItem, "i128_shlo", i128_shlo_fn;
|
||||
U128ShloFnLangItem, "u128_shlo", u128_shlo_fn;
|
||||
I128ShroFnLangItem, "i128_shro", i128_shro_fn;
|
||||
U128ShroFnLangItem, "u128_shro", u128_shro_fn;
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'gcx> TyCtxt<'a, 'tcx, 'gcx> {
|
||||
|
@ -170,6 +170,15 @@ impl<'tcx> Mir<'tcx> {
|
||||
&mut self.basic_blocks
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn basic_blocks_and_local_decls_mut(&mut self) -> (
|
||||
&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>,
|
||||
&mut LocalDecls<'tcx>,
|
||||
) {
|
||||
self.cache.invalidate();
|
||||
(&mut self.basic_blocks, &mut self.local_decls)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn predecessors(&self) -> Ref<IndexVec<BasicBlock, Vec<BasicBlock>>> {
|
||||
self.cache.predecessors(self)
|
||||
|
@ -1144,6 +1144,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||
saturating_float_casts: bool = (false, parse_bool, [TRACKED],
|
||||
"make float->int casts UB-free: numbers outside the integer type's range are clipped to \
|
||||
the max/min integer respectively, and NaN is mapped to 0"),
|
||||
lower_128bit_ops: bool = (false, parse_bool, [TRACKED],
|
||||
"rewrite operators on i128 and u128 into lang item calls (typically provided \
|
||||
by compiler-builtins) so translation doesn't need to support them"),
|
||||
}
|
||||
|
||||
pub fn default_lib_output() -> CrateType {
|
||||
|
240
src/librustc_mir/transform/lower_128bit.rs
Normal file
240
src/librustc_mir/transform/lower_128bit.rs
Normal file
@ -0,0 +1,240 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Replaces 128-bit operators with lang item calls
|
||||
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::middle::lang_items::LangItem;
|
||||
use rustc::mir::*;
|
||||
use rustc::ty::{Slice, Ty, TyCtxt, TypeVariants};
|
||||
use rustc_data_structures::indexed_vec::{Idx};
|
||||
use transform::{MirPass, MirSource};
|
||||
use syntax;
|
||||
|
||||
pub struct Lower128Bit;
|
||||
|
||||
impl MirPass for Lower128Bit {
|
||||
fn run_pass<'a, 'tcx>(&self,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
_src: MirSource,
|
||||
mir: &mut Mir<'tcx>) {
|
||||
if !tcx.sess.opts.debugging_opts.lower_128bit_ops {
|
||||
return
|
||||
}
|
||||
|
||||
self.lower_128bit_ops(tcx, mir);
|
||||
}
|
||||
}
|
||||
|
||||
impl Lower128Bit {
|
||||
fn lower_128bit_ops<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &mut Mir<'tcx>) {
|
||||
let mut new_blocks = Vec::new();
|
||||
let cur_len = mir.basic_blocks().len();
|
||||
|
||||
let (basic_blocks, local_decls) = mir.basic_blocks_and_local_decls_mut();
|
||||
for block in basic_blocks.iter_mut() {
|
||||
for i in (0..block.statements.len()).rev() {
|
||||
let (lang_item, rhs_kind) =
|
||||
if let Some((lang_item, rhs_kind)) =
|
||||
lower_to(&block.statements[i], local_decls, tcx)
|
||||
{
|
||||
(lang_item, rhs_kind)
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let rhs_override_ty = rhs_kind.ty(tcx);
|
||||
let cast_local =
|
||||
match rhs_override_ty {
|
||||
None => None,
|
||||
Some(ty) => {
|
||||
let local_decl = LocalDecl::new_internal(
|
||||
ty, block.statements[i].source_info.span);
|
||||
Some(local_decls.push(local_decl))
|
||||
},
|
||||
};
|
||||
|
||||
let storage_dead = cast_local.map(|local| {
|
||||
Statement {
|
||||
source_info: block.statements[i].source_info,
|
||||
kind: StatementKind::StorageDead(local),
|
||||
}
|
||||
});
|
||||
let after_call = BasicBlockData {
|
||||
statements: storage_dead.into_iter()
|
||||
.chain(block.statements.drain((i+1)..)).collect(),
|
||||
is_cleanup: block.is_cleanup,
|
||||
terminator: block.terminator.take(),
|
||||
};
|
||||
|
||||
let bin_statement = block.statements.pop().unwrap();
|
||||
let (source_info, lvalue, lhs, mut rhs) = match bin_statement {
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Assign(
|
||||
lvalue,
|
||||
Rvalue::BinaryOp(_, lhs, rhs))
|
||||
} => (source_info, lvalue, lhs, rhs),
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Assign(
|
||||
lvalue,
|
||||
Rvalue::CheckedBinaryOp(_, lhs, rhs))
|
||||
} => (source_info, lvalue, lhs, rhs),
|
||||
_ => bug!("Statement doesn't match pattern any more?"),
|
||||
};
|
||||
|
||||
if let Some(local) = cast_local {
|
||||
block.statements.push(Statement {
|
||||
source_info: source_info,
|
||||
kind: StatementKind::StorageLive(local),
|
||||
});
|
||||
block.statements.push(Statement {
|
||||
source_info: source_info,
|
||||
kind: StatementKind::Assign(
|
||||
Lvalue::Local(local),
|
||||
Rvalue::Cast(
|
||||
CastKind::Misc,
|
||||
rhs,
|
||||
rhs_override_ty.unwrap())),
|
||||
});
|
||||
rhs = Operand::Consume(Lvalue::Local(local));
|
||||
}
|
||||
|
||||
let call_did = check_lang_item_type(
|
||||
lang_item, &lvalue, &lhs, &rhs, local_decls, tcx);
|
||||
|
||||
let bb = BasicBlock::new(cur_len + new_blocks.len());
|
||||
new_blocks.push(after_call);
|
||||
|
||||
block.terminator =
|
||||
Some(Terminator {
|
||||
source_info,
|
||||
kind: TerminatorKind::Call {
|
||||
func: Operand::function_handle(tcx, call_did,
|
||||
Slice::empty(), source_info.span),
|
||||
args: vec![lhs, rhs],
|
||||
destination: Some((lvalue, bb)),
|
||||
cleanup: None,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
basic_blocks.extend(new_blocks);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_lang_item_type<'a, 'tcx, D>(
|
||||
lang_item: LangItem,
|
||||
lvalue: &Lvalue<'tcx>,
|
||||
lhs: &Operand<'tcx>,
|
||||
rhs: &Operand<'tcx>,
|
||||
local_decls: &D,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>)
|
||||
-> DefId
|
||||
where D: HasLocalDecls<'tcx>
|
||||
{
|
||||
let did = tcx.require_lang_item(lang_item);
|
||||
let poly_sig = tcx.fn_sig(did);
|
||||
let sig = tcx.no_late_bound_regions(&poly_sig).unwrap();
|
||||
let lhs_ty = lhs.ty(local_decls, tcx);
|
||||
let rhs_ty = rhs.ty(local_decls, tcx);
|
||||
let lvalue_ty = lvalue.ty(local_decls, tcx).to_ty(tcx);
|
||||
let expected = [lhs_ty, rhs_ty, lvalue_ty];
|
||||
assert_eq!(sig.inputs_and_output[..], expected,
|
||||
"lang item {}", tcx.def_symbol_name(did));
|
||||
did
|
||||
}
|
||||
|
||||
fn lower_to<'a, 'tcx, D>(statement: &Statement<'tcx>, local_decls: &D, tcx: TyCtxt<'a, 'tcx, 'tcx>)
|
||||
-> Option<(LangItem, RhsKind)>
|
||||
where D: HasLocalDecls<'tcx>
|
||||
{
|
||||
match statement.kind {
|
||||
StatementKind::Assign(_, Rvalue::BinaryOp(bin_op, ref lhs, _)) => {
|
||||
let ty = lhs.ty(local_decls, tcx);
|
||||
if let Some(is_signed) = sign_of_128bit(ty) {
|
||||
return item_for_op(bin_op, is_signed);
|
||||
}
|
||||
},
|
||||
StatementKind::Assign(_, Rvalue::CheckedBinaryOp(bin_op, ref lhs, _)) => {
|
||||
let ty = lhs.ty(local_decls, tcx);
|
||||
if let Some(is_signed) = sign_of_128bit(ty) {
|
||||
return item_for_checked_op(bin_op, is_signed);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum RhsKind {
|
||||
Unchanged,
|
||||
ForceU128,
|
||||
ForceU32,
|
||||
}
|
||||
|
||||
impl RhsKind {
|
||||
fn ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Ty<'tcx>> {
|
||||
match *self {
|
||||
RhsKind::Unchanged => None,
|
||||
RhsKind::ForceU128 => Some(tcx.types.u128),
|
||||
RhsKind::ForceU32 => Some(tcx.types.u32),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sign_of_128bit(ty: Ty) -> Option<bool> {
|
||||
match ty.sty {
|
||||
TypeVariants::TyInt(syntax::ast::IntTy::I128) => Some(true),
|
||||
TypeVariants::TyUint(syntax::ast::UintTy::U128) => Some(false),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn item_for_op(bin_op: BinOp, is_signed: bool) -> Option<(LangItem, RhsKind)> {
|
||||
let i = match (bin_op, is_signed) {
|
||||
(BinOp::Add, true) => (LangItem::I128AddFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Add, false) => (LangItem::U128AddFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Sub, true) => (LangItem::I128SubFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Sub, false) => (LangItem::U128SubFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Mul, true) => (LangItem::I128MulFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Mul, false) => (LangItem::U128MulFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Div, true) => (LangItem::I128DivFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Div, false) => (LangItem::U128DivFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Rem, true) => (LangItem::I128RemFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Rem, false) => (LangItem::U128RemFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Shl, true) => (LangItem::I128ShlFnLangItem, RhsKind::ForceU32),
|
||||
(BinOp::Shl, false) => (LangItem::U128ShlFnLangItem, RhsKind::ForceU32),
|
||||
(BinOp::Shr, true) => (LangItem::I128ShrFnLangItem, RhsKind::ForceU32),
|
||||
(BinOp::Shr, false) => (LangItem::U128ShrFnLangItem, RhsKind::ForceU32),
|
||||
_ => return None,
|
||||
};
|
||||
Some(i)
|
||||
}
|
||||
|
||||
fn item_for_checked_op(bin_op: BinOp, is_signed: bool) -> Option<(LangItem, RhsKind)> {
|
||||
let i = match (bin_op, is_signed) {
|
||||
(BinOp::Add, true) => (LangItem::I128AddoFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Add, false) => (LangItem::U128AddoFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Sub, true) => (LangItem::I128SuboFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Sub, false) => (LangItem::U128SuboFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Mul, true) => (LangItem::I128MuloFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Mul, false) => (LangItem::U128MuloFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Shl, true) => (LangItem::I128ShloFnLangItem, RhsKind::ForceU128),
|
||||
(BinOp::Shl, false) => (LangItem::U128ShloFnLangItem, RhsKind::ForceU128),
|
||||
(BinOp::Shr, true) => (LangItem::I128ShroFnLangItem, RhsKind::ForceU128),
|
||||
(BinOp::Shr, false) => (LangItem::U128ShroFnLangItem, RhsKind::ForceU128),
|
||||
_ => bug!("That should be all the checked ones?"),
|
||||
};
|
||||
Some(i)
|
||||
}
|
@ -42,6 +42,7 @@ pub mod copy_prop;
|
||||
pub mod generator;
|
||||
pub mod inline;
|
||||
pub mod nll;
|
||||
pub mod lower_128bit;
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
self::qualify_consts::provide(providers);
|
||||
@ -241,6 +242,8 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
|
||||
// From here on out, regions are gone.
|
||||
erase_regions::EraseRegions,
|
||||
|
||||
lower_128bit::Lower128Bit,
|
||||
|
||||
// Optimizations begin.
|
||||
inline::Inline,
|
||||
instcombine::InstCombine,
|
||||
|
145
src/test/mir-opt/lower_128bit_debug_test.rs
Normal file
145
src/test/mir-opt/lower_128bit_debug_test.rs
Normal file
@ -0,0 +1,145 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// compile-flags: -Z lower_128bit_ops -C debug_assertions=yes
|
||||
|
||||
#![feature(i128_type)]
|
||||
#![feature(lang_items)]
|
||||
|
||||
#[lang="i128_div"]
|
||||
fn i128_div(_x: i128, _y: i128) -> i128 { 3 }
|
||||
#[lang="u128_div"]
|
||||
fn u128_div(_x: u128, _y: u128) -> u128 { 4 }
|
||||
#[lang="i128_rem"]
|
||||
fn i128_rem(_x: i128, _y: i128) -> i128 { 5 }
|
||||
#[lang="u128_rem"]
|
||||
fn u128_rem(_x: u128, _y: u128) -> u128 { 6 }
|
||||
|
||||
#[lang="i128_addo"]
|
||||
fn i128_addo(_x: i128, _y: i128) -> (i128, bool) { (0, false) }
|
||||
#[lang="u128_addo"]
|
||||
fn u128_addo(_x: u128, _y: u128) -> (u128, bool) { (1, false) }
|
||||
#[lang="i128_subo"]
|
||||
fn i128_subo(_x: i128, _y: i128) -> (i128, bool) { (2, false) }
|
||||
#[lang="u128_subo"]
|
||||
fn u128_subo(_x: u128, _y: u128) -> (u128, bool) { (3, false) }
|
||||
#[lang="i128_mulo"]
|
||||
fn i128_mulo(_x: i128, _y: i128) -> (i128, bool) { (4, false) }
|
||||
#[lang="u128_mulo"]
|
||||
fn u128_mulo(_x: u128, _y: u128) -> (u128, bool) { (5, false) }
|
||||
#[lang="i128_shlo"]
|
||||
fn i128_shlo(_x: i128, _y: u128) -> (i128, bool) { (6, false) }
|
||||
#[lang="u128_shlo"]
|
||||
fn u128_shlo(_x: u128, _y: u128) -> (u128, bool) { (6, false) }
|
||||
#[lang="i128_shro"]
|
||||
fn i128_shro(_x: i128, _y: u128) -> (i128, bool) { (7, false) }
|
||||
#[lang="u128_shro"]
|
||||
fn u128_shro(_x: u128, _y: u128) -> (u128, bool) { (8, false) }
|
||||
|
||||
fn test_signed(mut x: i128) -> i128 {
|
||||
x += 1;
|
||||
x -= 2;
|
||||
x *= 3;
|
||||
x /= 4;
|
||||
x %= 5;
|
||||
x <<= 6;
|
||||
x >>= 7;
|
||||
x
|
||||
}
|
||||
|
||||
fn test_unsigned(mut x: u128) -> u128 {
|
||||
x += 1;
|
||||
x -= 2;
|
||||
x *= 3;
|
||||
x /= 4;
|
||||
x %= 5;
|
||||
x <<= 6;
|
||||
x >>= 7;
|
||||
x
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test_signed(-200);
|
||||
test_unsigned(200);
|
||||
}
|
||||
|
||||
// END RUST SOURCE
|
||||
|
||||
// START rustc.test_signed.Lower128Bit.after.mir
|
||||
// _2 = const i128_addo(_1, const 1i128) -> bb10;
|
||||
// ...
|
||||
// _1 = (_2.0: i128);
|
||||
// _3 = const i128_subo(_1, const 2i128) -> bb11;
|
||||
// ...
|
||||
// _1 = (_3.0: i128);
|
||||
// _4 = const i128_mulo(_1, const 3i128) -> bb12;
|
||||
// ...
|
||||
// _1 = (_4.0: i128);
|
||||
// ...
|
||||
// _1 = const i128_div(_1, const 4i128) -> bb13;
|
||||
// ...
|
||||
// _1 = const i128_rem(_1, const 5i128) -> bb15;
|
||||
// ...
|
||||
// _1 = (_13.0: i128);
|
||||
// ...
|
||||
// _17 = const 7i32 as u128 (Misc);
|
||||
// _14 = const i128_shro(_1, _17) -> bb16;
|
||||
// ...
|
||||
// _1 = (_14.0: i128);
|
||||
// ...
|
||||
// assert(!(_2.1: bool), "attempt to add with overflow") -> bb1;
|
||||
// ...
|
||||
// assert(!(_3.1: bool), "attempt to subtract with overflow") -> bb2;
|
||||
// ...
|
||||
// assert(!(_4.1: bool), "attempt to multiply with overflow") -> bb3;
|
||||
// ...
|
||||
// assert(!(_13.1: bool), "attempt to shift left with overflow") -> bb8;
|
||||
// ...
|
||||
// _16 = const 6i32 as u128 (Misc);
|
||||
// _13 = const i128_shlo(_1, _16) -> bb14;
|
||||
// ...
|
||||
// assert(!(_14.1: bool), "attempt to shift right with overflow") -> bb9;
|
||||
// END rustc.test_signed.Lower128Bit.after.mir
|
||||
|
||||
// START rustc.test_unsigned.Lower128Bit.after.mir
|
||||
// _2 = const u128_addo(_1, const 1u128) -> bb8;
|
||||
// ...
|
||||
// _1 = (_2.0: u128);
|
||||
// _3 = const u128_subo(_1, const 2u128) -> bb9;
|
||||
// ...
|
||||
// _1 = (_3.0: u128);
|
||||
// _4 = const u128_mulo(_1, const 3u128) -> bb10;
|
||||
// ...
|
||||
// _1 = (_4.0: u128);
|
||||
// ...
|
||||
// _1 = const u128_div(_1, const 4u128) -> bb11;
|
||||
// ...
|
||||
// _1 = const u128_rem(_1, const 5u128) -> bb13;
|
||||
// ...
|
||||
// _1 = (_7.0: u128);
|
||||
// ...
|
||||
// _11 = const 7i32 as u128 (Misc);
|
||||
// _8 = const u128_shro(_1, _11) -> bb14;
|
||||
// ...
|
||||
// _1 = (_8.0: u128);
|
||||
// ...
|
||||
// assert(!(_2.1: bool), "attempt to add with overflow") -> bb1;
|
||||
// ...
|
||||
// assert(!(_3.1: bool), "attempt to subtract with overflow") -> bb2;
|
||||
// ...
|
||||
// assert(!(_4.1: bool), "attempt to multiply with overflow") -> bb3;
|
||||
// ...
|
||||
// assert(!(_7.1: bool), "attempt to shift left with overflow") -> bb6;
|
||||
// ...
|
||||
// _10 = const 6i32 as u128 (Misc);
|
||||
// _7 = const u128_shlo(_1, _10) -> bb12;
|
||||
// ...
|
||||
// assert(!(_8.1: bool), "attempt to shift right with overflow") -> bb7;
|
||||
// END rustc.test_unsigned.Lower128Bit.after.mir
|
108
src/test/mir-opt/lower_128bit_test.rs
Normal file
108
src/test/mir-opt/lower_128bit_test.rs
Normal file
@ -0,0 +1,108 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// compile-flags: -Z lower_128bit_ops -C debug_assertions=no
|
||||
|
||||
#![feature(i128_type)]
|
||||
#![feature(lang_items)]
|
||||
|
||||
#[lang="i128_add"]
|
||||
fn i128_add(_x: i128, _y: i128) -> i128 { 0 }
|
||||
#[lang="u128_add"]
|
||||
fn u128_add(_x: u128, _y: u128) -> u128 { 0 }
|
||||
#[lang="i128_sub"]
|
||||
fn i128_sub(_x: i128, _y: i128) -> i128 { 1 }
|
||||
#[lang="u128_sub"]
|
||||
fn u128_sub(_x: u128, _y: u128) -> u128 { 1 }
|
||||
#[lang="i128_mul"]
|
||||
fn i128_mul(_x: i128, _y: i128) -> i128 { 2 }
|
||||
#[lang="u128_mul"]
|
||||
fn u128_mul(_x: u128, _y: u128) -> u128 { 2 }
|
||||
#[lang="i128_div"]
|
||||
fn i128_div(_x: i128, _y: i128) -> i128 { 3 }
|
||||
#[lang="u128_div"]
|
||||
fn u128_div(_x: u128, _y: u128) -> u128 { 4 }
|
||||
#[lang="i128_rem"]
|
||||
fn i128_rem(_x: i128, _y: i128) -> i128 { 5 }
|
||||
#[lang="u128_rem"]
|
||||
fn u128_rem(_x: u128, _y: u128) -> u128 { 6 }
|
||||
#[lang="i128_shl"]
|
||||
fn i128_shl(_x: i128, _y: u32) -> i128 { 7 }
|
||||
#[lang="u128_shl"]
|
||||
fn u128_shl(_x: u128, _y: u32) -> u128 { 7 }
|
||||
#[lang="i128_shr"]
|
||||
fn i128_shr(_x: i128, _y: u32) -> i128 { 8 }
|
||||
#[lang="u128_shr"]
|
||||
fn u128_shr(_x: u128, _y: u32) -> u128 { 9 }
|
||||
|
||||
fn test_signed(mut x: i128) -> i128 {
|
||||
x += 1;
|
||||
x -= 2;
|
||||
x *= 3;
|
||||
x /= 4;
|
||||
x %= 5;
|
||||
x <<= 6;
|
||||
x >>= 7;
|
||||
x
|
||||
}
|
||||
|
||||
fn test_unsigned(mut x: u128) -> u128 {
|
||||
x += 1;
|
||||
x -= 2;
|
||||
x *= 3;
|
||||
x /= 4;
|
||||
x %= 5;
|
||||
x <<= 6;
|
||||
x >>= 7;
|
||||
x
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test_signed(-200);
|
||||
test_unsigned(200);
|
||||
}
|
||||
|
||||
// END RUST SOURCE
|
||||
|
||||
// START rustc.test_signed.Lower128Bit.after.mir
|
||||
// _1 = const i128_add(_1, const 1i128) -> bb7;
|
||||
// ...
|
||||
// _1 = const i128_div(_1, const 4i128) -> bb8;
|
||||
// ...
|
||||
// _1 = const i128_rem(_1, const 5i128) -> bb11;
|
||||
// ...
|
||||
// _1 = const i128_mul(_1, const 3i128) -> bb5;
|
||||
// ...
|
||||
// _1 = const i128_sub(_1, const 2i128) -> bb6;
|
||||
// ...
|
||||
// _11 = const 7i32 as u32 (Misc);
|
||||
// _1 = const i128_shr(_1, _11) -> bb9;
|
||||
// ...
|
||||
// _12 = const 6i32 as u32 (Misc);
|
||||
// _1 = const i128_shl(_1, _12) -> bb10;
|
||||
// END rustc.test_signed.Lower128Bit.after.mir
|
||||
|
||||
// START rustc.test_unsigned.Lower128Bit.after.mir
|
||||
// _1 = const u128_add(_1, const 1u128) -> bb5;
|
||||
// ...
|
||||
// _1 = const u128_div(_1, const 4u128) -> bb6;
|
||||
// ...
|
||||
// _1 = const u128_rem(_1, const 5u128) -> bb9;
|
||||
// ...
|
||||
// _1 = const u128_mul(_1, const 3u128) -> bb3;
|
||||
// ...
|
||||
// _1 = const u128_sub(_1, const 2u128) -> bb4;
|
||||
// ...
|
||||
// _5 = const 7i32 as u32 (Misc);
|
||||
// _1 = const u128_shr(_1, _5) -> bb7;
|
||||
// ...
|
||||
// _6 = const 6i32 as u32 (Misc);
|
||||
// _1 = const u128_shl(_1, _6) -> bb8;
|
||||
// END rustc.test_unsigned.Lower128Bit.after.mir
|
Loading…
x
Reference in New Issue
Block a user