Skip to content

Commit e7bcf35

Browse files
committed
Simplify PrimValKind and remove a horrible hack.
This takes the `AllocId` out of PrimValKind, replacing it with a `relocation` field on `PrimVal`, which is closer to an earlier design for `PrimVal` I discussed with @eddyb. This commit prepares the code for removing the `PrimValKind` from `PrimVal` and making them more pure bitbags. The only code dealing with `PrimValKind` will be code making decisions like "what kind of operation do I need to do on these bits", like operators and casting. Transmutes of `PrimVal`s will become true no-ops, not even adjusting a `kind` field. This commit also removes my horrible `value_to_primval` hack that made an allocation for every `ByVal` passed in, so it could use `read_value` to get a `PrimVal` with the right kind. Now I just compute the `PrimValKind` from the `Ty` and re-tag the `PrimVal`. The code got slightly messier in some areas here, but I think a _lot_ of code will simplify in obvious ways once I remove the `kind` field from `PrimVal`. Gosh, if my commit messages aren't turning into essays these days.
1 parent 330be77 commit e7bcf35

File tree

7 files changed

+214
-150
lines changed

7 files changed

+214
-150
lines changed

src/interpreter/cast.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
2121

2222
Bool | Char | U8 | U16 | U32 | U64 => self.cast_int(val.bits, ty, false),
2323

24-
FnPtr(alloc) | Ptr(alloc) => {
25-
let ptr = Pointer::new(alloc, val.bits as usize);
24+
FnPtr | Ptr => {
25+
let ptr = val.expect_ptr("FnPtr- or Ptr-tagged PrimVal had no relocation");
2626
self.cast_ptr(ptr, ty)
2727
}
2828
}

src/interpreter/mod.rs

Lines changed: 87 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -972,7 +972,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
972972
}
973973

974974
Deref => {
975-
use primval::PrimValKind::*;
976975
use interpreter::value::Value::*;
977976

978977
let val = match self.eval_and_read_lvalue(&proj.base)? {
@@ -981,22 +980,21 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
981980
};
982981

983982
match val {
984-
ByValPair(
985-
PrimVal { kind: Ptr(ptr_alloc), bits: ptr_offset },
986-
PrimVal { kind: Ptr(vtable_alloc), bits: vtable_offset },
987-
) => {
988-
let ptr = Pointer::new(ptr_alloc, ptr_offset as usize);
989-
let vtable = Pointer::new(vtable_alloc, vtable_offset as usize);
983+
ByValPair(ptr, vtable)
984+
if ptr.try_as_ptr().is_some() && vtable.try_as_ptr().is_some()
985+
=> {
986+
let ptr = ptr.try_as_ptr().unwrap();
987+
let vtable = vtable.try_as_ptr().unwrap();
990988
(ptr, LvalueExtra::Vtable(vtable))
991989
}
992990

993-
ByValPair(PrimVal { kind: Ptr(alloc), bits: offset }, n) => {
994-
let ptr = Pointer::new(alloc, offset as usize);
991+
ByValPair(ptr, n) if ptr.try_as_ptr().is_some() => {
992+
let ptr = ptr.try_as_ptr().unwrap();
995993
(ptr, LvalueExtra::Length(n.expect_uint("slice length")))
996994
}
997995

998-
ByVal(PrimVal { kind: Ptr(alloc), bits: offset }) => {
999-
let ptr = Pointer::new(alloc, offset as usize);
996+
ByVal(ptr) if ptr.try_as_ptr().is_some() => {
997+
let ptr = ptr.try_as_ptr().unwrap();
1000998
(ptr, LvalueExtra::None)
1001999
}
10021000

@@ -1122,39 +1120,20 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
11221120
Value::ByValPair(..) => bug!("value_to_primval can't work with fat pointers"),
11231121
},
11241122

1125-
// FIXME(solson): This unnecessarily allocates to work around a new issue my `Value`
1126-
// locals refactoring introduced. There is code that calls this function and expects to
1127-
// get a PrimVal reflecting the specific type that it asked for, e.g. `PrimVal::Bool`
1128-
// when it was asking for `TyBool`. This used to always work because it would go
1129-
// through `read_value` which does the right thing.
1130-
//
1131-
// This is the comment and implementation from before my refactor:
1132-
//
1133-
// TODO(solson): Sanity-check the primval type against the input type.
1134-
// Value::ByVal(primval) => Ok(primval),
1135-
//
1136-
// Turns out sanity-checking isn't enough now, and we need conversion.
1137-
//
1138-
// Now that we can possibly be reading a `ByVal` straight out of the locals vec, if the
1139-
// user did something tricky like transmuting a `u8` to a `bool`, then we'll have a
1140-
// `PrimVal::U8` and need to convert to `PrimVal::Bool`.
1141-
//
1142-
// I want to avoid handling the full set of conversions between `PrimVal`s, so for now
1143-
// I will use this hack. I have a plan to change the representation of `PrimVal` to be
1144-
// more like a small piece of memory tagged with a `PrimValKind`, which should make the
1145-
// conversion easy and make the problem solveable using code already in `Memory`.
11461123
Value::ByVal(primval) => {
1147-
let ptr = self.alloc_ptr(ty)?;
1148-
self.memory.write_primval(ptr, primval)?;
1149-
let primval = self.value_to_primval(Value::ByRef(ptr), ty)?;
1150-
self.memory.deallocate(ptr)?;
1151-
Ok(primval)
1124+
let new_primval = self.transmute_primval(primval, ty)?;
1125+
self.ensure_valid_value(new_primval, ty)?;
1126+
Ok(new_primval)
11521127
}
11531128

11541129
Value::ByValPair(..) => bug!("value_to_primval can't work with fat pointers"),
11551130
}
11561131
}
11571132

1133+
fn transmute_primval(&self, val: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
1134+
Ok(PrimVal { kind: self.ty_to_primval_kind(ty)?, ..val })
1135+
}
1136+
11581137
fn write_primval(
11591138
&mut self,
11601139
dest: Lvalue,
@@ -1252,6 +1231,77 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
12521231
Ok(())
12531232
}
12541233

1234+
fn ty_to_primval_kind(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimValKind> {
1235+
use syntax::ast::FloatTy;
1236+
1237+
let kind = match ty.sty {
1238+
ty::TyBool => PrimValKind::Bool,
1239+
ty::TyChar => PrimValKind::Char,
1240+
1241+
ty::TyInt(int_ty) => {
1242+
use syntax::ast::IntTy::*;
1243+
let size = match int_ty {
1244+
I8 => 1,
1245+
I16 => 2,
1246+
I32 => 4,
1247+
I64 => 8,
1248+
Is => self.memory.pointer_size(),
1249+
};
1250+
PrimValKind::from_int_size(size)
1251+
}
1252+
1253+
ty::TyUint(uint_ty) => {
1254+
use syntax::ast::UintTy::*;
1255+
let size = match uint_ty {
1256+
U8 => 1,
1257+
U16 => 2,
1258+
U32 => 4,
1259+
U64 => 8,
1260+
Us => self.memory.pointer_size(),
1261+
};
1262+
PrimValKind::from_uint_size(size)
1263+
}
1264+
1265+
ty::TyFloat(FloatTy::F32) => PrimValKind::F32,
1266+
ty::TyFloat(FloatTy::F64) => PrimValKind::F64,
1267+
1268+
ty::TyFnPtr(_) => PrimValKind::FnPtr,
1269+
1270+
ty::TyBox(ty) |
1271+
ty::TyRef(_, ty::TypeAndMut { ty, .. }) |
1272+
ty::TyRawPtr(ty::TypeAndMut { ty, .. }) if self.type_is_sized(ty) => PrimValKind::Ptr,
1273+
1274+
ty::TyAdt(..) => {
1275+
use rustc::ty::layout::Layout::*;
1276+
if let CEnum { discr, signed, .. } = *self.type_layout(ty) {
1277+
let size = discr.size().bytes() as usize;
1278+
if signed {
1279+
PrimValKind::from_int_size(size)
1280+
} else {
1281+
PrimValKind::from_uint_size(size)
1282+
}
1283+
} else {
1284+
bug!("primitive read of non-clike enum: {:?}", ty);
1285+
}
1286+
},
1287+
1288+
_ => bug!("primitive read of non-primitive type: {:?}", ty),
1289+
};
1290+
1291+
Ok(kind)
1292+
}
1293+
1294+
fn ensure_valid_value(&self, val: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx, ()> {
1295+
match ty.sty {
1296+
ty::TyBool if val.bits > 1 => Err(EvalError::InvalidBool),
1297+
1298+
ty::TyChar if ::std::char::from_u32(val.bits as u32).is_none()
1299+
=> Err(EvalError::InvalidChar(val.bits as u32 as u64)),
1300+
1301+
_ => Ok(()),
1302+
}
1303+
}
1304+
12551305
fn read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
12561306
use syntax::ast::FloatTy;
12571307

src/interpreter/terminator/intrinsics.rs

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
1919
dest_ty: Ty<'tcx>,
2020
dest_layout: &'tcx Layout,
2121
) -> EvalResult<'tcx, ()> {
22-
let args_ptrs: EvalResult<Vec<Value>> = args.iter()
22+
let arg_vals: EvalResult<Vec<Value>> = args.iter()
2323
.map(|arg| self.eval_operand(arg))
2424
.collect();
25-
let args_ptrs = args_ptrs?;
25+
let arg_vals = arg_vals?;
2626
let i32 = self.tcx.types.i32;
2727
let isize = self.tcx.types.isize;
2828
let usize = self.tcx.types.usize;
@@ -42,32 +42,31 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
4242

4343

4444
"arith_offset" => {
45-
let ptr = args_ptrs[0].read_ptr(&self.memory)?;
46-
let offset = self.value_to_primval(args_ptrs[1], isize)?
45+
let ptr = arg_vals[0].read_ptr(&self.memory)?;
46+
let offset = self.value_to_primval(arg_vals[1], isize)?
4747
.expect_int("arith_offset second arg not isize");
4848
let new_ptr = ptr.offset(offset as isize);
4949
self.write_primval(dest, PrimVal::from_ptr(new_ptr))?;
5050
}
5151

5252
"assume" => {
5353
let bool = self.tcx.types.bool;
54-
let cond = self.value_to_primval(args_ptrs[0], bool)?
55-
.expect_bool("assume arg not bool");
54+
let cond = self.value_to_primval(arg_vals[0], bool)?.try_as_bool()?;
5655
if !cond { return Err(EvalError::AssumptionNotHeld); }
5756
}
5857

5958
"atomic_load" |
6059
"volatile_load" => {
6160
let ty = substs.type_at(0);
62-
let ptr = args_ptrs[0].read_ptr(&self.memory)?;
61+
let ptr = arg_vals[0].read_ptr(&self.memory)?;
6362
self.write_value(Value::ByRef(ptr), dest, ty)?;
6463
}
6564

6665
"atomic_store" |
6766
"volatile_store" => {
6867
let ty = substs.type_at(0);
69-
let dest = args_ptrs[0].read_ptr(&self.memory)?;
70-
self.write_value_to_ptr(args_ptrs[1], dest, ty)?;
68+
let dest = arg_vals[0].read_ptr(&self.memory)?;
69+
self.write_value_to_ptr(arg_vals[1], dest, ty)?;
7170
}
7271

7372
"breakpoint" => unimplemented!(), // halt miri
@@ -78,9 +77,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
7877
let elem_ty = substs.type_at(0);
7978
let elem_size = self.type_size(elem_ty);
8079
let elem_align = self.type_align(elem_ty);
81-
let src = args_ptrs[0].read_ptr(&self.memory)?;
82-
let dest = args_ptrs[1].read_ptr(&self.memory)?;
83-
let count = self.value_to_primval(args_ptrs[2], usize)?
80+
let src = arg_vals[0].read_ptr(&self.memory)?;
81+
let dest = arg_vals[1].read_ptr(&self.memory)?;
82+
let count = self.value_to_primval(arg_vals[2], usize)?
8483
.expect_uint("arith_offset second arg not isize");
8584
self.memory.copy(src, dest, count as usize * elem_size, elem_align)?;
8685
}
@@ -90,34 +89,34 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
9089
"ctlz" |
9190
"bswap" => {
9291
let elem_ty = substs.type_at(0);
93-
let num = self.value_to_primval(args_ptrs[0], elem_ty)?;
92+
let num = self.value_to_primval(arg_vals[0], elem_ty)?;
9493
let num = numeric_intrinsic(intrinsic_name, num);
9594
self.write_primval(dest, num)?;
9695
}
9796

9897
"discriminant_value" => {
9998
let ty = substs.type_at(0);
100-
let adt_ptr = args_ptrs[0].read_ptr(&self.memory)?;
99+
let adt_ptr = arg_vals[0].read_ptr(&self.memory)?;
101100
let discr_val = self.read_discriminant_value(adt_ptr, ty)?;
102101
self.write_primval(dest, PrimVal::new(discr_val, PrimValKind::U64))?;
103102
}
104103

105104
"fabsf32" => {
106-
let f = self.value_to_primval(args_ptrs[2], f32)?
105+
let f = self.value_to_primval(arg_vals[2], f32)?
107106
.expect_f32("fabsf32 read non f32");
108107
self.write_primval(dest, PrimVal::from_f32(f.abs()))?;
109108
}
110109

111110
"fabsf64" => {
112-
let f = self.value_to_primval(args_ptrs[2], f64)?
111+
let f = self.value_to_primval(arg_vals[2], f64)?
113112
.expect_f64("fabsf64 read non f64");
114113
self.write_primval(dest, PrimVal::from_f64(f.abs()))?;
115114
}
116115

117116
"fadd_fast" => {
118117
let ty = substs.type_at(0);
119-
let a = self.value_to_primval(args_ptrs[0], ty)?;
120-
let b = self.value_to_primval(args_ptrs[0], ty)?;
118+
let a = self.value_to_primval(arg_vals[0], ty)?;
119+
let b = self.value_to_primval(arg_vals[0], ty)?;
121120
let result = primval::binary_op(mir::BinOp::Add, a, b)?;
122121
self.write_primval(dest, result.0)?;
123122
}
@@ -151,8 +150,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
151150

152151
"move_val_init" => {
153152
let ty = substs.type_at(0);
154-
let ptr = args_ptrs[0].read_ptr(&self.memory)?;
155-
self.write_value_to_ptr(args_ptrs[1], ptr, ty)?;
153+
let ptr = arg_vals[0].read_ptr(&self.memory)?;
154+
self.write_value_to_ptr(arg_vals[1], ptr, ty)?;
156155
}
157156

158157
"needs_drop" => {
@@ -165,10 +164,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
165164
"offset" => {
166165
let pointee_ty = substs.type_at(0);
167166
let pointee_size = self.type_size(pointee_ty) as isize;
168-
let offset = self.value_to_primval(args_ptrs[1], isize)?
167+
let offset = self.value_to_primval(arg_vals[1], isize)?
169168
.expect_int("offset second arg not isize");
170169

171-
let ptr = args_ptrs[0].read_ptr(&self.memory)?;
170+
let ptr = arg_vals[0].read_ptr(&self.memory)?;
172171
let result_ptr = ptr.offset(offset as isize * pointee_size);
173172
self.write_primval(dest, PrimVal::from_ptr(result_ptr))?;
174173
}
@@ -186,29 +185,29 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
186185
}
187186

188187
"powif32" => {
189-
let f = self.value_to_primval(args_ptrs[0], f32)?
188+
let f = self.value_to_primval(arg_vals[0], f32)?
190189
.expect_f32("powif32 first arg not f32");
191-
let i = self.value_to_primval(args_ptrs[1], i32)?
190+
let i = self.value_to_primval(arg_vals[1], i32)?
192191
.expect_int("powif32 second arg not i32");
193192
self.write_primval(dest, PrimVal::from_f32(f.powi(i as i32)))?;
194193
}
195194

196195
"powif64" => {
197-
let f = self.value_to_primval(args_ptrs[0], f64)?
196+
let f = self.value_to_primval(arg_vals[0], f64)?
198197
.expect_f64("powif64 first arg not f64");
199-
let i = self.value_to_primval(args_ptrs[1], i32)?
198+
let i = self.value_to_primval(arg_vals[1], i32)?
200199
.expect_int("powif64 second arg not i32");
201200
self.write_primval(dest, PrimVal::from_f64(f.powi(i as i32)))?;
202201
}
203202

204203
"sqrtf32" => {
205-
let f = self.value_to_primval(args_ptrs[0], f32)?
204+
let f = self.value_to_primval(arg_vals[0], f32)?
206205
.expect_f32("sqrtf32 first arg not f32");
207206
self.write_primval(dest, PrimVal::from_f32(f.sqrt()))?;
208207
}
209208

210209
"sqrtf64" => {
211-
let f = self.value_to_primval(args_ptrs[0], f64)?
210+
let f = self.value_to_primval(arg_vals[0], f64)?
212211
.expect_f64("sqrtf64 first arg not f64");
213212
self.write_primval(dest, PrimVal::from_f64(f.sqrt()))?;
214213
}
@@ -222,7 +221,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
222221

223222
"size_of_val" => {
224223
let ty = substs.type_at(0);
225-
let (size, _) = self.size_and_align_of_dst(ty, args_ptrs[0])?;
224+
let (size, _) = self.size_and_align_of_dst(ty, arg_vals[0])?;
226225
let size_val = self.usize_primval(size);
227226
self.write_primval(dest, size_val)?;
228227
}
@@ -239,8 +238,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
239238
}
240239

241240
"transmute" => {
242-
let ty = substs.type_at(0);
243-
self.write_value(args_ptrs[0], dest, ty)?;
241+
let dest_ty = substs.type_at(1);
242+
let val = match arg_vals[0] {
243+
Value::ByVal(primval) =>
244+
Value::ByVal(self.transmute_primval(primval, dest_ty)?),
245+
v => v,
246+
};
247+
self.write_value(val, dest, dest_ty)?;
244248
}
245249

246250
"uninit" => {

src/interpreter/terminator/mod.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
3535
Goto { target } => self.goto_block(target),
3636

3737
If { ref cond, targets: (then_target, else_target) } => {
38-
let cond_val = self.eval_operand_to_primval(cond)?
39-
.expect_bool("TerminatorKind::If condition constant was not a bool");
38+
let cond_val = self.eval_operand_to_primval(cond)?.try_as_bool()?;
4039
self.goto_block(if cond_val { then_target } else { else_target });
4140
}
4241

@@ -116,8 +115,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
116115
}
117116

118117
Assert { ref cond, expected, ref msg, target, .. } => {
119-
let cond_val = self.eval_operand_to_primval(cond)?
120-
.expect_bool("TerminatorKind::Assert condition constant was not a bool");
118+
let cond_val = self.eval_operand_to_primval(cond)?.try_as_bool()?;
121119
if expected == cond_val {
122120
self.goto_block(target);
123121
} else {

0 commit comments

Comments
 (0)