Skip to content

Commit 400866b

Browse files
committed
1 parent c2ccc85 commit 400866b

11 files changed

+234
-67
lines changed

Diff for: compiler/rustc_mir_build/src/build/expr/as_rvalue.rs

+58-43
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc_middle::mir::Place;
1515
use rustc_middle::mir::*;
1616
use rustc_middle::thir::*;
1717
use rustc_middle::ty::cast::{mir_cast_kind, CastTy};
18+
use rustc_middle::ty::layout::IntegerExt;
1819
use rustc_middle::ty::{self, Ty, UpvarSubsts};
1920
use rustc_span::Span;
2021

@@ -225,49 +226,63 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
225226
);
226227
let (op,ty) = (Operand::Move(discr), discr_ty);
227228

228-
if let Abi::Scalar(scalar) = layout.unwrap().abi{
229-
if let Primitive::Int(_, signed) = scalar.primitive() {
230-
let range = scalar.valid_range(&this.tcx);
231-
// FIXME: Handle wraparound cases too.
232-
if range.end >= range.start {
233-
let mut assumer = |range: u128, bin_op: BinOp| {
234-
// We will be overwriting this val if our scalar is signed value
235-
// because sign extension on unsigned types might cause unintended things
236-
let mut range_val =
237-
ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(discr_ty));
238-
let bool_ty = this.tcx.types.bool;
239-
if signed {
240-
let scalar_size_extend = scalar.size(&this.tcx).sign_extend(range);
241-
let discr_layout = this.tcx.layout_of(this.param_env.and(discr_ty));
242-
let truncated_val = discr_layout.unwrap().size.truncate(scalar_size_extend);
243-
range_val = ConstantKind::from_bits(
244-
this.tcx,
245-
truncated_val,
246-
ty::ParamEnv::empty().and(discr_ty),
247-
);
248-
}
249-
let lit_op = this.literal_operand(expr.span, range_val);
250-
let is_bin_op = this.temp(bool_ty, expr_span);
251-
this.cfg.push_assign(
252-
block,
253-
source_info,
254-
is_bin_op,
255-
Rvalue::BinaryOp(bin_op, Box::new(((lit_op), (Operand::Copy(discr))))),
256-
);
257-
this.cfg.push(
258-
block,
259-
Statement {
260-
source_info,
261-
kind: StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(
262-
Operand::Copy(is_bin_op),
263-
))),
264-
},
265-
)
266-
};
267-
assumer(range.end, BinOp::Ge);
268-
assumer(range.start, BinOp::Le);
269-
}
270-
}
229+
if let Abi::Scalar(scalar) = layout.unwrap().abi
230+
&& !scalar.is_always_valid(&this.tcx)
231+
&& let Primitive::Int(int_width, _signed) = scalar.primitive()
232+
{
233+
let unsigned_ty = int_width.to_ty(this.tcx, false);
234+
let unsigned_place = this.temp(unsigned_ty, expr_span);
235+
this.cfg.push_assign(
236+
block,
237+
source_info,
238+
unsigned_place,
239+
Rvalue::Cast(CastKind::IntToInt, Operand::Copy(discr), unsigned_ty));
240+
241+
let bool_ty = this.tcx.types.bool;
242+
let range = scalar.valid_range(&this.tcx);
243+
let merge_op =
244+
if range.start <= range.end {
245+
BinOp::BitAnd
246+
} else {
247+
BinOp::BitOr
248+
};
249+
250+
let mut comparer = |range: u128, bin_op: BinOp| -> Place<'tcx> {
251+
let range_val =
252+
ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(unsigned_ty));
253+
let lit_op = this.literal_operand(expr.span, range_val);
254+
let is_bin_op = this.temp(bool_ty, expr_span);
255+
this.cfg.push_assign(
256+
block,
257+
source_info,
258+
is_bin_op,
259+
Rvalue::BinaryOp(bin_op, Box::new((Operand::Copy(unsigned_place), lit_op))),
260+
);
261+
is_bin_op
262+
};
263+
let assert_place = if range.start == 0 {
264+
comparer(range.end, BinOp::Le)
265+
} else {
266+
let start_place = comparer(range.start, BinOp::Ge);
267+
let end_place = comparer(range.end, BinOp::Le);
268+
let merge_place = this.temp(bool_ty, expr_span);
269+
this.cfg.push_assign(
270+
block,
271+
source_info,
272+
merge_place,
273+
Rvalue::BinaryOp(merge_op, Box::new((Operand::Move(start_place), Operand::Move(end_place)))),
274+
);
275+
merge_place
276+
};
277+
this.cfg.push(
278+
block,
279+
Statement {
280+
source_info,
281+
kind: StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(
282+
Operand::Move(assert_place),
283+
))),
284+
},
285+
);
271286
}
272287

273288
(op,ty)

Diff for: tests/assembly/option-nonzero-eq.rs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// revisions: WIN LIN
2+
// [WIN] only-windows
3+
// [LIN] only-linux
4+
// assembly-output: emit-asm
5+
// compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel
6+
// only-x86_64
7+
// ignore-sgx
8+
// ignore-debug
9+
10+
use std::cmp::Ordering;
11+
12+
// CHECK-lABEL: ordering_eq:
13+
#[no_mangle]
14+
pub fn ordering_eq(l: Option<Ordering>, r: Option<Ordering>) -> bool {
15+
// Linux (System V): first two arguments are rdi then rsi
16+
// Windows: first two arguments are rcx then rdx
17+
// Both use rax for the return value.
18+
19+
// CHECK-NOT: mov
20+
// CHECK-NOT: test
21+
// CHECK-NOT: cmp
22+
23+
// LIN: cmp dil, sil
24+
// WIN: cmp cl, dl
25+
// CHECK-NEXT: sete al
26+
// CHECK-NEXT: ret
27+
l == r
28+
}

Diff for: tests/codegen/option-nonzero-eq.rs

+3-9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ use core::cmp::Ordering;
77
use core::num::{NonZeroU32, NonZeroI64};
88
use core::ptr::NonNull;
99

10+
// See also tests/assembly/option-nonzero-eq.rs, for cases with `assume`s in the
11+
// LLVM and thus don't optimize down clearly here, but do in assembly.
12+
1013
// CHECK-lABEL: @non_zero_eq
1114
#[no_mangle]
1215
pub fn non_zero_eq(l: Option<NonZeroU32>, r: Option<NonZeroU32>) -> bool {
@@ -33,12 +36,3 @@ pub fn non_null_eq(l: Option<NonNull<u8>>, r: Option<NonNull<u8>>) -> bool {
3336
// CHECK-NEXT: ret i1
3437
l == r
3538
}
36-
37-
// CHECK-lABEL: @ordering_eq
38-
#[no_mangle]
39-
pub fn ordering_eq(l: Option<Ordering>, r: Option<Ordering>) -> bool {
40-
// CHECK: start:
41-
// CHECK-NEXT: icmp eq i8
42-
// CHECK-NEXT: ret i1
43-
l == r
44-
}

Diff for: tests/mir-opt/building/enum_cast.bar.built.after.mir

+4-5
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,16 @@ fn bar(_1: Bar) -> usize {
55
let mut _0: usize; // return place in scope 0 at $DIR/enum_cast.rs:+0:21: +0:26
66
let _2: Bar; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
77
let mut _3: isize; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
8-
let mut _4: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
8+
let mut _4: u8; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
99
let mut _5: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
1010

1111
bb0: {
1212
StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
1313
_2 = move _1; // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
1414
_3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
15-
_4 = Ge(const 1_isize, _3); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
16-
assume(_4); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
17-
_5 = Le(const 0_isize, _3); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
18-
assume(_5); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
15+
_4 = _3 as u8 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
16+
_5 = Le(_4, const 1_u8); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
17+
assume(move _5); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
1918
_0 = move _3 as usize (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
2019
StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+1:16: +1:17
2120
return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2

Diff for: tests/mir-opt/building/enum_cast.boo.built.after.mir

+4-5
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,16 @@ fn boo(_1: Boo) -> usize {
55
let mut _0: usize; // return place in scope 0 at $DIR/enum_cast.rs:+0:21: +0:26
66
let _2: Boo; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
77
let mut _3: u8; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
8-
let mut _4: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
8+
let mut _4: u8; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
99
let mut _5: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
1010

1111
bb0: {
1212
StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
1313
_2 = move _1; // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
1414
_3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
15-
_4 = Ge(const 1_u8, _3); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
16-
assume(_4); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
17-
_5 = Le(const 0_u8, _3); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
18-
assume(_5); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
15+
_4 = _3 as u8 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
16+
_5 = Le(_4, const 1_u8); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
17+
assume(move _5); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
1918
_0 = move _3 as usize (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
2019
StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+1:16: +1:17
2120
return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2

Diff for: tests/mir-opt/building/enum_cast.droppy.built.after.mir

+4-5
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ fn droppy() -> () {
66
let _2: Droppy; // in scope 0 at $DIR/enum_cast.rs:+2:13: +2:14
77
let _4: Droppy; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:18
88
let mut _5: isize; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:18
9-
let mut _6: bool; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:27
9+
let mut _6: u8; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:27
1010
let mut _7: bool; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:27
1111
let _8: Droppy; // in scope 0 at $DIR/enum_cast.rs:+7:9: +7:10
1212
scope 1 {
@@ -31,10 +31,9 @@ fn droppy() -> () {
3131
StorageLive(_4); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:18
3232
_4 = move _2; // scope 3 at $DIR/enum_cast.rs:+5:17: +5:18
3333
_5 = discriminant(_4); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
34-
_6 = Ge(const 2_isize, _5); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
35-
assume(_6); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
36-
_7 = Le(const 0_isize, _5); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
37-
assume(_7); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
34+
_6 = _5 as u8 (IntToInt); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
35+
_7 = Le(_6, const 2_u8); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
36+
assume(move _7); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
3837
_3 = move _5 as usize (IntToInt); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
3938
drop(_4) -> [return: bb1, unwind: bb4]; // scope 3 at $DIR/enum_cast.rs:+5:26: +5:27
4039
}

Diff for: tests/mir-opt/building/enum_cast.far.built.after.mir

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// MIR for `far` after built
2+
3+
fn far(_1: Far) -> isize {
4+
debug far => _1; // in scope 0 at $DIR/enum_cast.rs:+0:8: +0:11
5+
let mut _0: isize; // return place in scope 0 at $DIR/enum_cast.rs:+0:21: +0:26
6+
let _2: Far; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
7+
let mut _3: i16; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
8+
let mut _4: u16; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
9+
let mut _5: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
10+
11+
bb0: {
12+
StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
13+
_2 = move _1; // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
14+
_3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
15+
_4 = _3 as u16 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
16+
_5 = Le(_4, const 1_u16); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
17+
assume(move _5); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
18+
_0 = move _3 as isize (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
19+
StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+1:16: +1:17
20+
return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2
21+
}
22+
}
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// MIR for `offsetty` after built
2+
3+
fn offsetty(_1: NotStartingAtZero) -> u32 {
4+
debug x => _1; // in scope 0 at $DIR/enum_cast.rs:+0:13: +0:14
5+
let mut _0: u32; // return place in scope 0 at $DIR/enum_cast.rs:+0:38: +0:41
6+
let _2: NotStartingAtZero; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:6
7+
let mut _3: isize; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:6
8+
let mut _4: u8; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
9+
let mut _5: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
10+
let mut _6: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
11+
let mut _7: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
12+
13+
bb0: {
14+
StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:6
15+
_2 = move _1; // scope 0 at $DIR/enum_cast.rs:+1:5: +1:6
16+
_3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
17+
_4 = _3 as u8 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
18+
_5 = Ge(_4, const 4_u8); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
19+
_6 = Le(_4, const 8_u8); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
20+
_7 = BitAnd(move _5, move _6); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
21+
assume(move _7); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
22+
_0 = move _3 as u32 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
23+
StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+1:12: +1:13
24+
return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2
25+
}
26+
}

Diff for: tests/mir-opt/building/enum_cast.rs

+42
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// EMIT_MIR enum_cast.foo.built.after.mir
22
// EMIT_MIR enum_cast.bar.built.after.mir
33
// EMIT_MIR enum_cast.boo.built.after.mir
4+
// EMIT_MIR enum_cast.far.built.after.mir
45

56
enum Foo {
67
A
@@ -15,6 +16,11 @@ enum Boo {
1516
A, B
1617
}
1718

19+
#[repr(i16)]
20+
enum Far {
21+
A, B
22+
}
23+
1824
fn foo(foo: Foo) -> usize {
1925
foo as usize
2026
}
@@ -27,6 +33,10 @@ fn boo(boo: Boo) -> usize {
2733
boo as usize
2834
}
2935

36+
fn far(far: Far) -> isize {
37+
far as isize
38+
}
39+
3040
// EMIT_MIR enum_cast.droppy.built.after.mir
3141
enum Droppy {
3242
A, B, C
@@ -46,5 +56,37 @@ fn droppy() {
4656
let z = Droppy::B;
4757
}
4858

59+
#[repr(i16)]
60+
enum SignedAroundZero {
61+
A = -2,
62+
B = 0,
63+
C = 2,
64+
}
65+
66+
#[repr(u16)]
67+
enum UnsignedAroundZero {
68+
A = 65535,
69+
B = 0,
70+
C = 1,
71+
}
72+
73+
// EMIT_MIR enum_cast.signy.built.after.mir
74+
fn signy(x: SignedAroundZero) -> i16 {
75+
x as i16
76+
}
77+
78+
// EMIT_MIR enum_cast.unsigny.built.after.mir
79+
fn unsigny(x: UnsignedAroundZero) -> u16 {
80+
// FIXME: This doesn't get an around-the-end range today, sadly.
81+
x as u16
82+
}
83+
84+
enum NotStartingAtZero { A = 4, B = 6, C = 8 }
85+
86+
// EMIT_MIR enum_cast.offsetty.built.after.mir
87+
fn offsetty(x: NotStartingAtZero) -> u32 {
88+
x as u32
89+
}
90+
4991
fn main() {
5092
}
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// MIR for `signy` after built
2+
3+
fn signy(_1: SignedAroundZero) -> i16 {
4+
debug x => _1; // in scope 0 at $DIR/enum_cast.rs:+0:10: +0:11
5+
let mut _0: i16; // return place in scope 0 at $DIR/enum_cast.rs:+0:34: +0:37
6+
let _2: SignedAroundZero; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:6
7+
let mut _3: i16; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:6
8+
let mut _4: u16; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
9+
let mut _5: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
10+
let mut _6: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
11+
let mut _7: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
12+
13+
bb0: {
14+
StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:6
15+
_2 = move _1; // scope 0 at $DIR/enum_cast.rs:+1:5: +1:6
16+
_3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
17+
_4 = _3 as u16 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
18+
_5 = Ge(_4, const 65534_u16); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
19+
_6 = Le(_4, const 2_u16); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
20+
_7 = BitOr(move _5, move _6); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
21+
assume(move _7); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
22+
_0 = move _3 as i16 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:13
23+
StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+1:12: +1:13
24+
return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2
25+
}
26+
}
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// MIR for `unsigny` after built
2+
3+
fn unsigny(_1: UnsignedAroundZero) -> u16 {
4+
debug x => _1; // in scope 0 at $DIR/enum_cast.rs:+0:12: +0:13
5+
let mut _0: u16; // return place in scope 0 at $DIR/enum_cast.rs:+0:38: +0:41
6+
let _2: UnsignedAroundZero; // in scope 0 at $DIR/enum_cast.rs:+2:5: +2:6
7+
let mut _3: u16; // in scope 0 at $DIR/enum_cast.rs:+2:5: +2:6
8+
9+
bb0: {
10+
StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+2:5: +2:6
11+
_2 = move _1; // scope 0 at $DIR/enum_cast.rs:+2:5: +2:6
12+
_3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+2:5: +2:13
13+
_0 = move _3 as u16 (IntToInt); // scope 0 at $DIR/enum_cast.rs:+2:5: +2:13
14+
StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+2:12: +2:13
15+
return; // scope 0 at $DIR/enum_cast.rs:+3:2: +3:2
16+
}
17+
}

0 commit comments

Comments
 (0)