about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLuqman Aden <me@luqman.ca>2014-07-25 18:33:10 -0700
committerLuqman Aden <me@luqman.ca>2014-07-25 18:33:10 -0700
commite10d674de0e64e34eee7157ae9705992154b4443 (patch)
treebd7f1a7e6d2caf348534039937893c862b095fad
parent17256197a963561d02faff0634e11d7a079e7105 (diff)
downloadrust-e10d674de0e64e34eee7157ae9705992154b4443.tar.gz
rust-e10d674de0e64e34eee7157ae9705992154b4443.zip
librustc: Use dereferenceable attribute instead of nonnull where we can.
-rw-r--r--src/librustc/middle/trans/base.rs63
-rw-r--r--src/librustc/middle/trans/foreign.rs7
2 files changed, 55 insertions, 15 deletions
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 41493ce38c4..5433923441a 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -2070,12 +2070,15 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
     // implications directly to the call instruction. Right now,
     // the only attribute we need to worry about is `sret`.
     if type_of::return_uses_outptr(ccx, ret_ty) {
+        let llret_sz = llsize_of_real(ccx, type_of::type_of(ccx, ret_ty));
+
         // The outptr can be noalias and nocapture because it's entirely
-        // invisible to the program. We can also mark it as nonnull
+        // invisible to the program. We also know it's nonnull as well
+        // as how many bytes we can dereference
         attrs.arg(1, llvm::StructRetAttribute)
              .arg(1, llvm::NoAliasAttribute)
              .arg(1, llvm::NoCaptureAttribute)
-             .arg(1, llvm::NonNullAttribute);
+             .arg(1, llvm::DereferenceableAttribute(llret_sz));
 
         // Add one more since there's an outptr
         first_arg_offset += 1;
@@ -2094,15 +2097,16 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
             _ => {}
         }
 
-        // We can also mark the return value as `nonnull` in certain cases
+        // We can also mark the return value as `dereferenceable` in certain cases
         match ty::get(ret_ty).sty {
             // These are not really pointers but pairs, (pointer, len)
             ty::ty_uniq(it) |
             ty::ty_rptr(_, ty::mt { ty: it, .. }) if match ty::get(it).sty {
                 ty::ty_str | ty::ty_vec(..) | ty::ty_trait(..) => true, _ => false
             } => {}
-            ty::ty_uniq(_) | ty::ty_rptr(_, _) => {
-                attrs.ret(llvm::NonNullAttribute);
+            ty::ty_uniq(inner) | ty::ty_rptr(_, ty::mt { ty: inner, .. }) => {
+                let llret_sz = llsize_of_real(ccx, type_of::type_of(ccx, inner));
+                attrs.ret(llvm::DereferenceableAttribute(llret_sz));
             }
             _ => {}
         }
@@ -2119,28 +2123,56 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
         match ty::get(t).sty {
             // this needs to be first to prevent fat pointers from falling through
             _ if !type_is_immediate(ccx, t) => {
+                let llarg_sz = llsize_of_real(ccx, type_of::type_of(ccx, t));
+
                 // For non-immediate arguments the callee gets its own copy of
                 // the value on the stack, so there are no aliases. It's also
                 // program-invisible so can't possibly capture
                 attrs.arg(idx, llvm::NoAliasAttribute)
                      .arg(idx, llvm::NoCaptureAttribute)
-                     .arg(idx, llvm::NonNullAttribute);
+                     .arg(idx, llvm::DereferenceableAttribute(llarg_sz));
             }
+
             ty::ty_bool => {
                 attrs.arg(idx, llvm::ZExtAttribute);
             }
+
             // `~` pointer parameters never alias because ownership is transferred
-            ty::ty_uniq(_) => {
+            ty::ty_uniq(inner) => {
+                let llsz = llsize_of_real(ccx, type_of::type_of(ccx, inner));
+
+                attrs.arg(idx, llvm::NoAliasAttribute)
+                     .arg(idx, llvm::DereferenceableAttribute(llsz));
+            }
+
+            // The visit glue deals only with opaque pointers so we don't
+            // actually know the concrete type of Self thus we don't know how
+            // many bytes to mark as dereferenceable so instead we just mark
+            // it as nonnull which still holds true
+            ty::ty_rptr(b, ty::mt { ty: it, mutbl }) if match ty::get(it).sty {
+                ty::ty_param(_) => true, _ => false
+            } && mutbl == ast::MutMutable => {
                 attrs.arg(idx, llvm::NoAliasAttribute)
                      .arg(idx, llvm::NonNullAttribute);
+
+                match b {
+                    ReLateBound(_, BrAnon(_)) => {
+                        attrs.arg(idx, llvm::NoCaptureAttribute);
+                    }
+                    _ => {}
+                }
             }
+
             // `&mut` pointer parameters never alias other parameters, or mutable global data
             // `&` pointer parameters never alias either (for LLVM's purposes) as long as the
             // interior is safe
             ty::ty_rptr(b, mt) if mt.mutbl == ast::MutMutable ||
                                   !ty::type_contents(ccx.tcx(), mt.ty).interior_unsafe() => {
+
+                let llsz = llsize_of_real(ccx, type_of::type_of(ccx, mt.ty));
                 attrs.arg(idx, llvm::NoAliasAttribute)
-                     .arg(idx, llvm::NonNullAttribute);
+                     .arg(idx, llvm::DereferenceableAttribute(llsz));
+
                 match b {
                     ReLateBound(_, BrAnon(_)) => {
                         attrs.arg(idx, llvm::NoCaptureAttribute);
@@ -2148,15 +2180,20 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
                     _ => {}
                 }
             }
+
             // When a reference in an argument has no named lifetime, it's impossible for that
             // reference to escape this function (returned or stored beyond the call by a closure).
-            ty::ty_rptr(ReLateBound(_, BrAnon(_)), _) => {
+            ty::ty_rptr(ReLateBound(_, BrAnon(_)), mt) => {
+                let llsz = llsize_of_real(ccx, type_of::type_of(ccx, mt.ty));
                 attrs.arg(idx, llvm::NoCaptureAttribute)
-                     .arg(idx, llvm::NonNullAttribute);
+                     .arg(idx, llvm::DereferenceableAttribute(llsz));
             }
-            // & pointer parameters are never null
-            ty::ty_rptr(_, _) => {
-                attrs.arg(idx, llvm::NonNullAttribute);
+
+            // & pointer parameters are also never null and we know exactly how
+            // many bytes we can dereference
+            ty::ty_rptr(_, mt) => {
+                let llsz = llsize_of_real(ccx, type_of::type_of(ccx, mt.ty));
+                attrs.arg(idx, llvm::DereferenceableAttribute(llsz));
             }
             _ => ()
         }
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index 8fb36862f0d..f305ae90d46 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -386,11 +386,14 @@ pub fn trans_native_call<'a>(
 
     // Add attributes that are always applicable, independent of the concrete foreign ABI
     if fn_type.ret_ty.is_indirect() {
+        let llret_sz = machine::llsize_of_real(ccx, fn_type.ret_ty.ty);
+
         // The outptr can be noalias and nocapture because it's entirely
-        // invisible to the program. We can also mark it as nonnull
+        // invisible to the program. We also know it's nonnull as well
+        // as how many bytes we can dereference
         attrs.arg(1, llvm::NoAliasAttribute)
              .arg(1, llvm::NoCaptureAttribute)
-             .arg(1, llvm::NonNullAttribute);
+             .arg(1, llvm::DereferenceableAttribute(llret_sz));
     };
 
     // Add attributes that depend on the concrete foreign ABI