@@ -281,11 +281,7 @@ pub fn decl_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> ValueRef {
281
281
282
282
let llfn = decl_fn ( ccx, name, llvm:: CCallConv , llfty, output) ;
283
283
let attrs = get_fn_llvm_attributes ( ccx, fn_ty) ;
284
- for & ( idx, attr) in attrs. iter ( ) {
285
- unsafe {
286
- llvm:: LLVMAddFunctionAttribute ( llfn, idx as c_uint , attr) ;
287
- }
288
- }
284
+ attrs. apply_llfn ( llfn) ;
289
285
290
286
llfn
291
287
}
@@ -962,7 +958,7 @@ pub fn invoke<'a>(
962
958
llargs. as_slice ( ) ,
963
959
normal_bcx. llbb ,
964
960
landing_pad,
965
- attributes . as_slice ( ) ) ;
961
+ Some ( attributes ) ) ;
966
962
return ( llresult, normal_bcx) ;
967
963
} else {
968
964
debug ! ( "calling {} at {}" , llfn, bcx. llbb) ;
@@ -975,7 +971,7 @@ pub fn invoke<'a>(
975
971
None => debuginfo:: clear_source_location ( bcx. fcx )
976
972
} ;
977
973
978
- let llresult = Call ( bcx, llfn, llargs. as_slice ( ) , attributes . as_slice ( ) ) ;
974
+ let llresult = Call ( bcx, llfn, llargs. as_slice ( ) , Some ( attributes ) ) ;
979
975
return ( llresult, bcx) ;
980
976
}
981
977
}
@@ -1081,7 +1077,7 @@ pub fn call_lifetime_start(cx: &Block, ptr: ValueRef) {
1081
1077
let llsize = C_u64 ( ccx, machine:: llsize_of_alloc ( ccx, val_ty ( ptr) . element_type ( ) ) ) ;
1082
1078
let ptr = PointerCast ( cx, ptr, Type :: i8p ( ccx) ) ;
1083
1079
let lifetime_start = ccx. get_intrinsic ( & "llvm.lifetime.start" ) ;
1084
- Call ( cx, lifetime_start, [ llsize, ptr] , [ ] ) ;
1080
+ Call ( cx, lifetime_start, [ llsize, ptr] , None ) ;
1085
1081
}
1086
1082
1087
1083
pub fn call_lifetime_end ( cx : & Block , ptr : ValueRef ) {
@@ -1095,7 +1091,7 @@ pub fn call_lifetime_end(cx: &Block, ptr: ValueRef) {
1095
1091
let llsize = C_u64 ( ccx, machine:: llsize_of_alloc ( ccx, val_ty ( ptr) . element_type ( ) ) ) ;
1096
1092
let ptr = PointerCast ( cx, ptr, Type :: i8p ( ccx) ) ;
1097
1093
let lifetime_end = ccx. get_intrinsic ( & "llvm.lifetime.end" ) ;
1098
- Call ( cx, lifetime_end, [ llsize, ptr] , [ ] ) ;
1094
+ Call ( cx, lifetime_end, [ llsize, ptr] , None ) ;
1099
1095
}
1100
1096
1101
1097
pub fn call_memcpy ( cx : & Block , dst : ValueRef , src : ValueRef , n_bytes : ValueRef , align : u32 ) {
@@ -1111,7 +1107,7 @@ pub fn call_memcpy(cx: &Block, dst: ValueRef, src: ValueRef, n_bytes: ValueRef,
1111
1107
let size = IntCast ( cx, n_bytes, ccx. int_type ) ;
1112
1108
let align = C_i32 ( ccx, align as i32 ) ;
1113
1109
let volatile = C_bool ( ccx, false ) ;
1114
- Call ( cx, memcpy, [ dst_ptr, src_ptr, size, align, volatile] , [ ] ) ;
1110
+ Call ( cx, memcpy, [ dst_ptr, src_ptr, size, align, volatile] , None ) ;
1115
1111
}
1116
1112
1117
1113
pub fn memcpy_ty ( bcx : & Block , dst : ValueRef , src : ValueRef , t : ty:: t ) {
@@ -1156,7 +1152,7 @@ fn memzero(b: &Builder, llptr: ValueRef, ty: Type) {
1156
1152
let size = machine:: llsize_of ( ccx, ty) ;
1157
1153
let align = C_i32 ( ccx, llalign_of_min ( ccx, ty) as i32 ) ;
1158
1154
let volatile = C_bool ( ccx, false ) ;
1159
- b. call ( llintrinsicfn, [ llptr, llzeroval, size, align, volatile] , [ ] ) ;
1155
+ b. call ( llintrinsicfn, [ llptr, llzeroval, size, align, volatile] , None ) ;
1160
1156
}
1161
1157
1162
1158
pub fn alloc_ty ( bcx : & Block , t : ty:: t , name : & str ) -> ValueRef {
@@ -2040,7 +2036,7 @@ fn register_fn(ccx: &CrateContext,
2040
2036
}
2041
2037
2042
2038
pub fn get_fn_llvm_attributes( ccx: & CrateContext , fn_ty: ty:: t)
2043
- -> Vec < ( uint , u64 ) > {
2039
+ -> llvm :: AttrBuilder {
2044
2040
use middle:: ty:: { BrAnon , ReLateBound } ;
2045
2041
2046
2042
let ( fn_sig, abi, has_env) = match ty:: get( fn_ty) . sty {
@@ -2056,31 +2052,33 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
2056
2052
_ => fail!( "expected closure or function." )
2057
2053
} ;
2058
2054
2055
+ // Since index 0 is the return value of the llvm func, we start
2056
+ // at either 1 or 2 depending on whether there's an env slot or not
2057
+ let mut first_arg_offset = if has_env { 2 } else { 1 } ;
2058
+ let mut attrs = llvm:: AttrBuilder :: new( ) ;
2059
+ let ret_ty = fn_sig. output;
2060
+
2059
2061
// These have an odd calling convention, so we skip them for now.
2060
2062
//
2061
2063
// FIXME(pcwalton): We don't have to skip them; just untuple the result.
2062
2064
if abi == RustCall {
2063
- return Vec :: new ( )
2065
+ return attrs ;
2064
2066
}
2065
2067
2066
- // Since index 0 is the return value of the llvm func, we start
2067
- // at either 1 or 2 depending on whether there's an env slot or not
2068
- let mut first_arg_offset = if has_env { 2 } else { 1 } ;
2069
- let mut attrs = Vec :: new( ) ;
2070
- let ret_ty = fn_sig. output;
2071
-
2072
2068
// A function pointer is called without the declaration
2073
2069
// available, so we have to apply any attributes with ABI
2074
2070
// implications directly to the call instruction. Right now,
2075
2071
// the only attribute we need to worry about is `sret`.
2076
2072
if type_of:: return_uses_outptr( ccx, ret_ty) {
2077
- attrs . push ( ( 1 , llvm :: StructRetAttribute as u64 ) ) ;
2073
+ let llret_sz = llsize_of_real ( ccx , type_of :: type_of ( ccx , ret_ty ) ) ;
2078
2074
2079
2075
// The outptr can be noalias and nocapture because it's entirely
2080
- // invisible to the program. We can also mark it as nonnull
2081
- attrs. push( ( 1 , llvm:: NoAliasAttribute as u64 ) ) ;
2082
- attrs. push( ( 1 , llvm:: NoCaptureAttribute as u64 ) ) ;
2083
- attrs. push( ( 1 , llvm:: NonNullAttribute as u64 ) ) ;
2076
+ // invisible to the program. We also know it's nonnull as well
2077
+ // as how many bytes we can dereference
2078
+ attrs. arg( 1 , llvm:: StructRetAttribute )
2079
+ . arg( 1 , llvm:: NoAliasAttribute )
2080
+ . arg( 1 , llvm:: NoCaptureAttribute )
2081
+ . arg( 1 , llvm:: DereferenceableAttribute ( llret_sz) ) ;
2084
2082
2085
2083
// Add one more since there's an outptr
2086
2084
first_arg_offset += 1 ;
@@ -2094,27 +2092,28 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
2094
2092
ty:: ty_str | ty:: ty_vec( ..) | ty:: ty_trait( ..) => true , _ => false
2095
2093
} => { }
2096
2094
ty:: ty_uniq( _) => {
2097
- attrs. push ( ( llvm:: ReturnIndex as uint , llvm :: NoAliasAttribute as u64 ) ) ;
2095
+ attrs. ret ( llvm:: NoAliasAttribute ) ;
2098
2096
}
2099
2097
_ => { }
2100
2098
}
2101
2099
2102
- // We can also mark the return value as `nonnull ` in certain cases
2100
+ // We can also mark the return value as `dereferenceable ` in certain cases
2103
2101
match ty:: get( ret_ty) . sty {
2104
2102
// These are not really pointers but pairs, (pointer, len)
2105
2103
ty:: ty_uniq( it) |
2106
2104
ty:: ty_rptr( _, ty:: mt { ty: it, .. } ) if match ty:: get( it) . sty {
2107
2105
ty:: ty_str | ty:: ty_vec( ..) | ty:: ty_trait( ..) => true , _ => false
2108
2106
} => { }
2109
- ty:: ty_uniq( _) | ty:: ty_rptr( _, _) => {
2110
- attrs. push( ( llvm:: ReturnIndex as uint, llvm:: NonNullAttribute as u64 ) ) ;
2107
+ ty:: ty_uniq( inner) | ty:: ty_rptr( _, ty:: mt { ty: inner, .. } ) => {
2108
+ let llret_sz = llsize_of_real( ccx, type_of:: type_of( ccx, inner) ) ;
2109
+ attrs. ret( llvm:: DereferenceableAttribute ( llret_sz) ) ;
2111
2110
}
2112
2111
_ => { }
2113
2112
}
2114
2113
2115
2114
match ty:: get( ret_ty) . sty {
2116
2115
ty:: ty_bool => {
2117
- attrs. push ( ( llvm:: ReturnIndex as uint , llvm :: ZExtAttribute as u64 ) ) ;
2116
+ attrs. ret ( llvm:: ZExtAttribute ) ;
2118
2117
}
2119
2118
_ => { }
2120
2119
}
@@ -2124,44 +2123,77 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
2124
2123
match ty:: get( t) . sty {
2125
2124
// this needs to be first to prevent fat pointers from falling through
2126
2125
_ if !type_is_immediate( ccx, t) => {
2126
+ let llarg_sz = llsize_of_real( ccx, type_of:: type_of( ccx, t) ) ;
2127
+
2127
2128
// For non-immediate arguments the callee gets its own copy of
2128
2129
// the value on the stack, so there are no aliases. It's also
2129
2130
// program-invisible so can't possibly capture
2130
- attrs. push ( ( idx, llvm:: NoAliasAttribute as u64 ) ) ;
2131
- attrs . push ( ( idx, llvm:: NoCaptureAttribute as u64 ) ) ;
2132
- attrs . push ( ( idx, llvm:: NonNullAttribute as u64 ) ) ;
2131
+ attrs. arg ( idx, llvm:: NoAliasAttribute )
2132
+ . arg ( idx, llvm:: NoCaptureAttribute )
2133
+ . arg ( idx, llvm:: DereferenceableAttribute ( llarg_sz ) ) ;
2133
2134
}
2135
+
2134
2136
ty:: ty_bool => {
2135
- attrs. push ( ( idx, llvm:: ZExtAttribute as u64 ) ) ;
2137
+ attrs. arg ( idx, llvm:: ZExtAttribute ) ;
2136
2138
}
2139
+
2137
2140
// `~` pointer parameters never alias because ownership is transferred
2138
- ty:: ty_uniq( _) => {
2139
- attrs. push( ( idx, llvm:: NoAliasAttribute as u64 ) ) ;
2140
- attrs. push( ( idx, llvm:: NonNullAttribute as u64 ) ) ;
2141
+ ty:: ty_uniq( inner) => {
2142
+ let llsz = llsize_of_real( ccx, type_of:: type_of( ccx, inner) ) ;
2143
+
2144
+ attrs. arg( idx, llvm:: NoAliasAttribute )
2145
+ . arg( idx, llvm:: DereferenceableAttribute ( llsz) ) ;
2146
+ }
2147
+
2148
+ // The visit glue deals only with opaque pointers so we don't
2149
+ // actually know the concrete type of Self thus we don't know how
2150
+ // many bytes to mark as dereferenceable so instead we just mark
2151
+ // it as nonnull which still holds true
2152
+ ty:: ty_rptr( b, ty:: mt { ty: it, mutbl } ) if match ty:: get( it) . sty {
2153
+ ty:: ty_param( _) => true , _ => false
2154
+ } && mutbl == ast:: MutMutable => {
2155
+ attrs. arg( idx, llvm:: NoAliasAttribute )
2156
+ . arg( idx, llvm:: NonNullAttribute ) ;
2157
+
2158
+ match b {
2159
+ ReLateBound ( _, BrAnon ( _) ) => {
2160
+ attrs. arg( idx, llvm:: NoCaptureAttribute ) ;
2161
+ }
2162
+ _ => { }
2163
+ }
2141
2164
}
2165
+
2142
2166
// `&mut` pointer parameters never alias other parameters, or mutable global data
2143
2167
// `&` pointer parameters never alias either (for LLVM's purposes) as long as the
2144
2168
// interior is safe
2145
2169
ty:: ty_rptr( b, mt) if mt. mutbl == ast:: MutMutable ||
2146
2170
!ty:: type_contents( ccx. tcx( ) , mt. ty) . interior_unsafe( ) => {
2147
- attrs. push( ( idx, llvm:: NoAliasAttribute as u64 ) ) ;
2148
- attrs. push( ( idx, llvm:: NonNullAttribute as u64 ) ) ;
2171
+
2172
+ let llsz = llsize_of_real( ccx, type_of:: type_of( ccx, mt. ty) ) ;
2173
+ attrs. arg( idx, llvm:: NoAliasAttribute )
2174
+ . arg( idx, llvm:: DereferenceableAttribute ( llsz) ) ;
2175
+
2149
2176
match b {
2150
2177
ReLateBound ( _, BrAnon ( _) ) => {
2151
- attrs. push ( ( idx, llvm:: NoCaptureAttribute as u64 ) ) ;
2178
+ attrs. arg ( idx, llvm:: NoCaptureAttribute ) ;
2152
2179
}
2153
2180
_ => { }
2154
2181
}
2155
2182
}
2183
+
2156
2184
// When a reference in an argument has no named lifetime, it's impossible for that
2157
2185
// reference to escape this function (returned or stored beyond the call by a closure).
2158
- ty:: ty_rptr( ReLateBound ( _, BrAnon ( _) ) , _) => {
2159
- attrs. push( ( idx, llvm:: NoCaptureAttribute as u64 ) ) ;
2160
- attrs. push( ( idx, llvm:: NonNullAttribute as u64 ) ) ;
2186
+ ty:: ty_rptr( ReLateBound ( _, BrAnon ( _) ) , mt) => {
2187
+ let llsz = llsize_of_real( ccx, type_of:: type_of( ccx, mt. ty) ) ;
2188
+ attrs. arg( idx, llvm:: NoCaptureAttribute )
2189
+ . arg( idx, llvm:: DereferenceableAttribute ( llsz) ) ;
2161
2190
}
2162
- // & pointer parameters are never null
2163
- ty:: ty_rptr( _, _) => {
2164
- attrs. push( ( idx, llvm:: NonNullAttribute as u64 ) ) ;
2191
+
2192
+ // & pointer parameters are also never null and we know exactly how
2193
+ // many bytes we can dereference
2194
+ ty:: ty_rptr( _, mt) => {
2195
+ let llsz = llsize_of_real( ccx, type_of:: type_of( ccx, mt. ty) ) ;
2196
+ attrs. arg( idx, llvm:: DereferenceableAttribute ( llsz) ) ;
2165
2197
}
2166
2198
_ => ( )
2167
2199
}
0 commit comments