@@ -13,13 +13,13 @@ use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
13
13
use rustc_middle:: ty:: query:: Providers ;
14
14
use rustc_middle:: ty:: subst:: SubstsRef ;
15
15
use rustc_middle:: ty:: {
16
- self , Const , FloatTy , GeneratorSubsts , IntTy , ParamEnv , PolyFnSig , Ty , TyKind , TypeAndMut ,
17
- UintTy ,
16
+ self , Const , FloatTy , GeneratorSubsts , IntTy , ParamEnv , PolyFnSig , Ty , TyCtxt , TyKind ,
17
+ TypeAndMut , UintTy ,
18
18
} ;
19
19
use rustc_span:: def_id:: DefId ;
20
20
use rustc_span:: Span ;
21
21
use rustc_span:: DUMMY_SP ;
22
- use rustc_target:: abi:: call:: { CastTarget , FnAbi , PassMode , Reg , RegKind } ;
22
+ use rustc_target:: abi:: call:: { ArgAbi , ArgAttributes , CastTarget , FnAbi , PassMode , Reg , RegKind } ;
23
23
use rustc_target:: abi:: { Abi , Align , FieldsShape , Primitive , Scalar , Size , VariantIdx , Variants } ;
24
24
use rustc_target:: spec:: abi:: Abi as SpecAbi ;
25
25
use std:: cell:: RefCell ;
@@ -35,7 +35,7 @@ pub(crate) fn provide(providers: &mut Providers) {
35
35
// However, those functions will be implemented by compiler-builtins:
36
36
// https://github.com/rust-lang/rust/blob/5fae56971d8487088c0099c82c0a5ce1638b5f62/library/core/src/lib.rs#L23-L27
37
37
// This theoretically then should be fine to leave as C, but, there's no backend hook for
38
- // FnAbi::adjust_for_cabi, causing it to panic:
38
+ // ` FnAbi::adjust_for_cabi` , causing it to panic:
39
39
// https://github.com/rust-lang/rust/blob/5fae56971d8487088c0099c82c0a5ce1638b5f62/compiler/rustc_target/src/abi/call/mod.rs#L603
40
40
// So, treat any `extern "C"` functions as `extern "unadjusted"`, to be able to compile libcore with arch=spirv.
41
41
providers. fn_sig = |tcx, def_id| {
@@ -49,6 +49,46 @@ pub(crate) fn provide(providers: &mut Providers) {
49
49
inner
50
50
} )
51
51
} ;
52
+
53
+ // For the Rust ABI, `FnAbi` adjustments are backend-agnostic, but they will
54
+ // use features like `PassMode::Cast`, that are incompatible with SPIR-V.
55
+ // By hooking the queries computing `FnAbi`s, we can recompute the `FnAbi`
56
+ // from the return/args layouts, to e.g. prefer using `PassMode::Direct`.
57
+ fn readjust_fn_abi < ' tcx > (
58
+ tcx : TyCtxt < ' tcx > ,
59
+ fn_abi : & ' tcx FnAbi < ' tcx , Ty < ' tcx > > ,
60
+ ) -> & ' tcx FnAbi < ' tcx , Ty < ' tcx > > {
61
+ let readjust_arg_abi = |arg : & ArgAbi < ' tcx , Ty < ' tcx > > | {
62
+ let mut arg = ArgAbi :: new ( & tcx, arg. layout , |_, _, _| ArgAttributes :: new ( ) ) ;
63
+
64
+ // Avoid pointlessly passing ZSTs, just like the official Rust ABI.
65
+ if arg. layout . is_zst ( ) {
66
+ arg. mode = PassMode :: Ignore ;
67
+ }
68
+
69
+ arg
70
+ } ;
71
+ tcx. arena . alloc ( FnAbi {
72
+ args : fn_abi. args . iter ( ) . map ( readjust_arg_abi) . collect ( ) ,
73
+ ret : readjust_arg_abi ( & fn_abi. ret ) ,
74
+
75
+ // FIXME(eddyb) validate some of these, and report errors - however,
76
+ // we can't just emit errors from here, since we have no `Span`, so
77
+ // we should have instead a check on MIR for e.g. C variadic calls.
78
+ c_variadic : fn_abi. c_variadic ,
79
+ fixed_count : fn_abi. fixed_count ,
80
+ conv : fn_abi. conv ,
81
+ can_unwind : fn_abi. can_unwind ,
82
+ } )
83
+ }
84
+ providers. fn_abi_of_fn_ptr = |tcx, key| {
85
+ let result = ( rustc_interface:: DEFAULT_QUERY_PROVIDERS . fn_abi_of_fn_ptr ) ( tcx, key) ;
86
+ Ok ( readjust_fn_abi ( tcx, result?) )
87
+ } ;
88
+ providers. fn_abi_of_instance = |tcx, key| {
89
+ let result = ( rustc_interface:: DEFAULT_QUERY_PROVIDERS . fn_abi_of_instance ) ( tcx, key) ;
90
+ Ok ( readjust_fn_abi ( tcx, result?) )
91
+ } ;
52
92
}
53
93
54
94
pub ( crate ) fn provide_extern ( providers : & mut Providers ) {
0 commit comments