Skip to content

Commit 42fe613

Browse files
Stop generating assumes for validity ranges
Now that LLVM has implemented range attributes on arguments and returns, and now that we generate such attributes, we no longer need to use assumes to represent validity ranges.
1 parent e08b80c commit 42fe613

15 files changed

+53
-333
lines changed

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

+4-65
Original file line numberDiff line numberDiff line change
@@ -240,13 +240,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
240240
if let OperandValueKind::Immediate(to_scalar) = cast_kind
241241
&& from_scalar.size(self.cx) == to_scalar.size(self.cx)
242242
{
243-
let from_backend_ty = bx.backend_type(operand.layout);
244243
let to_backend_ty = bx.backend_type(cast);
245244
Some(OperandValue::Immediate(self.transmute_immediate(
246245
bx,
247246
imm,
248247
from_scalar,
249-
from_backend_ty,
250248
to_scalar,
251249
to_backend_ty,
252250
)))
@@ -262,13 +260,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
262260
&& in_a.size(self.cx) == out_a.size(self.cx)
263261
&& in_b.size(self.cx) == out_b.size(self.cx)
264262
{
265-
let in_a_ibty = bx.scalar_pair_element_backend_type(operand.layout, 0, false);
266-
let in_b_ibty = bx.scalar_pair_element_backend_type(operand.layout, 1, false);
267263
let out_a_ibty = bx.scalar_pair_element_backend_type(cast, 0, false);
268264
let out_b_ibty = bx.scalar_pair_element_backend_type(cast, 1, false);
269265
Some(OperandValue::Pair(
270-
self.transmute_immediate(bx, imm_a, in_a, in_a_ibty, out_a, out_a_ibty),
271-
self.transmute_immediate(bx, imm_b, in_b, in_b_ibty, out_b, out_b_ibty),
266+
self.transmute_immediate(bx, imm_a, in_a, out_a, out_a_ibty),
267+
self.transmute_immediate(bx, imm_b, in_b, out_b, out_b_ibty),
272268
))
273269
} else {
274270
None
@@ -292,12 +288,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
292288
) -> Option<Bx::Value> {
293289
use abi::Primitive::*;
294290

295-
// When scalars are passed by value, there's no metadata recording their
296-
// valid ranges. For example, `char`s are passed as just `i32`, with no
297-
// way for LLVM to know that they're 0x10FFFF at most. Thus we assume
298-
// the range of the input value too, not just the output range.
299-
self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
300-
301291
imm = match (from_scalar.primitive(), to_scalar.primitive()) {
302292
(Int(_, is_signed), Int(..)) => bx.intcast(imm, to_backend_ty, is_signed),
303293
(Float(_), Float(_)) => {
@@ -339,21 +329,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
339329
bx: &mut Bx,
340330
mut imm: Bx::Value,
341331
from_scalar: abi::Scalar,
342-
from_backend_ty: Bx::Type,
343332
to_scalar: abi::Scalar,
344333
to_backend_ty: Bx::Type,
345334
) -> Bx::Value {
335+
use abi::Primitive::*;
336+
346337
assert_eq!(from_scalar.size(self.cx), to_scalar.size(self.cx));
347338

348-
use abi::Primitive::*;
349339
imm = bx.from_immediate(imm);
350340

351-
// When scalars are passed by value, there's no metadata recording their
352-
// valid ranges. For example, `char`s are passed as just `i32`, with no
353-
// way for LLVM to know that they're 0x10FFFF at most. Thus we assume
354-
// the range of the input value too, not just the output range.
355-
self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
356-
357341
imm = match (from_scalar.primitive(), to_scalar.primitive()) {
358342
(Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
359343
(Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
@@ -368,55 +352,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
368352
bx.bitcast(int_imm, to_backend_ty)
369353
}
370354
};
371-
self.assume_scalar_range(bx, imm, to_scalar, to_backend_ty);
372355
imm = bx.to_immediate_scalar(imm, to_scalar);
373356
imm
374357
}
375358

376-
fn assume_scalar_range(
377-
&self,
378-
bx: &mut Bx,
379-
imm: Bx::Value,
380-
scalar: abi::Scalar,
381-
backend_ty: Bx::Type,
382-
) {
383-
if matches!(self.cx.sess().opts.optimize, OptLevel::No | OptLevel::Less)
384-
// For now, the critical niches are all over `Int`eger values.
385-
// Should floating-point values or pointers ever get more complex
386-
// niches, then this code will probably want to handle them too.
387-
|| !matches!(scalar.primitive(), abi::Primitive::Int(..))
388-
|| scalar.is_always_valid(self.cx)
389-
{
390-
return;
391-
}
392-
393-
let abi::WrappingRange { start, end } = scalar.valid_range(self.cx);
394-
395-
if start <= end {
396-
if start > 0 {
397-
let low = bx.const_uint_big(backend_ty, start);
398-
let cmp = bx.icmp(IntPredicate::IntUGE, imm, low);
399-
bx.assume(cmp);
400-
}
401-
402-
let type_max = scalar.size(self.cx).unsigned_int_max();
403-
if end < type_max {
404-
let high = bx.const_uint_big(backend_ty, end);
405-
let cmp = bx.icmp(IntPredicate::IntULE, imm, high);
406-
bx.assume(cmp);
407-
}
408-
} else {
409-
let low = bx.const_uint_big(backend_ty, start);
410-
let cmp_low = bx.icmp(IntPredicate::IntUGE, imm, low);
411-
412-
let high = bx.const_uint_big(backend_ty, end);
413-
let cmp_high = bx.icmp(IntPredicate::IntULE, imm, high);
414-
415-
let or = bx.or(cmp_low, cmp_high);
416-
bx.assume(or);
417-
}
418-
}
419-
420359
pub fn codegen_rvalue_unsized(
421360
&mut self,
422361
bx: &mut Bx,

compiler/rustc_mir_build/src/build/expr/as_rvalue.rs

+2-74
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@ use rustc_middle::mir::interpret::Scalar;
88
use rustc_middle::mir::*;
99
use rustc_middle::thir::*;
1010
use rustc_middle::ty::cast::{mir_cast_kind, CastTy};
11-
use rustc_middle::ty::layout::IntegerExt;
1211
use rustc_middle::ty::util::IntTypeExt;
1312
use rustc_middle::ty::{self, Ty, UpvarArgs};
1413
use rustc_span::source_map::Spanned;
1514
use rustc_span::{Span, DUMMY_SP};
16-
use rustc_target::abi::{Abi, FieldIdx, Primitive};
15+
use rustc_target::abi::FieldIdx;
1716
use tracing::debug;
1817

1918
use crate::build::expr::as_place::PlaceBase;
@@ -201,85 +200,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
201200
{
202201
let discr_ty = adt_def.repr().discr_type().to_ty(this.tcx);
203202
let temp = unpack!(block = this.as_temp(block, scope, source, Mutability::Not));
204-
let layout = this.tcx.layout_of(this.param_env.and(source_expr.ty));
205203
let discr = this.temp(discr_ty, source_expr.span);
206204
this.cfg.push_assign(
207205
block,
208206
source_info,
209207
discr,
210208
Rvalue::Discriminant(temp.into()),
211209
);
212-
let (op, ty) = (Operand::Move(discr), discr_ty);
213-
214-
if let Abi::Scalar(scalar) = layout.unwrap().abi
215-
&& !scalar.is_always_valid(&this.tcx)
216-
&& let Primitive::Int(int_width, _signed) = scalar.primitive()
217-
{
218-
let unsigned_ty = int_width.to_ty(this.tcx, false);
219-
let unsigned_place = this.temp(unsigned_ty, expr_span);
220-
this.cfg.push_assign(
221-
block,
222-
source_info,
223-
unsigned_place,
224-
Rvalue::Cast(CastKind::IntToInt, Operand::Copy(discr), unsigned_ty),
225-
);
226-
227-
let bool_ty = this.tcx.types.bool;
228-
let range = scalar.valid_range(&this.tcx);
229-
let merge_op =
230-
if range.start <= range.end { BinOp::BitAnd } else { BinOp::BitOr };
231-
232-
let mut comparer = |range: u128, bin_op: BinOp| -> Place<'tcx> {
233-
let range_val = Const::from_bits(
234-
this.tcx,
235-
range,
236-
ty::ParamEnv::empty().and(unsigned_ty),
237-
);
238-
let lit_op = this.literal_operand(expr.span, range_val);
239-
let is_bin_op = this.temp(bool_ty, expr_span);
240-
this.cfg.push_assign(
241-
block,
242-
source_info,
243-
is_bin_op,
244-
Rvalue::BinaryOp(
245-
bin_op,
246-
Box::new((Operand::Copy(unsigned_place), lit_op)),
247-
),
248-
);
249-
is_bin_op
250-
};
251-
let assert_place = if range.start == 0 {
252-
comparer(range.end, BinOp::Le)
253-
} else {
254-
let start_place = comparer(range.start, BinOp::Ge);
255-
let end_place = comparer(range.end, BinOp::Le);
256-
let merge_place = this.temp(bool_ty, expr_span);
257-
this.cfg.push_assign(
258-
block,
259-
source_info,
260-
merge_place,
261-
Rvalue::BinaryOp(
262-
merge_op,
263-
Box::new((
264-
Operand::Move(start_place),
265-
Operand::Move(end_place),
266-
)),
267-
),
268-
);
269-
merge_place
270-
};
271-
this.cfg.push(
272-
block,
273-
Statement {
274-
source_info,
275-
kind: StatementKind::Intrinsic(Box::new(
276-
NonDivergingIntrinsic::Assume(Operand::Move(assert_place)),
277-
)),
278-
},
279-
);
280-
}
281-
282-
(op, ty)
210+
(Operand::Move(discr), discr_ty)
283211
} else {
284212
let ty = source_expr.ty;
285213
let source = unpack!(

src/tools/tidy/src/issues.txt

-1
Original file line numberDiff line numberDiff line change
@@ -3628,7 +3628,6 @@ ui/regions/issue-56537-closure-uses-region-from-container.rs
36283628
ui/regions/issue-6157.rs
36293629
ui/regions/issue-72051-member-region-hang.rs
36303630
ui/regions/issue-78262.rs
3631-
ui/repr/issue-83505-repr-simd.rs
36323631
ui/resolve/auxiliary/issue-112831-aux.rs
36333632
ui/resolve/auxiliary/issue-19452-aux.rs
36343633
ui/resolve/auxiliary/issue-21221-3.rs
+10-101
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
//@ revisions: OPT DBG
2-
//@ [OPT] compile-flags: -C opt-level=3 -C no-prepopulate-passes
3-
//@ [DBG] compile-flags: -C opt-level=0 -C no-prepopulate-passes
4-
//@ only-64bit (so I don't need to worry about usize)
1+
//@ compile-flags: -C opt-level=3 -C no-prepopulate-passes
52
#![crate_type = "lib"]
63

74
use std::mem::transmute;
@@ -14,59 +11,27 @@ pub enum SmallEnum {
1411
C = 12,
1512
}
1613

17-
// CHECK-LABEL: @check_to_enum(
14+
// CHECK: noundef range(i8 10, 13) i8 @check_to_enum(
1815
#[no_mangle]
1916
pub unsafe fn check_to_enum(x: i8) -> SmallEnum {
20-
// OPT: %0 = icmp uge i8 %x, 10
21-
// OPT: call void @llvm.assume(i1 %0)
22-
// OPT: %1 = icmp ule i8 %x, 12
23-
// OPT: call void @llvm.assume(i1 %1)
24-
// DBG-NOT: icmp
25-
// DBG-NOT: assume
26-
// CHECK: ret i8 %x
27-
2817
transmute(x)
2918
}
3019

31-
// CHECK-LABEL: @check_from_enum(
20+
// CHECK: @check_from_enum(i8 noundef range(i8 10, 13) %x)
3221
#[no_mangle]
3322
pub unsafe fn check_from_enum(x: SmallEnum) -> i8 {
34-
// OPT: %0 = icmp uge i8 %x, 10
35-
// OPT: call void @llvm.assume(i1 %0)
36-
// OPT: %1 = icmp ule i8 %x, 12
37-
// OPT: call void @llvm.assume(i1 %1)
38-
// DBG-NOT: icmp
39-
// DBG-NOT: assume
40-
// CHECK: ret i8 %x
41-
4223
transmute(x)
4324
}
4425

45-
// CHECK-LABEL: @check_to_ordering(
26+
// CHECK: noundef range(i8 -1, 2) i8 @check_to_ordering(
4627
#[no_mangle]
4728
pub unsafe fn check_to_ordering(x: u8) -> std::cmp::Ordering {
48-
// OPT: %0 = icmp uge i8 %x, -1
49-
// OPT: %1 = icmp ule i8 %x, 1
50-
// OPT: %2 = or i1 %0, %1
51-
// OPT: call void @llvm.assume(i1 %2)
52-
// DBG-NOT: icmp
53-
// DBG-NOT: assume
54-
// CHECK: ret i8 %x
55-
5629
transmute(x)
5730
}
5831

59-
// CHECK-LABEL: @check_from_ordering(
32+
// CHECK: @check_from_ordering(i8 noundef range(i8 -1, 2) %x)
6033
#[no_mangle]
6134
pub unsafe fn check_from_ordering(x: std::cmp::Ordering) -> u8 {
62-
// OPT: %0 = icmp uge i8 %x, -1
63-
// OPT: %1 = icmp ule i8 %x, 1
64-
// OPT: %2 = or i1 %0, %1
65-
// OPT: call void @llvm.assume(i1 %2)
66-
// DBG-NOT: icmp
67-
// DBG-NOT: assume
68-
// CHECK: ret i8 %x
69-
7035
transmute(x)
7136
}
7237

@@ -95,88 +60,32 @@ pub enum Minus100ToPlus100 {
9560
U = 100,
9661
}
9762

98-
// CHECK-LABEL: @check_enum_from_char(
63+
// CHECK: noundef range(i32 -100, 101) i32 @check_enum_from_char(i32 noundef range(i32 0, 1114112) %x)
9964
#[no_mangle]
10065
pub unsafe fn check_enum_from_char(x: char) -> Minus100ToPlus100 {
101-
// OPT: %0 = icmp ule i32 %x, 1114111
102-
// OPT: call void @llvm.assume(i1 %0)
103-
// OPT: %1 = icmp uge i32 %x, -100
104-
// OPT: %2 = icmp ule i32 %x, 100
105-
// OPT: %3 = or i1 %1, %2
106-
// OPT: call void @llvm.assume(i1 %3)
107-
// DBG-NOT: icmp
108-
// DBG-NOT: assume
109-
// CHECK: ret i32 %x
110-
11166
transmute(x)
11267
}
11368

114-
// CHECK-LABEL: @check_enum_to_char(
69+
// CHECK: noundef range(i32 0, 1114112) i32 @check_enum_to_char(i32 noundef range(i32 -100, 101) %x)
11570
#[no_mangle]
11671
pub unsafe fn check_enum_to_char(x: Minus100ToPlus100) -> char {
117-
// OPT: %0 = icmp uge i32 %x, -100
118-
// OPT: %1 = icmp ule i32 %x, 100
119-
// OPT: %2 = or i1 %0, %1
120-
// OPT: call void @llvm.assume(i1 %2)
121-
// OPT: %3 = icmp ule i32 %x, 1114111
122-
// OPT: call void @llvm.assume(i1 %3)
123-
// DBG-NOT: icmp
124-
// DBG-NOT: assume
125-
// CHECK: ret i32 %x
126-
12772
transmute(x)
12873
}
12974

130-
// CHECK-LABEL: @check_swap_pair(
75+
// CHECK: @check_swap_pair(i32 noundef range(i32 0, 1114112) %x.0, i32 noundef range(i32 1, 0) %x.1)
13176
#[no_mangle]
13277
pub unsafe fn check_swap_pair(x: (char, NonZero<u32>)) -> (NonZero<u32>, char) {
133-
// OPT: %0 = icmp ule i32 %x.0, 1114111
134-
// OPT: call void @llvm.assume(i1 %0)
135-
// OPT: %1 = icmp uge i32 %x.0, 1
136-
// OPT: call void @llvm.assume(i1 %1)
137-
// OPT: %2 = icmp uge i32 %x.1, 1
138-
// OPT: call void @llvm.assume(i1 %2)
139-
// OPT: %3 = icmp ule i32 %x.1, 1114111
140-
// OPT: call void @llvm.assume(i1 %3)
141-
// DBG-NOT: icmp
142-
// DBG-NOT: assume
143-
// CHECK: %[[P1:.+]] = insertvalue { i32, i32 } poison, i32 %x.0, 0
144-
// CHECK: %[[P2:.+]] = insertvalue { i32, i32 } %[[P1]], i32 %x.1, 1
145-
// CHECK: ret { i32, i32 } %[[P2]]
146-
14778
transmute(x)
14879
}
14980

150-
// CHECK-LABEL: @check_bool_from_ordering(
81+
// CHECK: @check_bool_from_ordering(i8 noundef range(i8 -1, 2) %x)
15182
#[no_mangle]
15283
pub unsafe fn check_bool_from_ordering(x: std::cmp::Ordering) -> bool {
153-
// OPT: %0 = icmp uge i8 %x, -1
154-
// OPT: %1 = icmp ule i8 %x, 1
155-
// OPT: %2 = or i1 %0, %1
156-
// OPT: call void @llvm.assume(i1 %2)
157-
// OPT: %3 = icmp ule i8 %x, 1
158-
// OPT: call void @llvm.assume(i1 %3)
159-
// DBG-NOT: icmp
160-
// DBG-NOT: assume
161-
// CHECK: %[[R:.+]] = trunc i8 %x to i1
162-
// CHECK: ret i1 %[[R]]
163-
16484
transmute(x)
16585
}
16686

167-
// CHECK-LABEL: @check_bool_to_ordering(
87+
// CHECK: noundef range(i8 -1, 2) i8 @check_bool_to_ordering(
16888
#[no_mangle]
16989
pub unsafe fn check_bool_to_ordering(x: bool) -> std::cmp::Ordering {
170-
// CHECK: %_0 = zext i1 %x to i8
171-
// OPT: %0 = icmp ule i8 %_0, 1
172-
// OPT: call void @llvm.assume(i1 %0)
173-
// OPT: %1 = icmp uge i8 %_0, -1
174-
// OPT: %2 = icmp ule i8 %_0, 1
175-
// OPT: %3 = or i1 %1, %2
176-
// OPT: call void @llvm.assume(i1 %3)
177-
// DBG-NOT: icmp
178-
// DBG-NOT: assume
179-
// CHECK: ret i8 %_0
180-
18190
transmute(x)
18291
}

0 commit comments

Comments
 (0)