Refactor num.rs
This commit is contained in:
parent
db071db95a
commit
b4e55cdedd
4 changed files with 181 additions and 267 deletions
18
src/base.rs
18
src/base.rs
|
@ -264,18 +264,7 @@ fn trans_stmt<'a, 'tcx: 'a>(
|
||||||
let lhs = trans_operand(fx, lhs);
|
let lhs = trans_operand(fx, lhs);
|
||||||
let rhs = trans_operand(fx, rhs);
|
let rhs = trans_operand(fx, rhs);
|
||||||
|
|
||||||
let res = match lhs.layout().ty.sty {
|
let res = crate::num::codegen_binop(fx, *bin_op, lhs, rhs);
|
||||||
ty::Bool => crate::num::trans_bool_binop(fx, *bin_op, lhs, rhs),
|
|
||||||
ty::Uint(_) | ty::Int(_ )=> {
|
|
||||||
crate::num::trans_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty)
|
|
||||||
}
|
|
||||||
ty::Float(_) => crate::num::trans_float_binop(fx, *bin_op, lhs, rhs, lval.layout().ty),
|
|
||||||
ty::Char => crate::num::trans_char_binop(fx, *bin_op, lhs, rhs, lval.layout().ty),
|
|
||||||
ty::RawPtr(..) | ty::FnPtr(..) => {
|
|
||||||
crate::num::trans_ptr_binop(fx, *bin_op, lhs, rhs, lval.layout().ty)
|
|
||||||
}
|
|
||||||
_ => unimplemented!("{:?}({:?}, {:?})", bin_op, lhs.layout().ty, rhs.layout().ty),
|
|
||||||
};
|
|
||||||
lval.write_cvalue(fx, res);
|
lval.write_cvalue(fx, res);
|
||||||
}
|
}
|
||||||
Rvalue::CheckedBinaryOp(bin_op, lhs, rhs) => {
|
Rvalue::CheckedBinaryOp(bin_op, lhs, rhs) => {
|
||||||
|
@ -283,11 +272,11 @@ fn trans_stmt<'a, 'tcx: 'a>(
|
||||||
let rhs = trans_operand(fx, rhs);
|
let rhs = trans_operand(fx, rhs);
|
||||||
|
|
||||||
let res = if !fx.tcx.sess.overflow_checks() {
|
let res = if !fx.tcx.sess.overflow_checks() {
|
||||||
let val = crate::num::trans_int_binop(fx, *bin_op, lhs, rhs, lhs.layout().ty).load_scalar(fx);
|
let val = crate::num::trans_int_binop(fx, *bin_op, lhs, rhs).load_scalar(fx);
|
||||||
let is_overflow = fx.bcx.ins().iconst(types::I8, 0);
|
let is_overflow = fx.bcx.ins().iconst(types::I8, 0);
|
||||||
CValue::by_val_pair(val, is_overflow, lval.layout())
|
CValue::by_val_pair(val, is_overflow, lval.layout())
|
||||||
} else {
|
} else {
|
||||||
crate::num::trans_checked_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty)
|
crate::num::trans_checked_int_binop(fx, *bin_op, lhs, rhs)
|
||||||
};
|
};
|
||||||
|
|
||||||
lval.write_cvalue(fx, res);
|
lval.write_cvalue(fx, res);
|
||||||
|
@ -314,6 +303,7 @@ fn trans_stmt<'a, 'tcx: 'a>(
|
||||||
ty::Int(_) => {
|
ty::Int(_) => {
|
||||||
let clif_ty = fx.clif_type(layout.ty).unwrap();
|
let clif_ty = fx.clif_type(layout.ty).unwrap();
|
||||||
if clif_ty == types::I128 {
|
if clif_ty == types::I128 {
|
||||||
|
// FIXME implement it
|
||||||
crate::trap::trap_unreachable_ret_value(fx, layout, "i128 neg is not yet supported").load_scalar(fx)
|
crate::trap::trap_unreachable_ret_value(fx, layout, "i128 neg is not yet supported").load_scalar(fx)
|
||||||
} else {
|
} else {
|
||||||
let zero = fx.bcx.ins().iconst(clif_ty, 0);
|
let zero = fx.bcx.ins().iconst(clif_ty, 0);
|
||||||
|
|
|
@ -8,7 +8,6 @@ pub fn maybe_codegen<'a, 'tcx>(
|
||||||
checked: bool,
|
checked: bool,
|
||||||
lhs: CValue<'tcx>,
|
lhs: CValue<'tcx>,
|
||||||
rhs: CValue<'tcx>,
|
rhs: CValue<'tcx>,
|
||||||
out_ty: Ty<'tcx>,
|
|
||||||
) -> Option<CValue<'tcx>> {
|
) -> Option<CValue<'tcx>> {
|
||||||
if lhs.layout().ty != fx.tcx.types.u128 && lhs.layout().ty != fx.tcx.types.i128 {
|
if lhs.layout().ty != fx.tcx.types.u128 && lhs.layout().ty != fx.tcx.types.i128 {
|
||||||
return None;
|
return None;
|
||||||
|
@ -26,6 +25,7 @@ pub fn maybe_codegen<'a, 'tcx>(
|
||||||
}
|
}
|
||||||
BinOp::Add | BinOp::Sub if !checked => return None,
|
BinOp::Add | BinOp::Sub if !checked => return None,
|
||||||
BinOp::Add => {
|
BinOp::Add => {
|
||||||
|
let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter());
|
||||||
return Some(if is_signed {
|
return Some(if is_signed {
|
||||||
fx.easy_call("__rust_i128_addo", &[lhs, rhs], out_ty)
|
fx.easy_call("__rust_i128_addo", &[lhs, rhs], out_ty)
|
||||||
} else {
|
} else {
|
||||||
|
@ -33,6 +33,7 @@ pub fn maybe_codegen<'a, 'tcx>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
BinOp::Sub => {
|
BinOp::Sub => {
|
||||||
|
let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter());
|
||||||
return Some(if is_signed {
|
return Some(if is_signed {
|
||||||
fx.easy_call("__rust_i128_subo", &[lhs, rhs], out_ty)
|
fx.easy_call("__rust_i128_subo", &[lhs, rhs], out_ty)
|
||||||
} else {
|
} else {
|
||||||
|
@ -42,6 +43,7 @@ pub fn maybe_codegen<'a, 'tcx>(
|
||||||
BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
|
BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
|
||||||
BinOp::Mul => {
|
BinOp::Mul => {
|
||||||
let res = if checked {
|
let res = if checked {
|
||||||
|
let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter());
|
||||||
if is_signed {
|
if is_signed {
|
||||||
fx.easy_call("__rust_i128_mulo", &[lhs, rhs], out_ty)
|
fx.easy_call("__rust_i128_mulo", &[lhs, rhs], out_ty)
|
||||||
} else {
|
} else {
|
||||||
|
@ -91,18 +93,7 @@ pub fn maybe_codegen<'a, 'tcx>(
|
||||||
// } else {
|
// } else {
|
||||||
// msb_cc
|
// msb_cc
|
||||||
// }
|
// }
|
||||||
let cc = match (bin_op, is_signed) {
|
let cc = crate::num::bin_op_to_intcc(bin_op, is_signed).unwrap();
|
||||||
(BinOp::Ge, false) => IntCC::UnsignedGreaterThanOrEqual,
|
|
||||||
(BinOp::Gt, false) => IntCC::UnsignedGreaterThan,
|
|
||||||
(BinOp::Lt, false) => IntCC::UnsignedLessThan,
|
|
||||||
(BinOp::Le, false) => IntCC::UnsignedLessThanOrEqual,
|
|
||||||
|
|
||||||
(BinOp::Ge, true) => IntCC::SignedGreaterThanOrEqual,
|
|
||||||
(BinOp::Gt, true) => IntCC::SignedGreaterThan,
|
|
||||||
(BinOp::Lt, true) => IntCC::SignedLessThan,
|
|
||||||
(BinOp::Le, true) => IntCC::SignedLessThanOrEqual,
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let msb_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_msb, rhs_msb);
|
let msb_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_msb, rhs_msb);
|
||||||
let lsb_cc = fx.bcx.ins().icmp(cc, lhs_lsb, rhs_lsb);
|
let lsb_cc = fx.bcx.ins().icmp(cc, lhs_lsb, rhs_lsb);
|
||||||
|
@ -160,6 +151,7 @@ pub fn maybe_codegen<'a, 'tcx>(
|
||||||
};
|
};
|
||||||
if let Some(val) = val {
|
if let Some(val) = val {
|
||||||
if let Some(is_overflow) = is_overflow {
|
if let Some(is_overflow) = is_overflow {
|
||||||
|
let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter());
|
||||||
let val = val.load_scalar(fx);
|
let val = val.load_scalar(fx);
|
||||||
return Some(CValue::by_val_pair(val, is_overflow, fx.layout_of(out_ty)))
|
return Some(CValue::by_val_pair(val, is_overflow, fx.layout_of(out_ty)))
|
||||||
} else {
|
} else {
|
||||||
|
@ -186,6 +178,7 @@ pub fn maybe_codegen<'a, 'tcx>(
|
||||||
(_, _) => unreachable!(),
|
(_, _) => unreachable!(),
|
||||||
};
|
};
|
||||||
if let Some(is_overflow) = is_overflow {
|
if let Some(is_overflow) = is_overflow {
|
||||||
|
let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter());
|
||||||
let val = val.load_scalar(fx);
|
let val = val.load_scalar(fx);
|
||||||
Some(CValue::by_val_pair(val, is_overflow, fx.layout_of(out_ty)))
|
Some(CValue::by_val_pair(val, is_overflow, fx.layout_of(out_ty)))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -446,7 +446,7 @@ pub fn codegen_intrinsic_call<'a, 'tcx: 'a>(
|
||||||
"unchecked_shr" => BinOp::Shr,
|
"unchecked_shr" => BinOp::Shr,
|
||||||
_ => unimplemented!("intrinsic {}", intrinsic),
|
_ => unimplemented!("intrinsic {}", intrinsic),
|
||||||
};
|
};
|
||||||
let res = crate::num::trans_int_binop(fx, bin_op, x, y, ret.layout().ty);
|
let res = crate::num::trans_int_binop(fx, bin_op, x, y);
|
||||||
ret.write_cvalue(fx, res);
|
ret.write_cvalue(fx, res);
|
||||||
};
|
};
|
||||||
_ if intrinsic.ends_with("_with_overflow"), (c x, c y) {
|
_ if intrinsic.ends_with("_with_overflow"), (c x, c y) {
|
||||||
|
@ -463,7 +463,6 @@ pub fn codegen_intrinsic_call<'a, 'tcx: 'a>(
|
||||||
bin_op,
|
bin_op,
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
ret.layout().ty,
|
|
||||||
);
|
);
|
||||||
ret.write_cvalue(fx, res);
|
ret.write_cvalue(fx, res);
|
||||||
};
|
};
|
||||||
|
@ -480,7 +479,6 @@ pub fn codegen_intrinsic_call<'a, 'tcx: 'a>(
|
||||||
bin_op,
|
bin_op,
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
ret.layout().ty,
|
|
||||||
);
|
);
|
||||||
ret.write_cvalue(fx, res);
|
ret.write_cvalue(fx, res);
|
||||||
};
|
};
|
||||||
|
@ -499,7 +497,6 @@ pub fn codegen_intrinsic_call<'a, 'tcx: 'a>(
|
||||||
bin_op,
|
bin_op,
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
fx.tcx.mk_tup([T, fx.tcx.types.bool].into_iter()),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let (val, has_overflow) = checked_res.load_scalar_pair(fx);
|
let (val, has_overflow) = checked_res.load_scalar_pair(fx);
|
||||||
|
|
406
src/num.rs
406
src/num.rs
|
@ -1,147 +1,141 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
macro_rules! binop_match {
|
pub fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> Option<IntCC> {
|
||||||
(@single $fx:expr, $bug_fmt:expr, $var:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, bug) => {
|
use BinOp::*;
|
||||||
bug!("binop {} on {} lhs: {:?} rhs: {:?}", stringify!($var), $bug_fmt, $lhs, $rhs)
|
use IntCC::*;
|
||||||
};
|
Some(match bin_op {
|
||||||
(@single $fx:expr, $bug_fmt:expr, $var:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, icmp($cc:ident)) => {{
|
Eq => Equal,
|
||||||
assert_eq!($fx.tcx.types.bool, $ret_ty);
|
Lt => if signed { SignedLessThan } else { UnsignedLessThan},
|
||||||
let ret_layout = $fx.layout_of($ret_ty);
|
Le => if signed { SignedLessThanOrEqual } else { UnsignedLessThanOrEqual},
|
||||||
|
Ne => NotEqual,
|
||||||
|
Ge => if signed { SignedGreaterThanOrEqual } else { UnsignedGreaterThanOrEqual },
|
||||||
|
Gt => if signed { SignedGreaterThan } else { UnsignedGreaterThan },
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
let b = $fx.bcx.ins().icmp(IntCC::$cc, $lhs, $rhs);
|
fn codegen_compare_bin_op<'tcx>(
|
||||||
CValue::by_val($fx.bcx.ins().bint(types::I8, b), ret_layout)
|
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
|
||||||
}};
|
bin_op: BinOp,
|
||||||
(@single $fx:expr, $bug_fmt:expr, $var:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, fcmp($cc:ident)) => {{
|
signed: bool,
|
||||||
assert_eq!($fx.tcx.types.bool, $ret_ty);
|
lhs: Value,
|
||||||
let ret_layout = $fx.layout_of($ret_ty);
|
rhs: Value,
|
||||||
let b = $fx.bcx.ins().fcmp(FloatCC::$cc, $lhs, $rhs);
|
) -> CValue<'tcx> {
|
||||||
CValue::by_val($fx.bcx.ins().bint(types::I8, b), ret_layout)
|
let val = fx.bcx.ins().icmp(bin_op_to_intcc(bin_op, signed).unwrap(), lhs, rhs);
|
||||||
}};
|
let val = fx.bcx.ins().bint(types::I8, val);
|
||||||
(@single $fx:expr, $bug_fmt:expr, $var:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, custom(|| $body:expr)) => {{
|
CValue::by_val(val, fx.layout_of(fx.tcx.types.bool))
|
||||||
$body
|
}
|
||||||
}};
|
|
||||||
(@single $fx:expr, $bug_fmt:expr, $var:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, $name:ident) => {{
|
pub fn codegen_binop<'tcx>(
|
||||||
let ret_layout = $fx.layout_of($ret_ty);
|
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
|
||||||
CValue::by_val($fx.bcx.ins().$name($lhs, $rhs), ret_layout)
|
bin_op: BinOp,
|
||||||
}};
|
in_lhs: CValue<'tcx>,
|
||||||
(
|
in_rhs: CValue<'tcx>,
|
||||||
$fx:expr, $bin_op:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, $bug_fmt:expr;
|
) -> CValue<'tcx> {
|
||||||
$(
|
match bin_op {
|
||||||
$var:ident ($sign:pat) $name:tt $( ( $($next:tt)* ) )? ;
|
BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
|
||||||
)*
|
match in_lhs.layout().ty.sty {
|
||||||
) => {{
|
ref sty if *sty == fx.tcx.types.u128.sty || *sty == fx.tcx.types.i128.sty => {}
|
||||||
let lhs = $lhs.load_scalar($fx);
|
ty::Bool | ty::Uint(_) | ty::Int(_) | ty::Char => {
|
||||||
let rhs = $rhs.load_scalar($fx);
|
let signed = type_sign(in_lhs.layout().ty);
|
||||||
match ($bin_op, $signed) {
|
let lhs = in_lhs.load_scalar(fx);
|
||||||
$(
|
let rhs = in_rhs.load_scalar(fx);
|
||||||
(BinOp::$var, $sign) => binop_match!(@single $fx, $bug_fmt, $var, $signed, lhs, rhs, $ret_ty, $name $( ( $($next)* ) )?),
|
|
||||||
)*
|
let (lhs, rhs) = if
|
||||||
|
(bin_op == BinOp::Eq || bin_op == BinOp::Ne)
|
||||||
|
&& (in_lhs.layout().ty.sty == fx.tcx.types.i8.sty || in_lhs.layout().ty.sty == fx.tcx.types.i16.sty)
|
||||||
|
{
|
||||||
|
// FIXME(CraneStation/cranelift#896) icmp_imm.i8/i16 with eq/ne for signed ints is implemented wrong.
|
||||||
|
(
|
||||||
|
fx.bcx.ins().sextend(types::I32, lhs),
|
||||||
|
fx.bcx.ins().sextend(types::I32, rhs),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(lhs, rhs)
|
||||||
|
};
|
||||||
|
|
||||||
|
return codegen_compare_bin_op(fx, bin_op, signed, lhs, rhs);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}}
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
match in_lhs.layout().ty.sty {
|
||||||
|
ty::Bool => crate::num::trans_bool_binop(fx, bin_op, in_lhs, in_rhs),
|
||||||
|
ty::Uint(_) | ty::Int(_)=> {
|
||||||
|
crate::num::trans_int_binop(fx, bin_op, in_lhs, in_rhs)
|
||||||
|
}
|
||||||
|
ty::Float(_) => crate::num::trans_float_binop(fx, bin_op, in_lhs, in_rhs),
|
||||||
|
ty::RawPtr(..) | ty::FnPtr(..) => {
|
||||||
|
crate::num::trans_ptr_binop(fx, bin_op, in_lhs, in_rhs)
|
||||||
|
}
|
||||||
|
_ => unimplemented!("{:?}({:?}, {:?})", bin_op, in_lhs.layout().ty, in_rhs.layout().ty),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trans_bool_binop<'a, 'tcx: 'a>(
|
pub fn trans_bool_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>,
|
||||||
) -> CValue<'tcx> {
|
) -> CValue<'tcx> {
|
||||||
let res = binop_match! {
|
let lhs = in_lhs.load_scalar(fx);
|
||||||
fx, bin_op, false, lhs, rhs, fx.tcx.types.bool, "bool";
|
let rhs = in_rhs.load_scalar(fx);
|
||||||
Add (_) bug;
|
|
||||||
Sub (_) bug;
|
|
||||||
Mul (_) bug;
|
|
||||||
Div (_) bug;
|
|
||||||
Rem (_) bug;
|
|
||||||
BitXor (_) bxor;
|
|
||||||
BitAnd (_) band;
|
|
||||||
BitOr (_) bor;
|
|
||||||
Shl (_) bug;
|
|
||||||
Shr (_) bug;
|
|
||||||
|
|
||||||
Eq (_) icmp(Equal);
|
let b = fx.bcx.ins();
|
||||||
Lt (_) icmp(UnsignedLessThan);
|
let res = match bin_op {
|
||||||
Le (_) icmp(UnsignedLessThanOrEqual);
|
BinOp::BitXor => b.bxor(lhs, rhs),
|
||||||
Ne (_) icmp(NotEqual);
|
BinOp::BitAnd => b.band(lhs, rhs),
|
||||||
Ge (_) icmp(UnsignedGreaterThanOrEqual);
|
BinOp::BitOr => b.bor(lhs, rhs),
|
||||||
Gt (_) icmp(UnsignedGreaterThan);
|
// Compare binops handles by `codegen_binop`.
|
||||||
|
_ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs),
|
||||||
Offset (_) bug;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
res
|
CValue::by_val(res, fx.layout_of(fx.tcx.types.bool))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trans_int_binop<'a, 'tcx: 'a>(
|
pub fn trans_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>,
|
|
||||||
) -> 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,
|
||||||
"int binop requires lhs and rhs of same type"
|
"int binop requires lhs and rhs of same type"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
match out_ty.sty {
|
if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, false, in_lhs, in_rhs) {
|
||||||
ty::Bool | ty::Uint(_) | ty::Int(_) => {}
|
|
||||||
_ => unreachable!("Out ty {:?} is not an integer or bool", out_ty),
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, false, lhs, rhs, out_ty) {
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
let signed = type_sign(lhs.layout().ty);
|
let signed = type_sign(in_lhs.layout().ty);
|
||||||
|
|
||||||
let (lhs, rhs) = if
|
let lhs = in_lhs.load_scalar(fx);
|
||||||
(bin_op == BinOp::Eq || bin_op == BinOp::Ne)
|
let rhs = in_rhs.load_scalar(fx);
|
||||||
&& (lhs.layout().ty.sty == fx.tcx.types.i8.sty || lhs.layout().ty.sty == fx.tcx.types.i16.sty)
|
|
||||||
{
|
let b = fx.bcx.ins();
|
||||||
// FIXME(CraneStation/cranelift#896) icmp_imm.i8/i16 with eq/ne for signed ints is implemented wrong.
|
let val = match bin_op {
|
||||||
let lhs = lhs.load_scalar(fx);
|
BinOp::Add => b.iadd(lhs, rhs),
|
||||||
let rhs = rhs.load_scalar(fx);
|
BinOp::Sub => b.isub(lhs, rhs),
|
||||||
(
|
BinOp::Mul => b.imul(lhs, rhs),
|
||||||
CValue::by_val(fx.bcx.ins().sextend(types::I32, lhs), fx.layout_of(fx.tcx.types.i32)),
|
BinOp::Div => if signed { b.sdiv(lhs, rhs) } else { b.udiv(lhs, rhs) },
|
||||||
CValue::by_val(fx.bcx.ins().sextend(types::I32, rhs), fx.layout_of(fx.tcx.types.i32)),
|
BinOp::Rem => if signed { b.srem(lhs, rhs) } else { b.urem(lhs, rhs) },
|
||||||
)
|
BinOp::BitXor => b.bxor(lhs, rhs),
|
||||||
} else {
|
BinOp::BitAnd => b.band(lhs, rhs),
|
||||||
(lhs, rhs)
|
BinOp::BitOr => b.bor(lhs, rhs),
|
||||||
|
BinOp::Shl => b.ishl(lhs, rhs),
|
||||||
|
BinOp::Shr => if signed { b.sshr(lhs, rhs) } else { b.ushr(lhs, rhs) },
|
||||||
|
// Compare binops handles by `codegen_binop`.
|
||||||
|
_ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs.layout().ty, in_rhs.layout().ty),
|
||||||
};
|
};
|
||||||
|
|
||||||
binop_match! {
|
CValue::by_val(val, in_lhs.layout())
|
||||||
fx, bin_op, signed, lhs, rhs, out_ty, "int/uint";
|
|
||||||
Add (_) iadd;
|
|
||||||
Sub (_) isub;
|
|
||||||
Mul (_) imul;
|
|
||||||
Div (false) udiv;
|
|
||||||
Div (true) sdiv;
|
|
||||||
Rem (false) urem;
|
|
||||||
Rem (true) srem;
|
|
||||||
BitXor (_) bxor;
|
|
||||||
BitAnd (_) band;
|
|
||||||
BitOr (_) bor;
|
|
||||||
Shl (_) ishl;
|
|
||||||
Shr (false) ushr;
|
|
||||||
Shr (true) sshr;
|
|
||||||
|
|
||||||
Eq (_) icmp(Equal);
|
|
||||||
Lt (false) icmp(UnsignedLessThan);
|
|
||||||
Lt (true) icmp(SignedLessThan);
|
|
||||||
Le (false) icmp(UnsignedLessThanOrEqual);
|
|
||||||
Le (true) icmp(SignedLessThanOrEqual);
|
|
||||||
Ne (_) icmp(NotEqual);
|
|
||||||
Ge (false) icmp(UnsignedGreaterThanOrEqual);
|
|
||||||
Ge (true) icmp(SignedGreaterThanOrEqual);
|
|
||||||
Gt (false) icmp(UnsignedGreaterThan);
|
|
||||||
Gt (true) icmp(SignedGreaterThan);
|
|
||||||
|
|
||||||
Offset (_) bug;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trans_checked_int_binop<'a, 'tcx: 'a>(
|
pub fn trans_checked_int_binop<'a, 'tcx: 'a>(
|
||||||
|
@ -149,7 +143,6 @@ pub fn trans_checked_int_binop<'a, 'tcx: 'a>(
|
||||||
bin_op: BinOp,
|
bin_op: BinOp,
|
||||||
in_lhs: CValue<'tcx>,
|
in_lhs: CValue<'tcx>,
|
||||||
in_rhs: CValue<'tcx>,
|
in_rhs: CValue<'tcx>,
|
||||||
out_ty: Ty<'tcx>,
|
|
||||||
) -> 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!(
|
||||||
|
@ -162,7 +155,7 @@ pub fn trans_checked_int_binop<'a, 'tcx: 'a>(
|
||||||
let lhs = in_lhs.load_scalar(fx);
|
let lhs = in_lhs.load_scalar(fx);
|
||||||
let rhs = in_rhs.load_scalar(fx);
|
let rhs = in_rhs.load_scalar(fx);
|
||||||
|
|
||||||
if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, true, in_lhs, in_rhs, out_ty) {
|
if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, true, in_lhs, in_rhs) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,7 +227,7 @@ pub fn trans_checked_int_binop<'a, 'tcx: 'a>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let has_overflow = fx.bcx.ins().bint(types::I8, has_overflow);
|
let has_overflow = fx.bcx.ins().bint(types::I8, has_overflow);
|
||||||
let out_place = CPlace::new_stack_slot(fx, out_ty);
|
let out_place = CPlace::new_stack_slot(fx, fx.tcx.mk_tup([in_lhs.layout().ty, fx.tcx.types.bool].iter()));
|
||||||
let out_layout = out_place.layout();
|
let out_layout = out_place.layout();
|
||||||
out_place.write_cvalue(fx, CValue::by_val_pair(res, has_overflow, out_layout));
|
out_place.write_cvalue(fx, CValue::by_val_pair(res, has_overflow, out_layout));
|
||||||
|
|
||||||
|
@ -244,85 +237,55 @@ pub fn trans_checked_int_binop<'a, 'tcx: 'a>(
|
||||||
pub fn trans_float_binop<'a, 'tcx: 'a>(
|
pub fn trans_float_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>,
|
||||||
ty: Ty<'tcx>,
|
|
||||||
) -> CValue<'tcx> {
|
) -> CValue<'tcx> {
|
||||||
let res = binop_match! {
|
assert_eq!(in_lhs.layout().ty, in_rhs.layout().ty);
|
||||||
fx, bin_op, false, lhs, rhs, ty, "float";
|
|
||||||
Add (_) fadd;
|
let lhs = in_lhs.load_scalar(fx);
|
||||||
Sub (_) fsub;
|
let rhs = in_rhs.load_scalar(fx);
|
||||||
Mul (_) fmul;
|
|
||||||
Div (_) fdiv;
|
let b = fx.bcx.ins();
|
||||||
Rem (_) custom(|| {
|
let res = match bin_op {
|
||||||
assert_eq!(lhs.layout().ty, ty);
|
BinOp::Add => b.fadd(lhs, rhs),
|
||||||
assert_eq!(rhs.layout().ty, ty);
|
BinOp::Sub => b.fsub(lhs, rhs),
|
||||||
match ty.sty {
|
BinOp::Mul => b.fmul(lhs, rhs),
|
||||||
ty::Float(FloatTy::F32) => fx.easy_call("fmodf", &[lhs, rhs], ty),
|
BinOp::Div => b.fdiv(lhs, rhs),
|
||||||
ty::Float(FloatTy::F64) => fx.easy_call("fmod", &[lhs, rhs], ty),
|
BinOp::Rem => {
|
||||||
|
let name = match in_lhs.layout().ty.sty {
|
||||||
|
ty::Float(FloatTy::F32) => "fmodf",
|
||||||
|
ty::Float(FloatTy::F64) => "fmod",
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
}
|
};
|
||||||
});
|
return fx.easy_call(name, &[in_lhs, in_rhs], in_lhs.layout().ty);
|
||||||
BitXor (_) bxor;
|
}
|
||||||
BitAnd (_) band;
|
BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
|
||||||
BitOr (_) bor;
|
let fltcc = match bin_op {
|
||||||
Shl (_) bug;
|
BinOp::Eq => FloatCC::Equal,
|
||||||
Shr (_) bug;
|
BinOp::Lt => FloatCC::LessThan,
|
||||||
|
BinOp::Le => FloatCC::LessThanOrEqual,
|
||||||
Eq (_) fcmp(Equal);
|
BinOp::Ne => FloatCC::NotEqual,
|
||||||
Lt (_) fcmp(LessThan);
|
BinOp::Ge => FloatCC::GreaterThanOrEqual,
|
||||||
Le (_) fcmp(LessThanOrEqual);
|
BinOp::Gt => FloatCC::GreaterThan,
|
||||||
Ne (_) fcmp(NotEqual);
|
_ => unreachable!(),
|
||||||
Ge (_) fcmp(GreaterThanOrEqual);
|
};
|
||||||
Gt (_) fcmp(GreaterThan);
|
let val = fx.bcx.ins().fcmp(fltcc, lhs, rhs);
|
||||||
|
let val = fx.bcx.ins().bint(types::I8, val);
|
||||||
Offset (_) bug;
|
return CValue::by_val(val, fx.layout_of(fx.tcx.types.bool));
|
||||||
|
}
|
||||||
|
_ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs),
|
||||||
};
|
};
|
||||||
|
|
||||||
res
|
CValue::by_val(res, in_lhs.layout())
|
||||||
}
|
|
||||||
|
|
||||||
pub fn trans_char_binop<'a, 'tcx: 'a>(
|
|
||||||
fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
|
|
||||||
bin_op: BinOp,
|
|
||||||
lhs: CValue<'tcx>,
|
|
||||||
rhs: CValue<'tcx>,
|
|
||||||
ty: Ty<'tcx>,
|
|
||||||
) -> CValue<'tcx> {
|
|
||||||
let res = binop_match! {
|
|
||||||
fx, bin_op, false, lhs, rhs, ty, "char";
|
|
||||||
Add (_) bug;
|
|
||||||
Sub (_) bug;
|
|
||||||
Mul (_) bug;
|
|
||||||
Div (_) bug;
|
|
||||||
Rem (_) bug;
|
|
||||||
BitXor (_) bug;
|
|
||||||
BitAnd (_) bug;
|
|
||||||
BitOr (_) bug;
|
|
||||||
Shl (_) bug;
|
|
||||||
Shr (_) bug;
|
|
||||||
|
|
||||||
Eq (_) icmp(Equal);
|
|
||||||
Lt (_) icmp(UnsignedLessThan);
|
|
||||||
Le (_) icmp(UnsignedLessThanOrEqual);
|
|
||||||
Ne (_) icmp(NotEqual);
|
|
||||||
Ge (_) icmp(UnsignedGreaterThanOrEqual);
|
|
||||||
Gt (_) icmp(UnsignedGreaterThan);
|
|
||||||
|
|
||||||
Offset (_) bug;
|
|
||||||
};
|
|
||||||
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trans_ptr_binop<'a, 'tcx: 'a>(
|
pub fn trans_ptr_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>,
|
||||||
ret_ty: Ty<'tcx>,
|
|
||||||
) -> CValue<'tcx> {
|
) -> CValue<'tcx> {
|
||||||
let not_fat = match lhs.layout().ty.sty {
|
let not_fat = match in_lhs.layout().ty.sty {
|
||||||
ty::RawPtr(TypeAndMut { ty, mutbl: _ }) => {
|
ty::RawPtr(TypeAndMut { ty, mutbl: _ }) => {
|
||||||
ty.is_sized(fx.tcx.at(DUMMY_SP), ParamEnv::reveal_all())
|
ty.is_sized(fx.tcx.at(DUMMY_SP), ParamEnv::reveal_all())
|
||||||
}
|
}
|
||||||
|
@ -330,41 +293,27 @@ pub fn trans_ptr_binop<'a, 'tcx: 'a>(
|
||||||
_ => bug!("trans_ptr_binop on non ptr"),
|
_ => bug!("trans_ptr_binop on non ptr"),
|
||||||
};
|
};
|
||||||
if not_fat {
|
if not_fat {
|
||||||
if let BinOp::Offset = bin_op {
|
match bin_op {
|
||||||
let (base, offset) = (lhs, rhs.load_scalar(fx));
|
BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
|
||||||
let pointee_ty = base.layout().ty.builtin_deref(true).unwrap().ty;
|
let lhs = in_lhs.load_scalar(fx);
|
||||||
let pointee_size = fx.layout_of(pointee_ty).size.bytes();
|
let rhs = in_rhs.load_scalar(fx);
|
||||||
let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64);
|
|
||||||
let base_val = base.load_scalar(fx);
|
|
||||||
let res = fx.bcx.ins().iadd(base_val, ptr_diff);
|
|
||||||
return CValue::by_val(res, base.layout());
|
|
||||||
}
|
|
||||||
|
|
||||||
binop_match! {
|
return codegen_compare_bin_op(fx, bin_op, false, lhs, rhs);
|
||||||
fx, bin_op, false, lhs, rhs, ret_ty, "ptr";
|
}
|
||||||
Add (_) bug;
|
BinOp::Offset => {
|
||||||
Sub (_) bug;
|
let (base, offset) = (in_lhs, in_rhs.load_scalar(fx));
|
||||||
Mul (_) bug;
|
let pointee_ty = base.layout().ty.builtin_deref(true).unwrap().ty;
|
||||||
Div (_) bug;
|
let pointee_size = fx.layout_of(pointee_ty).size.bytes();
|
||||||
Rem (_) bug;
|
let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64);
|
||||||
BitXor (_) bug;
|
let base_val = base.load_scalar(fx);
|
||||||
BitAnd (_) bug;
|
let res = fx.bcx.ins().iadd(base_val, ptr_diff);
|
||||||
BitOr (_) bug;
|
return CValue::by_val(res, base.layout());
|
||||||
Shl (_) bug;
|
}
|
||||||
Shr (_) bug;
|
_ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs),
|
||||||
|
};
|
||||||
Eq (_) icmp(Equal);
|
|
||||||
Lt (_) icmp(UnsignedLessThan);
|
|
||||||
Le (_) icmp(UnsignedLessThanOrEqual);
|
|
||||||
Ne (_) icmp(NotEqual);
|
|
||||||
Ge (_) icmp(UnsignedGreaterThanOrEqual);
|
|
||||||
Gt (_) icmp(UnsignedGreaterThan);
|
|
||||||
|
|
||||||
Offset (_) bug; // Handled above
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let (lhs_ptr, lhs_extra) = lhs.load_scalar_pair(fx);
|
let (lhs_ptr, lhs_extra) = in_lhs.load_scalar_pair(fx);
|
||||||
let (rhs_ptr, rhs_extra) = rhs.load_scalar_pair(fx);
|
let (rhs_ptr, rhs_extra) = in_rhs.load_scalar_pair(fx);
|
||||||
|
|
||||||
let res = match bin_op {
|
let res = match bin_op {
|
||||||
BinOp::Eq => {
|
BinOp::Eq => {
|
||||||
|
@ -380,29 +329,14 @@ pub fn trans_ptr_binop<'a, 'tcx: 'a>(
|
||||||
BinOp::Lt | BinOp::Le | BinOp::Ge | BinOp::Gt => {
|
BinOp::Lt | BinOp::Le | BinOp::Ge | BinOp::Gt => {
|
||||||
let ptr_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_ptr, rhs_ptr);
|
let ptr_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_ptr, rhs_ptr);
|
||||||
|
|
||||||
let ptr_cmp = fx.bcx.ins().icmp(match bin_op {
|
let ptr_cmp = fx.bcx.ins().icmp(bin_op_to_intcc(bin_op, false).unwrap(), lhs_ptr, rhs_ptr);
|
||||||
BinOp::Lt => IntCC::UnsignedLessThan,
|
let extra_cmp = fx.bcx.ins().icmp(bin_op_to_intcc(bin_op, false).unwrap(), lhs_extra, rhs_extra);
|
||||||
BinOp::Le => IntCC::UnsignedLessThanOrEqual,
|
|
||||||
BinOp::Ge => IntCC::UnsignedGreaterThanOrEqual,
|
|
||||||
BinOp::Gt => IntCC::UnsignedGreaterThan,
|
|
||||||
_ => unreachable!(),
|
|
||||||
}, lhs_ptr, rhs_ptr);
|
|
||||||
|
|
||||||
let extra_cmp = fx.bcx.ins().icmp(match bin_op {
|
|
||||||
BinOp::Lt => IntCC::UnsignedLessThan,
|
|
||||||
BinOp::Le => IntCC::UnsignedLessThanOrEqual,
|
|
||||||
BinOp::Ge => IntCC::UnsignedGreaterThanOrEqual,
|
|
||||||
BinOp::Gt => IntCC::UnsignedGreaterThan,
|
|
||||||
_ => unreachable!(),
|
|
||||||
}, lhs_extra, rhs_extra);
|
|
||||||
|
|
||||||
fx.bcx.ins().select(ptr_eq, extra_cmp, ptr_cmp)
|
fx.bcx.ins().select(ptr_eq, extra_cmp, ptr_cmp)
|
||||||
}
|
}
|
||||||
_ => panic!("bin_op {:?} on ptr", bin_op),
|
_ => panic!("bin_op {:?} on ptr", bin_op),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(fx.tcx.types.bool, ret_ty);
|
CValue::by_val(fx.bcx.ins().bint(types::I8, res), fx.layout_of(fx.tcx.types.bool))
|
||||||
let ret_layout = fx.layout_of(ret_ty);
|
|
||||||
CValue::by_val(fx.bcx.ins().bint(types::I8, res), ret_layout)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue