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

View file

@ -82,12 +82,15 @@ fn codegen_field<'a, 'tcx: 'a>(
pub enum CValue<'tcx> { pub enum CValue<'tcx> {
ByRef(Value, TyLayout<'tcx>), ByRef(Value, TyLayout<'tcx>),
ByVal(Value, TyLayout<'tcx>), ByVal(Value, TyLayout<'tcx>),
ByValPair(Value, Value, TyLayout<'tcx>),
} }
impl<'tcx> CValue<'tcx> { impl<'tcx> CValue<'tcx> {
pub fn layout(&self) -> TyLayout<'tcx> { pub fn layout(&self) -> TyLayout<'tcx> {
match *self { 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() .ins()
.stack_addr(fx.module.pointer_type(), stack_slot, 0) .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) fx.bcx.ins().load(cton_ty, MemFlags::new(), addr, 0)
} }
CValue::ByVal(value, _layout) => value, 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 { match self {
CValue::ByRef(value, layout) => (value, layout), CValue::ByRef(value, layout) => (value, layout),
CValue::ByVal(_, _) => bug!("Expected CValue::ByRef, found CValue::ByVal: {:?}", self), 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 { match self {
CValue::ByRef(addr, _) => CValue::ByRef(addr, layout), CValue::ByRef(addr, _) => CValue::ByRef(addr, layout),
CValue::ByVal(val, _) => CValue::ByVal(val, layout), CValue::ByVal(val, _) => CValue::ByVal(val, layout),
CValue::ByValPair(val, extra, _) => CValue::ByValPair(val, extra, layout),
} }
} }
} }
@ -262,37 +311,38 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> {
CPlace::Addr(addr, layout) => { CPlace::Addr(addr, layout) => {
let size = layout.size.bytes() as i32; let size = layout.size.bytes() as i32;
if let Some(_) = fx.cton_type(layout.ty) { match from {
let data = from.load_value(fx); CValue::ByVal(val, _layout) => {
fx.bcx.ins().store(MemFlags::new(), data, addr, 0); fx.bcx.ins().store(MemFlags::new(), val, addr, 0);
} else {
let from = from.expect_byref();
let mut offset = 0;
while size - offset >= 8 {
let byte = fx.bcx.ins().load(
fx.module.pointer_type(),
MemFlags::new(),
from.0,
offset,
);
fx.bcx.ins().store(MemFlags::new(), byte, addr, offset);
offset += 8;
} }
while size - offset >= 4 { CValue::ByValPair(val1, val2, _layout) => {
let byte = fx let val1_offset = layout.fields.offset(0).bytes() as i32;
.bcx let val2_offset = layout.fields.offset(1).bytes() as i32;
.ins() fx.bcx.ins().store(MemFlags::new(), val1, addr, val1_offset);
.load(types::I32, MemFlags::new(), from.0, offset); fx.bcx.ins().store(MemFlags::new(), val2, addr, val2_offset);
fx.bcx.ins().store(MemFlags::new(), byte, addr, offset);
offset += 4;
} }
while offset < size { CValue::ByRef(from, _layout) => {
let byte = fx let mut offset = 0;
.bcx while size - offset >= 8 {
.ins() let byte = fx.bcx.ins().load(
.load(types::I8, MemFlags::new(), from.0, offset); fx.module.pointer_type(),
fx.bcx.ins().store(MemFlags::new(), byte, addr, offset); MemFlags::new(),
offset += 1; 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, 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, offset);
fx.bcx.ins().store(MemFlags::new(), byte, addr, offset);
offset += 1;
}
} }
} }
} }