@@ -2479,43 +2479,187 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
24792479 None ,
24802480 ) ;
24812481
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 {
25082485 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)
25102487 }
25112488 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 ( ) )
25132490 }
25142491 }
25152492
25162493 fty
25172494}
25182495
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+
25192663fn is_foreign_item ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> bool {
25202664 match tcx. hir ( ) . get_if_local ( def_id) {
25212665 Some ( Node :: ForeignItem ( ..) ) => true ,
0 commit comments