9
9
// except according to those terms.
10
10
//! Set and unset common attributes on LLVM values.
11
11
12
+ use libc:: { c_uint, c_ulonglong} ;
12
13
use llvm:: { self , ValueRef , AttrHelper } ;
14
+ use middle:: ty:: { self , ClosureTyper } ;
15
+ use syntax:: abi;
13
16
use syntax:: ast;
14
- use syntax:: attr:: InlineAttr ;
15
- pub use syntax:: attr:: InlineAttr :: * ;
17
+ pub use syntax:: attr:: InlineAttr ;
18
+ use trans:: base;
19
+ use trans:: common;
16
20
use trans:: context:: CrateContext ;
17
-
18
- use libc :: { c_uint , c_ulonglong } ;
21
+ use trans :: machine ;
22
+ use trans :: type_of ;
19
23
20
24
/// Mark LLVM function to use split stack.
21
25
#[ inline]
@@ -33,11 +37,12 @@ pub fn split_stack(val: ValueRef, set: bool) {
33
37
/// Mark LLVM function to use provided inline heuristic.
34
38
#[ inline]
35
39
pub fn inline ( val : ValueRef , inline : InlineAttr ) {
40
+ use self :: InlineAttr :: * ;
36
41
match inline {
37
- InlineHint => llvm:: SetFunctionAttribute ( val, llvm:: InlineHintAttribute ) ,
38
- InlineAlways => llvm:: SetFunctionAttribute ( val, llvm:: AlwaysInlineAttribute ) ,
39
- InlineNever => llvm:: SetFunctionAttribute ( val, llvm:: NoInlineAttribute ) ,
40
- InlineNone => {
42
+ Hint => llvm:: SetFunctionAttribute ( val, llvm:: InlineHintAttribute ) ,
43
+ Always => llvm:: SetFunctionAttribute ( val, llvm:: AlwaysInlineAttribute ) ,
44
+ Never => llvm:: SetFunctionAttribute ( val, llvm:: NoInlineAttribute ) ,
45
+ None => {
41
46
let attr = llvm:: InlineHintAttribute |
42
47
llvm:: AlwaysInlineAttribute |
43
48
llvm:: NoInlineAttribute ;
@@ -88,7 +93,7 @@ pub fn set_optimize_for_size(val: ValueRef, optimize: bool) {
88
93
89
94
/// Composite function which sets LLVM attributes for function depending on its AST (#[attribute])
90
95
/// attributes.
91
- pub fn convert_fn_attrs_to_llvm ( ccx : & CrateContext , attrs : & [ ast:: Attribute ] , llfn : ValueRef ) {
96
+ pub fn from_fn_attrs ( ccx : & CrateContext , attrs : & [ ast:: Attribute ] , llfn : ValueRef ) {
92
97
use syntax:: attr:: * ;
93
98
inline ( llfn, find_inline_attr ( Some ( ccx. sess ( ) . diagnostic ( ) ) , attrs) ) ;
94
99
@@ -106,3 +111,173 @@ pub fn convert_fn_attrs_to_llvm(ccx: &CrateContext, attrs: &[ast::Attribute], ll
106
111
}
107
112
}
108
113
}
114
+
115
+ /// Composite function which converts function type into LLVM attributes for the function.
116
+ pub fn from_fn_type < ' a , ' tcx > ( ccx : & CrateContext < ' a , ' tcx > , fn_type : ty:: Ty < ' tcx > )
117
+ -> llvm:: AttrBuilder {
118
+ use middle:: ty:: { BrAnon , ReLateBound } ;
119
+
120
+ let function_type;
121
+ let ( fn_sig, abi, env_ty) = match fn_type. sty {
122
+ ty:: ty_bare_fn( _, ref f) => ( & f. sig , f. abi , None ) ,
123
+ ty:: ty_closure( closure_did, substs) => {
124
+ let typer = common:: NormalizingClosureTyper :: new ( ccx. tcx ( ) ) ;
125
+ function_type = typer. closure_type ( closure_did, substs) ;
126
+ let self_type = base:: self_type_for_closure ( ccx, closure_did, fn_type) ;
127
+ ( & function_type. sig , abi:: RustCall , Some ( self_type) )
128
+ }
129
+ _ => ccx. sess ( ) . bug ( "expected closure or function." )
130
+ } ;
131
+
132
+ let fn_sig = ty:: erase_late_bound_regions ( ccx. tcx ( ) , fn_sig) ;
133
+
134
+ let mut attrs = llvm:: AttrBuilder :: new ( ) ;
135
+ let ret_ty = fn_sig. output ;
136
+
137
+ // These have an odd calling convention, so we need to manually
138
+ // unpack the input ty's
139
+ let input_tys = match fn_type. sty {
140
+ ty:: ty_closure( ..) => {
141
+ assert ! ( abi == abi:: RustCall ) ;
142
+
143
+ match fn_sig. inputs [ 0 ] . sty {
144
+ ty:: ty_tup( ref inputs) => {
145
+ let mut full_inputs = vec ! [ env_ty. expect( "Missing closure environment" ) ] ;
146
+ full_inputs. push_all ( inputs) ;
147
+ full_inputs
148
+ }
149
+ _ => ccx. sess ( ) . bug ( "expected tuple'd inputs" )
150
+ }
151
+ } ,
152
+ ty:: ty_bare_fn( ..) if abi == abi:: RustCall => {
153
+ let mut inputs = vec ! [ fn_sig. inputs[ 0 ] ] ;
154
+
155
+ match fn_sig. inputs [ 1 ] . sty {
156
+ ty:: ty_tup( ref t_in) => {
157
+ inputs. push_all ( & t_in[ ..] ) ;
158
+ inputs
159
+ }
160
+ _ => ccx. sess ( ) . bug ( "expected tuple'd inputs" )
161
+ }
162
+ }
163
+ _ => fn_sig. inputs . clone ( )
164
+ } ;
165
+
166
+ // Index 0 is the return value of the llvm func, so we start at 1
167
+ let mut first_arg_offset = 1 ;
168
+ if let ty:: FnConverging ( ret_ty) = ret_ty {
169
+ // A function pointer is called without the declaration
170
+ // available, so we have to apply any attributes with ABI
171
+ // implications directly to the call instruction. Right now,
172
+ // the only attribute we need to worry about is `sret`.
173
+ if type_of:: return_uses_outptr ( ccx, ret_ty) {
174
+ let llret_sz = machine:: llsize_of_real ( ccx, type_of:: type_of ( ccx, ret_ty) ) ;
175
+
176
+ // The outptr can be noalias and nocapture because it's entirely
177
+ // invisible to the program. We also know it's nonnull as well
178
+ // as how many bytes we can dereference
179
+ attrs. arg ( 1 , llvm:: StructRetAttribute )
180
+ . arg ( 1 , llvm:: NoAliasAttribute )
181
+ . arg ( 1 , llvm:: NoCaptureAttribute )
182
+ . arg ( 1 , llvm:: DereferenceableAttribute ( llret_sz) ) ;
183
+
184
+ // Add one more since there's an outptr
185
+ first_arg_offset += 1 ;
186
+ } else {
187
+ // The `noalias` attribute on the return value is useful to a
188
+ // function ptr caller.
189
+ match ret_ty. sty {
190
+ // `~` pointer return values never alias because ownership
191
+ // is transferred
192
+ ty:: ty_uniq( it) if !common:: type_is_sized ( ccx. tcx ( ) , it) => { }
193
+ ty:: ty_uniq( _) => {
194
+ attrs. ret ( llvm:: NoAliasAttribute ) ;
195
+ }
196
+ _ => { }
197
+ }
198
+
199
+ // We can also mark the return value as `dereferenceable` in certain cases
200
+ match ret_ty. sty {
201
+ // These are not really pointers but pairs, (pointer, len)
202
+ ty:: ty_uniq( it) |
203
+ ty:: ty_rptr( _, ty:: mt { ty : it, .. } ) if !common:: type_is_sized ( ccx. tcx ( ) , it) => { }
204
+ ty:: ty_uniq( inner) | ty:: ty_rptr( _, ty:: mt { ty : inner, .. } ) => {
205
+ let llret_sz = machine:: llsize_of_real ( ccx, type_of:: type_of ( ccx, inner) ) ;
206
+ attrs. ret ( llvm:: DereferenceableAttribute ( llret_sz) ) ;
207
+ }
208
+ _ => { }
209
+ }
210
+
211
+ if let ty:: ty_bool = ret_ty. sty {
212
+ attrs. ret ( llvm:: ZExtAttribute ) ;
213
+ }
214
+ }
215
+ }
216
+
217
+ for ( idx, & t) in input_tys. iter ( ) . enumerate ( ) . map ( |( i, v) | ( i + first_arg_offset, v) ) {
218
+ match t. sty {
219
+ // this needs to be first to prevent fat pointers from falling through
220
+ _ if !common:: type_is_immediate ( ccx, t) => {
221
+ let llarg_sz = machine:: llsize_of_real ( ccx, type_of:: type_of ( ccx, t) ) ;
222
+
223
+ // For non-immediate arguments the callee gets its own copy of
224
+ // the value on the stack, so there are no aliases. It's also
225
+ // program-invisible so can't possibly capture
226
+ attrs. arg ( idx, llvm:: NoAliasAttribute )
227
+ . arg ( idx, llvm:: NoCaptureAttribute )
228
+ . arg ( idx, llvm:: DereferenceableAttribute ( llarg_sz) ) ;
229
+ }
230
+
231
+ ty:: ty_bool => {
232
+ attrs. arg ( idx, llvm:: ZExtAttribute ) ;
233
+ }
234
+
235
+ // `~` pointer parameters never alias because ownership is transferred
236
+ ty:: ty_uniq( inner) => {
237
+ let llsz = machine:: llsize_of_real ( ccx, type_of:: type_of ( ccx, inner) ) ;
238
+
239
+ attrs. arg ( idx, llvm:: NoAliasAttribute )
240
+ . arg ( idx, llvm:: DereferenceableAttribute ( llsz) ) ;
241
+ }
242
+
243
+ // `&mut` pointer parameters never alias other parameters, or mutable global data
244
+ //
245
+ // `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as both
246
+ // `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely on
247
+ // memory dependencies rather than pointer equality
248
+ ty:: ty_rptr( b, mt) if mt. mutbl == ast:: MutMutable ||
249
+ !ty:: type_contents ( ccx. tcx ( ) , mt. ty ) . interior_unsafe ( ) => {
250
+
251
+ let llsz = machine:: llsize_of_real ( ccx, type_of:: type_of ( ccx, mt. ty ) ) ;
252
+ attrs. arg ( idx, llvm:: NoAliasAttribute )
253
+ . arg ( idx, llvm:: DereferenceableAttribute ( llsz) ) ;
254
+
255
+ if mt. mutbl == ast:: MutImmutable {
256
+ attrs. arg ( idx, llvm:: ReadOnlyAttribute ) ;
257
+ }
258
+
259
+ if let ReLateBound ( _, BrAnon ( _) ) = * b {
260
+ attrs. arg ( idx, llvm:: NoCaptureAttribute ) ;
261
+ }
262
+ }
263
+
264
+ // When a reference in an argument has no named lifetime, it's impossible for that
265
+ // reference to escape this function (returned or stored beyond the call by a closure).
266
+ ty:: ty_rptr( & ReLateBound ( _, BrAnon ( _) ) , mt) => {
267
+ let llsz = machine:: llsize_of_real ( ccx, type_of:: type_of ( ccx, mt. ty ) ) ;
268
+ attrs. arg ( idx, llvm:: NoCaptureAttribute )
269
+ . arg ( idx, llvm:: DereferenceableAttribute ( llsz) ) ;
270
+ }
271
+
272
+ // & pointer parameters are also never null and we know exactly how
273
+ // many bytes we can dereference
274
+ ty:: ty_rptr( _, mt) => {
275
+ let llsz = machine:: llsize_of_real ( ccx, type_of:: type_of ( ccx, mt. ty ) ) ;
276
+ attrs. arg ( idx, llvm:: DereferenceableAttribute ( llsz) ) ;
277
+ }
278
+ _ => ( )
279
+ }
280
+ }
281
+
282
+ attrs
283
+ }
0 commit comments