@@ -3,7 +3,7 @@ use rustc::middle::const_val::{ConstEvalErr, ErrKind};
3
3
use rustc:: middle:: const_val:: ErrKind :: { TypeckError , CheckMatchError } ;
4
4
use rustc:: mir;
5
5
use rustc:: ty:: { self , TyCtxt , Ty , Instance } ;
6
- use rustc:: ty:: layout:: { self , LayoutOf } ;
6
+ use rustc:: ty:: layout:: { self , LayoutOf , Primitive } ;
7
7
use rustc:: ty:: subst:: Subst ;
8
8
9
9
use syntax:: ast:: Mutability ;
@@ -307,7 +307,7 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
307
307
fn call_intrinsic < ' a > (
308
308
ecx : & mut EvalContext < ' a , ' mir , ' tcx , Self > ,
309
309
instance : ty:: Instance < ' tcx > ,
310
- _args : & [ ValTy < ' tcx > ] ,
310
+ args : & [ ValTy < ' tcx > ] ,
311
311
dest : Place ,
312
312
dest_layout : layout:: TyLayout < ' tcx > ,
313
313
target : mir:: BasicBlock ,
@@ -345,8 +345,28 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
345
345
} ;
346
346
ecx. write_scalar ( dest, id_val, dest_layout. ty ) ?;
347
347
}
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
+ }
348
366
349
- name => return Err ( ConstEvalError :: NeedsRfc ( format ! ( "calling intrinsic `{}`" , name) ) . into ( ) ) ,
367
+ name => return Err (
368
+ ConstEvalError :: NeedsRfc ( format ! ( "calling intrinsic `{}`" , name) ) . into ( )
369
+ ) ,
350
370
}
351
371
352
372
ecx. goto_block ( target) ;
@@ -570,3 +590,40 @@ pub fn const_eval_provider<'a, 'tcx>(
570
590
}
571
591
} )
572
592
}
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