Skip to content

Commit e10d674

Browse files
committed
librustc: Use dereferenceable attribute instead of nonnull where we can.
1 parent 1725619 commit e10d674

File tree

2 files changed

+55
-15
lines changed

2 files changed

+55
-15
lines changed

src/librustc/middle/trans/base.rs

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2070,12 +2070,15 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
20702070
// implications directly to the call instruction. Right now,
20712071
// the only attribute we need to worry about is `sret`.
20722072
if type_of::return_uses_outptr(ccx, ret_ty) {
2073+
let llret_sz = llsize_of_real(ccx, type_of::type_of(ccx, ret_ty));
2074+
20732075
// The outptr can be noalias and nocapture because it's entirely
2074-
// invisible to the program. We can also mark it as nonnull
2076+
// invisible to the program. We also know it's nonnull as well
2077+
// as how many bytes we can dereference
20752078
attrs.arg(1, llvm::StructRetAttribute)
20762079
.arg(1, llvm::NoAliasAttribute)
20772080
.arg(1, llvm::NoCaptureAttribute)
2078-
.arg(1, llvm::NonNullAttribute);
2081+
.arg(1, llvm::DereferenceableAttribute(llret_sz));
20792082

20802083
// Add one more since there's an outptr
20812084
first_arg_offset += 1;
@@ -2094,15 +2097,16 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
20942097
_ => {}
20952098
}
20962099

2097-
// 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
20982101
match ty::get(ret_ty).sty {
20992102
// These are not really pointers but pairs, (pointer, len)
21002103
ty::ty_uniq(it) |
21012104
ty::ty_rptr(_, ty::mt { ty: it, .. }) if match ty::get(it).sty {
21022105
ty::ty_str | ty::ty_vec(..) | ty::ty_trait(..) => true, _ => false
21032106
} => {}
2104-
ty::ty_uniq(_) | ty::ty_rptr(_, _) => {
2105-
attrs.ret(llvm::NonNullAttribute);
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));
21062110
}
21072111
_ => {}
21082112
}
@@ -2119,44 +2123,77 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
21192123
match ty::get(t).sty {
21202124
// this needs to be first to prevent fat pointers from falling through
21212125
_ if !type_is_immediate(ccx, t) => {
2126+
let llarg_sz = llsize_of_real(ccx, type_of::type_of(ccx, t));
2127+
21222128
// For non-immediate arguments the callee gets its own copy of
21232129
// the value on the stack, so there are no aliases. It's also
21242130
// program-invisible so can't possibly capture
21252131
attrs.arg(idx, llvm::NoAliasAttribute)
21262132
.arg(idx, llvm::NoCaptureAttribute)
2127-
.arg(idx, llvm::NonNullAttribute);
2133+
.arg(idx, llvm::DereferenceableAttribute(llarg_sz));
21282134
}
2135+
21292136
ty::ty_bool => {
21302137
attrs.arg(idx, llvm::ZExtAttribute);
21312138
}
2139+
21322140
// `~` pointer parameters never alias because ownership is transferred
2133-
ty::ty_uniq(_) => {
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 => {
21342155
attrs.arg(idx, llvm::NoAliasAttribute)
21352156
.arg(idx, llvm::NonNullAttribute);
2157+
2158+
match b {
2159+
ReLateBound(_, BrAnon(_)) => {
2160+
attrs.arg(idx, llvm::NoCaptureAttribute);
2161+
}
2162+
_ => {}
2163+
}
21362164
}
2165+
21372166
// `&mut` pointer parameters never alias other parameters, or mutable global data
21382167
// `&` pointer parameters never alias either (for LLVM's purposes) as long as the
21392168
// interior is safe
21402169
ty::ty_rptr(b, mt) if mt.mutbl == ast::MutMutable ||
21412170
!ty::type_contents(ccx.tcx(), mt.ty).interior_unsafe() => {
2171+
2172+
let llsz = llsize_of_real(ccx, type_of::type_of(ccx, mt.ty));
21422173
attrs.arg(idx, llvm::NoAliasAttribute)
2143-
.arg(idx, llvm::NonNullAttribute);
2174+
.arg(idx, llvm::DereferenceableAttribute(llsz));
2175+
21442176
match b {
21452177
ReLateBound(_, BrAnon(_)) => {
21462178
attrs.arg(idx, llvm::NoCaptureAttribute);
21472179
}
21482180
_ => {}
21492181
}
21502182
}
2183+
21512184
// When a reference in an argument has no named lifetime, it's impossible for that
21522185
// reference to escape this function (returned or stored beyond the call by a closure).
2153-
ty::ty_rptr(ReLateBound(_, BrAnon(_)), _) => {
2186+
ty::ty_rptr(ReLateBound(_, BrAnon(_)), mt) => {
2187+
let llsz = llsize_of_real(ccx, type_of::type_of(ccx, mt.ty));
21542188
attrs.arg(idx, llvm::NoCaptureAttribute)
2155-
.arg(idx, llvm::NonNullAttribute);
2189+
.arg(idx, llvm::DereferenceableAttribute(llsz));
21562190
}
2157-
// & pointer parameters are never null
2158-
ty::ty_rptr(_, _) => {
2159-
attrs.arg(idx, llvm::NonNullAttribute);
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));
21602197
}
21612198
_ => ()
21622199
}

src/librustc/middle/trans/foreign.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,11 +386,14 @@ pub fn trans_native_call<'a>(
386386

387387
// Add attributes that are always applicable, independent of the concrete foreign ABI
388388
if fn_type.ret_ty.is_indirect() {
389+
let llret_sz = machine::llsize_of_real(ccx, fn_type.ret_ty.ty);
390+
389391
// The outptr can be noalias and nocapture because it's entirely
390-
// invisible to the program. We can also mark it as nonnull
392+
// invisible to the program. We also know it's nonnull as well
393+
// as how many bytes we can dereference
391394
attrs.arg(1, llvm::NoAliasAttribute)
392395
.arg(1, llvm::NoCaptureAttribute)
393-
.arg(1, llvm::NonNullAttribute);
396+
.arg(1, llvm::DereferenceableAttribute(llret_sz));
394397
};
395398

396399
// Add attributes that depend on the concrete foreign ABI

0 commit comments

Comments
 (0)