Skip to content

Commit d735f6b

Browse files
committed
trans: implement CheckedBinaryOp in mir::constant.
1 parent b8c5053 commit d735f6b

File tree

1 file changed

+112
-70
lines changed

1 file changed

+112
-70
lines changed

src/librustc_trans/mir/constant.rs

+112-70
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@ use llvm::{self, ValueRef};
1212
use rustc::middle::const_val::ConstVal;
1313
use rustc_const_eval::ErrKind;
1414
use rustc_const_math::ConstInt::*;
15+
use rustc_const_math::ConstMathErr;
1516
use rustc::hir::def_id::DefId;
1617
use rustc::infer::TransNormalize;
1718
use rustc::mir::repr as mir;
1819
use rustc::mir::tcx::LvalueTy;
1920
use rustc::traits;
20-
use rustc::ty::{self, Ty, TypeFoldable};
21+
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
2122
use rustc::ty::cast::{CastTy, IntTy};
2223
use rustc::ty::subst::Substs;
2324
use {abi, adt, base, Disr};
@@ -713,73 +714,28 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
713714
let ty = lhs.ty;
714715
let binop_ty = self.mir.binop_ty(tcx, op, lhs.ty, rhs.ty);
715716
let (lhs, rhs) = (lhs.llval, rhs.llval);
716-
assert!(!ty.is_simd());
717-
let is_float = ty.is_fp();
718-
let signed = ty.is_signed();
719-
720-
if let (Some(lhs), Some(rhs)) = (to_const_int(lhs, ty, tcx),
721-
to_const_int(rhs, ty, tcx)) {
722-
let result = match op {
723-
mir::BinOp::Add => lhs + rhs,
724-
mir::BinOp::Sub => lhs - rhs,
725-
mir::BinOp::Mul => lhs * rhs,
726-
mir::BinOp::Div => lhs / rhs,
727-
mir::BinOp::Rem => lhs % rhs,
728-
mir::BinOp::Shl => lhs << rhs,
729-
mir::BinOp::Shr => lhs >> rhs,
730-
_ => Ok(lhs)
731-
};
732-
consts::const_err(self.ccx, span,
733-
result.map_err(ErrKind::Math),
734-
TrueConst::Yes)?;
735-
}
736-
737-
let llval = unsafe {
738-
match op {
739-
mir::BinOp::Add if is_float => llvm::LLVMConstFAdd(lhs, rhs),
740-
mir::BinOp::Add => llvm::LLVMConstAdd(lhs, rhs),
741-
742-
mir::BinOp::Sub if is_float => llvm::LLVMConstFSub(lhs, rhs),
743-
mir::BinOp::Sub => llvm::LLVMConstSub(lhs, rhs),
744-
745-
mir::BinOp::Mul if is_float => llvm::LLVMConstFMul(lhs, rhs),
746-
mir::BinOp::Mul => llvm::LLVMConstMul(lhs, rhs),
747-
748-
mir::BinOp::Div if is_float => llvm::LLVMConstFDiv(lhs, rhs),
749-
mir::BinOp::Div if signed => llvm::LLVMConstSDiv(lhs, rhs),
750-
mir::BinOp::Div => llvm::LLVMConstUDiv(lhs, rhs),
717+
Const::new(const_scalar_binop(op, lhs, rhs, ty), binop_ty)
718+
}
751719

752-
mir::BinOp::Rem if is_float => llvm::LLVMConstFRem(lhs, rhs),
753-
mir::BinOp::Rem if signed => llvm::LLVMConstSRem(lhs, rhs),
754-
mir::BinOp::Rem => llvm::LLVMConstURem(lhs, rhs),
720+
mir::Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
721+
let lhs = self.const_operand(lhs, span)?;
722+
let rhs = self.const_operand(rhs, span)?;
723+
let ty = lhs.ty;
724+
let val_ty = self.mir.binop_ty(tcx, op, lhs.ty, rhs.ty);
725+
let binop_ty = tcx.mk_tup(vec![val_ty, tcx.types.bool]);
726+
let (lhs, rhs) = (lhs.llval, rhs.llval);
727+
assert!(!ty.is_fp());
755728

756-
mir::BinOp::BitXor => llvm::LLVMConstXor(lhs, rhs),
757-
mir::BinOp::BitAnd => llvm::LLVMConstAnd(lhs, rhs),
758-
mir::BinOp::BitOr => llvm::LLVMConstOr(lhs, rhs),
759-
mir::BinOp::Shl => {
760-
let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs);
761-
llvm::LLVMConstShl(lhs, rhs)
762-
}
763-
mir::BinOp::Shr => {
764-
let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs);
765-
if signed { llvm::LLVMConstAShr(lhs, rhs) }
766-
else { llvm::LLVMConstLShr(lhs, rhs) }
767-
}
768-
mir::BinOp::Eq | mir::BinOp::Ne |
769-
mir::BinOp::Lt | mir::BinOp::Le |
770-
mir::BinOp::Gt | mir::BinOp::Ge => {
771-
if is_float {
772-
let cmp = base::bin_op_to_fcmp_predicate(op.to_hir_binop());
773-
llvm::ConstFCmp(cmp, lhs, rhs)
774-
} else {
775-
let cmp = base::bin_op_to_icmp_predicate(op.to_hir_binop(),
776-
signed);
777-
llvm::ConstICmp(cmp, lhs, rhs)
778-
}
779-
}
729+
match const_scalar_checked_binop(tcx, op, lhs, rhs, ty) {
730+
Some((llval, of)) => {
731+
let llof = C_bool(self.ccx, of);
732+
Const::new(C_struct(self.ccx, &[llval, llof], false), binop_ty)
780733
}
781-
};
782-
Const::new(llval, binop_ty)
734+
None => {
735+
span_bug!(span, "{:?} got non-integer operands: {:?} and {:?}",
736+
rvalue, Value(lhs), Value(rhs));
737+
}
738+
}
783739
}
784740

785741
mir::Rvalue::UnaryOp(op, ref operand) => {
@@ -792,11 +748,6 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
792748
}
793749
}
794750
mir::UnOp::Neg => {
795-
if let Some(cval) = to_const_int(lloperand, operand.ty, tcx) {
796-
consts::const_err(self.ccx, span,
797-
(-cval).map_err(ErrKind::Math),
798-
TrueConst::Yes)?;
799-
}
800751
let is_float = operand.ty.is_fp();
801752
unsafe {
802753
if is_float {
@@ -815,6 +766,97 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
815766

816767
Ok(val)
817768
}
769+
770+
}
771+
772+
pub fn const_scalar_binop(op: mir::BinOp,
773+
lhs: ValueRef,
774+
rhs: ValueRef,
775+
input_ty: Ty) -> ValueRef {
776+
assert!(!input_ty.is_simd());
777+
let is_float = input_ty.is_fp();
778+
let signed = input_ty.is_signed();
779+
780+
unsafe {
781+
match op {
782+
mir::BinOp::Add if is_float => llvm::LLVMConstFAdd(lhs, rhs),
783+
mir::BinOp::Add => llvm::LLVMConstAdd(lhs, rhs),
784+
785+
mir::BinOp::Sub if is_float => llvm::LLVMConstFSub(lhs, rhs),
786+
mir::BinOp::Sub => llvm::LLVMConstSub(lhs, rhs),
787+
788+
mir::BinOp::Mul if is_float => llvm::LLVMConstFMul(lhs, rhs),
789+
mir::BinOp::Mul => llvm::LLVMConstMul(lhs, rhs),
790+
791+
mir::BinOp::Div if is_float => llvm::LLVMConstFDiv(lhs, rhs),
792+
mir::BinOp::Div if signed => llvm::LLVMConstSDiv(lhs, rhs),
793+
mir::BinOp::Div => llvm::LLVMConstUDiv(lhs, rhs),
794+
795+
mir::BinOp::Rem if is_float => llvm::LLVMConstFRem(lhs, rhs),
796+
mir::BinOp::Rem if signed => llvm::LLVMConstSRem(lhs, rhs),
797+
mir::BinOp::Rem => llvm::LLVMConstURem(lhs, rhs),
798+
799+
mir::BinOp::BitXor => llvm::LLVMConstXor(lhs, rhs),
800+
mir::BinOp::BitAnd => llvm::LLVMConstAnd(lhs, rhs),
801+
mir::BinOp::BitOr => llvm::LLVMConstOr(lhs, rhs),
802+
mir::BinOp::Shl => {
803+
let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs);
804+
llvm::LLVMConstShl(lhs, rhs)
805+
}
806+
mir::BinOp::Shr => {
807+
let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs);
808+
if signed { llvm::LLVMConstAShr(lhs, rhs) }
809+
else { llvm::LLVMConstLShr(lhs, rhs) }
810+
}
811+
mir::BinOp::Eq | mir::BinOp::Ne |
812+
mir::BinOp::Lt | mir::BinOp::Le |
813+
mir::BinOp::Gt | mir::BinOp::Ge => {
814+
if is_float {
815+
let cmp = base::bin_op_to_fcmp_predicate(op.to_hir_binop());
816+
llvm::ConstFCmp(cmp, lhs, rhs)
817+
} else {
818+
let cmp = base::bin_op_to_icmp_predicate(op.to_hir_binop(),
819+
signed);
820+
llvm::ConstICmp(cmp, lhs, rhs)
821+
}
822+
}
823+
}
824+
}
825+
}
826+
827+
pub fn const_scalar_checked_binop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
828+
op: mir::BinOp,
829+
lllhs: ValueRef,
830+
llrhs: ValueRef,
831+
input_ty: Ty<'tcx>)
832+
-> Option<(ValueRef, bool)> {
833+
if let (Some(lhs), Some(rhs)) = (to_const_int(lllhs, input_ty, tcx),
834+
to_const_int(llrhs, input_ty, tcx)) {
835+
let result = match op {
836+
mir::BinOp::Add => lhs + rhs,
837+
mir::BinOp::Sub => lhs - rhs,
838+
mir::BinOp::Mul => lhs * rhs,
839+
mir::BinOp::Shl => lhs << rhs,
840+
mir::BinOp::Shr => lhs >> rhs,
841+
_ => {
842+
bug!("Operator `{:?}` is not a checkable operator", op)
843+
}
844+
};
845+
846+
let of = match result {
847+
Ok(_) => false,
848+
Err(ConstMathErr::Overflow(_)) |
849+
Err(ConstMathErr::ShiftNegative) => true,
850+
Err(err) => {
851+
bug!("Operator `{:?}` on `{:?}` and `{:?}` errored: {}",
852+
op, lhs, rhs, err.description());
853+
}
854+
};
855+
856+
Some((const_scalar_binop(op, lllhs, llrhs, input_ty), of))
857+
} else {
858+
None
859+
}
818860
}
819861

820862
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {

0 commit comments

Comments
 (0)