@@ -3,7 +3,7 @@ use rustc::middle::const_val::{ConstEvalErr, ErrKind};
33use rustc:: middle:: const_val:: ErrKind :: { TypeckError , CheckMatchError } ;
44use rustc:: mir;
55use rustc:: ty:: { self , TyCtxt , Ty , Instance } ;
6- use rustc:: ty:: layout:: { self , LayoutOf } ;
6+ use rustc:: ty:: layout:: { self , LayoutOf , Primitive } ;
77use rustc:: ty:: subst:: Subst ;
88
99use syntax:: ast:: Mutability ;
@@ -307,7 +307,7 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
307307 fn call_intrinsic < ' a > (
308308 ecx : & mut EvalContext < ' a , ' mir , ' tcx , Self > ,
309309 instance : ty:: Instance < ' tcx > ,
310- _args : & [ ValTy < ' tcx > ] ,
310+ args : & [ ValTy < ' tcx > ] ,
311311 dest : Place ,
312312 dest_layout : layout:: TyLayout < ' tcx > ,
313313 target : mir:: BasicBlock ,
@@ -345,8 +345,28 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
345345 } ;
346346 ecx. write_scalar ( dest, id_val, dest_layout. ty ) ?;
347347 }
348+ "ctpop" | "cttz" | "cttz_nonzero" | "ctlz" | "ctlz_nonzero" | "bswap" => {
349+ let ty = substs. type_at ( 0 ) ;
350+ let layout_of = ecx. layout_of ( ty) ?;
351+ let num = ecx. value_to_scalar ( args[ 0 ] ) ?. to_bits ( layout_of. size ) ?;
352+ let kind = match layout_of. abi {
353+ ty:: layout:: Abi :: Scalar ( ref scalar) => scalar. value ,
354+ _ => Err ( :: rustc:: mir:: interpret:: EvalErrorKind :: TypeNotPrimitive ( ty) ) ?,
355+ } ;
356+ let num = if intrinsic_name. ends_with ( "_nonzero" ) {
357+ if num == 0 {
358+ return err ! ( Intrinsic ( format!( "{} called on 0" , intrinsic_name) ) ) ;
359+ }
360+ numeric_intrinsic ( intrinsic_name. trim_right_matches ( "_nonzero" ) , num, kind) ?
361+ } else {
362+ numeric_intrinsic ( intrinsic_name, num, kind) ?
363+ } ;
364+ ecx. write_scalar ( dest, num, ty) ?;
365+ }
348366
349- name => return Err ( ConstEvalError :: NeedsRfc ( format ! ( "calling intrinsic `{}`" , name) ) . into ( ) ) ,
367+ name => return Err (
368+ ConstEvalError :: NeedsRfc ( format ! ( "calling intrinsic `{}`" , name) ) . into ( )
369+ ) ,
350370 }
351371
352372 ecx. goto_block ( target) ;
@@ -570,3 +590,40 @@ pub fn const_eval_provider<'a, 'tcx>(
570590 }
571591 } )
572592}
593+
594+ fn numeric_intrinsic < ' tcx > (
595+ name : & str ,
596+ bytes : u128 ,
597+ kind : Primitive ,
598+ ) -> EvalResult < ' tcx , Scalar > {
599+ macro_rules! integer_intrinsic {
600+ ( $method: ident) => ( {
601+ use rustc_target:: abi:: Integer ;
602+ let ( bits, defined) = match kind {
603+ Primitive :: Int ( Integer :: I8 , true ) => ( ( bytes as i8 ) . $method( ) as u128 , 8 ) ,
604+ Primitive :: Int ( Integer :: I8 , false ) => ( ( bytes as u8 ) . $method( ) as u128 , 8 ) ,
605+ Primitive :: Int ( Integer :: I16 , true ) => ( ( bytes as i16 ) . $method( ) as u128 , 16 ) ,
606+ Primitive :: Int ( Integer :: I16 , false ) => ( ( bytes as u16 ) . $method( ) as u128 , 16 ) ,
607+ Primitive :: Int ( Integer :: I32 , true ) => ( ( bytes as i32 ) . $method( ) as u128 , 32 ) ,
608+ Primitive :: Int ( Integer :: I32 , false ) => ( ( bytes as u32 ) . $method( ) as u128 , 32 ) ,
609+ Primitive :: Int ( Integer :: I64 , true ) => ( ( bytes as i64 ) . $method( ) as u128 , 64 ) ,
610+ Primitive :: Int ( Integer :: I64 , false ) => ( ( bytes as u64 ) . $method( ) as u128 , 64 ) ,
611+ Primitive :: Int ( Integer :: I128 , true ) => ( ( bytes as i128 ) . $method( ) as u128 , 128 ) ,
612+ Primitive :: Int ( Integer :: I128 , false ) => ( bytes. $method( ) as u128 , 128 ) ,
613+ _ => bug!( "invalid `{}` argument: {:?}" , name, bytes) ,
614+ } ;
615+
616+ Scalar :: Bits { bits, defined }
617+ } ) ;
618+ }
619+
620+ let result_val = match name {
621+ "bswap" => integer_intrinsic ! ( swap_bytes) ,
622+ "ctlz" => integer_intrinsic ! ( leading_zeros) ,
623+ "ctpop" => integer_intrinsic ! ( count_ones) ,
624+ "cttz" => integer_intrinsic ! ( trailing_zeros) ,
625+ _ => bug ! ( "not a numeric intrinsic: {}" , name) ,
626+ } ;
627+
628+ Ok ( result_val)
629+ }
0 commit comments