10
10
11
11
pub use self :: ArgKind :: * ;
12
12
13
- use llvm:: Attribute ;
14
- use std:: option;
13
+ use llvm:: { self , AttrHelper , ValueRef } ;
14
+ use trans:: attributes;
15
+ use trans:: common:: return_type_is_void;
15
16
use trans:: context:: CrateContext ;
16
17
use trans:: cabi_x86;
17
18
use trans:: cabi_x86_64;
@@ -23,6 +24,11 @@ use trans::cabi_powerpc64;
23
24
use trans:: cabi_mips;
24
25
use trans:: cabi_asmjs;
25
26
use trans:: type_:: Type ;
27
+ use trans:: type_of;
28
+
29
+ use middle:: ty:: { self , Ty } ;
30
+
31
+ use syntax:: abi:: Abi ;
26
32
27
33
#[ derive( Clone , Copy , PartialEq , Debug ) ]
28
34
pub enum ArgKind {
@@ -45,17 +51,17 @@ pub struct ArgType {
45
51
/// Original LLVM type
46
52
pub ty : Type ,
47
53
/// Coerced LLVM Type
48
- pub cast : option :: Option < Type > ,
54
+ pub cast : Option < Type > ,
49
55
/// Dummy argument, which is emitted before the real argument
50
- pub pad : option :: Option < Type > ,
56
+ pub pad : Option < Type > ,
51
57
/// LLVM attribute of argument
52
- pub attr : option :: Option < Attribute >
58
+ pub attr : Option < llvm :: Attribute >
53
59
}
54
60
55
61
impl ArgType {
56
- pub fn direct ( ty : Type , cast : option :: Option < Type > ,
57
- pad : option :: Option < Type > ,
58
- attr : option :: Option < Attribute > ) -> ArgType {
62
+ pub fn direct ( ty : Type , cast : Option < Type > ,
63
+ pad : Option < Type > ,
64
+ attr : Option < llvm :: Attribute > ) -> ArgType {
59
65
ArgType {
60
66
kind : Direct ,
61
67
ty : ty,
@@ -65,12 +71,12 @@ impl ArgType {
65
71
}
66
72
}
67
73
68
- pub fn indirect ( ty : Type , attr : option :: Option < Attribute > ) -> ArgType {
74
+ pub fn indirect ( ty : Type , attr : Option < llvm :: Attribute > ) -> ArgType {
69
75
ArgType {
70
76
kind : Indirect ,
71
77
ty : ty,
72
- cast : option :: Option :: None ,
73
- pad : option :: Option :: None ,
78
+ cast : Option :: None ,
79
+ pad : Option :: None ,
74
80
attr : attr
75
81
}
76
82
}
@@ -94,44 +100,175 @@ impl ArgType {
94
100
}
95
101
}
96
102
103
+ fn c_type_of < ' a , ' tcx > ( cx : & CrateContext < ' a , ' tcx > , ty : Ty < ' tcx > ) -> Type {
104
+ if ty. is_bool ( ) {
105
+ Type :: i1 ( cx)
106
+ } else {
107
+ type_of:: type_of ( cx, ty)
108
+ }
109
+ }
110
+
97
111
/// Metadata describing how the arguments to a native function
98
112
/// should be passed in order to respect the native ABI.
99
113
///
100
114
/// I will do my best to describe this structure, but these
101
115
/// comments are reverse-engineered and may be inaccurate. -NDM
102
116
pub struct FnType {
103
117
/// The LLVM types of each argument.
104
- pub arg_tys : Vec < ArgType > ,
118
+ pub args : Vec < ArgType > ,
105
119
106
120
/// LLVM return type.
107
- pub ret_ty : ArgType ,
121
+ pub ret : ArgType ,
122
+
123
+ pub variadic : bool ,
124
+
125
+ pub cconv : llvm:: CallConv
108
126
}
109
127
110
- pub fn compute_abi_info ( ccx : & CrateContext ,
111
- atys : & [ Type ] ,
112
- rty : Type ,
113
- ret_def : bool ) -> FnType {
114
- match & ccx. sess ( ) . target . target . arch [ ..] {
115
- "x86" => cabi_x86:: compute_abi_info ( ccx, atys, rty, ret_def) ,
116
- "x86_64" => if ccx. sess ( ) . target . target . options . is_like_windows {
117
- cabi_x86_win64:: compute_abi_info ( ccx, atys, rty, ret_def)
128
+ impl FnType {
129
+ pub fn new < ' a , ' tcx > ( ccx : & CrateContext < ' a , ' tcx > ,
130
+ abi : Abi ,
131
+ sig : & ty:: FnSig < ' tcx > ,
132
+ extra_args : & [ Ty < ' tcx > ] ) -> FnType {
133
+ use syntax:: abi:: Abi :: * ;
134
+ let cconv = match ccx. sess ( ) . target . target . adjust_abi ( abi) {
135
+ RustIntrinsic => {
136
+ // Intrinsics are emitted at the call site
137
+ ccx. sess ( ) . bug ( "asked to register intrinsic fn" ) ;
138
+ }
139
+ PlatformIntrinsic => {
140
+ // Intrinsics are emitted at the call site
141
+ ccx. sess ( ) . bug ( "asked to register platform intrinsic fn" ) ;
142
+ }
143
+
144
+ Rust => {
145
+ // FIXME(#3678) Implement linking to foreign fns with Rust ABI
146
+ ccx. sess ( ) . unimpl ( "foreign functions with Rust ABI" ) ;
147
+ }
148
+
149
+ RustCall => {
150
+ // FIXME(#3678) Implement linking to foreign fns with Rust ABI
151
+ ccx. sess ( ) . unimpl ( "foreign functions with RustCall ABI" ) ;
152
+ }
153
+
154
+ // It's the ABI's job to select this, not us.
155
+ System => ccx. sess ( ) . bug ( "system abi should be selected elsewhere" ) ,
156
+
157
+ Stdcall => llvm:: X86StdcallCallConv ,
158
+ Fastcall => llvm:: X86FastcallCallConv ,
159
+ Vectorcall => llvm:: X86_VectorCall ,
160
+ C => llvm:: CCallConv ,
161
+ Win64 => llvm:: X86_64_Win64 ,
162
+
163
+ // These API constants ought to be more specific...
164
+ Cdecl => llvm:: CCallConv ,
165
+ Aapcs => llvm:: CCallConv ,
166
+ } ;
167
+
168
+ let rty = match sig. output {
169
+ ty:: FnConverging ( ret_ty) if !return_type_is_void ( ccx, ret_ty) => {
170
+ c_type_of ( ccx, ret_ty)
171
+ }
172
+ _ => Type :: void ( ccx)
173
+ } ;
174
+
175
+ let mut fty = FnType {
176
+ args : sig. inputs . iter ( ) . chain ( extra_args. iter ( ) ) . map ( |& ty| {
177
+ ArgType :: direct ( c_type_of ( ccx, ty) , None , None , None )
178
+ } ) . collect ( ) ,
179
+ ret : ArgType :: direct ( rty, None , None , None ) ,
180
+ variadic : sig. variadic ,
181
+ cconv : cconv
182
+ } ;
183
+
184
+ match & ccx. sess ( ) . target . target . arch [ ..] {
185
+ "x86" => cabi_x86:: compute_abi_info ( ccx, & mut fty) ,
186
+ "x86_64" => if ccx. sess ( ) . target . target . options . is_like_windows {
187
+ cabi_x86_win64:: compute_abi_info ( ccx, & mut fty) ;
188
+ } else {
189
+ cabi_x86_64:: compute_abi_info ( ccx, & mut fty) ;
190
+ } ,
191
+ "aarch64" => cabi_aarch64:: compute_abi_info ( ccx, & mut fty) ,
192
+ "arm" => {
193
+ let flavor = if ccx. sess ( ) . target . target . target_os == "ios" {
194
+ cabi_arm:: Flavor :: Ios
195
+ } else {
196
+ cabi_arm:: Flavor :: General
197
+ } ;
198
+ cabi_arm:: compute_abi_info ( ccx, & mut fty, flavor) ;
199
+ } ,
200
+ "mips" => cabi_mips:: compute_abi_info ( ccx, & mut fty) ,
201
+ "powerpc" => cabi_powerpc:: compute_abi_info ( ccx, & mut fty) ,
202
+ "powerpc64" => cabi_powerpc64:: compute_abi_info ( ccx, & mut fty) ,
203
+ "asmjs" => cabi_asmjs:: compute_abi_info ( ccx, & mut fty) ,
204
+ a => ccx. sess ( ) . fatal ( & format ! ( "unrecognized arch \" {}\" in target specification" , a) )
205
+ }
206
+
207
+ fty
208
+ }
209
+
210
+ pub fn to_llvm ( & self , ccx : & CrateContext ) -> Type {
211
+ let mut llargument_tys = Vec :: new ( ) ;
212
+
213
+ let llreturn_ty = if self . ret . is_indirect ( ) {
214
+ llargument_tys. push ( self . ret . ty . ptr_to ( ) ) ;
215
+ Type :: void ( ccx)
118
216
} else {
119
- cabi_x86_64:: compute_abi_info ( ccx, atys, rty, ret_def)
120
- } ,
121
- "aarch64" => cabi_aarch64:: compute_abi_info ( ccx, atys, rty, ret_def) ,
122
- "arm" => {
123
- let flavor = if ccx. sess ( ) . target . target . target_os == "ios" {
124
- cabi_arm:: Flavor :: Ios
217
+ self . ret . cast . unwrap_or ( self . ret . ty )
218
+ } ;
219
+
220
+ for arg in & self . args {
221
+ if arg. is_ignore ( ) {
222
+ continue ;
223
+ }
224
+ // add padding
225
+ if let Some ( ty) = arg. pad {
226
+ llargument_tys. push ( ty) ;
227
+ }
228
+
229
+ let llarg_ty = if arg. is_indirect ( ) {
230
+ arg. ty . ptr_to ( )
125
231
} else {
126
- cabi_arm :: Flavor :: General
232
+ arg . cast . unwrap_or ( arg . ty )
127
233
} ;
128
- cabi_arm:: compute_abi_info ( ccx, atys, rty, ret_def, flavor)
129
- } ,
130
- "mips" => cabi_mips:: compute_abi_info ( ccx, atys, rty, ret_def) ,
131
- "powerpc" => cabi_powerpc:: compute_abi_info ( ccx, atys, rty, ret_def) ,
132
- "powerpc64" => cabi_powerpc64:: compute_abi_info ( ccx, atys, rty, ret_def) ,
133
- "asmjs" => cabi_asmjs:: compute_abi_info ( ccx, atys, rty, ret_def) ,
134
- a => ccx. sess ( ) . fatal ( & format ! ( "unrecognized arch \" {}\" in target specification" , a)
135
- ) ,
234
+
235
+ llargument_tys. push ( llarg_ty) ;
236
+ }
237
+
238
+ if self . variadic {
239
+ Type :: variadic_func ( & llargument_tys, & llreturn_ty)
240
+ } else {
241
+ Type :: func ( & llargument_tys, & llreturn_ty)
242
+ }
243
+ }
244
+
245
+ pub fn add_attributes ( & self , llfn : ValueRef ) {
246
+ let mut i = if self . ret . is_indirect ( ) {
247
+ 1
248
+ } else {
249
+ 0
250
+ } ;
251
+
252
+ if let Some ( attr) = self . ret . attr {
253
+ attr. apply_llfn ( i, llfn) ;
254
+ }
255
+
256
+ i += 1 ;
257
+
258
+ for arg in & self . args {
259
+ if arg. is_ignore ( ) {
260
+ continue ;
261
+ }
262
+ // skip padding
263
+ if arg. pad . is_some ( ) { i += 1 ; }
264
+
265
+ if let Some ( attr) = arg. attr {
266
+ attr. apply_llfn ( i, llfn) ;
267
+ }
268
+
269
+ i += 1 ;
270
+ }
271
+
272
+ attributes:: unwind ( llfn, false ) ;
136
273
}
137
274
}
0 commit comments