1
+ //! The Xtensa ABI implementation
2
+ //!
3
+ //! This ABI implementation is based on the following sources:
4
+ //!
5
+ //! Section 8.1.4 & 8.1.5 of the Xtensa ISA reference manual, as well as snippets from
6
+ //! Section 2.3 from the Xtensa programmers guide.
7
+
8
+ use crate :: abi:: call:: { ArgAbi , FnAbi , Reg , Uniform } ;
9
+ use crate :: abi:: { Abi , HasDataLayout , Size , TyAbiInterface } ;
10
+ use crate :: spec:: HasTargetSpec ;
11
+
12
+ const NUM_ARG_GPRS : u64 = 6 ;
13
+ const NUM_RET_GPRS : u64 = 4 ;
14
+ const MAX_ARG_IN_REGS_SIZE : u64 = NUM_ARG_GPRS * 32 ;
15
+ const MAX_RET_IN_REGS_SIZE : u64 = NUM_RET_GPRS * 32 ;
16
+
17
+ fn classify_ret_ty < ' a , Ty , C > ( arg : & mut ArgAbi < ' _ , Ty > )
18
+ where
19
+ Ty : TyAbiInterface < ' a , C > + Copy ,
20
+ {
21
+ if arg. is_ignore ( ) {
22
+ return ;
23
+ }
24
+
25
+ // The rules for return and argument types are the same,
26
+ // so defer to `classify_arg_ty`.
27
+ let mut arg_gprs_left = NUM_RET_GPRS ;
28
+ classify_arg_ty ( arg, & mut arg_gprs_left, MAX_RET_IN_REGS_SIZE ) ;
29
+ // Ret args cannot be passed via stack, we lower to indirect and let the backend handle the invisble reference
30
+ match arg. mode {
31
+ super :: PassMode :: Indirect { attrs : _, extra_attrs : _, ref mut on_stack } => {
32
+ * on_stack = false ;
33
+ } ,
34
+ _ => { }
35
+ }
36
+ }
37
+
38
+ fn classify_arg_ty < ' a , Ty , C > ( arg : & mut ArgAbi < ' _ , Ty > , arg_gprs_left : & mut u64 , max_size : u64 )
39
+ where
40
+ Ty : TyAbiInterface < ' a , C > + Copy ,
41
+ {
42
+ assert ! ( * arg_gprs_left <= NUM_ARG_GPRS , "Arg GPR tracking underflow" ) ;
43
+
44
+ // Ignore empty structs/unions.
45
+ if arg. layout . is_zst ( ) {
46
+ return ;
47
+ }
48
+
49
+ let size = arg. layout . size . bits ( ) ;
50
+ let needed_align = arg. layout . align . abi . bits ( ) ;
51
+ let mut must_use_stack = false ;
52
+
53
+ // Determine the number of GPRs needed to pass the current argument
54
+ // according to the ABI. 2*XLen-aligned varargs are passed in "aligned"
55
+ // register pairs, so may consume 3 registers.
56
+ let mut needed_arg_gprs = ( size + 32 - 1 ) / 32 ;
57
+ if needed_align == 64 {
58
+ needed_arg_gprs += * arg_gprs_left % 2 ;
59
+ }
60
+
61
+ if needed_arg_gprs > * arg_gprs_left
62
+ || needed_align > 128
63
+ || ( * arg_gprs_left < ( max_size / 32 ) && needed_align == 128 )
64
+ {
65
+ must_use_stack = true ;
66
+ needed_arg_gprs = * arg_gprs_left;
67
+ }
68
+ * arg_gprs_left -= needed_arg_gprs;
69
+
70
+ if must_use_stack {
71
+ arg. make_indirect_byval ( ) ;
72
+ } else {
73
+ if is_xtensa_aggregate ( arg) {
74
+ // Aggregates which are <= max_size will be passed in
75
+ // registers if possible, so coerce to integers.
76
+
77
+ // Use a single `xlen` int if possible, 2 * `xlen` if 2 * `xlen` alignment
78
+ // is required, and a 2-element `xlen` array if only `xlen` alignment is
79
+ // required.
80
+ if size <= 32 {
81
+ arg. cast_to ( Reg :: i32 ( ) ) ;
82
+ } else {
83
+ let reg = if needed_align == 2 * 32 { Reg :: i64 ( ) } else { Reg :: i32 ( ) } ;
84
+ let total = Size :: from_bits ( ( ( size + 32 - 1 ) / 32 ) * 32 ) ;
85
+ arg. cast_to ( Uniform { unit : reg, total } ) ;
86
+ }
87
+ } else {
88
+ // All integral types are promoted to `xlen`
89
+ // width.
90
+ //
91
+ // We let the LLVM backend handle integral types >= xlen.
92
+ if size < 32 {
93
+ arg. extend_integer_width_to ( 32 ) ;
94
+ }
95
+ }
96
+ }
97
+ }
98
+
99
+ pub fn compute_abi_info < ' a , Ty , C > ( _cx : & C , fn_abi : & mut FnAbi < ' a , Ty > )
100
+ where
101
+ Ty : TyAbiInterface < ' a , C > + Copy ,
102
+ C : HasDataLayout + HasTargetSpec ,
103
+ {
104
+ if !fn_abi. ret . is_ignore ( ) {
105
+ classify_ret_ty ( & mut fn_abi. ret ) ;
106
+ }
107
+
108
+ let mut arg_gprs_left = NUM_ARG_GPRS ;
109
+
110
+ for arg in fn_abi. args . iter_mut ( ) {
111
+ if arg. is_ignore ( ) {
112
+ continue ;
113
+ }
114
+ classify_arg_ty ( arg, & mut arg_gprs_left, MAX_ARG_IN_REGS_SIZE ) ;
115
+ }
116
+ }
117
+
118
+ fn is_xtensa_aggregate < ' a , Ty > ( arg : & ArgAbi < ' a , Ty > ) -> bool {
119
+ match arg. layout . abi {
120
+ Abi :: Vector { .. } => true ,
121
+ _ => arg. layout . is_aggregate ( ) ,
122
+ }
123
+ }
0 commit comments