@@ -2479,43 +2479,187 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
2479
2479
None ,
2480
2480
) ;
2481
2481
2482
- // Feature gate SIMD types in FFI, since I am not sure that the
2483
- // ABIs are handled at all correctly. -huonw
2484
- if abi != abi:: Abi :: RustIntrinsic
2485
- && abi != abi:: Abi :: PlatformIntrinsic
2486
- && !tcx. features ( ) . simd_ffi
2487
- {
2488
- let check = |ast_ty : & hir:: Ty < ' _ > , ty : Ty < ' _ > | {
2489
- if ty. is_simd ( ) {
2490
- let snip = tcx
2491
- . sess
2492
- . source_map ( )
2493
- . span_to_snippet ( ast_ty. span )
2494
- . map_or_else ( |_| String :: new ( ) , |s| format ! ( " `{}`" , s) ) ;
2495
- tcx. sess
2496
- . struct_span_err (
2497
- ast_ty. span ,
2498
- & format ! (
2499
- "use of SIMD type{} in FFI is highly experimental and \
2500
- may result in invalid code",
2501
- snip
2502
- ) ,
2503
- )
2504
- . help ( "add `#![feature(simd_ffi)]` to the crate attributes to enable" )
2505
- . emit ( ) ;
2506
- }
2507
- } ;
2482
+ // Using SIMD types in FFI signatures requires the signature
2483
+ // to have appropriate `#[target_feature]`'s enabled.
2484
+ if abi != abi:: Abi :: RustIntrinsic && abi != abi:: Abi :: PlatformIntrinsic {
2508
2485
for ( input, ty) in iter:: zip ( decl. inputs , fty. inputs ( ) . skip_binder ( ) ) {
2509
- check ( & input, ty)
2486
+ simd_ffi_check ( tcx , def_id , & input, ty)
2510
2487
}
2511
2488
if let hir:: FnRetTy :: Return ( ref ty) = decl. output {
2512
- check ( & ty, fty. output ( ) . skip_binder ( ) )
2489
+ simd_ffi_check ( tcx , def_id , & ty, fty. output ( ) . skip_binder ( ) )
2513
2490
}
2514
2491
}
2515
2492
2516
2493
fty
2517
2494
}
2518
2495
2496
+ /// Returns `Ok()` if the target-feature allows using the SIMD type on C FFI.
2497
+ /// Otherwise, returns `Err(Some())` if the target_feature needs to be enabled or
2498
+ /// or `Err(None)` if it's unsupported.
2499
+ fn simd_ffi_feature_check (
2500
+ target : & str ,
2501
+ simd_width : u64 ,
2502
+ simd_elem_width : u64 ,
2503
+ feature : String ,
2504
+ ) -> Result < ( ) , Option < & ' static str > > {
2505
+ match target {
2506
+ t if t. contains ( "x86" ) => {
2507
+ // FIXME: this needs to be architecture dependent and
2508
+ // should probably belong somewhere else:
2509
+ // * on mips: 16 => msa,
2510
+ // * wasm: 16 => simd128
2511
+ match simd_width {
2512
+ 8 if feature. contains ( "mmx" )
2513
+ || feature. contains ( "sse" )
2514
+ || feature. contains ( "ssse" )
2515
+ || feature. contains ( "avx" ) =>
2516
+ {
2517
+ Ok ( ( ) )
2518
+ }
2519
+ 8 => Err ( Some ( "mmx" ) ) ,
2520
+ 16 if feature. contains ( "sse" )
2521
+ || feature. contains ( "ssse" )
2522
+ || feature. contains ( "avx" ) =>
2523
+ {
2524
+ Ok ( ( ) )
2525
+ }
2526
+ 16 => Err ( Some ( "sse" ) ) ,
2527
+ 32 if feature. contains ( "avx" ) => Ok ( ( ) ) ,
2528
+ 32 => Err ( Some ( "avx" ) ) ,
2529
+ 64 if feature. contains ( "avx512" ) => Ok ( ( ) ) ,
2530
+ 64 => Err ( Some ( "acx512" ) ) ,
2531
+ _ => Err ( None ) ,
2532
+ }
2533
+ }
2534
+ t if t. contains ( "arm" ) => {
2535
+ match simd_width {
2536
+ // 32-bit arm does not support vectors with 64-bit wide elements
2537
+ 8 | 16 if simd_elem_width < 8 => {
2538
+ if feature. contains ( "neon" ) {
2539
+ Ok ( ( ) )
2540
+ } else {
2541
+ Err ( Some ( "neon" ) )
2542
+ }
2543
+ }
2544
+ _ => Err ( None ) ,
2545
+ }
2546
+ }
2547
+ t if t. contains ( "aarch64" ) => match simd_width {
2548
+ 8 | 16 => {
2549
+ if feature. contains ( "neon" ) {
2550
+ Ok ( ( ) )
2551
+ } else {
2552
+ Err ( Some ( "neon" ) )
2553
+ }
2554
+ }
2555
+ _ => Err ( None ) ,
2556
+ } ,
2557
+ t if t. contains ( "powerpc" ) => {
2558
+ match simd_width {
2559
+ // 64-bit wide elements are only available in VSX:
2560
+ 16 if simd_elem_width == 8 => {
2561
+ if feature. contains ( "vsx" ) {
2562
+ Ok ( ( ) )
2563
+ } else {
2564
+ Err ( Some ( "vsx" ) )
2565
+ }
2566
+ }
2567
+ 16 if simd_elem_width < 8 => {
2568
+ if feature. contains ( "altivec" ) {
2569
+ Ok ( ( ) )
2570
+ } else {
2571
+ Err ( Some ( "altivec" ) )
2572
+ }
2573
+ }
2574
+ _ => Err ( None ) ,
2575
+ }
2576
+ }
2577
+ t if t. contains ( "mips" ) => match simd_width {
2578
+ 16 => {
2579
+ if feature. contains ( "msa" ) {
2580
+ Ok ( ( ) )
2581
+ } else {
2582
+ Err ( Some ( "msa" ) )
2583
+ }
2584
+ }
2585
+ _ => Err ( None ) ,
2586
+ } ,
2587
+ _ => Err ( None ) ,
2588
+ }
2589
+ }
2590
+
2591
+ fn simd_ffi_check < ' tcx > (
2592
+ tcx : TyCtxt < ' tcx > ,
2593
+ def_id : DefId ,
2594
+ ast_ty : & hir:: Ty < ' _ > ,
2595
+ ty : Ty < ' tcx > ,
2596
+ ) {
2597
+ if !ty. is_simd ( ) {
2598
+ return ;
2599
+ }
2600
+
2601
+ // The use of SIMD types in FFI is feature-gated:
2602
+ if !tcx. features ( ) . simd_ffi {
2603
+ tcx. sess
2604
+ . struct_span_err (
2605
+ ast_ty. span ,
2606
+ & format ! (
2607
+ "use of SIMD type `{}` in FFI is unstable" ,
2608
+ tcx. hir( ) . node_to_string( ast_ty. hir_id)
2609
+ ) ,
2610
+ )
2611
+ . help ( "add #![feature(simd_ffi)] to the crate attributes to enable" )
2612
+ . emit ( ) ;
2613
+ return ;
2614
+ }
2615
+
2616
+ // If rustdoc, then we don't type check SIMD on FFI because rustdoc requires
2617
+ // being able to compile a target, with features of other targets enabled
2618
+ // (e.g. `x86+neon`, yikes).
2619
+ if tcx. sess . opts . actually_rustdoc {
2620
+ return ;
2621
+ }
2622
+
2623
+ let attrs = tcx. codegen_fn_attrs ( def_id) ;
2624
+
2625
+ // Skip LLVM intrinsics.
2626
+ if let Some ( link_name) = attrs. link_name {
2627
+ if link_name. to_ident_string ( ) . starts_with ( "llvm." ) {
2628
+ return ;
2629
+ }
2630
+ }
2631
+
2632
+ let features = & attrs. target_features ;
2633
+ let simd_len = tcx
2634
+ . layout_of ( ty:: ParamEnvAnd { param_env : ty:: ParamEnv :: empty ( ) , value : ty } )
2635
+ . unwrap ( )
2636
+ . layout
2637
+ . size
2638
+ . bytes ( ) ;
2639
+ let ( simd_size, _) = ty. simd_size_and_type ( tcx) ;
2640
+ let simd_elem_width = simd_len / simd_size;
2641
+ let target: & str = & tcx. sess . target . arch ;
2642
+
2643
+ for f in features {
2644
+ if let Err ( v) = simd_ffi_feature_check ( target, simd_len, simd_elem_width, f. to_ident_string ( ) ) {
2645
+ let type_str = tcx. hir ( ) . node_to_string ( ast_ty. hir_id ) ;
2646
+ let msg = if let Some ( f) = v {
2647
+ format ! (
2648
+ "use of SIMD type `{}` in FFI requires `#[target_feature(enable = \" {}\" )]`" ,
2649
+ type_str, f,
2650
+ )
2651
+ } else {
2652
+ format ! (
2653
+ "use of SIMD type `{}` in FFI not supported by any target features" ,
2654
+ type_str
2655
+ )
2656
+ } ;
2657
+ tcx. sess . struct_span_err ( ast_ty. span , & msg) . emit ( ) ;
2658
+ return ;
2659
+ }
2660
+ }
2661
+ }
2662
+
2519
2663
fn is_foreign_item ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> bool {
2520
2664
match tcx. hir ( ) . get_if_local ( def_id) {
2521
2665
Some ( Node :: ForeignItem ( ..) ) => true ,
0 commit comments