1
Fork 0

Add CValue variant ByValPair

This commit is contained in:
bjorn3 2018-08-22 12:35:07 +02:00
parent 65641b8872
commit d87edae73b
2 changed files with 105 additions and 63 deletions

View file

@ -727,15 +727,15 @@ pub fn trans_int_binop<'a, 'tcx: 'a>(
pub fn trans_checked_int_binop<'a, 'tcx: 'a>(
fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
bin_op: BinOp,
lhs: CValue<'tcx>,
rhs: CValue<'tcx>,
in_lhs: CValue<'tcx>,
in_rhs: CValue<'tcx>,
out_ty: Ty<'tcx>,
signed: bool,
) -> CValue<'tcx> {
if bin_op != BinOp::Shl && bin_op != BinOp::Shr {
assert_eq!(
lhs.layout().ty,
rhs.layout().ty,
in_lhs.layout().ty,
in_rhs.layout().ty,
"checked int binop requires lhs and rhs of same type"
);
}
@ -747,40 +747,32 @@ pub fn trans_checked_int_binop<'a, 'tcx: 'a>(
),
};
let res = binop_match! {
fx, bin_op, signed, lhs, rhs, res_ty, "checked int/uint";
Add (_) iadd;
Sub (_) isub;
Mul (_) imul;
Div (_) bug;
Rem (_) bug;
BitXor (_) bug;
BitAnd (_) bug;
BitOr (_) bug;
Shl (_) ishl;
Shr (false) ushr;
Shr (true) sshr;
Eq (_) bug;
Lt (_) bug;
Le (_) bug;
Ne (_) bug;
Ge (_) bug;
Gt (_) bug;
Offset (_) bug;
let lhs = in_lhs.load_value(fx);
let rhs = in_rhs.load_value(fx);
let res = match bin_op {
BinOp::Add => fx.bcx.ins().iadd(lhs, rhs),
BinOp::Sub => fx.bcx.ins().isub(lhs, rhs),
BinOp::Mul => fx.bcx.ins().imul(lhs, rhs),
BinOp::Shl => fx.bcx.ins().ishl(lhs, rhs),
BinOp::Shr => if !signed {
fx.bcx.ins().ushr(lhs, rhs)
} else {
fx.bcx.ins().sshr(lhs, rhs)
},
_ => bug!(
"binop {:?} on checked int/uint lhs: {:?} rhs: {:?}",
bin_op,
in_lhs,
in_rhs
),
};
// TODO: check for overflow
let has_overflow = CValue::const_val(fx, fx.tcx.types.bool, 0);
let has_overflow = fx.bcx.ins().iconst(types::I8, 0);
let out_place = CPlace::temp(fx, out_ty);
out_place
.place_field(fx, mir::Field::new(0))
.write_cvalue(fx, res);
out_place
.place_field(fx, mir::Field::new(1))
.write_cvalue(fx, has_overflow);
let out_layout = out_place.layout();
out_place.write_cvalue(fx, CValue::ByValPair(res, has_overflow, out_layout));
out_place.to_cvalue(fx)
}

View file

@ -82,12 +82,15 @@ fn codegen_field<'a, 'tcx: 'a>(
pub enum CValue<'tcx> {
ByRef(Value, TyLayout<'tcx>),
ByVal(Value, TyLayout<'tcx>),
ByValPair(Value, Value, TyLayout<'tcx>),
}
impl<'tcx> CValue<'tcx> {
pub fn layout(&self) -> TyLayout<'tcx> {
match *self {
CValue::ByRef(_, layout) | CValue::ByVal(_, layout) => layout,
CValue::ByRef(_, layout)
| CValue::ByVal(_, layout)
| CValue::ByValPair(_, _, layout) => layout,
}
}
@ -108,6 +111,19 @@ impl<'tcx> CValue<'tcx> {
.ins()
.stack_addr(fx.module.pointer_type(), stack_slot, 0)
}
CValue::ByValPair(value, extra, layout) => {
let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
kind: StackSlotKind::ExplicitSlot,
size: layout.size.bytes() as u32,
offset: None,
});
let base = fx.bcx.ins().stack_addr(types::I64, stack_slot, 0);
let a_addr = codegen_field(fx, base, layout, mir::Field::new(0)).0;
let b_addr = codegen_field(fx, base, layout, mir::Field::new(1)).0;
fx.bcx.ins().store(MemFlags::new(), value, a_addr, 0);
fx.bcx.ins().store(MemFlags::new(), extra, b_addr, 0);
base
}
}
}
@ -123,6 +139,34 @@ impl<'tcx> CValue<'tcx> {
fx.bcx.ins().load(cton_ty, MemFlags::new(), addr, 0)
}
CValue::ByVal(value, _layout) => value,
CValue::ByValPair(_, _, _layout) => bug!("Please use load_value_pair for ByValPair"),
}
}
pub fn load_value_pair<'a>(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>) -> (Value, Value)
where
'tcx: 'a,
{
match self {
CValue::ByRef(addr, layout) => {
assert_eq!(
layout.size.bytes(),
fx.tcx.data_layout.pointer_size.bytes() * 2
);
let val1_offset = layout.fields.offset(0).bytes() as i32;
let val2_offset = layout.fields.offset(1).bytes() as i32;
let val1 =
fx.bcx
.ins()
.load(fx.module.pointer_type(), MemFlags::new(), addr, val1_offset);
let val2 =
fx.bcx
.ins()
.load(fx.module.pointer_type(), MemFlags::new(), addr, val2_offset);
(val1, val2)
}
CValue::ByVal(_, _layout) => bug!("Please use load_value for ByVal"),
CValue::ByValPair(val1, val2, _layout) => (val1, val2),
}
}
@ -130,6 +174,10 @@ impl<'tcx> CValue<'tcx> {
match self {
CValue::ByRef(value, layout) => (value, layout),
CValue::ByVal(_, _) => bug!("Expected CValue::ByRef, found CValue::ByVal: {:?}", self),
CValue::ByValPair(_, _, _) => bug!(
"Expected CValue::ByRef, found CValue::ByValPair: {:?}",
self
),
}
}
@ -167,6 +215,7 @@ impl<'tcx> CValue<'tcx> {
match self {
CValue::ByRef(addr, _) => CValue::ByRef(addr, layout),
CValue::ByVal(val, _) => CValue::ByVal(val, layout),
CValue::ByValPair(val, extra, _) => CValue::ByValPair(val, extra, layout),
}
}
}
@ -262,35 +311,35 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> {
CPlace::Addr(addr, layout) => {
let size = layout.size.bytes() as i32;
if let Some(_) = fx.cton_type(layout.ty) {
let data = from.load_value(fx);
fx.bcx.ins().store(MemFlags::new(), data, addr, 0);
} else {
let from = from.expect_byref();
match from {
CValue::ByVal(val, _layout) => {
fx.bcx.ins().store(MemFlags::new(), val, addr, 0);
}
CValue::ByValPair(val1, val2, _layout) => {
let val1_offset = layout.fields.offset(0).bytes() as i32;
let val2_offset = layout.fields.offset(1).bytes() as i32;
fx.bcx.ins().store(MemFlags::new(), val1, addr, val1_offset);
fx.bcx.ins().store(MemFlags::new(), val2, addr, val2_offset);
}
CValue::ByRef(from, _layout) => {
let mut offset = 0;
while size - offset >= 8 {
let byte = fx.bcx.ins().load(
fx.module.pointer_type(),
MemFlags::new(),
from.0,
from,
offset,
);
fx.bcx.ins().store(MemFlags::new(), byte, addr, offset);
offset += 8;
}
while size - offset >= 4 {
let byte = fx
.bcx
.ins()
.load(types::I32, MemFlags::new(), from.0, offset);
let byte = fx.bcx.ins().load(types::I32, MemFlags::new(), from, offset);
fx.bcx.ins().store(MemFlags::new(), byte, addr, offset);
offset += 4;
}
while offset < size {
let byte = fx
.bcx
.ins()
.load(types::I8, MemFlags::new(), from.0, offset);
let byte = fx.bcx.ins().load(types::I8, MemFlags::new(), from, offset);
fx.bcx.ins().store(MemFlags::new(), byte, addr, offset);
offset += 1;
}
@ -298,6 +347,7 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> {
}
}
}
}
pub fn place_field(
self,