// Important to get types for both lhs and rhs, because one might be _|_
// and the other not.
Important to get types for both lhs and rhs, because one might be _|_
and the other not.
Important to get types for both lhs and rhs because one might be _|_ and the other not .
fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                 binop_expr: &hir::Expr,
                                 binop_ty: Ty<'tcx>,
                                 op: hir::BinOp,
                                 lhs_t: Ty<'tcx>,
                                 lhs: ValueRef,
                                 rhs_t: Ty<'tcx>,
                                 rhs: ValueRef)
                                 -> DatumBlock<'blk, 'tcx, Expr> {
    let _icx = push_ctxt("trans_eager_binop");
    let tcx = bcx.tcx();
    assert!(!lhs_t.is_simd());
    let is_float = lhs_t.is_fp();
    let is_signed = lhs_t.is_signed();
    let info = expr_info(binop_expr);
    let binop_debug_loc = binop_expr.debug_loc();
    let mut bcx = bcx;
    let val = match op.node {
      hir::BiAdd => {
        if is_float {
            FAdd(bcx, lhs, rhs, binop_debug_loc)
        } else {
            let (newbcx, res) = with_overflow_check(
                bcx, OverflowOp::Add, info, lhs_t, lhs, rhs, binop_debug_loc);
            bcx = newbcx;
            res
        }
      }
      hir::BiSub => {
        if is_float {
            FSub(bcx, lhs, rhs, binop_debug_loc)
        } else {
            let (newbcx, res) = with_overflow_check(
                bcx, OverflowOp::Sub, info, lhs_t, lhs, rhs, binop_debug_loc);
            bcx = newbcx;
            res
        }
      }
      hir::BiMul => {
        if is_float {
            FMul(bcx, lhs, rhs, binop_debug_loc)
        } else {
            let (newbcx, res) = with_overflow_check(
                bcx, OverflowOp::Mul, info, lhs_t, lhs, rhs, binop_debug_loc);
            bcx = newbcx;
            res
        }
      }
      hir::BiDiv => {
        if is_float {
            FDiv(bcx, lhs, rhs, binop_debug_loc)
        } else {
            // Only zero-check integers; fp /0 is NaN
            bcx = base::fail_if_zero_or_overflows(bcx,
                                                  expr_info(binop_expr),
                                                  op,
                                                  lhs,
                                                  rhs,
                                                  rhs_t);
            if is_signed {
                SDiv(bcx, lhs, rhs, binop_debug_loc)
            } else {
                UDiv(bcx, lhs, rhs, binop_debug_loc)
            }
        }
      }
      hir::BiRem => {
        if is_float {
            // LLVM currently always lowers the `frem` instructions appropriate
            // library calls typically found in libm. Notably f64 gets wired up
            // to `fmod` and f32 gets wired up to `fmodf`. Inconveniently for
            // us, 32-bit MSVC does not actually have a `fmodf` symbol, it's
            // instead just an inline function in a header that goes up to a
            // f64, uses `fmod`, and then comes back down to a f32.
            //
            // Although LLVM knows that `fmodf` doesn't exist on MSVC, it will
            // still unconditionally lower frem instructions over 32-bit floats
            // to a call to `fmodf`. To work around this we special case MSVC
            // 32-bit float rem instructions and instead do the call out to
            // `fmod` ourselves.
            //
            // Note that this is currently duplicated with src/libcore/ops.rs
            // which does the same thing, and it would be nice to perhaps unify
            // these two implementations on day! Also note that we call `fmod`
            // for both 32 and 64-bit floats because if we emit any FRem
            // instruction at all then LLVM is capable of optimizing it into a
            // 32-bit FRem (which we're trying to avoid).
            let use_fmod = tcx.sess.target.target.options.is_like_msvc &&
                           tcx.sess.target.target.arch == "x86";
            if use_fmod {
                let f64t = Type::f64(bcx.ccx());
                let fty = Type::func(&[f64t, f64t], &f64t);
                let llfn = declare::declare_cfn(bcx.ccx(), "fmod", fty,
                                                tcx.types.f64);
                if lhs_t == tcx.types.f32 {
                    let lhs = FPExt(bcx, lhs, f64t);
                    let rhs = FPExt(bcx, rhs, f64t);
                    let res = Call(bcx, llfn, &[lhs, rhs], None, binop_debug_loc);
                    FPTrunc(bcx, res, Type::f32(bcx.ccx()))
                } else {
                    Call(bcx, llfn, &[lhs, rhs], None, binop_debug_loc)
                }
            } else {
                FRem(bcx, lhs, rhs, binop_debug_loc)
            }
        } else {
            // Only zero-check integers; fp %0 is NaN
            bcx = base::fail_if_zero_or_overflows(bcx,
                                                  expr_info(binop_expr),
                                                  op, lhs, rhs, rhs_t);
            if is_signed {
                SRem(bcx, lhs, rhs, binop_debug_loc)
            } else {
                URem(bcx, lhs, rhs, binop_debug_loc)
            }
        }
      }
      hir::BiBitOr => Or(bcx, lhs, rhs, binop_debug_loc),
      hir::BiBitAnd => And(bcx, lhs, rhs, binop_debug_loc),
      hir::BiBitXor => Xor(bcx, lhs, rhs, binop_debug_loc),
      hir::BiShl => {
          let (newbcx, res) = with_overflow_check(
              bcx, OverflowOp::Shl, info, lhs_t, lhs, rhs, binop_debug_loc);
          bcx = newbcx;
          res
      }
      hir::BiShr => {
          let (newbcx, res) = with_overflow_check(
              bcx, OverflowOp::Shr, info, lhs_t, lhs, rhs, binop_debug_loc);
          bcx = newbcx;
          res
      }
      hir::BiEq | hir::BiNe | hir::BiLt | hir::BiGe | hir::BiLe | hir::BiGt => {
          base::compare_scalar_types(bcx, lhs, rhs, lhs_t, op.node, binop_debug_loc)
      }
      _ => {
        bcx.tcx().sess.span_bug(binop_expr.span, "unexpected binop");
      }
    };
    immediate_rvalue_bcx(bcx, val, binop_ty).to_expr_datumblock()
}
fn trans_eager_binop < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > , binop_expr : & hir :: Expr , binop_ty : Ty < ' tcx > , op : hir :: BinOp , lhs_t : Ty < ' tcx > , lhs : ValueRef , rhs_t : Ty < ' tcx > , rhs : ValueRef ) -> DatumBlock < ' blk , ' tcx , Expr > { let _icx = push_ctxt ( " " ) ; let tcx = bcx . tcx ( ) ; assert ! ( lhs_t is_simd ( ) ) ; let is_float = lhs_t . is_fp ( ) ; let is_signed = lhs_t . is_signed ( ) ; let info = expr_info ( binop_expr ) ; let binop_debug_loc = binop_expr . debug_loc ( ) ; let mut bcx = bcx ; let val = match op . node { hir :: BiAdd => { if is_float { FAdd ( bcx , lhs , rhs , binop_debug_loc ) } else { let ( newbcx , res ) = with_overflow_check ( bcx , OverflowOp :: Add , info , lhs_t , lhs , rhs , binop_debug_loc ) ; bcx = newbcx ; res } } hir :: BiSub => { if is_float { FSub ( bcx , lhs , rhs , binop_debug_loc ) } else { let ( newbcx , res ) = with_overflow_check ( bcx , OverflowOp :: Sub , info , lhs_t , lhs , rhs , binop_debug_loc ) ; bcx = newbcx ; res } } hir :: BiMul => { if is_float { FMul ( bcx , lhs , rhs , binop_debug_loc ) } else { let ( newbcx , res ) = with_overflow_check ( bcx , OverflowOp :: Mul , info , lhs_t , lhs , rhs , binop_debug_loc ) ; bcx = newbcx ; res } } hir :: BiDiv => { if is_float { FDiv ( bcx , lhs , rhs , binop_debug_loc ) } else { // Only zero-check integers; fp /0 is NaN bcx = base :: fail_if_zero_or_overflows ( bcx , expr_info ( binop_expr ) , op , lhs , rhs , rhs_t ) ; if is_signed { SDiv ( bcx , lhs , rhs , binop_debug_loc ) } else { UDiv ( bcx , lhs , rhs , binop_debug_loc ) } } } hir :: BiRem => { if is_float { // LLVM currently always lowers the `frem` instructions appropriate // library calls typically found in libm. Notably f64 gets wired up // to `fmod` and f32 gets wired up to `fmodf`. Inconveniently for // us, 32-bit MSVC does not actually have a `fmodf` symbol, it's // instead just an inline function in a header that goes up to a // f64, uses `fmod`, and then comes back down to a f32. // // Although LLVM knows that `fmodf` doesn't exist on MSVC, it will // still unconditionally lower frem instructions over 32-bit floats // to a call to `fmodf`. To work around this we special case MSVC // 32-bit float rem instructions and instead do the call out to // `fmod` ourselves. // // Note that this is currently duplicated with src/libcore/ops.rs // which does the same thing, and it would be nice to perhaps unify // these two implementations on day! Also note that we call `fmod` // for both 32 and 64-bit floats because if we emit any FRem // instruction at all then LLVM is capable of optimizing it into a // 32-bit FRem (which we're trying to avoid). let use_fmod = tcx . sess . target . target . options . is_like_msvc && tcx . sess . target . target . arch == " " ; if use_fmod { let f64t = Type :: f64 ( bcx . ccx ( ) ) ; let fty = Type :: func ( & [ f64t , f64t ] , & f64t ) ; let llfn = declare :: declare_cfn ( bcx . ccx ( ) , " " , fty , tcx . types . f64 ) ; if lhs_t == tcx . types . f32 { let lhs = FPExt ( bcx , lhs , f64t ) ; let rhs = FPExt ( bcx , rhs , f64t ) ; let res = Call ( bcx , llfn , & [ lhs , rhs ] , None , binop_debug_loc ) ; FPTrunc ( bcx , res , Type :: f32 ( bcx . ccx ( ) ) ) } else { Call ( bcx , llfn , & [ lhs , rhs ] , None , binop_debug_loc ) } } else { FRem ( bcx , lhs , rhs , binop_debug_loc ) } } else { // Only zero-check integers; fp %0 is NaN bcx = base :: fail_if_zero_or_overflows ( bcx , expr_info ( binop_expr ) , op , lhs , rhs , rhs_t ) ; if is_signed { SRem ( bcx , lhs , rhs , binop_debug_loc ) } else { URem ( bcx , lhs , rhs , binop_debug_loc ) } } } hir :: BiBitOr => Or ( bcx , lhs , rhs , binop_debug_loc ) , hir :: BiBitAnd => And ( bcx , lhs , rhs , binop_debug_loc ) , hir :: BiBitXor => Xor ( bcx , lhs , rhs , binop_debug_loc ) , hir :: BiShl => { let ( newbcx , res ) = with_overflow_check ( bcx , OverflowOp :: Shl , info , lhs_t , lhs , rhs , binop_debug_loc ) ; bcx = newbcx ; res } hir :: BiShr => { let ( newbcx , res ) = with_overflow_check ( bcx , OverflowOp :: Shr , info , lhs_t , lhs , rhs , binop_debug_loc ) ; bcx = newbcx ; res } hir :: BiEq | hir :: BiNe | hir :: BiLt | hir :: BiGe | hir :: BiLe | hir :: BiGt => { base :: compare_scalar_types ( bcx , lhs , rhs , lhs_t , op . node , binop_debug_loc ) } _ => { bcx . tcx ( ) . sess . span_bug ( binop_expr . span , " " ) ; } } ; immediate_rvalue_bcx ( bcx , val , binop_ty ) . to_expr_datumblock ( ) }
Important to get types for both lhs and rhs, because one might be _|_
and the other not.
Important to get types for both lhs and rhs because one might be _|_ and the other not .
bcx
Block<'blk, 'tcx>
binop_expr
&hir::Expr
binop_ty
Ty<'tcx>
op
hir::BinOp
lhs_t
Ty<'tcx>
lhs
ValueRef
rhs_t
Ty<'tcx>
rhs
ValueRef