@@ -12,12 +12,13 @@ use llvm::{self, ValueRef};
1212use rustc:: middle:: const_val:: ConstVal ;
1313use rustc_const_eval:: ErrKind ;
1414use rustc_const_math:: ConstInt :: * ;
15+ use rustc_const_math:: ConstMathErr ;
1516use rustc:: hir:: def_id:: DefId ;
1617use rustc:: infer:: TransNormalize ;
1718use rustc:: mir:: repr as mir;
1819use rustc:: mir:: tcx:: LvalueTy ;
1920use rustc:: traits;
20- use rustc:: ty:: { self , Ty , TypeFoldable } ;
21+ use rustc:: ty:: { self , Ty , TyCtxt , TypeFoldable } ;
2122use rustc:: ty:: cast:: { CastTy , IntTy } ;
2223use rustc:: ty:: subst:: Substs ;
2324use { 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
820862impl < ' bcx , ' tcx > MirContext < ' bcx , ' tcx > {
0 commit comments