diff options
author | Sanjoy Das <sanjoy@playingwithpointers.com> | 2015-04-16 20:29:50 +0000 |
---|---|---|
committer | Sanjoy Das <sanjoy@playingwithpointers.com> | 2015-04-16 20:29:50 +0000 |
commit | 31ea6d1590ce79845504b8d928f07cb71bd4be80 (patch) | |
tree | f253459b724d977c2b1ff6a0cdbcc620a8e89f9d /llvm/lib | |
parent | 90356501f54dd6eebcb053a3206d5a4afc3bebb9 (diff) | |
download | bcm5719-llvm-31ea6d1590ce79845504b8d928f07cb71bd4be80.tar.gz bcm5719-llvm-31ea6d1590ce79845504b8d928f07cb71bd4be80.zip |
[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
llvm-svn: 235132
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/AsmParser/LLLexer.cpp | 1 | ||||
-rw-r--r-- | llvm/lib/AsmParser/LLParser.cpp | 34 | ||||
-rw-r--r-- | llvm/lib/AsmParser/LLParser.h | 2 | ||||
-rw-r--r-- | llvm/lib/AsmParser/LLToken.h | 1 | ||||
-rw-r--r-- | llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 4 | ||||
-rw-r--r-- | llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 2 | ||||
-rw-r--r-- | llvm/lib/IR/AttributeImpl.h | 8 | ||||
-rw-r--r-- | llvm/lib/IR/Attributes.cpp | 81 | ||||
-rw-r--r-- | llvm/lib/IR/Function.cpp | 6 | ||||
-rw-r--r-- | llvm/lib/IR/Instructions.cpp | 12 |
10 files changed, 121 insertions, 30 deletions
diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp index 3bf090a4b33..a72f713c490 100644 --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -598,6 +598,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(inalloca); KEYWORD(cold); KEYWORD(dereferenceable); + KEYWORD(dereferenceable_or_null); KEYWORD(inlinehint); KEYWORD(inreg); KEYWORD(jumptable); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 64ed2a2b7e3..2b306dbd642 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -976,6 +976,7 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B, break; case lltok::kw_byval: case lltok::kw_dereferenceable: + case lltok::kw_dereferenceable_or_null: case lltok::kw_inalloca: case lltok::kw_nest: case lltok::kw_noalias: @@ -1220,11 +1221,18 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) { case lltok::kw_byval: B.addAttribute(Attribute::ByVal); break; case lltok::kw_dereferenceable: { uint64_t Bytes; - if (ParseOptionalDereferenceableBytes(Bytes)) + if (ParseOptionalDerefAttrBytes(lltok::kw_dereferenceable, Bytes)) return true; B.addDereferenceableAttr(Bytes); continue; } + case lltok::kw_dereferenceable_or_null: { + uint64_t Bytes; + if (ParseOptionalDerefAttrBytes(lltok::kw_dereferenceable_or_null, Bytes)) + return true; + B.addDereferenceableOrNullAttr(Bytes); + continue; + } case lltok::kw_inalloca: B.addAttribute(Attribute::InAlloca); break; case lltok::kw_inreg: B.addAttribute(Attribute::InReg); break; case lltok::kw_nest: B.addAttribute(Attribute::Nest); break; @@ -1284,11 +1292,18 @@ bool LLParser::ParseOptionalReturnAttrs(AttrBuilder &B) { return HaveError; case lltok::kw_dereferenceable: { uint64_t Bytes; - if (ParseOptionalDereferenceableBytes(Bytes)) + if (ParseOptionalDerefAttrBytes(lltok::kw_dereferenceable, Bytes)) return true; B.addDereferenceableAttr(Bytes); continue; } + case lltok::kw_dereferenceable_or_null: { + uint64_t Bytes; + if (ParseOptionalDerefAttrBytes(lltok::kw_dereferenceable_or_null, Bytes)) + return true; + B.addDereferenceableOrNullAttr(Bytes); + continue; + } case lltok::kw_inreg: B.addAttribute(Attribute::InReg); break; case lltok::kw_noalias: B.addAttribute(Attribute::NoAlias); break; case lltok::kw_nonnull: B.addAttribute(Attribute::NonNull); break; @@ -1516,12 +1531,19 @@ bool LLParser::ParseOptionalAlignment(unsigned &Alignment) { return false; } -/// ParseOptionalDereferenceableBytes +/// ParseOptionalDerefAttrBytes /// ::= /* empty */ -/// ::= 'dereferenceable' '(' 4 ')' -bool LLParser::ParseOptionalDereferenceableBytes(uint64_t &Bytes) { +/// ::= AttrKind '(' 4 ')' +/// +/// where AttrKind is either 'dereferenceable' or 'dereferenceable_or_null'. +bool LLParser::ParseOptionalDerefAttrBytes(lltok::Kind AttrKind, + uint64_t &Bytes) { + assert((AttrKind == lltok::kw_dereferenceable || + AttrKind == lltok::kw_dereferenceable_or_null) && + "contract!"); + Bytes = 0; - if (!EatIfPresent(lltok::kw_dereferenceable)) + if (!EatIfPresent(AttrKind)) return false; LocTy ParenLoc = Lex.getLoc(); if (!EatIfPresent(lltok::lparen)) diff --git a/llvm/lib/AsmParser/LLParser.h b/llvm/lib/AsmParser/LLParser.h index 5e92e570e72..117cdcba255 100644 --- a/llvm/lib/AsmParser/LLParser.h +++ b/llvm/lib/AsmParser/LLParser.h @@ -223,7 +223,7 @@ namespace llvm { bool ParseOptionalDLLStorageClass(unsigned &DLLStorageClass); bool ParseOptionalCallingConv(unsigned &CC); bool ParseOptionalAlignment(unsigned &Alignment); - bool ParseOptionalDereferenceableBytes(uint64_t &Bytes); + bool ParseOptionalDerefAttrBytes(lltok::Kind AttrKind, uint64_t &Bytes); bool ParseScopeAndOrdering(bool isAtomic, SynchronizationScope &Scope, AtomicOrdering &Ordering); bool ParseOrdering(AtomicOrdering &Ordering); diff --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h index a7aa17c37cc..2bdc53b3e2e 100644 --- a/llvm/lib/AsmParser/LLToken.h +++ b/llvm/lib/AsmParser/LLToken.h @@ -106,6 +106,7 @@ namespace lltok { kw_inalloca, kw_cold, kw_dereferenceable, + kw_dereferenceable_or_null, kw_inlinehint, kw_inreg, kw_jumptable, diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 6caec344d1f..5366f5fb4ea 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1098,6 +1098,8 @@ static Attribute::AttrKind GetAttrFromCode(uint64_t Code) { return Attribute::NonNull; case bitc::ATTR_KIND_DEREFERENCEABLE: return Attribute::Dereferenceable; + case bitc::ATTR_KIND_DEREFERENCEABLE_OR_NULL: + return Attribute::DereferenceableOrNull; case bitc::ATTR_KIND_NO_RED_ZONE: return Attribute::NoRedZone; case bitc::ATTR_KIND_NO_RETURN: @@ -1214,6 +1216,8 @@ std::error_code BitcodeReader::ParseAttributeGroupBlock() { B.addStackAlignmentAttr(Record[++i]); else if (Kind == Attribute::Dereferenceable) B.addDereferenceableAttr(Record[++i]); + else if (Kind == Attribute::DereferenceableOrNull) + B.addDereferenceableOrNullAttr(Record[++i]); } else { // String attribute assert((Record[i] == 3 || Record[i] == 4) && "Invalid attribute group entry"); diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 743ffe3cb1f..aa4a6a4c28a 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -200,6 +200,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) { return bitc::ATTR_KIND_NON_NULL; case Attribute::Dereferenceable: return bitc::ATTR_KIND_DEREFERENCEABLE; + case Attribute::DereferenceableOrNull: + return bitc::ATTR_KIND_DEREFERENCEABLE_OR_NULL; case Attribute::NoRedZone: return bitc::ATTR_KIND_NO_RED_ZONE; case Attribute::NoReturn: diff --git a/llvm/lib/IR/AttributeImpl.h b/llvm/lib/IR/AttributeImpl.h index 199c3187205..d544689abec 100644 --- a/llvm/lib/IR/AttributeImpl.h +++ b/llvm/lib/IR/AttributeImpl.h @@ -115,10 +115,10 @@ class IntAttributeImpl : public EnumAttributeImpl { public: IntAttributeImpl(Attribute::AttrKind Kind, uint64_t Val) : EnumAttributeImpl(IntAttrEntry, Kind), Val(Val) { - assert( - (Kind == Attribute::Alignment || Kind == Attribute::StackAlignment || - Kind == Attribute::Dereferenceable) && - "Wrong kind for int attribute!"); + assert((Kind == Attribute::Alignment || Kind == Attribute::StackAlignment || + Kind == Attribute::Dereferenceable || + Kind == Attribute::DereferenceableOrNull) && + "Wrong kind for int attribute!"); } uint64_t getValue() const { return Val; } diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp index 52cc71018e5..be5b74f59a2 100644 --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -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) diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp index 8275cc692a6..d3a09348220 100644 --- a/llvm/lib/IR/Function.cpp +++ b/llvm/lib/IR/Function.cpp @@ -348,6 +348,12 @@ void Function::addDereferenceableAttr(unsigned i, uint64_t Bytes) { setAttributes(PAL); } +void Function::addDereferenceableOrNullAttr(unsigned i, uint64_t Bytes) { + AttributeSet PAL = getAttributes(); + PAL = PAL.addDereferenceableOrNullAttr(getContext(), i, Bytes); + setAttributes(PAL); +} + // Maintain the GC name for each function in an on-the-side table. This saves // allocating an additional word in Function for programs which do not use GC // (i.e., most programs) at the cost of increased overhead for clients which do diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp index 8e3ddaa4b1b..85b7521f316 100644 --- a/llvm/lib/IR/Instructions.cpp +++ b/llvm/lib/IR/Instructions.cpp @@ -352,6 +352,12 @@ void CallInst::addDereferenceableAttr(unsigned i, uint64_t Bytes) { setAttributes(PAL); } +void CallInst::addDereferenceableOrNullAttr(unsigned i, uint64_t Bytes) { + AttributeSet PAL = getAttributes(); + PAL = PAL.addDereferenceableOrNullAttr(getContext(), i, Bytes); + setAttributes(PAL); +} + bool CallInst::hasFnAttrImpl(Attribute::AttrKind A) const { if (AttributeList.hasAttribute(AttributeSet::FunctionIndex, A)) return true; @@ -617,6 +623,12 @@ void InvokeInst::addDereferenceableAttr(unsigned i, uint64_t Bytes) { setAttributes(PAL); } +void InvokeInst::addDereferenceableOrNullAttr(unsigned i, uint64_t Bytes) { + AttributeSet PAL = getAttributes(); + PAL = PAL.addDereferenceableOrNullAttr(getContext(), i, Bytes); + setAttributes(PAL); +} + LandingPadInst *InvokeInst::getLandingPadInst() const { return cast<LandingPadInst>(getUnwindDest()->getFirstNonPHI()); } |