about summary refs log tree commit diff
path: root/src/rustllvm/RustWrapper.cpp
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-07-26 15:46:18 +0000
committerbors <bors@rust-lang.org>2014-07-26 15:46:18 +0000
commit7aa407958b8ab2aec16b0182f0103ad92380b5dc (patch)
tree59dd1c3707de288a8b9584ca859a9bfdd3b7b9f3 /src/rustllvm/RustWrapper.cpp
parent50c62b466723077ba725c1d7ea8093928613c311 (diff)
parenta78c0f1019a4a023de60ae1228ad47fafc96e423 (diff)
downloadrust-7aa407958b8ab2aec16b0182f0103ad92380b5dc.tar.gz
rust-7aa407958b8ab2aec16b0182f0103ad92380b5dc.zip
auto merge of #15998 : luqmana/rust/nmnnbd, r=thestinger
LLVM recently added a new attribute, dereferenceable: http://reviews.llvm.org/D4449

>This patch adds a dereferencable attribute. In some sense, this is a companion to the nonnull attribute, but specifies that the pointer is known to be dereferencable in the same sense as a pointer generated by alloca is known to be dereferencable.

With rust, everywhere that we previously marked `nonnull` we can actually mark as `dereferenceable` (which implies nonnull) since we know the size. That is, except for one case: when generating calls for TyVisitor. It seems like we haven't substituted the self type (so we have `ty_param`) and just treat it as an opaque pointer so I just left that bit as nonnull.

With this, LLVM can for example hoist a load out of a loop where it previously couldn't:

```Rust
pub fn baz(c: &uint, n: uint) -> uint {
    let mut res = 0;
    for i in range(0, n) {
        if i > 0 {
            res += *c * i;
        }
    }
    res
}
```

Before:
```llvm
define i64 @baz(i64* noalias nocapture nonnull readonly, i64) unnamed_addr #0 {
entry-block:
  br label %for_loopback.outer

for_loopback.outer:                               ; preds = %then-block-33-, %entry-block
  %.ph = phi i64 [ %.lcssa, %then-block-33- ], [ 0, %entry-block ]
  %res.0.ph = phi i64 [ %8, %then-block-33- ], [ 0, %entry-block ]
  br label %for_loopback

for_exit:                                         ; preds = %for_loopback
  %res.0.ph.lcssa = phi i64 [ %res.0.ph, %for_loopback ]
  ret i64 %res.0.ph.lcssa

for_loopback:                                     ; preds = %for_loopback.outer, %for_body
  %2 = phi i64 [ %4, %for_body ], [ %.ph, %for_loopback.outer ]
  %3 = icmp ult i64 %2, %1
  br i1 %3, label %for_body, label %for_exit

for_body:                                         ; preds = %for_loopback
  %4 = add i64 %2, 1
  %5 = icmp eq i64 %2, 0
  br i1 %5, label %for_loopback, label %then-block-33-

then-block-33-:                                   ; preds = %for_body
  %.lcssa = phi i64 [ %4, %for_body ]
  %.lcssa15 = phi i64 [ %2, %for_body ]
  %6 = load i64* %0, align 8                     ; <------- this load
  %7 = mul i64 %6, %.lcssa15
  %8 = add i64 %7, %res.0.ph
  br label %for_loopback.outer
}
```

After:
```llvm
define i64 @baz(i64* noalias nocapture readonly dereferenceable(8), i64) unnamed_addr #0 {
entry-block:
  %2 = load i64* %0, align 8                    ; <------- load once instead
  br label %for_loopback.outer

for_loopback.outer:                               ; preds = %then-block-33-, %entry-block
  %.ph = phi i64 [ %.lcssa, %then-block-33- ], [ 0, %entry-block ]
  %res.0.ph = phi i64 [ %8, %then-block-33- ], [ 0, %entry-block ]
  br label %for_loopback

for_exit:                                         ; preds = %for_loopback
  %res.0.ph.lcssa = phi i64 [ %res.0.ph, %for_loopback ]
  ret i64 %res.0.ph.lcssa

for_loopback:                                     ; preds = %for_loopback.outer, %for_body
  %3 = phi i64 [ %5, %for_body ], [ %.ph, %for_loopback.outer ]
  %4 = icmp ult i64 %3, %1
  br i1 %4, label %for_body, label %for_exit

for_body:                                         ; preds = %for_loopback
  %5 = add i64 %3, 1
  %6 = icmp eq i64 %3, 0
  br i1 %6, label %for_loopback, label %then-block-33-

then-block-33-:                                   ; preds = %for_body
  %.lcssa = phi i64 [ %5, %for_body ]
  %.lcssa15 = phi i64 [ %3, %for_body ]
  %7 = mul i64 %2, %.lcssa15
  %8 = add i64 %7, %res.0.ph
  br label %for_loopback.outer
}
```
Diffstat (limited to 'src/rustllvm/RustWrapper.cpp')
-rw-r--r--src/rustllvm/RustWrapper.cpp26
1 files changed, 26 insertions, 0 deletions
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index e28a78b1ee7..8a3e06aabc6 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -113,6 +113,21 @@ extern "C" void LLVMAddCallSiteAttribute(LLVMValueRef Instr, unsigned index, uin
                                                          index, B)));
 }
 
+
+#if LLVM_VERSION_MINOR >= 5
+extern "C" void LLVMAddDereferenceableCallSiteAttr(LLVMValueRef Instr, unsigned idx, uint64_t b) {
+  CallSite Call = CallSite(unwrap<Instruction>(Instr));
+  AttrBuilder B;
+  B.addDereferenceableAttr(b);
+  Call.setAttributes(
+    Call.getAttributes().addAttributes(Call->getContext(), idx,
+                                       AttributeSet::get(Call->getContext(),
+                                                         idx, B)));
+}
+#else
+extern "C" void LLVMAddDereferenceableCallSiteAttr(LLVMValueRef, unsigned, uint64_t) {}
+#endif
+
 extern "C" void LLVMAddFunctionAttribute(LLVMValueRef Fn, unsigned index, uint64_t Val) {
   Function *A = unwrap<Function>(Fn);
   AttrBuilder B;
@@ -120,6 +135,17 @@ extern "C" void LLVMAddFunctionAttribute(LLVMValueRef Fn, unsigned index, uint64
   A->addAttributes(index, AttributeSet::get(A->getContext(), index, B));
 }
 
+#if LLVM_VERSION_MINOR >= 5
+extern "C" void LLVMAddDereferenceableAttr(LLVMValueRef Fn, unsigned index, uint64_t bytes) {
+  Function *A = unwrap<Function>(Fn);
+  AttrBuilder B;
+  B.addDereferenceableAttr(bytes);
+  A->addAttributes(index, AttributeSet::get(A->getContext(), index, B));
+}
+#else
+extern "C" void LLVMAddDereferenceableAttr(LLVMValueRef, unsigned, uint64_t) {}
+#endif
+
 extern "C" void LLVMAddFunctionAttrString(LLVMValueRef Fn, unsigned index, const char *Name) {
   Function *F = unwrap<Function>(Fn);
   AttrBuilder B;