]> git.lizzy.rs Git - rust.git/blobdiff - src/num.rs
Use Cranelift legalization for icmp.i128
[rust.git] / src / num.rs
index 8d3bb01921805fcab76acae415111d99a6f8e990..5acff80768eafcbfc4bcb3d7b89186ab361bed1f 100644 (file)
@@ -1,15 +1,39 @@
 use crate::prelude::*;
 
-pub fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> Option<IntCC> {
+pub(crate) fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> Option<IntCC> {
     use BinOp::*;
     use IntCC::*;
     Some(match bin_op {
         Eq => Equal,
-        Lt => if signed { SignedLessThan } else { UnsignedLessThan},
-        Le => if signed { SignedLessThanOrEqual } else { UnsignedLessThanOrEqual},
+        Lt => {
+            if signed {
+                SignedLessThan
+            } else {
+                UnsignedLessThan
+            }
+        }
+        Le => {
+            if signed {
+                SignedLessThanOrEqual
+            } else {
+                UnsignedLessThanOrEqual
+            }
+        }
         Ne => NotEqual,
-        Ge => if signed { SignedGreaterThanOrEqual } else { UnsignedGreaterThanOrEqual },
-        Gt => if signed { SignedGreaterThan } else { UnsignedGreaterThan },
+        Ge => {
+            if signed {
+                SignedGreaterThanOrEqual
+            } else {
+                UnsignedGreaterThanOrEqual
+            }
+        }
+        Gt => {
+            if signed {
+                SignedGreaterThan
+            } else {
+                UnsignedGreaterThan
+            }
+        }
         _ => return None,
     })
 }
@@ -22,12 +46,12 @@ fn codegen_compare_bin_op<'tcx>(
     rhs: Value,
 ) -> CValue<'tcx> {
     let intcc = crate::num::bin_op_to_intcc(bin_op, signed).unwrap();
-    let val = codegen_icmp(fx, intcc, lhs, rhs);
+    let val = fx.bcx.ins().icmp(intcc, lhs, rhs);
     let val = fx.bcx.ins().bint(types::I8, val);
     CValue::by_val(val, fx.layout_of(fx.tcx.types.bool))
 }
 
-pub fn codegen_binop<'tcx>(
+pub(crate) fn codegen_binop<'tcx>(
     fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
     bin_op: BinOp,
     in_lhs: CValue<'tcx>,
@@ -35,15 +59,15 @@ pub fn codegen_binop<'tcx>(
 ) -> CValue<'tcx> {
     match bin_op {
         BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
-            match in_lhs.layout().ty.sty {
+            match in_lhs.layout().ty.kind {
                 ty::Bool | ty::Uint(_) | ty::Int(_) | ty::Char => {
                     let signed = type_sign(in_lhs.layout().ty);
                     let lhs = in_lhs.load_scalar(fx);
                     let rhs = in_rhs.load_scalar(fx);
 
-                    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)
+                    let (lhs, rhs) = if (bin_op == BinOp::Eq || bin_op == BinOp::Ne)
+                        && (in_lhs.layout().ty.kind == fx.tcx.types.i8.kind
+                            || in_lhs.layout().ty.kind == fx.tcx.types.i16.kind)
                     {
                         // FIXME(CraneStation/cranelift#896) icmp_imm.i8/i16 with eq/ne for signed ints is implemented wrong.
                         (
@@ -62,21 +86,22 @@ pub fn codegen_binop<'tcx>(
         _ => {}
     }
 
-    match in_lhs.layout().ty.sty {
+    match in_lhs.layout().ty.kind {
         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::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),
+        ty::RawPtr(..) | ty::FnPtr(..) => crate::num::trans_ptr_binop(fx, bin_op, in_lhs, in_rhs),
+        _ => unreachable!(
+            "{:?}({:?}, {:?})",
+            bin_op,
+            in_lhs.layout().ty,
+            in_rhs.layout().ty
+        ),
     }
 }
 
-pub fn trans_bool_binop<'a, 'tcx: 'a>(
-    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
+pub(crate) fn trans_bool_binop<'tcx>(
+    fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
     bin_op: BinOp,
     in_lhs: CValue<'tcx>,
     in_rhs: CValue<'tcx>,
@@ -96,8 +121,8 @@ pub fn trans_bool_binop<'a, 'tcx: 'a>(
     CValue::by_val(res, fx.layout_of(fx.tcx.types.bool))
 }
 
-pub fn trans_int_binop<'a, 'tcx: 'a>(
-    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
+pub(crate) fn trans_int_binop<'tcx>(
+    fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
     bin_op: BinOp,
     in_lhs: CValue<'tcx>,
     in_rhs: CValue<'tcx>,
@@ -124,8 +149,20 @@ pub fn trans_int_binop<'a, 'tcx: 'a>(
         BinOp::Add => b.iadd(lhs, rhs),
         BinOp::Sub => b.isub(lhs, rhs),
         BinOp::Mul => b.imul(lhs, rhs),
-        BinOp::Div => if signed { b.sdiv(lhs, rhs) } else { b.udiv(lhs, rhs) },
-        BinOp::Rem => if signed { b.srem(lhs, rhs) } else { b.urem(lhs, rhs) },
+        BinOp::Div => {
+            if signed {
+                b.sdiv(lhs, rhs)
+            } else {
+                b.udiv(lhs, rhs)
+            }
+        }
+        BinOp::Rem => {
+            if signed {
+                b.srem(lhs, rhs)
+            } else {
+                b.urem(lhs, rhs)
+            }
+        }
         BinOp::BitXor => b.bxor(lhs, rhs),
         BinOp::BitAnd => b.band(lhs, rhs),
         BinOp::BitOr => b.bor(lhs, rhs),
@@ -144,14 +181,19 @@ pub fn trans_int_binop<'a, 'tcx: 'a>(
             }
         }
         // Compare binops handles by `codegen_binop`.
-        _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs.layout().ty, in_rhs.layout().ty),
+        _ => unreachable!(
+            "{:?}({:?}, {:?})",
+            bin_op,
+            in_lhs.layout().ty,
+            in_rhs.layout().ty
+        ),
     };
 
     CValue::by_val(val, in_lhs.layout())
 }
 
-pub fn trans_checked_int_binop<'a, 'tcx: 'a>(
-    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
+pub(crate) fn trans_checked_int_binop<'tcx>(
+    fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
     bin_op: BinOp,
     in_lhs: CValue<'tcx>,
     in_rhs: CValue<'tcx>,
@@ -216,8 +258,10 @@ pub fn trans_checked_int_binop<'a, 'tcx: 'a>(
         }
         BinOp::Shl => {
             let val = fx.bcx.ins().ishl(lhs, rhs);
-            // TODO: check for overflow
-            let has_overflow = fx.bcx.ins().bconst(types::B1, false);
+            let ty = fx.bcx.func.dfg.value_type(val);
+            let max_shift = i64::from(ty.bits()) - 1;
+            let has_overflow =
+                fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, rhs, max_shift);
             (val, has_overflow)
         }
         BinOp::Shr => {
@@ -226,8 +270,10 @@ pub fn trans_checked_int_binop<'a, 'tcx: 'a>(
             } else {
                 fx.bcx.ins().sshr(lhs, rhs)
             };
-            // TODO: check for overflow
-            let has_overflow = fx.bcx.ins().bconst(types::B1, false);
+            let ty = fx.bcx.func.dfg.value_type(val);
+            let max_shift = i64::from(ty.bits()) - 1;
+            let has_overflow =
+                fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, rhs, max_shift);
             (val, has_overflow)
         }
         _ => bug!(
@@ -239,15 +285,20 @@ pub fn trans_checked_int_binop<'a, 'tcx: 'a>(
     };
 
     let has_overflow = fx.bcx.ins().bint(types::I8, has_overflow);
-    let out_place = CPlace::new_stack_slot(fx, fx.tcx.mk_tup([in_lhs.layout().ty, fx.tcx.types.bool].iter()));
+
+    // FIXME directly write to result place instead
+    let out_place = CPlace::new_stack_slot(
+        fx,
+        fx.layout_of(fx.tcx.mk_tup([in_lhs.layout().ty, fx.tcx.types.bool].iter())),
+    );
     let out_layout = out_place.layout();
     out_place.write_cvalue(fx, CValue::by_val_pair(res, has_overflow, out_layout));
 
     out_place.to_cvalue(fx)
 }
 
-pub fn trans_float_binop<'a, 'tcx: 'a>(
-    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
+pub(crate) fn trans_float_binop<'tcx>(
+    fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
     bin_op: BinOp,
     in_lhs: CValue<'tcx>,
     in_rhs: CValue<'tcx>,
@@ -264,7 +315,7 @@ pub fn trans_float_binop<'a, 'tcx: 'a>(
         BinOp::Mul => b.fmul(lhs, rhs),
         BinOp::Div => b.fdiv(lhs, rhs),
         BinOp::Rem => {
-            let name = match in_lhs.layout().ty.sty {
+            let name = match in_lhs.layout().ty.kind {
                 ty::Float(FloatTy::F32) => "fmodf",
                 ty::Float(FloatTy::F64) => "fmod",
                 _ => bug!(),
@@ -291,20 +342,17 @@ pub fn trans_float_binop<'a, 'tcx: 'a>(
     CValue::by_val(res, in_lhs.layout())
 }
 
-pub fn trans_ptr_binop<'a, 'tcx: 'a>(
-    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
+pub(crate) fn trans_ptr_binop<'tcx>(
+    fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
     bin_op: BinOp,
     in_lhs: CValue<'tcx>,
     in_rhs: CValue<'tcx>,
 ) -> CValue<'tcx> {
-    let not_fat = match in_lhs.layout().ty.sty {
-        ty::RawPtr(TypeAndMut { ty, mutbl: _ }) => {
-            ty.is_sized(fx.tcx.at(DUMMY_SP), ParamEnv::reveal_all())
-        }
-        ty::FnPtr(..) => true,
-        _ => bug!("trans_ptr_binop on non ptr"),
-    };
-    if not_fat {
+    let is_thin_ptr = in_lhs.layout().ty.builtin_deref(true).map(|TypeAndMut { ty, mutbl: _}| {
+        !has_ptr_meta(fx.tcx, ty)
+    }).unwrap_or(true);
+
+    if is_thin_ptr {
         match bin_op {
             BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
                 let lhs = in_lhs.load_scalar(fx);
@@ -313,8 +361,8 @@ pub fn trans_ptr_binop<'a, 'tcx: 'a>(
                 return codegen_compare_bin_op(fx, bin_op, false, lhs, rhs);
             }
             BinOp::Offset => {
+                let pointee_ty = in_lhs.layout().ty.builtin_deref(true).unwrap().ty;
                 let (base, offset) = (in_lhs, in_rhs.load_scalar(fx));
-                let pointee_ty = base.layout().ty.builtin_deref(true).unwrap().ty;
                 let pointee_size = fx.layout_of(pointee_ty).size.bytes();
                 let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64);
                 let base_val = base.load_scalar(fx);
@@ -341,14 +389,24 @@ pub fn trans_ptr_binop<'a, 'tcx: 'a>(
             BinOp::Lt | BinOp::Le | BinOp::Ge | BinOp::Gt => {
                 let ptr_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_ptr, rhs_ptr);
 
-                let ptr_cmp = fx.bcx.ins().icmp(bin_op_to_intcc(bin_op, false).unwrap(), lhs_ptr, rhs_ptr);
-                let extra_cmp = fx.bcx.ins().icmp(bin_op_to_intcc(bin_op, false).unwrap(), lhs_extra, rhs_extra);
+                let ptr_cmp =
+                    fx.bcx
+                        .ins()
+                        .icmp(bin_op_to_intcc(bin_op, false).unwrap(), lhs_ptr, rhs_ptr);
+                let extra_cmp = fx.bcx.ins().icmp(
+                    bin_op_to_intcc(bin_op, false).unwrap(),
+                    lhs_extra,
+                    rhs_extra,
+                );
 
                 fx.bcx.ins().select(ptr_eq, extra_cmp, ptr_cmp)
             }
             _ => panic!("bin_op {:?} on ptr", bin_op),
         };
 
-        CValue::by_val(fx.bcx.ins().bint(types::I8, res), fx.layout_of(fx.tcx.types.bool))
+        CValue::by_val(
+            fx.bcx.ins().bint(types::I8, res),
+            fx.layout_of(fx.tcx.types.bool),
+        )
     }
 }