Skip to content

Commit a08f061

Browse files
authored
Merge pull request rust-lang#67 from oli-obk/master
fix multi field enum variants and some intrinsics + rustup
2 parents 2080fae + de38015 commit a08f061

File tree

11 files changed

+455
-86
lines changed

11 files changed

+455
-86
lines changed

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ log = "0.3.6"
2121
log_settings = "0.1.1"
2222

2323
[dev-dependencies]
24-
compiletest_rs = "0.2"
24+
compiletest_rs = "0.2.3"

src/bin/miri.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,5 +138,5 @@ fn main() {
138138
args.push(find_sysroot());
139139
}
140140

141-
rustc_driver::run_compiler(&args, &mut MiriCompilerCalls);
141+
rustc_driver::run_compiler(&args, &mut MiriCompilerCalls, None, None);
142142
}

src/interpreter/mod.rs

Lines changed: 25 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -73,23 +73,13 @@ pub struct Frame<'a, 'tcx: 'a> {
7373
// Return pointer and local allocations
7474
////////////////////////////////////////////////////////////////////////////////
7575

76-
/// A pointer for writing the return value of the current call if it's not a diverging call.
77-
pub return_ptr: Option<Pointer>,
78-
7976
/// The block to return to when returning from the current stack frame
8077
pub return_to_block: StackPopCleanup,
8178

8279
/// The list of locals for the current function, stored in order as
83-
/// `[arguments..., variables..., temporaries...]`. The variables begin at `self.var_offset`
84-
/// and the temporaries at `self.temp_offset`.
80+
/// `[return_ptr, arguments..., variables..., temporaries...]`.
8581
pub locals: Vec<Pointer>,
8682

87-
/// The offset of the first variable in `self.locals`.
88-
pub var_offset: usize,
89-
90-
/// The offset of the first temporary in `self.locals`.
91-
pub temp_offset: usize,
92-
9383
////////////////////////////////////////////////////////////////////////////////
9484
// Current position within the function
9585
////////////////////////////////////////////////////////////////////////////////
@@ -336,32 +326,26 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
336326
span: codemap::Span,
337327
mir: CachedMir<'a, 'tcx>,
338328
substs: &'tcx Substs<'tcx>,
339-
return_ptr: Option<Pointer>,
329+
return_ptr: Pointer,
340330
return_to_block: StackPopCleanup,
341331
) -> EvalResult<'tcx, ()> {
342-
let arg_tys = mir.arg_decls.iter().map(|a| a.ty);
343-
let var_tys = mir.var_decls.iter().map(|v| v.ty);
344-
let temp_tys = mir.temp_decls.iter().map(|t| t.ty);
345-
346-
let num_args = mir.arg_decls.len();
347-
let num_vars = mir.var_decls.len();
332+
let local_tys = mir.local_decls.iter().map(|a| a.ty);
348333

349334
::log_settings::settings().indentation += 1;
350335

351-
let locals: EvalResult<'tcx, Vec<Pointer>> = arg_tys.chain(var_tys).chain(temp_tys).map(|ty| {
336+
// directly change the first allocation (the return value) to *be* the allocation where the
337+
// caller stores the result
338+
let locals: EvalResult<'tcx, Vec<Pointer>> = iter::once(Ok(return_ptr)).chain(local_tys.skip(1).map(|ty| {
352339
let size = self.type_size_with_substs(ty, substs);
353340
let align = self.type_align_with_substs(ty, substs);
354341
self.memory.allocate(size, align)
355-
}).collect();
342+
})).collect();
356343

357344
self.stack.push(Frame {
358345
mir: mir.clone(),
359346
block: mir::START_BLOCK,
360-
return_ptr: return_ptr,
361347
return_to_block: return_to_block,
362348
locals: locals?,
363-
var_offset: num_args,
364-
temp_offset: num_args + num_vars,
365349
span: span,
366350
def_id: def_id,
367351
substs: substs,
@@ -793,11 +777,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
793777
fn eval_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult<'tcx, Lvalue> {
794778
use rustc::mir::repr::Lvalue::*;
795779
let ptr = match *lvalue {
796-
ReturnPointer => self.frame().return_ptr
797-
.expect("ReturnPointer used in a function with no return value"),
798-
Arg(i) => self.frame().locals[i.index()],
799-
Var(i) => self.frame().locals[self.frame().var_offset + i.index()],
800-
Temp(i) => self.frame().locals[self.frame().temp_offset + i.index()],
780+
Local(i) => self.frame().locals[i.index()],
801781

802782
Static(def_id) => {
803783
let substs = subst::Substs::empty(self.tcx);
@@ -819,11 +799,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
819799
Field(field, field_ty) => {
820800
let field_ty = self.monomorphize(field_ty, self.substs());
821801
use rustc::ty::layout::Layout::*;
822-
let variant = match *base_layout {
823-
Univariant { ref variant, .. } => variant,
802+
let field = field.index();
803+
let offset = match *base_layout {
804+
Univariant { ref variant, .. } => variant.field_offset(field),
824805
General { ref variants, .. } => {
825806
if let LvalueExtra::DowncastVariant(variant_idx) = base.extra {
826-
&variants[variant_idx]
807+
// +1 for the discriminant, which is field 0
808+
variants[variant_idx].field_offset(field + 1)
827809
} else {
828810
bug!("field access on enum had no variant index");
829811
}
@@ -832,14 +814,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
832814
assert_eq!(field.index(), 0);
833815
return Ok(base);
834816
}
835-
StructWrappedNullablePointer { ref nonnull, .. } => nonnull,
817+
StructWrappedNullablePointer { ref nonnull, .. } => nonnull.field_offset(field),
836818
_ => bug!("field access on non-product type: {:?}", base_layout),
837819
};
838820

839-
let offset = variant.field_offset(field.index()).bytes();
840-
let ptr = base.ptr.offset(offset as isize);
841-
trace!("{:?}", base);
842-
trace!("{:?}", field_ty);
821+
let ptr = base.ptr.offset(offset.bytes() as isize);
843822
if self.type_is_sized(field_ty) {
844823
ptr
845824
} else {
@@ -859,9 +838,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
859838
Downcast(_, variant) => {
860839
use rustc::ty::layout::Layout::*;
861840
match *base_layout {
862-
General { ref variants, .. } => {
841+
General { .. } => {
863842
return Ok(Lvalue {
864-
ptr: base.ptr.offset(variants[variant].field_offset(1).bytes() as isize),
843+
ptr: base.ptr,
865844
extra: LvalueExtra::DowncastVariant(variant),
866845
});
867846
}
@@ -1220,18 +1199,17 @@ pub fn eval_main<'a, 'tcx: 'a>(
12201199
let return_ptr = ecx.alloc_ret_ptr(mir.return_ty, substs)
12211200
.expect("should at least be able to allocate space for the main function's return value");
12221201

1223-
ecx.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, Some(return_ptr), StackPopCleanup::None)
1202+
ecx.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, return_ptr, StackPopCleanup::None)
12241203
.expect("could not allocate first stack frame");
12251204

1226-
if mir.arg_decls.len() == 2 {
1205+
// FIXME: this is a horrible and wrong way to detect the start function, but overwriting the first two locals shouldn't do much
1206+
if mir.local_decls.len() > 2 {
12271207
// start function
1228-
let ptr_size = ecx.memory().pointer_size();
1229-
let nargs = ecx.memory_mut().allocate(ptr_size, ptr_size).expect("can't allocate memory for nargs");
1230-
ecx.memory_mut().write_usize(nargs, 0).unwrap();
1231-
let args = ecx.memory_mut().allocate(ptr_size, ptr_size).expect("can't allocate memory for arg pointer");
1232-
ecx.memory_mut().write_usize(args, 0).unwrap();
1233-
ecx.frame_mut().locals[0] = nargs;
1234-
ecx.frame_mut().locals[1] = args;
1208+
let nargs = ecx.frame_mut().locals[1];
1209+
let args = ecx.frame_mut().locals[2];
1210+
// ignore errors, if the locals are too small this is not the start function
1211+
let _ = ecx.memory_mut().write_usize(nargs, 0);
1212+
let _ = ecx.memory_mut().write_usize(args, 0);
12351213
}
12361214

12371215
for _ in 0..step_limit {

src/interpreter/step.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ impl<'a, 'b, 'tcx> ConstantExtractor<'a, 'b, 'tcx> {
134134
} else {
135135
StackPopCleanup::None
136136
};
137-
this.ecx.push_stack_frame(def_id, span, mir, substs, Some(ptr), cleanup)
137+
this.ecx.push_stack_frame(def_id, span, mir, substs, ptr, cleanup)
138138
});
139139
}
140140
fn try<F: FnOnce(&mut Self) -> EvalResult<'tcx, ()>>(&mut self, f: F) {
@@ -183,7 +183,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> {
183183
constant.span,
184184
mir,
185185
this.substs,
186-
Some(return_ptr),
186+
return_ptr,
187187
StackPopCleanup::Freeze(return_ptr.alloc_id))
188188
});
189189
}

src/interpreter/terminator/intrinsics.rs

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
3131
let f32 = self.tcx.types.f32;
3232
let f64 = self.tcx.types.f64;
3333

34-
match &self.tcx.item_name(def_id).as_str()[..] {
34+
let intrinsic_name = &self.tcx.item_name(def_id).as_str()[..];
35+
match intrinsic_name {
3536
"add_with_overflow" => self.intrinsic_with_overflow(mir::BinOp::Add, &args[0], &args[1], dest, dest_layout)?,
3637
"sub_with_overflow" => self.intrinsic_with_overflow(mir::BinOp::Sub, &args[0], &args[1], dest, dest_layout)?,
3738
"mul_with_overflow" => self.intrinsic_with_overflow(mir::BinOp::Mul, &args[0], &args[1], dest, dest_layout)?,
@@ -64,30 +65,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
6465
self.memory.copy(src, dest, count as usize * elem_size, elem_align)?;
6566
}
6667

67-
"ctpop" => {
68+
"ctpop" |
69+
"cttz" |
70+
"ctlz" |
71+
"bswap" => {
6872
let elem_ty = substs.type_at(0);
69-
let elem_size = self.type_size(elem_ty);
70-
let num = self.value_to_primval(args_ptrs[2], elem_ty)?.expect_int("ctpop second arg not integral");
71-
let num = num.count_ones();
72-
self.memory.write_uint(dest, num.into(), elem_size)?;
73-
}
74-
75-
"ctlz" => {
76-
let elem_ty = substs.type_at(0);
77-
let elem_size = self.type_size(elem_ty);
78-
let num = self.value_to_primval(args_ptrs[2], elem_ty)?;
79-
let num = match num {
80-
PrimVal::I8(i) => i.leading_zeros(),
81-
PrimVal::U8(i) => i.leading_zeros(),
82-
PrimVal::I16(i) => i.leading_zeros(),
83-
PrimVal::U16(i) => i.leading_zeros(),
84-
PrimVal::I32(i) => i.leading_zeros(),
85-
PrimVal::U32(i) => i.leading_zeros(),
86-
PrimVal::I64(i) => i.leading_zeros(),
87-
PrimVal::U64(i) => i.leading_zeros(),
88-
_ => bug!("ctlz called with non-integer type"),
89-
};
90-
self.memory.write_uint(dest, num.into(), elem_size)?;
73+
let num = self.value_to_primval(args_ptrs[0], elem_ty)?;
74+
let num = numeric_intrinsic(intrinsic_name, num);
75+
self.memory.write_primval(dest, num)?;
9176
}
9277

9378
"discriminant_value" => {
@@ -350,3 +335,54 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
350335
self.tcx.normalize_associated_type(&f.ty(self.tcx, param_substs))
351336
}
352337
}
338+
339+
fn numeric_intrinsic(name: &str, val: PrimVal) -> PrimVal {
340+
use primval::PrimVal::*;
341+
match name {
342+
"ctpop" => match val {
343+
I8(i) => I8(i.count_ones() as i8),
344+
U8(i) => U8(i.count_ones() as u8),
345+
I16(i) => I16(i.count_ones() as i16),
346+
U16(i) => U16(i.count_ones() as u16),
347+
I32(i) => I32(i.count_ones() as i32),
348+
U32(i) => U32(i.count_ones() as u32),
349+
I64(i) => I64(i.count_ones() as i64),
350+
U64(i) => U64(i.count_ones() as u64),
351+
other => bug!("invalid `ctpop` argument: {:?}", other),
352+
},
353+
"cttz" => match val {
354+
I8(i) => I8(i.trailing_zeros() as i8),
355+
U8(i) => U8(i.trailing_zeros() as u8),
356+
I16(i) => I16(i.trailing_zeros() as i16),
357+
U16(i) => U16(i.trailing_zeros() as u16),
358+
I32(i) => I32(i.trailing_zeros() as i32),
359+
U32(i) => U32(i.trailing_zeros() as u32),
360+
I64(i) => I64(i.trailing_zeros() as i64),
361+
U64(i) => U64(i.trailing_zeros() as u64),
362+
other => bug!("invalid `cttz` argument: {:?}", other),
363+
},
364+
"ctlz" => match val {
365+
I8(i) => I8(i.leading_zeros() as i8),
366+
U8(i) => U8(i.leading_zeros() as u8),
367+
I16(i) => I16(i.leading_zeros() as i16),
368+
U16(i) => U16(i.leading_zeros() as u16),
369+
I32(i) => I32(i.leading_zeros() as i32),
370+
U32(i) => U32(i.leading_zeros() as u32),
371+
I64(i) => I64(i.leading_zeros() as i64),
372+
U64(i) => U64(i.leading_zeros() as u64),
373+
other => bug!("invalid `ctlz` argument: {:?}", other),
374+
},
375+
"bswap" => match val {
376+
I8(i) => I8(i.swap_bytes() as i8),
377+
U8(i) => U8(i.swap_bytes() as u8),
378+
I16(i) => I16(i.swap_bytes() as i16),
379+
U16(i) => U16(i.swap_bytes() as u16),
380+
I32(i) => I32(i.swap_bytes() as i32),
381+
U32(i) => U32(i.swap_bytes() as u32),
382+
I64(i) => I64(i.swap_bytes() as i64),
383+
U64(i) => U64(i.swap_bytes() as u64),
384+
other => bug!("invalid `bswap` argument: {:?}", other),
385+
},
386+
_ => bug!("not a numeric intrinsic: {}", name),
387+
}
388+
}

src/interpreter/terminator/mod.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
186186

187187
let mir = self.load_mir(resolved_def_id)?;
188188
let (return_ptr, return_to_block) = match destination {
189-
Some((ptr, block)) => (Some(ptr), StackPopCleanup::Goto(block)),
190-
None => (None, StackPopCleanup::None),
189+
Some((ptr, block)) => (ptr, StackPopCleanup::Goto(block)),
190+
None => (Pointer::never_ptr(), StackPopCleanup::None),
191191
};
192192
self.push_stack_frame(resolved_def_id, span, mir, resolved_substs, return_ptr, return_to_block)?;
193193

194194
for (i, (arg_val, arg_ty)) in args.into_iter().enumerate() {
195-
let dest = self.frame().locals[i];
195+
// argument start at index 1, since index 0 is reserved for the return allocation
196+
let dest = self.frame().locals[i + 1];
196197
self.write_value(arg_val, dest, arg_ty)?;
197198
}
198199

src/memory.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,10 @@ impl Pointer {
5656
self.alloc_id == ZST_ALLOC_ID
5757
}
5858
pub fn to_int<'tcx>(&self) -> EvalResult<'tcx, usize> {
59-
if self.points_to_zst() {
60-
Ok(self.offset)
61-
} else {
62-
Err(EvalError::ReadPointerAsBytes)
59+
match self.alloc_id {
60+
NEVER_ALLOC_ID |
61+
ZST_ALLOC_ID => Ok(self.offset),
62+
_ => Err(EvalError::ReadPointerAsBytes),
6363
}
6464
}
6565
pub fn from_int(i: usize) -> Self {
@@ -74,6 +74,12 @@ impl Pointer {
7474
offset: 0,
7575
}
7676
}
77+
pub fn never_ptr() -> Self {
78+
Pointer {
79+
alloc_id: NEVER_ALLOC_ID,
80+
offset: 0,
81+
}
82+
}
7783
}
7884

7985
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
@@ -115,14 +121,15 @@ pub struct Memory<'a, 'tcx> {
115121
}
116122

117123
const ZST_ALLOC_ID: AllocId = AllocId(0);
124+
const NEVER_ALLOC_ID: AllocId = AllocId(1);
118125

119126
impl<'a, 'tcx> Memory<'a, 'tcx> {
120127
pub fn new(layout: &'a TargetDataLayout, max_memory: usize) -> Self {
121128
Memory {
122129
alloc_map: HashMap::new(),
123130
functions: HashMap::new(),
124131
function_alloc_cache: HashMap::new(),
125-
next_id: AllocId(1),
132+
next_id: AllocId(2),
126133
layout: layout,
127134
memory_size: max_memory,
128135
memory_usage: 0,

0 commit comments

Comments
 (0)