Skip to content

Commit de3e581

Browse files
committed
rustc: support u128 discriminant ranges.
1 parent 018323f commit de3e581

File tree

9 files changed

+70
-101
lines changed

9 files changed

+70
-101
lines changed

src/librustc/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#![feature(const_fn)]
4747
#![feature(core_intrinsics)]
4848
#![feature(drain_filter)]
49+
#![feature(i128)]
4950
#![feature(i128_type)]
5051
#![feature(inclusive_range)]
5152
#![feature(inclusive_range_syntax)]

src/librustc/ty/layout.rs

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use syntax_pos::DUMMY_SP;
2020

2121
use std::cmp;
2222
use std::fmt;
23-
use std::i64;
23+
use std::i128;
2424
use std::iter;
2525
use std::mem;
2626
use std::ops::{Add, Sub, Mul, AddAssign, Deref, RangeInclusive};
@@ -467,7 +467,7 @@ impl<'a, 'tcx> Integer {
467467
}
468468

469469
/// Find the smallest Integer type which can represent the signed value.
470-
pub fn fit_signed(x: i64) -> Integer {
470+
pub fn fit_signed(x: i128) -> Integer {
471471
match x {
472472
-0x0000_0000_0000_0001...0x0000_0000_0000_0000 => I1,
473473
-0x0000_0000_0000_0080...0x0000_0000_0000_007f => I8,
@@ -479,7 +479,7 @@ impl<'a, 'tcx> Integer {
479479
}
480480

481481
/// Find the smallest Integer type which can represent the unsigned value.
482-
pub fn fit_unsigned(x: u64) -> Integer {
482+
pub fn fit_unsigned(x: u128) -> Integer {
483483
match x {
484484
0...0x0000_0000_0000_0001 => I1,
485485
0...0x0000_0000_0000_00ff => I8,
@@ -495,7 +495,7 @@ impl<'a, 'tcx> Integer {
495495
let dl = cx.data_layout();
496496

497497
let wanted = align.abi();
498-
for &candidate in &[I8, I16, I32, I64] {
498+
for &candidate in &[I8, I16, I32, I64, I128] {
499499
let ty = Int(candidate, false);
500500
if wanted == ty.align(dl).abi() && wanted == ty.size(dl).bytes() {
501501
return Some(candidate);
@@ -522,19 +522,19 @@ impl<'a, 'tcx> Integer {
522522

523523
/// Find the appropriate Integer type and signedness for the given
524524
/// signed discriminant range and #[repr] attribute.
525-
/// N.B.: u64 values above i64::MAX will be treated as signed, but
525+
/// N.B.: u128 values above i128::MAX will be treated as signed, but
526526
/// that shouldn't affect anything, other than maybe debuginfo.
527527
fn repr_discr(tcx: TyCtxt<'a, 'tcx, 'tcx>,
528528
ty: Ty<'tcx>,
529529
repr: &ReprOptions,
530-
min: i64,
531-
max: i64)
530+
min: i128,
531+
max: i128)
532532
-> (Integer, bool) {
533533
// Theoretically, negative values could be larger in unsigned representation
534534
// than the unsigned representation of the signed minimum. However, if there
535-
// are any negative values, the only valid unsigned representation is u64
536-
// which can fit all i64 values, so the result remains unaffected.
537-
let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u64, max as u64));
535+
// are any negative values, the only valid unsigned representation is u128
536+
// which can fit all i128 values, so the result remains unaffected.
537+
let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u128, max as u128));
538538
let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max));
539539

540540
let mut min_from_extern = None;
@@ -782,11 +782,11 @@ pub enum Variants {
782782
Tagged {
783783
discr: Primitive,
784784
/// Inclusive wrap-around range of discriminant values, that is,
785-
/// if min > max, it represents min..=u64::MAX followed by 0..=max.
785+
/// if min > max, it represents min..=u128::MAX followed by 0..=max.
786786
// FIXME(eddyb) always use the shortest range, e.g. by finding
787787
// the largest space between two consecutive discriminants and
788788
// taking everything else as the (shortest) discriminant range.
789-
discr_range: RangeInclusive<u64>,
789+
discr_range: RangeInclusive<u128>,
790790
variants: Vec<CachedLayout>,
791791
},
792792

@@ -1375,14 +1375,12 @@ impl<'a, 'tcx> CachedLayout {
13751375
}
13761376
}
13771377

1378-
let (mut min, mut max) = (i64::max_value(), i64::min_value());
1378+
let (mut min, mut max) = (i128::max_value(), i128::min_value());
13791379
for discr in def.discriminants(tcx) {
1380-
let x = discr.to_u128_unchecked() as i64;
1380+
let x = discr.to_u128_unchecked() as i128;
13811381
if x < min { min = x; }
13821382
if x > max { max = x; }
13831383
}
1384-
// FIXME: should handle i128? signed-value based impl is weird and hard to
1385-
// grok.
13861384
let (min_ity, signed) = Integer::repr_discr(tcx, ty, &def.repr, min, max);
13871385

13881386
let mut align = dl.aggregate_align;
@@ -1479,9 +1477,7 @@ impl<'a, 'tcx> CachedLayout {
14791477
tcx.intern_layout(CachedLayout {
14801478
variants: Variants::Tagged {
14811479
discr,
1482-
1483-
// FIXME: should be u128?
1484-
discr_range: (min as u64)..=(max as u64),
1480+
discr_range: (min as u128)..=(max as u128),
14851481
variants
14861482
},
14871483
// FIXME(eddyb): using `FieldPlacement::Arbitrary` here results

src/librustc_trans/builder.rs

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use rustc::session::{config, Session};
2424

2525
use std::borrow::Cow;
2626
use std::ffi::CString;
27+
use std::ops::Range;
2728
use std::ptr;
2829
use syntax_pos::Span;
2930

@@ -549,35 +550,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
549550
}
550551

551552

552-
pub fn load_range_assert(&self, ptr: ValueRef, lo: u64,
553-
hi: u64, signed: llvm::Bool,
554-
align: Option<Align>) -> ValueRef {
555-
let value = self.load(ptr, align);
556-
553+
pub fn range_metadata(&self, load: ValueRef, range: Range<u128>) {
557554
unsafe {
558-
let t = llvm::LLVMGetElementType(llvm::LLVMTypeOf(ptr));
559-
let min = llvm::LLVMConstInt(t, lo, signed);
560-
let max = llvm::LLVMConstInt(t, hi, signed);
561-
562-
let v = [min, max];
555+
let llty = val_ty(load);
556+
let v = [
557+
C_uint_big(llty, range.start),
558+
C_uint_big(llty, range.end)
559+
];
563560

564-
llvm::LLVMSetMetadata(value, llvm::MD_range as c_uint,
561+
llvm::LLVMSetMetadata(load, llvm::MD_range as c_uint,
565562
llvm::LLVMMDNodeInContext(self.ccx.llcx(),
566563
v.as_ptr(),
567564
v.len() as c_uint));
568565
}
569-
570-
value
571566
}
572567

573-
pub fn load_nonnull(&self, ptr: ValueRef, align: Option<Align>) -> ValueRef {
574-
let value = self.load(ptr, align);
568+
pub fn nonnull_metadata(&self, load: ValueRef) {
575569
unsafe {
576-
llvm::LLVMSetMetadata(value, llvm::MD_nonnull as c_uint,
570+
llvm::LLVMSetMetadata(load, llvm::MD_nonnull as c_uint,
577571
llvm::LLVMMDNodeInContext(self.ccx.llcx(), ptr::null(), 0));
578572
}
579-
580-
value
581573
}
582574

583575
pub fn store(&self, val: ValueRef, ptr: ValueRef, align: Option<Align>) -> ValueRef {

src/librustc_trans/common.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,9 @@ pub fn C_uint(t: Type, i: u64) -> ValueRef {
178178
}
179179
}
180180

181-
pub fn C_big_integral(t: Type, u: u128) -> ValueRef {
181+
pub fn C_uint_big(t: Type, u: u128) -> ValueRef {
182182
unsafe {
183-
let words = [u as u64, u.wrapping_shr(64) as u64];
183+
let words = [u as u64, (u >> 64) as u64];
184184
llvm::LLVMConstIntOfArbitraryPrecision(t.to_ref(), 2, words.as_ptr())
185185
}
186186
}

src/librustc_trans/meth.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ impl<'a, 'tcx> VirtualIndex {
4040
debug!("get_fn({:?}, {:?})", Value(llvtable), self);
4141

4242
let llvtable = bcx.pointercast(llvtable, fn_ty.llvm_type(bcx.ccx).ptr_to().ptr_to());
43-
let ptr = bcx.load_nonnull(bcx.inbounds_gep(llvtable, &[C_usize(bcx.ccx, self.0)]), None);
43+
let ptr = bcx.load(bcx.inbounds_gep(llvtable, &[C_usize(bcx.ccx, self.0)]), None);
44+
bcx.nonnull_metadata(ptr);
4445
// Vtable loads are invariant
4546
bcx.set_invariant_load(ptr);
4647
ptr

src/librustc_trans/mir/block.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -666,17 +666,18 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
666666

667667
if by_ref && !arg.is_indirect() {
668668
// Have to load the argument, maybe while casting it.
669-
if arg.layout.ty == bcx.tcx().types.bool {
670-
llval = bcx.load_range_assert(llval, 0, 2, llvm::False, None);
671-
// We store bools as i8 so we need to truncate to i1.
672-
llval = base::to_immediate(bcx, llval, arg.layout);
673-
} else if let Some(ty) = arg.cast {
669+
if let Some(ty) = arg.cast {
674670
llval = bcx.load(bcx.pointercast(llval, ty.llvm_type(bcx.ccx).ptr_to()),
675671
(align | Alignment::Packed(arg.layout.align))
676672
.non_abi());
677673
} else {
678674
llval = bcx.load(llval, align.non_abi());
679675
}
676+
if arg.layout.ty == bcx.tcx().types.bool {
677+
bcx.range_metadata(llval, 0..2);
678+
// We store bools as i8 so we need to truncate to i1.
679+
llval = base::to_immediate(bcx, llval, arg.layout);
680+
}
680681
}
681682

682683
llargs.push(llval);

src/librustc_trans/mir/constant.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use abi::{self, Abi};
2828
use callee;
2929
use builder::Builder;
3030
use common::{self, CrateContext, const_get_elt, val_ty};
31-
use common::{C_array, C_bool, C_bytes, C_int, C_uint, C_big_integral, C_u32, C_u64};
31+
use common::{C_array, C_bool, C_bytes, C_int, C_uint, C_uint_big, C_u32, C_u64};
3232
use common::{C_null, C_struct, C_str_slice, C_undef, C_usize, C_vector, C_fat_ptr};
3333
use common::const_to_opt_u128;
3434
use consts;
@@ -70,13 +70,13 @@ impl<'a, 'tcx> Const<'tcx> {
7070
I16(v) => (C_int(Type::i16(ccx), v as i64), tcx.types.i16),
7171
I32(v) => (C_int(Type::i32(ccx), v as i64), tcx.types.i32),
7272
I64(v) => (C_int(Type::i64(ccx), v as i64), tcx.types.i64),
73-
I128(v) => (C_big_integral(Type::i128(ccx), v as u128), tcx.types.i128),
73+
I128(v) => (C_uint_big(Type::i128(ccx), v as u128), tcx.types.i128),
7474
Isize(v) => (C_int(Type::isize(ccx), v.as_i64()), tcx.types.isize),
7575
U8(v) => (C_uint(Type::i8(ccx), v as u64), tcx.types.u8),
7676
U16(v) => (C_uint(Type::i16(ccx), v as u64), tcx.types.u16),
7777
U32(v) => (C_uint(Type::i32(ccx), v as u64), tcx.types.u32),
7878
U64(v) => (C_uint(Type::i64(ccx), v), tcx.types.u64),
79-
U128(v) => (C_big_integral(Type::i128(ccx), v), tcx.types.u128),
79+
U128(v) => (C_uint_big(Type::i128(ccx), v), tcx.types.u128),
8080
Usize(v) => (C_uint(Type::isize(ccx), v.as_u64()), tcx.types.usize),
8181
};
8282
Const { llval: llval, ty: ty }
@@ -994,7 +994,7 @@ unsafe fn cast_const_float_to_int(ccx: &CrateContext,
994994
let err = ConstEvalErr { span: span, kind: ErrKind::CannotCast };
995995
err.report(ccx.tcx(), span, "expression");
996996
}
997-
C_big_integral(int_ty, cast_result.value)
997+
C_uint_big(int_ty, cast_result.value)
998998
}
999999

10001000
unsafe fn cast_const_int_to_float(ccx: &CrateContext,

src/librustc_trans/mir/lvalue.rs

Lines changed: 25 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,9 @@ use rustc::ty::layout::{self, Align, TyLayout, LayoutOf};
1414
use rustc::mir;
1515
use rustc::mir::tcx::LvalueTy;
1616
use rustc_data_structures::indexed_vec::Idx;
17-
use abi;
1817
use base;
1918
use builder::Builder;
20-
use common::{self, CrateContext, C_usize, C_u8, C_u32, C_uint, C_int, C_null, val_ty};
19+
use common::{self, CrateContext, C_usize, C_u8, C_u32, C_uint, C_int, C_null};
2120
use consts;
2221
use type_of::LayoutLlvmExt;
2322
use type_::Type;
@@ -140,30 +139,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
140139
return OperandRef::new_zst(bcx.ccx, self.layout);
141140
}
142141

143-
let val = if common::type_is_fat_ptr(bcx.ccx, self.layout.ty) {
144-
let data = self.project_field(bcx, abi::FAT_PTR_ADDR);
145-
let lldata = if self.layout.ty.is_region_ptr() || self.layout.ty.is_box() {
146-
bcx.load_nonnull(data.llval, data.alignment.non_abi())
147-
} else {
148-
bcx.load(data.llval, data.alignment.non_abi())
149-
};
150-
151-
let extra = self.project_field(bcx, abi::FAT_PTR_EXTRA);
152-
let meta_ty = val_ty(extra.llval);
153-
// If the 'extra' field is a pointer, it's a vtable, so use load_nonnull
154-
// instead
155-
let llextra = if meta_ty.element_type().kind() == llvm::TypeKind::Pointer {
156-
bcx.load_nonnull(extra.llval, extra.alignment.non_abi())
157-
} else {
158-
bcx.load(extra.llval, extra.alignment.non_abi())
159-
};
160-
161-
OperandValue::Pair(lldata, llextra)
162-
} else if common::type_is_imm_pair(bcx.ccx, self.layout.ty) {
163-
OperandValue::Pair(
164-
self.project_field(bcx, 0).load(bcx).pack_if_pair(bcx).immediate(),
165-
self.project_field(bcx, 1).load(bcx).pack_if_pair(bcx).immediate())
166-
} else if self.layout.is_llvm_immediate() {
142+
let val = if self.layout.is_llvm_immediate() {
167143
let mut const_llval = ptr::null_mut();
168144
unsafe {
169145
let global = llvm::LLVMIsAGlobalVariable(self.llval);
@@ -174,22 +150,26 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
174150

175151
let llval = if !const_llval.is_null() {
176152
const_llval
177-
} else if self.layout.ty.is_bool() {
178-
bcx.load_range_assert(self.llval, 0, 2, llvm::False,
179-
self.alignment.non_abi())
180-
} else if self.layout.ty.is_char() {
181-
// a char is a Unicode codepoint, and so takes values from 0
182-
// to 0x10FFFF inclusive only.
183-
bcx.load_range_assert(self.llval, 0, 0x10FFFF + 1, llvm::False,
184-
self.alignment.non_abi())
185-
} else if self.layout.ty.is_region_ptr() ||
186-
self.layout.ty.is_box() ||
187-
self.layout.ty.is_fn() {
188-
bcx.load_nonnull(self.llval, self.alignment.non_abi())
189153
} else {
190-
bcx.load(self.llval, self.alignment.non_abi())
154+
let load = bcx.load(self.llval, self.alignment.non_abi());
155+
if self.layout.ty.is_bool() {
156+
bcx.range_metadata(load, 0..2);
157+
} else if self.layout.ty.is_char() {
158+
// a char is a Unicode codepoint, and so takes values from 0
159+
// to 0x10FFFF inclusive only.
160+
bcx.range_metadata(load, 0..0x10FFFF+1);
161+
} else if self.layout.ty.is_region_ptr() ||
162+
self.layout.ty.is_box() ||
163+
self.layout.ty.is_fn() {
164+
bcx.nonnull_metadata(load);
165+
}
166+
load
191167
};
192168
OperandValue::Immediate(base::to_immediate(bcx, llval, self.layout))
169+
} else if common::type_is_imm_pair(bcx.ccx, self.layout.ty) {
170+
OperandValue::Pair(
171+
self.project_field(bcx, 0).load(bcx).pack_if_pair(bcx).immediate(),
172+
self.project_field(bcx, 1).load(bcx).pack_if_pair(bcx).immediate())
193173
} else {
194174
OperandValue::Ref(self.llval, self.alignment)
195175
};
@@ -314,28 +294,26 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
314294
layout::Variants::Tagged { ref discr_range, .. } => {
315295
(discr_range.start, discr_range.end)
316296
}
317-
_ => (0, u64::max_value()),
297+
_ => (0, !0),
318298
};
319299
let max_next = max.wrapping_add(1);
320300
let bits = discr_scalar.size(bcx.ccx).bits();
321-
assert!(bits <= 64);
322-
let mask = !0u64 >> (64 - bits);
323-
let lldiscr = match discr_scalar {
301+
assert!(bits <= 128);
302+
let mask = !0u128 >> (128 - bits);
303+
let lldiscr = bcx.load(discr.llval, discr.alignment.non_abi());
304+
match discr_scalar {
324305
// For a (max) discr of -1, max will be `-1 as usize`, which overflows.
325306
// However, that is fine here (it would still represent the full range),
326307
layout::Int(..) if max_next & mask != min & mask => {
327308
// llvm::ConstantRange can deal with ranges that wrap around,
328309
// so an overflow on (max + 1) is fine.
329-
bcx.load_range_assert(discr.llval, min, max_next,
330-
/* signed: */ llvm::True,
331-
discr.alignment.non_abi())
310+
bcx.range_metadata(lldiscr, min..max_next);
332311
}
333312
_ => {
334313
// i.e., if the range is everything. The lo==hi case would be
335314
// rejected by the LLVM verifier (it would mean either an
336315
// empty set, which is impossible, or the entire range of the
337316
// type, which is pointless).
338-
bcx.load(discr.llval, discr.alignment.non_abi())
339317
}
340318
};
341319
match self.layout.variants {

0 commit comments

Comments
 (0)