Skip to content

Commit 42208c1

Browse files
committed
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
1 parent 6a5a086 commit 42208c1

File tree

3 files changed

+112
-48
lines changed

3 files changed

+112
-48
lines changed

src/librustc_mir/transform/lower_128bit.rs

+86-32
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,41 @@ impl Lower128Bit {
4141
let (basic_blocks, local_decls) = mir.basic_blocks_and_local_decls_mut();
4242
for block in basic_blocks.iter_mut() {
4343
for i in (0..block.statements.len()).rev() {
44-
let lang_item =
45-
if let Some(lang_item) = lower_to(&block.statements[i], local_decls, tcx) {
46-
lang_item
44+
let (lang_item, rhs_kind) =
45+
if let Some((lang_item, rhs_kind)) =
46+
lower_to(&block.statements[i], local_decls, tcx)
47+
{
48+
(lang_item, rhs_kind)
4749
} else {
4850
continue;
4951
};
5052

53+
let rhs_override_ty = rhs_kind.ty(tcx);
54+
let cast_local =
55+
match rhs_override_ty {
56+
None => None,
57+
Some(ty) => {
58+
let local_decl = LocalDecl::new_internal(
59+
ty, block.statements[i].source_info.span);
60+
Some(local_decls.push(local_decl))
61+
},
62+
};
63+
64+
let storage_dead = cast_local.map(|local| {
65+
Statement {
66+
source_info: block.statements[i].source_info,
67+
kind: StatementKind::StorageDead(local),
68+
}
69+
});
5170
let after_call = BasicBlockData {
52-
statements: block.statements.drain((i+1)..).collect(),
71+
statements: storage_dead.into_iter()
72+
.chain(block.statements.drain((i+1)..)).collect(),
5373
is_cleanup: block.is_cleanup,
5474
terminator: block.terminator.take(),
5575
};
5676

5777
let bin_statement = block.statements.pop().unwrap();
58-
let (source_info, lvalue, lhs, rhs) = match bin_statement {
78+
let (source_info, lvalue, lhs, mut rhs) = match bin_statement {
5979
Statement {
6080
source_info,
6181
kind: StatementKind::Assign(
@@ -71,6 +91,23 @@ impl Lower128Bit {
7191
_ => bug!("Statement doesn't match pattern any more?"),
7292
};
7393

94+
if let Some(local) = cast_local {
95+
block.statements.push(Statement {
96+
source_info: source_info,
97+
kind: StatementKind::StorageLive(local),
98+
});
99+
block.statements.push(Statement {
100+
source_info: source_info,
101+
kind: StatementKind::Assign(
102+
Lvalue::Local(local),
103+
Rvalue::Cast(
104+
CastKind::Misc,
105+
rhs,
106+
rhs_override_ty.unwrap())),
107+
});
108+
rhs = Operand::Consume(Lvalue::Local(local));
109+
}
110+
74111
let call_did = check_lang_item_type(
75112
lang_item, &lvalue, &lhs, &rhs, local_decls, tcx);
76113

@@ -118,7 +155,7 @@ fn check_lang_item_type<'a, 'tcx, D>(
118155
}
119156

120157
fn lower_to<'a, 'tcx, D>(statement: &Statement<'tcx>, local_decls: &D, tcx: TyCtxt<'a, 'tcx, 'tcx>)
121-
-> Option<LangItem>
158+
-> Option<(LangItem, RhsKind)>
122159
where D: HasLocalDecls<'tcx>
123160
{
124161
match statement.kind {
@@ -139,6 +176,23 @@ fn lower_to<'a, 'tcx, D>(statement: &Statement<'tcx>, local_decls: &D, tcx: TyCt
139176
None
140177
}
141178

179+
#[derive(Copy, Clone)]
180+
enum RhsKind {
181+
Unchanged,
182+
ForceU128,
183+
ForceU32,
184+
}
185+
186+
impl RhsKind {
187+
fn ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Ty<'tcx>> {
188+
match *self {
189+
RhsKind::Unchanged => None,
190+
RhsKind::ForceU128 => Some(tcx.types.u128),
191+
RhsKind::ForceU32 => Some(tcx.types.u32),
192+
}
193+
}
194+
}
195+
142196
fn sign_of_128bit(ty: Ty) -> Option<bool> {
143197
match ty.sty {
144198
TypeVariants::TyInt(syntax::ast::IntTy::I128) => Some(true),
@@ -147,39 +201,39 @@ fn sign_of_128bit(ty: Ty) -> Option<bool> {
147201
}
148202
}
149203

150-
fn item_for_op(bin_op: BinOp, is_signed: bool) -> Option<LangItem> {
204+
fn item_for_op(bin_op: BinOp, is_signed: bool) -> Option<(LangItem, RhsKind)> {
151205
let i = match (bin_op, is_signed) {
152-
(BinOp::Add, true) => LangItem::I128AddFnLangItem,
153-
(BinOp::Add, false) => LangItem::U128AddFnLangItem,
154-
(BinOp::Sub, true) => LangItem::I128SubFnLangItem,
155-
(BinOp::Sub, false) => LangItem::U128SubFnLangItem,
156-
(BinOp::Mul, true) => LangItem::I128MulFnLangItem,
157-
(BinOp::Mul, false) => LangItem::U128MulFnLangItem,
158-
(BinOp::Div, true) => LangItem::I128DivFnLangItem,
159-
(BinOp::Div, false) => LangItem::U128DivFnLangItem,
160-
(BinOp::Rem, true) => LangItem::I128RemFnLangItem,
161-
(BinOp::Rem, false) => LangItem::U128RemFnLangItem,
162-
(BinOp::Shl, true) => LangItem::I128ShlFnLangItem,
163-
(BinOp::Shl, false) => LangItem::U128ShlFnLangItem,
164-
(BinOp::Shr, true) => LangItem::I128ShrFnLangItem,
165-
(BinOp::Shr, false) => LangItem::U128ShrFnLangItem,
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),
166220
_ => return None,
167221
};
168222
Some(i)
169223
}
170224

171-
fn item_for_checked_op(bin_op: BinOp, is_signed: bool) -> Option<LangItem> {
225+
fn item_for_checked_op(bin_op: BinOp, is_signed: bool) -> Option<(LangItem, RhsKind)> {
172226
let i = match (bin_op, is_signed) {
173-
(BinOp::Add, true) => LangItem::I128AddoFnLangItem,
174-
(BinOp::Add, false) => LangItem::U128AddoFnLangItem,
175-
(BinOp::Sub, true) => LangItem::I128SuboFnLangItem,
176-
(BinOp::Sub, false) => LangItem::U128SuboFnLangItem,
177-
(BinOp::Mul, true) => LangItem::I128MuloFnLangItem,
178-
(BinOp::Mul, false) => LangItem::U128MuloFnLangItem,
179-
(BinOp::Shl, true) => LangItem::I128ShloFnLangItem,
180-
(BinOp::Shl, false) => LangItem::U128ShloFnLangItem,
181-
(BinOp::Shr, true) => LangItem::I128ShroFnLangItem,
182-
(BinOp::Shr, false) => LangItem::U128ShroFnLangItem,
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),
183237
_ => bug!("That should be all the checked ones?"),
184238
};
185239
Some(i)

src/test/mir-opt/lower_128bit_debug_test.rs

+14-8
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ fn i128_mulo(_x: i128, _y: i128) -> (i128, bool) { (4, false) }
3535
#[lang="u128_mulo"]
3636
fn u128_mulo(_x: u128, _y: u128) -> (u128, bool) { (5, false) }
3737
#[lang="i128_shlo"]
38-
fn i128_shlo(_x: i128, _y: i32) -> (i128, bool) { (6, false) }
38+
fn i128_shlo(_x: i128, _y: u128) -> (i128, bool) { (6, false) }
3939
#[lang="u128_shlo"]
40-
fn u128_shlo(_x: u128, _y: i32) -> (u128, bool) { (6, false) }
40+
fn u128_shlo(_x: u128, _y: u128) -> (u128, bool) { (6, false) }
4141
#[lang="i128_shro"]
42-
fn i128_shro(_x: i128, _y: i32) -> (i128, bool) { (7, false) }
42+
fn i128_shro(_x: i128, _y: u128) -> (i128, bool) { (7, false) }
4343
#[lang="u128_shro"]
44-
fn u128_shro(_x: u128, _y: i32) -> (u128, bool) { (8, false) }
44+
fn u128_shro(_x: u128, _y: u128) -> (u128, bool) { (8, false) }
4545

4646
fn test_signed(mut x: i128) -> i128 {
4747
x += 1;
@@ -88,7 +88,9 @@ fn main() {
8888
// _1 = const i128_rem(_1, const 5i128) -> bb15;
8989
// ...
9090
// _1 = (_13.0: i128);
91-
// _14 = const i128_shro(_1, const 7i32) -> bb16;
91+
// ...
92+
// _17 = const 7i32 as u128 (Misc);
93+
// _14 = const i128_shro(_1, _17) -> bb16;
9294
// ...
9395
// _1 = (_14.0: i128);
9496
// ...
@@ -100,7 +102,8 @@ fn main() {
100102
// ...
101103
// assert(!(_13.1: bool), "attempt to shift left with overflow") -> bb8;
102104
// ...
103-
// _13 = const i128_shlo(_1, const 6i32) -> bb14;
105+
// _16 = const 6i32 as u128 (Misc);
106+
// _13 = const i128_shlo(_1, _16) -> bb14;
104107
// ...
105108
// assert(!(_14.1: bool), "attempt to shift right with overflow") -> bb9;
106109
// END rustc.test_signed.Lower128Bit.after.mir
@@ -121,7 +124,9 @@ fn main() {
121124
// _1 = const u128_rem(_1, const 5u128) -> bb13;
122125
// ...
123126
// _1 = (_7.0: u128);
124-
// _8 = const u128_shro(_1, const 7i32) -> bb14;
127+
// ...
128+
// _11 = const 7i32 as u128 (Misc);
129+
// _8 = const u128_shro(_1, _11) -> bb14;
125130
// ...
126131
// _1 = (_8.0: u128);
127132
// ...
@@ -133,7 +138,8 @@ fn main() {
133138
// ...
134139
// assert(!(_7.1: bool), "attempt to shift left with overflow") -> bb6;
135140
// ...
136-
// _7 = const u128_shlo(_1, const 6i32) -> bb12;
141+
// _10 = const 6i32 as u128 (Misc);
142+
// _7 = const u128_shlo(_1, _10) -> bb12;
137143
// ...
138144
// assert(!(_8.1: bool), "attempt to shift right with overflow") -> bb7;
139145
// END rustc.test_unsigned.Lower128Bit.after.mir

src/test/mir-opt/lower_128bit_test.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ fn i128_rem(_x: i128, _y: i128) -> i128 { 5 }
3434
#[lang="u128_rem"]
3535
fn u128_rem(_x: u128, _y: u128) -> u128 { 6 }
3636
#[lang="i128_shl"]
37-
fn i128_shl(_x: i128, _y: i32) -> i128 { 7 }
37+
fn i128_shl(_x: i128, _y: u32) -> i128 { 7 }
3838
#[lang="u128_shl"]
39-
fn u128_shl(_x: u128, _y: i32) -> u128 { 7 }
39+
fn u128_shl(_x: u128, _y: u32) -> u128 { 7 }
4040
#[lang="i128_shr"]
41-
fn i128_shr(_x: i128, _y: i32) -> i128 { 8 }
41+
fn i128_shr(_x: i128, _y: u32) -> i128 { 8 }
4242
#[lang="u128_shr"]
43-
fn u128_shr(_x: u128, _y: i32) -> u128 { 9 }
43+
fn u128_shr(_x: u128, _y: u32) -> u128 { 9 }
4444

4545
fn test_signed(mut x: i128) -> i128 {
4646
x += 1;
@@ -82,9 +82,11 @@ fn main() {
8282
// ...
8383
// _1 = const i128_sub(_1, const 2i128) -> bb6;
8484
// ...
85-
// _1 = const i128_shr(_1, const 7i32) -> bb9;
85+
// _11 = const 7i32 as u32 (Misc);
86+
// _1 = const i128_shr(_1, _11) -> bb9;
8687
// ...
87-
// _1 = const i128_shl(_1, const 6i32) -> bb10;
88+
// _12 = const 6i32 as u32 (Misc);
89+
// _1 = const i128_shl(_1, _12) -> bb10;
8890
// END rustc.test_signed.Lower128Bit.after.mir
8991

9092
// START rustc.test_unsigned.Lower128Bit.after.mir
@@ -98,7 +100,9 @@ fn main() {
98100
// ...
99101
// _1 = const u128_sub(_1, const 2u128) -> bb4;
100102
// ...
101-
// _1 = const u128_shr(_1, const 7i32) -> bb7;
103+
// _5 = const 7i32 as u32 (Misc);
104+
// _1 = const u128_shr(_1, _5) -> bb7;
102105
// ...
103-
// _1 = const u128_shl(_1, const 6i32) -> bb8;
106+
// _6 = const 6i32 as u32 (Misc);
107+
// _1 = const u128_shl(_1, _6) -> bb8;
104108
// END rustc.test_unsigned.Lower128Bit.after.mir

0 commit comments

Comments
 (0)