Handle shifts properly
* The overflow-checking shift items need to take a full 128-bit type, since they need to be able to detect idiocy like `1i128 << (1u128 << 127)` * The unchecked ones just take u32, like the `*_sh?` methods in core * Because shift-by-anything is allowed, cast into a new local for every shift
This commit is contained in:
parent
6a5a086fd6
commit
42208c1227
@ -41,21 +41,41 @@ impl Lower128Bit {
|
||||
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 =
|
||||
if let Some(lang_item) = lower_to(&block.statements[i], local_decls, tcx) {
|
||||
lang_item
|
||||
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: block.statements.drain((i+1)..).collect(),
|
||||
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, rhs) = match bin_statement {
|
||||
let (source_info, lvalue, lhs, mut rhs) = match bin_statement {
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Assign(
|
||||
@ -71,6 +91,23 @@ impl Lower128Bit {
|
||||
_ => 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);
|
||||
|
||||
@ -118,7 +155,7 @@ fn check_lang_item_type<'a, 'tcx, D>(
|
||||
}
|
||||
|
||||
fn lower_to<'a, 'tcx, D>(statement: &Statement<'tcx>, local_decls: &D, tcx: TyCtxt<'a, 'tcx, 'tcx>)
|
||||
-> Option<LangItem>
|
||||
-> Option<(LangItem, RhsKind)>
|
||||
where D: HasLocalDecls<'tcx>
|
||||
{
|
||||
match statement.kind {
|
||||
@ -139,6 +176,23 @@ fn lower_to<'a, 'tcx, D>(statement: &Statement<'tcx>, local_decls: &D, tcx: TyCt
|
||||
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),
|
||||
@ -147,39 +201,39 @@ fn sign_of_128bit(ty: Ty) -> Option<bool> {
|
||||
}
|
||||
}
|
||||
|
||||
fn item_for_op(bin_op: BinOp, is_signed: bool) -> Option<LangItem> {
|
||||
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,
|
||||
(BinOp::Add, false) => LangItem::U128AddFnLangItem,
|
||||
(BinOp::Sub, true) => LangItem::I128SubFnLangItem,
|
||||
(BinOp::Sub, false) => LangItem::U128SubFnLangItem,
|
||||
(BinOp::Mul, true) => LangItem::I128MulFnLangItem,
|
||||
(BinOp::Mul, false) => LangItem::U128MulFnLangItem,
|
||||
(BinOp::Div, true) => LangItem::I128DivFnLangItem,
|
||||
(BinOp::Div, false) => LangItem::U128DivFnLangItem,
|
||||
(BinOp::Rem, true) => LangItem::I128RemFnLangItem,
|
||||
(BinOp::Rem, false) => LangItem::U128RemFnLangItem,
|
||||
(BinOp::Shl, true) => LangItem::I128ShlFnLangItem,
|
||||
(BinOp::Shl, false) => LangItem::U128ShlFnLangItem,
|
||||
(BinOp::Shr, true) => LangItem::I128ShrFnLangItem,
|
||||
(BinOp::Shr, false) => LangItem::U128ShrFnLangItem,
|
||||
(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> {
|
||||
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,
|
||||
(BinOp::Add, false) => LangItem::U128AddoFnLangItem,
|
||||
(BinOp::Sub, true) => LangItem::I128SuboFnLangItem,
|
||||
(BinOp::Sub, false) => LangItem::U128SuboFnLangItem,
|
||||
(BinOp::Mul, true) => LangItem::I128MuloFnLangItem,
|
||||
(BinOp::Mul, false) => LangItem::U128MuloFnLangItem,
|
||||
(BinOp::Shl, true) => LangItem::I128ShloFnLangItem,
|
||||
(BinOp::Shl, false) => LangItem::U128ShloFnLangItem,
|
||||
(BinOp::Shr, true) => LangItem::I128ShroFnLangItem,
|
||||
(BinOp::Shr, false) => LangItem::U128ShroFnLangItem,
|
||||
(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)
|
||||
|
@ -35,13 +35,13 @@ 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: i32) -> (i128, bool) { (6, false) }
|
||||
fn i128_shlo(_x: i128, _y: u128) -> (i128, bool) { (6, false) }
|
||||
#[lang="u128_shlo"]
|
||||
fn u128_shlo(_x: u128, _y: i32) -> (u128, bool) { (6, false) }
|
||||
fn u128_shlo(_x: u128, _y: u128) -> (u128, bool) { (6, false) }
|
||||
#[lang="i128_shro"]
|
||||
fn i128_shro(_x: i128, _y: i32) -> (i128, bool) { (7, false) }
|
||||
fn i128_shro(_x: i128, _y: u128) -> (i128, bool) { (7, false) }
|
||||
#[lang="u128_shro"]
|
||||
fn u128_shro(_x: u128, _y: i32) -> (u128, bool) { (8, false) }
|
||||
fn u128_shro(_x: u128, _y: u128) -> (u128, bool) { (8, false) }
|
||||
|
||||
fn test_signed(mut x: i128) -> i128 {
|
||||
x += 1;
|
||||
@ -88,7 +88,9 @@ fn main() {
|
||||
// _1 = const i128_rem(_1, const 5i128) -> bb15;
|
||||
// ...
|
||||
// _1 = (_13.0: i128);
|
||||
// _14 = const i128_shro(_1, const 7i32) -> bb16;
|
||||
// ...
|
||||
// _17 = const 7i32 as u128 (Misc);
|
||||
// _14 = const i128_shro(_1, _17) -> bb16;
|
||||
// ...
|
||||
// _1 = (_14.0: i128);
|
||||
// ...
|
||||
@ -100,7 +102,8 @@ fn main() {
|
||||
// ...
|
||||
// assert(!(_13.1: bool), "attempt to shift left with overflow") -> bb8;
|
||||
// ...
|
||||
// _13 = const i128_shlo(_1, const 6i32) -> bb14;
|
||||
// _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
|
||||
@ -121,7 +124,9 @@ fn main() {
|
||||
// _1 = const u128_rem(_1, const 5u128) -> bb13;
|
||||
// ...
|
||||
// _1 = (_7.0: u128);
|
||||
// _8 = const u128_shro(_1, const 7i32) -> bb14;
|
||||
// ...
|
||||
// _11 = const 7i32 as u128 (Misc);
|
||||
// _8 = const u128_shro(_1, _11) -> bb14;
|
||||
// ...
|
||||
// _1 = (_8.0: u128);
|
||||
// ...
|
||||
@ -133,7 +138,8 @@ fn main() {
|
||||
// ...
|
||||
// assert(!(_7.1: bool), "attempt to shift left with overflow") -> bb6;
|
||||
// ...
|
||||
// _7 = const u128_shlo(_1, const 6i32) -> bb12;
|
||||
// _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
|
||||
|
@ -34,13 +34,13 @@ 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: i32) -> i128 { 7 }
|
||||
fn i128_shl(_x: i128, _y: u32) -> i128 { 7 }
|
||||
#[lang="u128_shl"]
|
||||
fn u128_shl(_x: u128, _y: i32) -> u128 { 7 }
|
||||
fn u128_shl(_x: u128, _y: u32) -> u128 { 7 }
|
||||
#[lang="i128_shr"]
|
||||
fn i128_shr(_x: i128, _y: i32) -> i128 { 8 }
|
||||
fn i128_shr(_x: i128, _y: u32) -> i128 { 8 }
|
||||
#[lang="u128_shr"]
|
||||
fn u128_shr(_x: u128, _y: i32) -> u128 { 9 }
|
||||
fn u128_shr(_x: u128, _y: u32) -> u128 { 9 }
|
||||
|
||||
fn test_signed(mut x: i128) -> i128 {
|
||||
x += 1;
|
||||
@ -82,9 +82,11 @@ fn main() {
|
||||
// ...
|
||||
// _1 = const i128_sub(_1, const 2i128) -> bb6;
|
||||
// ...
|
||||
// _1 = const i128_shr(_1, const 7i32) -> bb9;
|
||||
// _11 = const 7i32 as u32 (Misc);
|
||||
// _1 = const i128_shr(_1, _11) -> bb9;
|
||||
// ...
|
||||
// _1 = const i128_shl(_1, const 6i32) -> bb10;
|
||||
// _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
|
||||
@ -98,7 +100,9 @@ fn main() {
|
||||
// ...
|
||||
// _1 = const u128_sub(_1, const 2u128) -> bb4;
|
||||
// ...
|
||||
// _1 = const u128_shr(_1, const 7i32) -> bb7;
|
||||
// _5 = const 7i32 as u32 (Misc);
|
||||
// _1 = const u128_shr(_1, _5) -> bb7;
|
||||
// ...
|
||||
// _1 = const u128_shl(_1, const 6i32) -> bb8;
|
||||
// _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