@@ -629,27 +629,24 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
629
629
}
630
630
631
631
sym:: float_to_int_unchecked => {
632
- if float_type_width ( arg_tys[ 0 ] ) . is_none ( ) {
633
- span_invalid_monomorphization_error (
634
- tcx. sess ,
635
- span,
636
- & format ! (
637
- "invalid monomorphization of `float_to_int_unchecked` \
632
+ let float_width = match float_type_width ( arg_tys[ 0 ] ) {
633
+ Some ( width) => width,
634
+ None => {
635
+ span_invalid_monomorphization_error (
636
+ tcx. sess ,
637
+ span,
638
+ & format ! (
639
+ "invalid monomorphization of `float_to_int_unchecked` \
638
640
intrinsic: expected basic float type, \
639
641
found `{}`",
640
- arg_tys[ 0 ]
641
- ) ,
642
- ) ;
643
- return ;
644
- }
645
- match int_type_width_signed ( ret_ty, self . cx ) {
646
- Some ( ( width, signed) ) => {
647
- if signed {
648
- self . fptosi ( args[ 0 ] . immediate ( ) , self . cx . type_ix ( width) )
649
- } else {
650
- self . fptoui ( args[ 0 ] . immediate ( ) , self . cx . type_ix ( width) )
651
- }
642
+ arg_tys[ 0 ]
643
+ ) ,
644
+ ) ;
645
+ return ;
652
646
}
647
+ } ;
648
+ let ( width, signed) = match int_type_width_signed ( ret_ty, self . cx ) {
649
+ Some ( pair) => pair,
653
650
None => {
654
651
span_invalid_monomorphization_error (
655
652
tcx. sess ,
@@ -663,7 +660,49 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
663
660
) ;
664
661
return ;
665
662
}
663
+ } ;
664
+
665
+ // The LLVM backend can reorder and speculate `fptosi` and
666
+ // `fptoui`, so on WebAssembly the codegen for this instruction
667
+ // is quite heavyweight. To avoid this heavyweight codegen we
668
+ // instead use the raw wasm intrinsics which will lower to one
669
+ // instruction in WebAssembly (`iNN.trunc_fMM_{s,u}`). This one
670
+ // instruction will trap if the operand is out of bounds, but
671
+ // that's ok since this intrinsic is UB if the operands are out
672
+ // of bounds, so the behavior can be different on WebAssembly
673
+ // than other targets.
674
+ //
675
+ // Note, however, that when the `nontrapping-fptoint` feature is
676
+ // enabled in LLVM then LLVM will lower `fptosi` to
677
+ // `iNN.trunc_sat_fMM_{s,u}`, so if that's the case we don't
678
+ // bother with intrinsics.
679
+ let mut result = None ;
680
+ if self . sess ( ) . target . target . arch == "wasm32"
681
+ && !self . sess ( ) . target_features . contains ( & sym:: nontrapping_dash_fptoint)
682
+ {
683
+ let name = match ( width, float_width, signed) {
684
+ ( 32 , 32 , true ) => Some ( "llvm.wasm.trunc.signed.i32.f32" ) ,
685
+ ( 32 , 64 , true ) => Some ( "llvm.wasm.trunc.signed.i32.f64" ) ,
686
+ ( 64 , 32 , true ) => Some ( "llvm.wasm.trunc.signed.i64.f32" ) ,
687
+ ( 64 , 64 , true ) => Some ( "llvm.wasm.trunc.signed.i64.f64" ) ,
688
+ ( 32 , 32 , false ) => Some ( "llvm.wasm.trunc.unsigned.i32.f32" ) ,
689
+ ( 32 , 64 , false ) => Some ( "llvm.wasm.trunc.unsigned.i32.f64" ) ,
690
+ ( 64 , 32 , false ) => Some ( "llvm.wasm.trunc.unsigned.i64.f32" ) ,
691
+ ( 64 , 64 , false ) => Some ( "llvm.wasm.trunc.unsigned.i64.f64" ) ,
692
+ _ => None ,
693
+ } ;
694
+ if let Some ( name) = name {
695
+ let intrinsic = self . get_intrinsic ( name) ;
696
+ result = Some ( self . call ( intrinsic, & [ args[ 0 ] . immediate ( ) ] , None ) ) ;
697
+ }
666
698
}
699
+ result. unwrap_or_else ( || {
700
+ if signed {
701
+ self . fptosi ( args[ 0 ] . immediate ( ) , self . cx . type_ix ( width) )
702
+ } else {
703
+ self . fptoui ( args[ 0 ] . immediate ( ) , self . cx . type_ix ( width) )
704
+ }
705
+ } )
667
706
}
668
707
669
708
sym:: discriminant_value => {
0 commit comments