Skip to content

Commit f62e43d

Browse files
committed
rustc: track validity ranges for layout::Abi::Scalar values.
1 parent 5df25c4 commit f62e43d

File tree

15 files changed

+294
-219
lines changed

15 files changed

+294
-219
lines changed

src/librustc/ty/layout.rs

+186-115
Large diffs are not rendered by default.

src/librustc_lint/types.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -753,8 +753,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
753753
bug!("failed to get layout for `{}`: {}", t, e)
754754
});
755755

756-
if let layout::Variants::Tagged { ref variants, discr, .. } = layout.variants {
757-
let discr_size = discr.size(cx.tcx).bytes();
756+
if let layout::Variants::Tagged { ref variants, ref discr, .. } = layout.variants {
757+
let discr_size = discr.value.size(cx.tcx).bytes();
758758

759759
debug!("enum `{}` is {} bytes large with layout:\n{:#?}",
760760
t, layout.size.bytes(), layout);

src/librustc_trans/abi.rs

+10-9
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,8 @@ impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> {
287287
fn homogeneous_aggregate<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Option<Reg> {
288288
match self.abi {
289289
// The primitive for this algorithm.
290-
layout::Abi::Scalar(value) => {
291-
let kind = match value {
290+
layout::Abi::Scalar(ref scalar) => {
291+
let kind = match scalar.value {
292292
layout::Int(..) |
293293
layout::Pointer => RegKind::Integer,
294294
layout::F32 |
@@ -471,8 +471,8 @@ impl<'a, 'tcx> ArgType<'tcx> {
471471

472472
pub fn extend_integer_width_to(&mut self, bits: u64) {
473473
// Only integers have signedness
474-
match self.layout.abi {
475-
layout::Abi::Scalar(layout::Int(i, signed)) => {
474+
if let layout::Abi::Scalar(ref scalar) = self.layout.abi {
475+
if let layout::Int(i, signed) = scalar.value {
476476
if i.size().bits() < bits {
477477
self.attrs.set(if signed {
478478
ArgAttribute::SExt
@@ -481,8 +481,6 @@ impl<'a, 'tcx> ArgType<'tcx> {
481481
});
482482
}
483483
}
484-
485-
_ => {}
486484
}
487485
}
488486

@@ -695,9 +693,12 @@ impl<'a, 'tcx> FnType<'tcx> {
695693

696694
let arg_of = |ty: Ty<'tcx>, is_return: bool| {
697695
let mut arg = ArgType::new(ccx.layout_of(ty));
698-
if let layout::Abi::Scalar(layout::Int(layout::I1, _)) = arg.layout.abi {
699-
arg.attrs.set(ArgAttribute::ZExt);
700-
} else if arg.layout.is_zst() {
696+
if let layout::Abi::Scalar(ref scalar) = arg.layout.abi {
697+
if scalar.is_bool() {
698+
arg.attrs.set(ArgAttribute::ZExt);
699+
}
700+
}
701+
if arg.layout.is_zst() {
701702
// For some forsaken reason, x86_64-pc-windows-gnu
702703
// doesn't ignore zero-sized struct arguments.
703704
// The same is true for s390x-unknown-linux-gnu.

src/librustc_trans/base.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -375,11 +375,12 @@ pub fn from_immediate(bcx: &Builder, val: ValueRef) -> ValueRef {
375375
}
376376

377377
pub fn to_immediate(bcx: &Builder, val: ValueRef, layout: layout::TyLayout) -> ValueRef {
378-
if let layout::Abi::Scalar(layout::Int(layout::I1, _)) = layout.abi {
379-
bcx.trunc(val, Type::i1(bcx.ccx))
380-
} else {
381-
val
378+
if let layout::Abi::Scalar(ref scalar) = layout.abi {
379+
if scalar.is_bool() {
380+
return bcx.trunc(val, Type::i1(bcx.ccx));
381+
}
382382
}
383+
val
383384
}
384385

385386
pub fn call_memcpy(b: &Builder,

src/librustc_trans/cabi_s390x.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,12 @@ fn classify_ret_ty(ret: &mut ArgType) {
2727
fn is_single_fp_element<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
2828
layout: TyLayout<'tcx>) -> bool {
2929
match layout.abi {
30-
layout::Abi::Scalar(layout::F32) |
31-
layout::Abi::Scalar(layout::F64) => true,
30+
layout::Abi::Scalar(ref scalar) => {
31+
match scalar.value {
32+
layout::F32 | layout::F64 => true,
33+
_ => false
34+
}
35+
}
3236
layout::Abi::Aggregate { .. } => {
3337
if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 {
3438
is_single_fp_element(ccx, layout.field(ccx, 0))

src/librustc_trans/cabi_x86.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,12 @@ pub enum Flavor {
2222
fn is_single_fp_element<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
2323
layout: TyLayout<'tcx>) -> bool {
2424
match layout.abi {
25-
layout::Abi::Scalar(layout::F32) |
26-
layout::Abi::Scalar(layout::F64) => true,
25+
layout::Abi::Scalar(ref scalar) => {
26+
match scalar.value {
27+
layout::F32 | layout::F64 => true,
28+
_ => false
29+
}
30+
}
2731
layout::Abi::Aggregate { .. } => {
2832
if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 {
2933
is_single_fp_element(ccx, layout.field(ccx, 0))

src/librustc_trans/cabi_x86_64.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>)
6565
}
6666

6767
match layout.abi {
68-
layout::Abi::Scalar(value) => {
69-
let reg = match value {
68+
layout::Abi::Scalar(ref scalar) => {
69+
let reg = match scalar.value {
7070
layout::Int(..) |
7171
layout::Pointer => Class::Int,
7272
layout::F32 |

src/librustc_trans/debuginfo/metadata.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -1429,11 +1429,13 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
14291429
let discriminant_type_metadata = match layout.variants {
14301430
layout::Variants::Single { .. } |
14311431
layout::Variants::NicheFilling { .. } => None,
1432-
layout::Variants::Tagged { discr, .. } => Some(discriminant_type_metadata(discr)),
1432+
layout::Variants::Tagged { ref discr, .. } => {
1433+
Some(discriminant_type_metadata(discr.value))
1434+
}
14331435
};
14341436

1435-
match (layout.abi, discriminant_type_metadata) {
1436-
(layout::Abi::Scalar(_), Some(discr)) => return FinalMetadata(discr),
1437+
match (&layout.abi, discriminant_type_metadata) {
1438+
(&layout::Abi::Scalar(_), Some(discr)) => return FinalMetadata(discr),
14371439
_ => {}
14381440
}
14391441

src/librustc_trans/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#![feature(i128_type)]
2727
#![feature(i128)]
2828
#![feature(inclusive_range)]
29+
#![feature(inclusive_range_syntax)]
2930
#![feature(libc)]
3031
#![feature(quote)]
3132
#![feature(rustc_diagnostic_macros)]

src/librustc_trans/mir/block.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -671,10 +671,17 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
671671
(align | Alignment::Packed(arg.layout.align))
672672
.non_abi());
673673
} else {
674+
// We can't use `LvalueRef::load` here because the argument
675+
// may have a type we don't treat as immediate, but the ABI
676+
// used for this call is passing it by-value. In that case,
677+
// the load would just produce `OperandValue::Ref` instead
678+
// of the `OperandValue::Immediate` we need for the call.
674679
llval = bcx.load(llval, align.non_abi());
675-
}
676-
if let layout::Abi::Scalar(layout::Int(layout::I1, _)) = arg.layout.abi {
677-
bcx.range_metadata(llval, 0..2);
680+
if let layout::Abi::Scalar(ref scalar) = arg.layout.abi {
681+
if scalar.is_bool() {
682+
bcx.range_metadata(llval, 0..2);
683+
}
684+
}
678685
// We store bools as i8 so we need to truncate to i1.
679686
llval = base::to_immediate(bcx, llval, arg.layout);
680687
}

src/librustc_trans/mir/constant.rs

+10-6
Original file line numberDiff line numberDiff line change
@@ -455,9 +455,9 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
455455
Value(base));
456456
}
457457
let layout = self.ccx.layout_of(projected_ty);
458-
if let layout::Abi::Scalar(layout::Int(layout::I1, _)) = layout.abi {
458+
if let layout::Abi::Scalar(ref scalar) = layout.abi {
459459
let i1_type = Type::i1(self.ccx);
460-
if val_ty(val) != i1_type {
460+
if scalar.is_bool() && val_ty(val) != i1_type {
461461
unsafe {
462462
val = llvm::LLVMConstTrunc(val, i1_type.to_ref());
463463
}
@@ -685,10 +685,14 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
685685
assert!(cast_layout.is_llvm_immediate());
686686
let ll_t_out = cast_layout.immediate_llvm_type(self.ccx);
687687
let llval = operand.llval;
688-
let signed = match self.ccx.layout_of(operand.ty).abi {
689-
layout::Abi::Scalar(layout::Int(_, signed)) => signed,
690-
_ => false
691-
};
688+
689+
let mut signed = false;
690+
let l = self.ccx.layout_of(operand.ty);
691+
if let layout::Abi::Scalar(ref scalar) = l.abi {
692+
if let layout::Int(_, true) = scalar.value {
693+
signed = true;
694+
}
695+
}
692696

693697
unsafe {
694698
match (r_t_in, r_t_out) {

src/librustc_trans/mir/lvalue.rs

+27-44
Original file line numberDiff line numberDiff line change
@@ -148,16 +148,29 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
148148
const_llval
149149
} else {
150150
let load = bcx.load(self.llval, self.alignment.non_abi());
151-
if self.layout.ty.is_bool() {
152-
bcx.range_metadata(load, 0..2);
153-
} else if self.layout.ty.is_char() {
154-
// a char is a Unicode codepoint, and so takes values from 0
155-
// to 0x10FFFF inclusive only.
156-
bcx.range_metadata(load, 0..0x10FFFF+1);
157-
} else if self.layout.ty.is_region_ptr() ||
158-
self.layout.ty.is_box() ||
159-
self.layout.ty.is_fn() {
160-
bcx.nonnull_metadata(load);
151+
if let layout::Abi::Scalar(ref scalar) = self.layout.abi {
152+
let (min, max) = (scalar.valid_range.start, scalar.valid_range.end);
153+
let max_next = max.wrapping_add(1);
154+
let bits = scalar.value.size(bcx.ccx).bits();
155+
assert!(bits <= 128);
156+
let mask = !0u128 >> (128 - bits);
157+
// For a (max) value of -1, max will be `-1 as usize`, which overflows.
158+
// However, that is fine here (it would still represent the full range),
159+
// i.e., if the range is everything. The lo==hi case would be
160+
// rejected by the LLVM verifier (it would mean either an
161+
// empty set, which is impossible, or the entire range of the
162+
// type, which is pointless).
163+
match scalar.value {
164+
layout::Int(..) if max_next & mask != min & mask => {
165+
// llvm::ConstantRange can deal with ranges that wrap around,
166+
// so an overflow on (max + 1) is fine.
167+
bcx.range_metadata(load, min..max_next);
168+
}
169+
layout::Pointer if 0 < min && min < max => {
170+
bcx.nonnull_metadata(load);
171+
}
172+
_ => {}
173+
}
161174
}
162175
load
163176
};
@@ -274,48 +287,18 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
274287
let cast_to = bcx.ccx.layout_of(cast_to).immediate_llvm_type(bcx.ccx);
275288
match self.layout.variants {
276289
layout::Variants::Single { index } => {
277-
assert_eq!(index, 0);
278-
return C_uint(cast_to, 0);
290+
return C_uint(cast_to, index as u64);
279291
}
280292
layout::Variants::Tagged { .. } |
281293
layout::Variants::NicheFilling { .. } => {},
282294
}
283295

284296
let discr = self.project_field(bcx, 0);
285-
let discr_scalar = match discr.layout.abi {
286-
layout::Abi::Scalar(discr) => discr,
287-
_ => bug!("discriminant not scalar: {:#?}", discr.layout)
288-
};
289-
let (min, max) = match self.layout.variants {
290-
layout::Variants::Tagged { ref discr_range, .. } => {
291-
(discr_range.start, discr_range.end)
292-
}
293-
_ => (0, !0),
294-
};
295-
let max_next = max.wrapping_add(1);
296-
let bits = discr_scalar.size(bcx.ccx).bits();
297-
assert!(bits <= 128);
298-
let mask = !0u128 >> (128 - bits);
299-
let lldiscr = bcx.load(discr.llval, discr.alignment.non_abi());
300-
match discr_scalar {
301-
// For a (max) discr of -1, max will be `-1 as usize`, which overflows.
302-
// However, that is fine here (it would still represent the full range),
303-
layout::Int(..) if max_next & mask != min & mask => {
304-
// llvm::ConstantRange can deal with ranges that wrap around,
305-
// so an overflow on (max + 1) is fine.
306-
bcx.range_metadata(lldiscr, min..max_next);
307-
}
308-
_ => {
309-
// i.e., if the range is everything. The lo==hi case would be
310-
// rejected by the LLVM verifier (it would mean either an
311-
// empty set, which is impossible, or the entire range of the
312-
// type, which is pointless).
313-
}
314-
};
297+
let lldiscr = discr.load(bcx).immediate();
315298
match self.layout.variants {
316299
layout::Variants::Single { .. } => bug!(),
317-
layout::Variants::Tagged { .. } => {
318-
let signed = match discr_scalar {
300+
layout::Variants::Tagged { ref discr, .. } => {
301+
let signed = match discr.value {
319302
layout::Int(_, signed) => signed,
320303
_ => false
321304
};

src/librustc_trans/mir/rvalue.rs

+17-19
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
119119
}
120120

121121
// Use llvm.memset.p0i8.* to initialize byte arrays
122+
let v = base::from_immediate(&bcx, v);
122123
if common::val_ty(v) == Type::i8(bcx.ccx) {
123124
base::call_memset(&bcx, start, v, size, align, false);
124125
return bcx;
@@ -278,28 +279,25 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
278279
let ll_t_out = cast.immediate_llvm_type(bcx.ccx);
279280
let llval = operand.immediate();
280281

281-
match operand.layout.variants {
282-
layout::Variants::Tagged {
283-
ref discr_range, ..
284-
} if discr_range.end > discr_range.start => {
285-
// We want `table[e as usize]` to not
286-
// have bound checks, and this is the most
287-
// convenient place to put the `assume`.
288-
289-
base::call_assume(&bcx, bcx.icmp(
290-
llvm::IntULE,
291-
llval,
292-
C_uint_big(ll_t_in, discr_range.end)
293-
));
282+
let mut signed = false;
283+
if let layout::Abi::Scalar(ref scalar) = operand.layout.abi {
284+
if let layout::Int(_, s) = scalar.value {
285+
signed = s;
286+
287+
if scalar.valid_range.end > scalar.valid_range.start {
288+
// We want `table[e as usize]` to not
289+
// have bound checks, and this is the most
290+
// convenient place to put the `assume`.
291+
292+
base::call_assume(&bcx, bcx.icmp(
293+
llvm::IntULE,
294+
llval,
295+
C_uint_big(ll_t_in, scalar.valid_range.end)
296+
));
297+
}
294298
}
295-
_ => {}
296299
}
297300

298-
let signed = match operand.layout.abi {
299-
layout::Abi::Scalar(layout::Int(_, signed)) => signed,
300-
_ => false
301-
};
302-
303301
let newval = match (r_t_in, r_t_out) {
304302
(CastTy::Int(_), CastTy::Int(_)) => {
305303
bcx.intcast(llval, ll_t_out, signed)

src/librustc_trans/type_.rs

-1
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,6 @@ impl Type {
268268
pub fn from_integer(cx: &CrateContext, i: layout::Integer) -> Type {
269269
use rustc::ty::layout::Integer::*;
270270
match i {
271-
I1 => Type::i1(cx),
272271
I8 => Type::i8(cx),
273272
I16 => Type::i16(cx),
274273
I32 => Type::i32(cx),

src/librustc_trans/type_of.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -176,14 +176,13 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
176176
/// of that field's type - this is useful for taking the address of
177177
/// that field and ensuring the struct has the right alignment.
178178
fn llvm_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Type {
179-
if let layout::Abi::Scalar(value) = self.abi {
179+
if let layout::Abi::Scalar(ref scalar) = self.abi {
180180
// Use a different cache for scalars because pointers to DSTs
181181
// can be either fat or thin (data pointers of fat pointers).
182182
if let Some(&llty) = ccx.scalar_lltypes().borrow().get(&self.ty) {
183183
return llty;
184184
}
185-
let llty = match value {
186-
layout::Int(layout::I1, _) => Type::i8(ccx),
185+
let llty = match scalar.value {
187186
layout::Int(i, _) => Type::from_integer(ccx, i),
188187
layout::F32 => Type::f32(ccx),
189188
layout::F64 => Type::f64(ccx),
@@ -249,11 +248,12 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
249248
}
250249

251250
fn immediate_llvm_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Type {
252-
if let layout::Abi::Scalar(layout::Int(layout::I1, _)) = self.abi {
253-
Type::i1(ccx)
254-
} else {
255-
self.llvm_type(ccx)
251+
if let layout::Abi::Scalar(ref scalar) = self.abi {
252+
if scalar.is_bool() {
253+
return Type::i1(ccx);
254+
}
256255
}
256+
self.llvm_type(ccx)
257257
}
258258

259259
fn over_align(&self) -> Option<Align> {

0 commit comments

Comments
 (0)