@@ -19,9 +19,9 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
19
19
StableHasherResult } ;
20
20
21
21
pub use rustc_target:: abi:: * ;
22
- use rustc_target:: spec:: HasTargetSpec ;
22
+ use rustc_target:: spec:: { HasTargetSpec , abi :: Abi as SpecAbi } ;
23
23
use rustc_target:: abi:: call:: {
24
- ArgAttribute , ArgAttributes , ArgType , Conv , FnType , IgnoreMode , PassMode
24
+ ArgAttribute , ArgAttributes , ArgType , Conv , FnType , IgnoreMode , PassMode , Reg , RegKind
25
25
} ;
26
26
27
27
@@ -2266,81 +2266,48 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for LayoutError<'gcx>
2266
2266
}
2267
2267
}
2268
2268
2269
- pub trait FnTypeExt < ' tcx , C > {
2270
- fn of_instance ( cx : & C , instance : & ty:: Instance < ' tcx > ) -> Self
2271
- where
2272
- C : LayoutOf < Ty = Ty < ' tcx > , TyLayout = TyLayout < ' tcx > >
2273
- + HasDataLayout
2274
- + HasTargetSpec
2275
- + HasTyCtxt < ' tcx >
2276
- + HasParamEnv < ' tcx > ;
2277
- fn new ( cx : & C , sig : ty:: FnSig < ' tcx > , extra_args : & [ Ty < ' tcx > ] ) -> Self
2278
- where
2279
- C : LayoutOf < Ty = Ty < ' tcx > , TyLayout = TyLayout < ' tcx > >
2280
- + HasDataLayout
2281
- + HasTargetSpec
2282
- + HasTyCtxt < ' tcx >
2283
- + HasParamEnv < ' tcx > ;
2284
- fn new_vtable ( cx : & C , sig : ty:: FnSig < ' tcx > , extra_args : & [ Ty < ' tcx > ] ) -> Self
2285
- where
2286
- C : LayoutOf < Ty = Ty < ' tcx > , TyLayout = TyLayout < ' tcx > >
2287
- + HasDataLayout
2288
- + HasTargetSpec
2289
- + HasTyCtxt < ' tcx >
2290
- + HasParamEnv < ' tcx > ;
2269
+ pub trait FnTypeExt < ' tcx , C >
2270
+ where
2271
+ C : LayoutOf < Ty = Ty < ' tcx > , TyLayout = TyLayout < ' tcx > >
2272
+ + HasDataLayout
2273
+ + HasTargetSpec
2274
+ + HasTyCtxt < ' tcx >
2275
+ + HasParamEnv < ' tcx > ,
2276
+ {
2277
+ fn of_instance ( cx : & C , instance : & ty:: Instance < ' tcx > ) -> Self ;
2278
+ fn new ( cx : & C , sig : ty:: FnSig < ' tcx > , extra_args : & [ Ty < ' tcx > ] ) -> Self ;
2279
+ fn new_vtable ( cx : & C , sig : ty:: FnSig < ' tcx > , extra_args : & [ Ty < ' tcx > ] ) -> Self ;
2291
2280
fn new_internal (
2292
2281
cx : & C ,
2293
2282
sig : ty:: FnSig < ' tcx > ,
2294
2283
extra_args : & [ Ty < ' tcx > ] ,
2295
2284
mk_arg_type : impl Fn ( Ty < ' tcx > , Option < usize > ) -> ArgType < ' tcx , Ty < ' tcx > > ,
2296
- ) -> Self
2297
- where
2298
- C : LayoutOf < Ty = Ty < ' tcx > , TyLayout = TyLayout < ' tcx > >
2299
- + HasDataLayout
2300
- + HasTargetSpec
2301
- + HasTyCtxt < ' tcx >
2302
- + HasParamEnv < ' tcx > ;
2285
+ ) -> Self ;
2286
+ fn adjust_for_abi ( & mut self , cx : & C , abi : SpecAbi ) ;
2303
2287
}
2304
2288
2305
-
2306
- impl < ' tcx , C > FnTypeExt < ' tcx , C > for call:: FnType < ' tcx , Ty < ' tcx > > {
2307
- fn of_instance ( cx : & C , instance : & ty:: Instance < ' tcx > ) -> Self
2308
- where
2309
- C : LayoutOf < Ty = Ty < ' tcx > , TyLayout = TyLayout < ' tcx > >
2310
- + HasDataLayout
2311
- + HasTargetSpec
2312
- + HasTargetSpec
2313
- + HasTyCtxt < ' tcx >
2314
- + HasParamEnv < ' tcx > ,
2315
- {
2289
+ impl < ' tcx , C > FnTypeExt < ' tcx , C > for call:: FnType < ' tcx , Ty < ' tcx > >
2290
+ where
2291
+ C : LayoutOf < Ty = Ty < ' tcx > , TyLayout = TyLayout < ' tcx > >
2292
+ + HasDataLayout
2293
+ + HasTargetSpec
2294
+ + HasTyCtxt < ' tcx >
2295
+ + HasParamEnv < ' tcx > ,
2296
+ {
2297
+ fn of_instance ( cx : & C , instance : & ty:: Instance < ' tcx > ) -> Self {
2316
2298
let sig = instance. fn_sig ( cx. tcx ( ) ) ;
2317
2299
let sig = cx
2318
2300
. tcx ( )
2319
2301
. normalize_erasing_late_bound_regions ( ty:: ParamEnv :: reveal_all ( ) , & sig) ;
2320
2302
call:: FnType :: new ( cx, sig, & [ ] )
2321
2303
}
2322
2304
2323
- fn new ( cx : & C , sig : ty:: FnSig < ' tcx > , extra_args : & [ Ty < ' tcx > ] ) -> Self
2324
- where
2325
- C : LayoutOf < Ty = Ty < ' tcx > , TyLayout = TyLayout < ' tcx > >
2326
- + HasDataLayout
2327
- + HasTargetSpec
2328
- + HasTyCtxt < ' tcx >
2329
- + HasParamEnv < ' tcx > ,
2330
- {
2305
+ fn new ( cx : & C , sig : ty:: FnSig < ' tcx > , extra_args : & [ Ty < ' tcx > ] ) -> Self {
2331
2306
call:: FnType :: new_internal ( cx, sig, extra_args, |ty, _| ArgType :: new ( cx. layout_of ( ty) ) )
2332
2307
}
2333
2308
2334
-
2335
- fn new_vtable ( cx : & C , sig : ty:: FnSig < ' tcx > , extra_args : & [ Ty < ' tcx > ] ) -> Self
2336
- where
2337
- C : LayoutOf < Ty = Ty < ' tcx > , TyLayout = TyLayout < ' tcx > >
2338
- + HasDataLayout
2339
- + HasTargetSpec
2340
- + HasTyCtxt < ' tcx >
2341
- + HasParamEnv < ' tcx > ,
2342
- {
2343
- FnType :: new_internal ( cx, sig, extra_args, |ty, arg_idx| {
2309
+ fn new_vtable ( cx : & C , sig : ty:: FnSig < ' tcx > , extra_args : & [ Ty < ' tcx > ] ) -> Self {
2310
+ FnTypeExt :: new_internal ( cx, sig, extra_args, |ty, arg_idx| {
2344
2311
let mut layout = cx. layout_of ( ty) ;
2345
2312
// Don't pass the vtable, it's not an argument of the virtual fn.
2346
2313
// Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
@@ -2395,19 +2362,11 @@ impl<'tcx, C> FnTypeExt<'tcx, C> for call::FnType<'tcx, Ty<'tcx>> {
2395
2362
}
2396
2363
2397
2364
fn new_internal (
2398
- cx : & C ,
2399
- sig : ty:: FnSig < ' tcx > ,
2400
- extra_args : & [ Ty < ' tcx > ] ,
2401
- mk_arg_type : impl Fn ( Ty < ' tcx > , Option < usize > ) -> ArgType < ' tcx , Ty < ' tcx > > ,
2402
- ) -> Self
2403
- where
2404
- C : LayoutOf < Ty = Ty < ' tcx > , TyLayout = TyLayout < ' tcx > >
2405
- + HasDataLayout
2406
- + HasTargetSpec
2407
- + HasTargetSpec
2408
- + HasTyCtxt < ' tcx >
2409
- + HasParamEnv < ' tcx > ,
2410
- {
2365
+ cx : & C ,
2366
+ sig : ty:: FnSig < ' tcx > ,
2367
+ extra_args : & [ Ty < ' tcx > ] ,
2368
+ mk_arg_type : impl Fn ( Ty < ' tcx > , Option < usize > ) -> ArgType < ' tcx , Ty < ' tcx > > ,
2369
+ ) -> Self {
2411
2370
debug ! ( "FnType::new_internal({:?}, {:?})" , sig, extra_args) ;
2412
2371
2413
2372
use rustc_target:: spec:: abi:: Abi :: * ;
@@ -2591,7 +2550,7 @@ impl<'tcx, C> FnTypeExt<'tcx, C> for call::FnType<'tcx, Ty<'tcx>> {
2591
2550
arg
2592
2551
} ;
2593
2552
2594
- let fn_ty = FnType {
2553
+ let mut fn_ty = FnType {
2595
2554
ret : arg_of ( sig. output ( ) , None ) ,
2596
2555
args : inputs
2597
2556
. iter ( )
@@ -2603,8 +2562,83 @@ impl<'tcx, C> FnTypeExt<'tcx, C> for call::FnType<'tcx, Ty<'tcx>> {
2603
2562
c_variadic : sig. c_variadic ,
2604
2563
conv,
2605
2564
} ;
2606
- // FIXME: uncomment this after figuring out wwhere should adjust_for_abi reside.
2607
- //fn_ty.adjust_for_abi(cx, sig.abi);
2565
+ fn_ty. adjust_for_abi ( cx, sig. abi ) ;
2608
2566
fn_ty
2609
2567
}
2568
+
2569
+ fn adjust_for_abi ( & mut self , cx : & C , abi : SpecAbi ) {
2570
+ if abi == SpecAbi :: Unadjusted {
2571
+ return ;
2572
+ }
2573
+
2574
+ if abi == SpecAbi :: Rust
2575
+ || abi == SpecAbi :: RustCall
2576
+ || abi == SpecAbi :: RustIntrinsic
2577
+ || abi == SpecAbi :: PlatformIntrinsic
2578
+ {
2579
+ let fixup = |arg : & mut ArgType < ' tcx , Ty < ' tcx > > | {
2580
+ if arg. is_ignore ( ) {
2581
+ return ;
2582
+ }
2583
+
2584
+ match arg. layout . abi {
2585
+ Abi :: Aggregate { .. } => { }
2586
+
2587
+ // This is a fun case! The gist of what this is doing is
2588
+ // that we want callers and callees to always agree on the
2589
+ // ABI of how they pass SIMD arguments. If we were to *not*
2590
+ // make these arguments indirect then they'd be immediates
2591
+ // in LLVM, which means that they'd used whatever the
2592
+ // appropriate ABI is for the callee and the caller. That
2593
+ // means, for example, if the caller doesn't have AVX
2594
+ // enabled but the callee does, then passing an AVX argument
2595
+ // across this boundary would cause corrupt data to show up.
2596
+ //
2597
+ // This problem is fixed by unconditionally passing SIMD
2598
+ // arguments through memory between callers and callees
2599
+ // which should get them all to agree on ABI regardless of
2600
+ // target feature sets. Some more information about this
2601
+ // issue can be found in #44367.
2602
+ //
2603
+ // Note that the platform intrinsic ABI is exempt here as
2604
+ // that's how we connect up to LLVM and it's unstable
2605
+ // anyway, we control all calls to it in libstd.
2606
+ Abi :: Vector { .. }
2607
+ if abi != SpecAbi :: PlatformIntrinsic
2608
+ && cx. tcx ( ) . sess . target . target . options . simd_types_indirect =>
2609
+ {
2610
+ arg. make_indirect ( ) ;
2611
+ return ;
2612
+ }
2613
+
2614
+ _ => return ,
2615
+ }
2616
+
2617
+ let size = arg. layout . size ;
2618
+ if arg. layout . is_unsized ( ) || size > Pointer . size ( cx) {
2619
+ arg. make_indirect ( ) ;
2620
+ } else {
2621
+ // We want to pass small aggregates as immediates, but using
2622
+ // a LLVM aggregate type for this leads to bad optimizations,
2623
+ // so we pick an appropriately sized integer type instead.
2624
+ arg. cast_to ( Reg {
2625
+ kind : RegKind :: Integer ,
2626
+ size,
2627
+ } ) ;
2628
+ }
2629
+ } ;
2630
+ fixup ( & mut self . ret ) ;
2631
+ for arg in & mut self . args {
2632
+ fixup ( arg) ;
2633
+ }
2634
+ if let PassMode :: Indirect ( ref mut attrs, _) = self . ret . mode {
2635
+ attrs. set ( ArgAttribute :: StructRet ) ;
2636
+ }
2637
+ return ;
2638
+ }
2639
+
2640
+ if let Err ( msg) = self . adjust_for_cabi ( cx, abi) {
2641
+ cx. tcx ( ) . sess . fatal ( & msg) ;
2642
+ }
2643
+ }
2610
2644
}
0 commit comments