78 changes: 74 additions & 4 deletions llvm/lib/IR/Attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ Attribute Attribute::getWithStackAlignment(LLVMContext &Context,
return get(Context, StackAlignment, Align);
}

Attribute Attribute::getWithDereferenceableBytes(LLVMContext &Context,
uint64_t Bytes) {
assert(Bytes && "Bytes must be non-zero.");
return get(Context, Dereferenceable, Bytes);
}

//===----------------------------------------------------------------------===//
// Attribute Accessor Methods
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -156,6 +162,14 @@ unsigned Attribute::getStackAlignment() const {
return pImpl->getValueAsInt();
}

/// This returns the number of dereferenceable bytes.
uint64_t Attribute::getDereferenceableBytes() const {
assert(hasAttribute(Attribute::Dereferenceable) &&
"Trying to get dereferenceable bytes from "
"non-dereferenceable attribute!");
return pImpl->getValueAsInt();
}

std::string Attribute::getAsString(bool InAttrGrp) const {
if (!pImpl) return "";

Expand Down Expand Up @@ -263,6 +277,20 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
return Result;
}

if (hasAttribute(Attribute::Dereferenceable)) {
std::string Result;
Result += "dereferenceable";
if (InAttrGrp) {
Result += "=";
Result += utostr(getValueAsInt());
} else {
Result += "(";
Result += utostr(getValueAsInt());
Result += ")";
}
return Result;
}

// Convert target-dependent attributes to strings of the form:
//
// "kind"
Expand Down Expand Up @@ -398,6 +426,8 @@ uint64_t AttributeImpl::getAttrMask(Attribute::AttrKind Val) {
case Attribute::InAlloca: return 1ULL << 43;
case Attribute::NonNull: return 1ULL << 44;
case Attribute::JumpTable: return 1ULL << 45;
case Attribute::Dereferenceable:
llvm_unreachable("dereferenceable attribute not supported in raw format");
}
llvm_unreachable("Unsupported attribute type");
}
Expand Down Expand Up @@ -482,6 +512,13 @@ unsigned AttributeSetNode::getStackAlignment() const {
return 0;
}

uint64_t AttributeSetNode::getDereferenceableBytes() const {
for (iterator I = begin(), E = end(); I != E; ++I)
if (I->hasAttribute(Attribute::Dereferenceable))
return I->getDereferenceableBytes();
return 0;
}

std::string AttributeSetNode::getAsString(bool InAttrGrp) const {
std::string Str;
for (iterator I = begin(), E = end(); I != E; ++I) {
Expand Down Expand Up @@ -515,6 +552,8 @@ uint64_t AttributeSetImpl::Raw(unsigned Index) const {
Mask |= (Log2_32(ASN->getAlignment()) + 1) << 16;
else if (Kind == Attribute::StackAlignment)
Mask |= (Log2_32(ASN->getStackAlignment()) + 1) << 26;
else if (Kind == Attribute::Dereferenceable)
llvm_unreachable("dereferenceable not supported in bit mask");
else
Mask |= AttributeImpl::getAttrMask(Kind);
}
Expand Down Expand Up @@ -620,6 +659,10 @@ AttributeSet AttributeSet::get(LLVMContext &C, unsigned Index,
else if (Kind == Attribute::StackAlignment)
Attrs.push_back(std::make_pair(Index, Attribute::
getWithStackAlignment(C, B.getStackAlignment())));
else if (Kind == Attribute::Dereferenceable)
Attrs.push_back(std::make_pair(Index,
Attribute::getWithDereferenceableBytes(C,
B.getDereferenceableBytes())));
else
Attrs.push_back(std::make_pair(Index, Attribute::get(C, Kind)));
}
Expand Down Expand Up @@ -877,6 +920,11 @@ unsigned AttributeSet::getStackAlignment(unsigned Index) const {
return ASN ? ASN->getStackAlignment() : 0;
}

uint64_t AttributeSet::getDereferenceableBytes(unsigned Index) const {
AttributeSetNode *ASN = getAttributes(Index);
return ASN ? ASN->getDereferenceableBytes() : 0;
}

std::string AttributeSet::getAsString(unsigned Index,
bool InAttrGrp) const {
AttributeSetNode *ASN = getAttributes(Index);
Expand Down Expand Up @@ -956,7 +1004,7 @@ void AttributeSet::dump() const {
//===----------------------------------------------------------------------===//

AttrBuilder::AttrBuilder(AttributeSet AS, unsigned Index)
: Attrs(0), Alignment(0), StackAlignment(0) {
: Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0) {
AttributeSetImpl *pImpl = AS.pImpl;
if (!pImpl) return;

Expand All @@ -973,13 +1021,14 @@ AttrBuilder::AttrBuilder(AttributeSet AS, unsigned Index)

void AttrBuilder::clear() {
Attrs.reset();
Alignment = StackAlignment = 0;
Alignment = StackAlignment = DerefBytes = 0;
}

AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Val) {
assert((unsigned)Val < Attribute::EndAttrKinds && "Attribute out of range!");
assert(Val != Attribute::Alignment && Val != Attribute::StackAlignment &&
"Adding alignment attribute without adding alignment value!");
Val != Attribute::Dereferenceable &&
"Adding integer attribute without adding a value!");
Attrs[Val] = true;
return *this;
}
Expand All @@ -997,6 +1046,8 @@ AttrBuilder &AttrBuilder::addAttribute(Attribute Attr) {
Alignment = Attr.getAlignment();
else if (Kind == Attribute::StackAlignment)
StackAlignment = Attr.getStackAlignment();
else if (Kind == Attribute::Dereferenceable)
DerefBytes = Attr.getDereferenceableBytes();
return *this;
}

Expand All @@ -1013,6 +1064,8 @@ AttrBuilder &AttrBuilder::removeAttribute(Attribute::AttrKind Val) {
Alignment = 0;
else if (Val == Attribute::StackAlignment)
StackAlignment = 0;
else if (Val == Attribute::Dereferenceable)
DerefBytes = 0;

return *this;
}
Expand All @@ -1037,6 +1090,8 @@ AttrBuilder &AttrBuilder::removeAttributes(AttributeSet A, uint64_t Index) {
Alignment = 0;
else if (Kind == Attribute::StackAlignment)
StackAlignment = 0;
else if (Kind == Attribute::Dereferenceable)
DerefBytes = 0;
} else {
assert(Attr.isStringAttribute() && "Invalid attribute type!");
std::map<std::string, std::string>::iterator
Expand Down Expand Up @@ -1079,6 +1134,14 @@ AttrBuilder &AttrBuilder::addStackAlignmentAttr(unsigned Align) {
return *this;
}

AttrBuilder &AttrBuilder::addDereferenceableAttr(uint64_t Bytes) {
if (Bytes == 0) return *this;

Attrs[Attribute::Dereferenceable] = true;
DerefBytes = Bytes;
return *this;
}

AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) {
// FIXME: What if both have alignments, but they don't match?!
if (!Alignment)
Expand All @@ -1087,6 +1150,9 @@ AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) {
if (!StackAlignment)
StackAlignment = B.StackAlignment;

if (!DerefBytes)
DerefBytes = B.DerefBytes;

Attrs |= B.Attrs;

for (td_const_iterator I = B.TargetDepAttrs.begin(),
Expand Down Expand Up @@ -1142,7 +1208,8 @@ bool AttrBuilder::operator==(const AttrBuilder &B) {
if (B.TargetDepAttrs.find(I->first) == B.TargetDepAttrs.end())
return false;

return Alignment == B.Alignment && StackAlignment == B.StackAlignment;
return Alignment == B.Alignment && StackAlignment == B.StackAlignment &&
DerefBytes == B.DerefBytes;
}

AttrBuilder &AttrBuilder::addRawValue(uint64_t Val) {
Expand All @@ -1151,6 +1218,8 @@ AttrBuilder &AttrBuilder::addRawValue(uint64_t Val) {

for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds;
I = Attribute::AttrKind(I + 1)) {
if (I == Attribute::Dereferenceable)
continue;
if (uint64_t A = (Val & AttributeImpl::getAttrMask(I))) {
Attrs[I] = true;

Expand Down Expand Up @@ -1184,6 +1253,7 @@ AttributeSet AttributeFuncs::typeIncompatible(Type *Ty, uint64_t Index) {
.addAttribute(Attribute::NoAlias)
.addAttribute(Attribute::NoCapture)
.addAttribute(Attribute::NonNull)
.addDereferenceableAttr(1) // the int here is ignored
.addAttribute(Attribute::ReadNone)
.addAttribute(Attribute::ReadOnly)
.addAttribute(Attribute::StructRet)
Expand Down
18 changes: 15 additions & 3 deletions llvm/lib/IR/Function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,17 @@ unsigned Argument::getArgNo() const {
}

/// hasNonNullAttr - Return true if this argument has the nonnull attribute on
/// it in its containing function.
/// it in its containing function. Also returns true if at least one byte is
/// known to be dereferenceable and the pointer is in addrspace(0).
bool Argument::hasNonNullAttr() const {
if (!getType()->isPointerTy()) return false;
return getParent()->getAttributes().
hasAttribute(getArgNo()+1, Attribute::NonNull);
if (getParent()->getAttributes().
hasAttribute(getArgNo()+1, Attribute::NonNull))
return true;
else if (getDereferenceableBytes() > 0 &&
getType()->getPointerAddressSpace() == 0)
return true;
return false;
}

/// hasByValAttr - Return true if this argument has the byval attribute on it
Expand Down Expand Up @@ -113,6 +119,12 @@ unsigned Argument::getParamAlignment() const {

}

uint64_t Argument::getDereferenceableBytes() const {
assert(getType()->isPointerTy() &&
"Only pointers have dereferenceable bytes");
return getParent()->getDereferenceableBytes(getArgNo()+1);
}

/// hasNestAttr - Return true if this argument has the nest attribute on
/// it in its containing function.
bool Argument::hasNestAttr() const {
Expand Down
27 changes: 24 additions & 3 deletions llvm/lib/IR/Value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "LLVMContextImpl.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
Expand Down Expand Up @@ -504,9 +505,29 @@ static bool isDereferenceablePointer(const Value *V, const DataLayout *DL,
if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(V))
return !GV->hasExternalWeakLinkage();

// byval arguments are ok.
if (const Argument *A = dyn_cast<Argument>(V))
return A->hasByValAttr();
// byval arguments are okay. Arguments specifically marked as
// dereferenceable are okay too.
if (const Argument *A = dyn_cast<Argument>(V)) {
if (A->hasByValAttr())
return true;
else if (uint64_t Bytes = A->getDereferenceableBytes()) {
Type *Ty = V->getType()->getPointerElementType();
if (Ty->isSized() && DL && DL->getTypeStoreSize(Ty) <= Bytes)
return true;
}

return false;
}

// Return values from call sites specifically marked as dereferenceable are
// also okay.
if (ImmutableCallSite CS = V) {
if (uint64_t Bytes = CS.getDereferenceableBytes(0)) {
Type *Ty = V->getType()->getPointerElementType();
if (Ty->isSized() && DL && DL->getTypeStoreSize(Ty) <= Bytes)
return true;
}
}

// For GEPs, determine if the indexing lands within the allocated object.
if (const GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
Expand Down
10 changes: 10 additions & 0 deletions llvm/test/Bitcode/attributes.ll
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,16 @@ define void @f38() unnamed_addr jumptable {
unreachable
}

define dereferenceable(2) i8* @f39(i8* dereferenceable(1) %a) {
; CHECK: define dereferenceable(2) i8* @f39(i8* dereferenceable(1) %a) {
ret i8* %a
}

define dereferenceable(18446744073709551606) i8* @f40(i8* dereferenceable(18446744073709551615) %a) {
; CHECK: define dereferenceable(18446744073709551606) i8* @f40(i8* dereferenceable(18446744073709551615) %a) {
ret i8* %a
}

; CHECK: attributes #0 = { noreturn }
; CHECK: attributes #1 = { nounwind }
; CHECK: attributes #2 = { readnone }
Expand Down
34 changes: 34 additions & 0 deletions llvm/test/Transforms/InstSimplify/compare.ll
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,21 @@ define i1 @nonnull_arg(i32* nonnull %i) {
; CHECK: ret i1 false
}

define i1 @nonnull_deref_arg(i32* dereferenceable(4) %i) {
%cmp = icmp eq i32* %i, null
ret i1 %cmp
; CHECK-LABEL: @nonnull_deref_arg
; CHECK: ret i1 false
}

define i1 @nonnull_deref_as_arg(i32 addrspace(1)* dereferenceable(4) %i) {
%cmp = icmp eq i32 addrspace(1)* %i, null
ret i1 %cmp
; CHECK-LABEL: @nonnull_deref_as_arg
; CHECK: icmp
; CHECK ret
}

declare nonnull i32* @returns_nonnull_helper()
define i1 @returns_nonnull() {
%call = call nonnull i32* @returns_nonnull_helper()
Expand All @@ -883,6 +898,25 @@ define i1 @returns_nonnull() {
; CHECK: ret i1 false
}

declare dereferenceable(4) i32* @returns_nonnull_deref_helper()
define i1 @returns_nonnull_deref() {
%call = call dereferenceable(4) i32* @returns_nonnull_deref_helper()
%cmp = icmp eq i32* %call, null
ret i1 %cmp
; CHECK-LABEL: @returns_nonnull_deref
; CHECK: ret i1 false
}

declare dereferenceable(4) i32 addrspace(1)* @returns_nonnull_deref_as_helper()
define i1 @returns_nonnull_as_deref() {
%call = call dereferenceable(4) i32 addrspace(1)* @returns_nonnull_deref_as_helper()
%cmp = icmp eq i32 addrspace(1)* %call, null
ret i1 %cmp
; CHECK-LABEL: @returns_nonnull_as_deref
; CHECK: icmp
; CHECK: ret
}

; If a bit is known to be zero for A and known to be one for B,
; then A and B cannot be equal.
define i1 @icmp_eq_const(i32 %a) nounwind {
Expand Down
86 changes: 86 additions & 0 deletions llvm/test/Transforms/LICM/hoist-deref-load.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
; RUN: opt -S -basicaa -licm < %s | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; This test represents the following function:
; void test1(int * __restrict__ a, int * __restrict__ b, int &c, int n) {
; for (int i = 0; i < n; ++i)
; if (a[i] > 0)
; a[i] = c*b[i];
; }
; and we want to hoist the load of %c out of the loop. This can be done only
; because the dereferenceable attribute is on %c.

; CHECK-LABEL: @test1
; CHECK: load i32* %c, align 4
; CHECK: for.body:

define void @test1(i32* noalias nocapture %a, i32* noalias nocapture readonly %b, i32* nocapture readonly nonnull dereferenceable(4) %c, i32 %n) #0 {
entry:
%cmp11 = icmp sgt i32 %n, 0
br i1 %cmp11, label %for.body, label %for.end

for.body: ; preds = %entry, %for.inc
%indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
%arrayidx = getelementptr inbounds i32* %a, i64 %indvars.iv
%0 = load i32* %arrayidx, align 4
%cmp1 = icmp sgt i32 %0, 0
br i1 %cmp1, label %if.then, label %for.inc

if.then: ; preds = %for.body
%1 = load i32* %c, align 4
%arrayidx3 = getelementptr inbounds i32* %b, i64 %indvars.iv
%2 = load i32* %arrayidx3, align 4
%mul = mul nsw i32 %2, %1
store i32 %mul, i32* %arrayidx, align 4
br label %for.inc

for.inc: ; preds = %for.body, %if.then
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
%lftr.wideiv = trunc i64 %indvars.iv.next to i32
%exitcond = icmp eq i32 %lftr.wideiv, %n
br i1 %exitcond, label %for.end, label %for.body

for.end: ; preds = %for.inc, %entry
ret void
}

; This is the same as @test1, but without the dereferenceable attribute on %c.
; Without this attribute, we should not hoist the load of %c.

; CHECK-LABEL: @test2
; CHECK: if.then:
; CHECK: load i32* %c, align 4

define void @test2(i32* noalias nocapture %a, i32* noalias nocapture readonly %b, i32* nocapture readonly nonnull %c, i32 %n) #0 {
entry:
%cmp11 = icmp sgt i32 %n, 0
br i1 %cmp11, label %for.body, label %for.end

for.body: ; preds = %entry, %for.inc
%indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
%arrayidx = getelementptr inbounds i32* %a, i64 %indvars.iv
%0 = load i32* %arrayidx, align 4
%cmp1 = icmp sgt i32 %0, 0
br i1 %cmp1, label %if.then, label %for.inc

if.then: ; preds = %for.body
%1 = load i32* %c, align 4
%arrayidx3 = getelementptr inbounds i32* %b, i64 %indvars.iv
%2 = load i32* %arrayidx3, align 4
%mul = mul nsw i32 %2, %1
store i32 %mul, i32* %arrayidx, align 4
br label %for.inc

for.inc: ; preds = %for.body, %if.then
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
%lftr.wideiv = trunc i64 %indvars.iv.next to i32
%exitcond = icmp eq i32 %lftr.wideiv, %n
br i1 %exitcond, label %for.end, label %for.body

for.end: ; preds = %for.inc, %entry
ret void
}

attributes #0 = { nounwind uwtable }