@@ -120,9 +120,20 @@ impl<'tcx> GotocCtx<'tcx> {
120
120
}
121
121
}
122
122
123
- /// c.f. `rustc_codegen_llvm::intrinsic` `impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx>`
124
- /// `fn codegen_intrinsic_call`
125
- /// c.f. <https://doc.rust-lang.org/std/intrinsics/index.html>
123
+ /// c.f. `rustc_codegen_llvm::intrinsic` `impl IntrinsicCallMethods<'tcx>
124
+ /// for Builder<'a, 'll, 'tcx>` `fn codegen_intrinsic_call` c.f.
125
+ /// <https://doc.rust-lang.org/std/intrinsics/index.html>
126
+ ///
127
+ /// ### A note on type checking
128
+ ///
129
+ /// The backend/codegen generally assumes that at this point arguments have
130
+ /// been type checked and that the given intrinsic is safe to call with the
131
+ /// provided arguments. However in rare cases the intrinsics type signature
132
+ /// is too permissive or has to be liberal because the types are enforced by
133
+ /// the specific code gen/backend. In such cases we handle the type checking
134
+ /// here. The type constraints enforced here must be at least as strict as
135
+ /// the assertions made in in the builder functions in
136
+ /// [`Expr`].
126
137
fn codegen_intrinsic (
127
138
& mut self ,
128
139
instance : Instance < ' tcx > ,
@@ -445,7 +456,7 @@ impl<'tcx> GotocCtx<'tcx> {
445
456
"cosf64" => codegen_simple_intrinsic ! ( Cos ) ,
446
457
"ctlz" => codegen_count_intrinsic ! ( ctlz, true ) ,
447
458
"ctlz_nonzero" => codegen_count_intrinsic ! ( ctlz, false ) ,
448
- "ctpop" => self . codegen_expr_to_place ( p, fargs. remove ( 0 ) . popcount ( ) ) ,
459
+ "ctpop" => self . codegen_ctpop ( * p, span , fargs. remove ( 0 ) , farg_types [ 0 ] ) ,
449
460
"cttz" => codegen_count_intrinsic ! ( cttz, true ) ,
450
461
"cttz_nonzero" => codegen_count_intrinsic ! ( cttz, false ) ,
451
462
"discriminant_value" => {
@@ -650,6 +661,48 @@ impl<'tcx> GotocCtx<'tcx> {
650
661
}
651
662
}
652
663
664
+ /// Perform type checking and code generation for the `ctpop` rust intrinsic.
665
+ fn codegen_ctpop (
666
+ & mut self ,
667
+ target_place : Place < ' tcx > ,
668
+ span : Option < Span > ,
669
+ arg : Expr ,
670
+ arg_rust_ty : Ty < ' tcx > ,
671
+ ) -> Stmt {
672
+ if !arg. typ ( ) . is_integer ( ) {
673
+ self . intrinsics_typecheck_fail ( span, "ctpop" , "integer type" , arg_rust_ty)
674
+ } else {
675
+ self . codegen_expr_to_place ( & target_place, arg. popcount ( ) )
676
+ }
677
+ }
678
+
679
+ /// Report that a delayed type check on an intrinsic failed.
680
+ ///
681
+ /// The idea is to blame one of the arguments on the failed type check and
682
+ /// report the type that was found for that argument in `actual`. The
683
+ /// `expected` type for that argument can be very permissive (e.g. "some
684
+ /// integer type") and as a result it allows a permissive string as
685
+ /// description.
686
+ ///
687
+ /// Calling this function will abort the compilation though that is not
688
+ /// obvious by the type.
689
+ fn intrinsics_typecheck_fail (
690
+ & self ,
691
+ span : Option < Span > ,
692
+ name : & str ,
693
+ expected : & str ,
694
+ actual : Ty ,
695
+ ) -> ! {
696
+ self . tcx . sess . span_err (
697
+ span. into_iter ( ) . collect :: < Vec < _ > > ( ) ,
698
+ format ! (
699
+ "Type check failed for intrinsic `{name}`: Expected {expected}, found {actual}"
700
+ ) ,
701
+ ) ;
702
+ self . tcx . sess . abort_if_errors ( ) ;
703
+ unreachable ! ( "Rustc should have aborted already" )
704
+ }
705
+
653
706
// Fast math intrinsics for floating point operations like `fadd_fast`
654
707
// assume that their inputs are finite:
655
708
// https://doc.rust-lang.org/std/intrinsics/fn.fadd_fast.html
0 commit comments