8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- use llvm;
11
+ use llvm:: { self , ValueRef } ;
12
12
use trans:: common:: { return_type_is_void, type_is_fat_ptr} ;
13
13
use trans:: context:: CrateContext ;
14
14
use trans:: cabi_x86;
@@ -24,6 +24,7 @@ use trans::machine::{llsize_of_alloc, llsize_of_real};
24
24
use trans:: type_:: Type ;
25
25
use trans:: type_of;
26
26
27
+ use rustc_front:: hir;
27
28
use middle:: ty:: { self , Ty } ;
28
29
29
30
pub use syntax:: abi:: Abi ;
@@ -204,22 +205,102 @@ impl FnType {
204
205
}
205
206
} ;
206
207
207
- let ret = match sig. output {
208
+ let mut ret = match sig. output {
208
209
ty:: FnConverging ( ret_ty) if !return_type_is_void ( ccx, ret_ty) => {
209
210
arg_of ( ret_ty)
210
211
}
211
212
_ => ArgType :: new ( Type :: void ( ccx) , Type :: void ( ccx) )
212
213
} ;
213
214
215
+ if let ty:: FnConverging ( ret_ty) = sig. output {
216
+ if !type_is_fat_ptr ( ccx. tcx ( ) , ret_ty) {
217
+ // The `noalias` attribute on the return value is useful to a
218
+ // function ptr caller.
219
+ if let ty:: TyBox ( _) = ret_ty. sty {
220
+ // `Box` pointer return values never alias because ownership
221
+ // is transferred
222
+ ret. attrs . set ( llvm:: Attribute :: NoAlias ) ;
223
+ }
224
+
225
+ // We can also mark the return value as `dereferenceable` in certain cases
226
+ match ret_ty. sty {
227
+ // These are not really pointers but pairs, (pointer, len)
228
+ ty:: TyRef ( _, ty:: TypeAndMut { ty, .. } ) |
229
+ ty:: TyBox ( ty) => {
230
+ let llty = type_of:: sizing_type_of ( ccx, ty) ;
231
+ let llsz = llsize_of_real ( ccx, llty) ;
232
+ ret. attrs . set_dereferenceable ( llsz) ;
233
+ }
234
+ _ => { }
235
+ }
236
+ }
237
+ }
238
+
214
239
let mut args = Vec :: with_capacity ( inputs. len ( ) + extra_args. len ( ) ) ;
240
+
241
+ // Handle safe Rust thin and fat pointers.
242
+ let rust_ptr_attrs = |ty : Ty < ' tcx > , arg : & mut ArgType | match ty. sty {
243
+ // `Box` pointer parameters never alias because ownership is transferred
244
+ ty:: TyBox ( inner) => {
245
+ arg. attrs . set ( llvm:: Attribute :: NoAlias ) ;
246
+ Some ( inner)
247
+ }
248
+
249
+ ty:: TyRef ( b, mt) => {
250
+ use middle:: ty:: { BrAnon , ReLateBound } ;
251
+
252
+ // `&mut` pointer parameters never alias other parameters, or mutable global data
253
+ //
254
+ // `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as
255
+ // both `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely
256
+ // on memory dependencies rather than pointer equality
257
+ let interior_unsafe = mt. ty . type_contents ( ccx. tcx ( ) ) . interior_unsafe ( ) ;
258
+
259
+ if mt. mutbl != hir:: MutMutable && !interior_unsafe {
260
+ arg. attrs . set ( llvm:: Attribute :: NoAlias ) ;
261
+ }
262
+
263
+ if mt. mutbl == hir:: MutImmutable && !interior_unsafe {
264
+ arg. attrs . set ( llvm:: Attribute :: ReadOnly ) ;
265
+ }
266
+
267
+ // When a reference in an argument has no named lifetime, it's
268
+ // impossible for that reference to escape this function
269
+ // (returned or stored beyond the call by a closure).
270
+ if let ReLateBound ( _, BrAnon ( _) ) = * b {
271
+ arg. attrs . set ( llvm:: Attribute :: NoCapture ) ;
272
+ }
273
+
274
+ Some ( mt. ty )
275
+ }
276
+ _ => None
277
+ } ;
278
+
215
279
for ty in inputs. iter ( ) . chain ( extra_args. iter ( ) ) {
216
- let arg = arg_of ( ty) ;
280
+ let mut arg = arg_of ( ty) ;
281
+
217
282
if type_is_fat_ptr ( ccx. tcx ( ) , ty) {
218
- let original = arg. original_ty . field_types ( ) ;
219
- let sizing = arg. ty . field_types ( ) ;
220
- args. extend ( original. into_iter ( ) . zip ( sizing)
221
- . map ( |( o, s) | ArgType :: new ( o, s) ) ) ;
283
+ let original_tys = arg. original_ty . field_types ( ) ;
284
+ let sizing_tys = arg. ty . field_types ( ) ;
285
+ assert_eq ! ( ( original_tys. len( ) , sizing_tys. len( ) ) , ( 2 , 2 ) ) ;
286
+
287
+ let mut data = ArgType :: new ( original_tys[ 0 ] , sizing_tys[ 0 ] ) ;
288
+ let mut info = ArgType :: new ( original_tys[ 1 ] , sizing_tys[ 1 ] ) ;
289
+
290
+ if let Some ( inner) = rust_ptr_attrs ( ty, & mut data) {
291
+ data. attrs . set ( llvm:: Attribute :: NonNull ) ;
292
+ if ccx. tcx ( ) . struct_tail ( inner) . is_trait ( ) {
293
+ info. attrs . set ( llvm:: Attribute :: NonNull ) ;
294
+ }
295
+ }
296
+ args. push ( data) ;
297
+ args. push ( info) ;
222
298
} else {
299
+ if let Some ( inner) = rust_ptr_attrs ( ty, & mut arg) {
300
+ let llty = type_of:: sizing_type_of ( ccx, inner) ;
301
+ let llsz = llsize_of_real ( ccx, llty) ;
302
+ arg. attrs . set_dereferenceable ( llsz) ;
303
+ }
223
304
args. push ( arg) ;
224
305
}
225
306
}
@@ -327,18 +408,29 @@ impl FnType {
327
408
}
328
409
}
329
410
330
- pub fn llvm_attrs ( & self ) -> llvm:: AttrBuilder {
331
- let mut attrs = llvm:: AttrBuilder :: new ( ) ;
411
+ pub fn apply_attrs_llfn ( & self , llfn : ValueRef ) {
412
+ let mut i = if self . ret . is_indirect ( ) { 1 } else { 0 } ;
413
+ self . ret . attrs . apply_llfn ( i, llfn) ;
414
+ i += 1 ;
415
+ for arg in & self . args {
416
+ if !arg. is_ignore ( ) {
417
+ if arg. pad . is_some ( ) { i += 1 ; }
418
+ arg. attrs . apply_llfn ( i, llfn) ;
419
+ i += 1 ;
420
+ }
421
+ }
422
+ }
423
+
424
+ pub fn apply_attrs_callsite ( & self , callsite : ValueRef ) {
332
425
let mut i = if self . ret . is_indirect ( ) { 1 } else { 0 } ;
333
- * attrs . arg ( i ) = self . ret . attrs ;
426
+ self . ret . attrs . apply_callsite ( i , callsite ) ;
334
427
i += 1 ;
335
428
for arg in & self . args {
336
429
if !arg. is_ignore ( ) {
337
430
if arg. pad . is_some ( ) { i += 1 ; }
338
- * attrs. arg ( i ) = arg . attrs ;
431
+ arg . attrs . apply_callsite ( i , callsite ) ;
339
432
i += 1 ;
340
433
}
341
434
}
342
- attrs
343
435
}
344
436
}
0 commit comments