mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-06-24 08:24:33 +00:00
[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:
@ -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)
|
||||
|
Reference in New Issue
Block a user