[IR] Introduce a dereferenceable_or_null(N) attribute.

Summary:
If a pointer is marked as dereferenceable_or_null(N), LLVM assumes it
is either `null` or `dereferenceable(N)` or both.  This change only
introduces the attribute and adds a token test case for the `llvm-as`
/ `llvm-dis`.  It does not hook up other parts of the optimizer to
actually exploit the attribute -- those changes will come later.

For pointers in address space 0, `dereferenceable(N)` is now exactly
equivalent to `dereferenceable_or_null(N)` && `nonnull`.  For other
address spaces, `dereferenceable(N)` is potentially weaker than
`dereferenceable_or_null(N)` && `nonnull` (since we could have a null
`dereferenceable(N)` pointer).

The motivating case for this change is Java (and other managed
languages), where pointers are either `null` or dereferenceable up to
some usually known-at-compile-time constant offset.

Reviewers: rafael, hfinkel

Reviewed By: hfinkel

Subscribers: nicholas, llvm-commits

Differential Revision: http://reviews.llvm.org/D8650

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235132 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Sanjoy Das
2015-04-16 20:29:50 +00:00
parent 3054c3e982
commit 5ff5907996
17 changed files with 181 additions and 31 deletions

View File

@ -94,6 +94,12 @@ Attribute Attribute::getWithDereferenceableBytes(LLVMContext &Context,
return get(Context, Dereferenceable, Bytes);
}
Attribute Attribute::getWithDereferenceableOrNullBytes(LLVMContext &Context,
uint64_t Bytes) {
assert(Bytes && "Bytes must be non-zero.");
return get(Context, DereferenceableOrNull, Bytes);
}
//===----------------------------------------------------------------------===//
// Attribute Accessor Methods
//===----------------------------------------------------------------------===//
@ -170,6 +176,13 @@ uint64_t Attribute::getDereferenceableBytes() const {
return pImpl->getValueAsInt();
}
uint64_t Attribute::getDereferenceableOrNullBytes() const {
assert(hasAttribute(Attribute::DereferenceableOrNull) &&
"Trying to get dereferenceable bytes from "
"non-dereferenceable attribute!");
return pImpl->getValueAsInt();
}
std::string Attribute::getAsString(bool InAttrGrp) const {
if (!pImpl) return "";
@ -263,9 +276,9 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
return Result;
}
if (hasAttribute(Attribute::StackAlignment)) {
auto AttrWithBytesToString = [&](const char *Name) {
std::string Result;
Result += "alignstack";
Result += Name;
if (InAttrGrp) {
Result += "=";
Result += utostr(getValueAsInt());
@ -275,21 +288,16 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
Result += ")";
}
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;
}
if (hasAttribute(Attribute::StackAlignment))
return AttrWithBytesToString("alignstack");
if (hasAttribute(Attribute::Dereferenceable))
return AttrWithBytesToString("dereferenceable");
if (hasAttribute(Attribute::DereferenceableOrNull))
return AttrWithBytesToString("dereferenceable_or_null");
// Convert target-dependent attributes to strings of the form:
//
@ -428,6 +436,11 @@ uint64_t AttributeImpl::getAttrMask(Attribute::AttrKind Val) {
case Attribute::JumpTable: return 1ULL << 45;
case Attribute::Dereferenceable:
llvm_unreachable("dereferenceable attribute not supported in raw format");
break;
case Attribute::DereferenceableOrNull:
llvm_unreachable("dereferenceable_or_null attribute not supported in raw "
"format");
break;
}
llvm_unreachable("Unsupported attribute type");
}
@ -663,6 +676,10 @@ AttributeSet AttributeSet::get(LLVMContext &C, unsigned Index,
Attrs.push_back(std::make_pair(Index,
Attribute::getWithDereferenceableBytes(C,
B.getDereferenceableBytes())));
else if (Kind == Attribute::DereferenceableOrNull)
Attrs.push_back(
std::make_pair(Index, Attribute::getWithDereferenceableOrNullBytes(
C, B.getDereferenceableOrNullBytes())));
else
Attrs.push_back(std::make_pair(Index, Attribute::get(C, Kind)));
}
@ -842,6 +859,14 @@ AttributeSet AttributeSet::addDereferenceableAttr(LLVMContext &C, unsigned Index
return addAttributes(C, Index, AttributeSet::get(C, Index, B));
}
AttributeSet AttributeSet::addDereferenceableOrNullAttr(LLVMContext &C,
unsigned Index,
uint64_t Bytes) const {
llvm::AttrBuilder B;
B.addDereferenceableOrNullAttr(Bytes);
return addAttributes(C, Index, AttributeSet::get(C, Index, B));
}
//===----------------------------------------------------------------------===//
// AttributeSet Accessor Methods
//===----------------------------------------------------------------------===//
@ -1011,7 +1036,8 @@ void AttributeSet::dump() const {
//===----------------------------------------------------------------------===//
AttrBuilder::AttrBuilder(AttributeSet AS, unsigned Index)
: Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0) {
: Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0),
DerefOrNullBytes(0) {
AttributeSetImpl *pImpl = AS.pImpl;
if (!pImpl) return;
@ -1028,7 +1054,7 @@ AttrBuilder::AttrBuilder(AttributeSet AS, unsigned Index)
void AttrBuilder::clear() {
Attrs.reset();
Alignment = StackAlignment = DerefBytes = 0;
Alignment = StackAlignment = DerefBytes = DerefOrNullBytes = 0;
}
AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Val) {
@ -1055,6 +1081,8 @@ AttrBuilder &AttrBuilder::addAttribute(Attribute Attr) {
StackAlignment = Attr.getStackAlignment();
else if (Kind == Attribute::Dereferenceable)
DerefBytes = Attr.getDereferenceableBytes();
else if (Kind == Attribute::DereferenceableOrNull)
DerefOrNullBytes = Attr.getDereferenceableOrNullBytes();
return *this;
}
@ -1073,6 +1101,8 @@ AttrBuilder &AttrBuilder::removeAttribute(Attribute::AttrKind Val) {
StackAlignment = 0;
else if (Val == Attribute::Dereferenceable)
DerefBytes = 0;
else if (Val == Attribute::DereferenceableOrNull)
DerefOrNullBytes = 0;
return *this;
}
@ -1099,6 +1129,8 @@ AttrBuilder &AttrBuilder::removeAttributes(AttributeSet A, uint64_t Index) {
StackAlignment = 0;
else if (Kind == Attribute::Dereferenceable)
DerefBytes = 0;
else if (Kind == Attribute::DereferenceableOrNull)
DerefOrNullBytes = 0;
} else {
assert(Attr.isStringAttribute() && "Invalid attribute type!");
std::map<std::string, std::string>::iterator
@ -1149,6 +1181,15 @@ AttrBuilder &AttrBuilder::addDereferenceableAttr(uint64_t Bytes) {
return *this;
}
AttrBuilder &AttrBuilder::addDereferenceableOrNullAttr(uint64_t Bytes) {
if (Bytes == 0)
return *this;
Attrs[Attribute::DereferenceableOrNull] = true;
DerefOrNullBytes = Bytes;
return *this;
}
AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) {
// FIXME: What if both have alignments, but they don't match?!
if (!Alignment)
@ -1225,7 +1266,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)
if (I == Attribute::Dereferenceable ||
I == Attribute::DereferenceableOrNull)
continue;
if (uint64_t A = (Val & AttributeImpl::getAttrMask(I))) {
Attrs[I] = true;
@ -1261,6 +1303,7 @@ AttributeSet AttributeFuncs::typeIncompatible(Type *Ty, uint64_t Index) {
.addAttribute(Attribute::NoCapture)
.addAttribute(Attribute::NonNull)
.addDereferenceableAttr(1) // the int here is ignored
.addDereferenceableOrNullAttr(1) // the int here is ignored
.addAttribute(Attribute::ReadNone)
.addAttribute(Attribute::ReadOnly)
.addAttribute(Attribute::StructRet)