summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
authorHal Finkel <hfinkel@anl.gov>2014-07-18 15:51:28 +0000
committerHal Finkel <hfinkel@anl.gov>2014-07-18 15:51:28 +0000
commitb0407ba0716d940d035f5da73f6d3bfbaffecb44 (patch)
tree0fb08700ec2601986a9f5195a9d57fb6e0b48444 /llvm/lib
parent9cf7ac75893c9f83099ce59dd4fd5d1ba7ead25a (diff)
downloadbcm5719-llvm-b0407ba0716d940d035f5da73f6d3bfbaffecb44.tar.gz
bcm5719-llvm-b0407ba0716d940d035f5da73f6d3bfbaffecb44.zip
Add a dereferenceable attribute
This attribute indicates that the parameter or return pointer is dereferenceable. Practically speaking, loads from such a pointer within the associated byte range are safe to speculatively execute. Such pointer parameters are common in source languages (C++ references, for example). llvm-svn: 213385
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/Analysis/ValueTracking.cpp2
-rw-r--r--llvm/lib/AsmParser/LLLexer.cpp1
-rw-r--r--llvm/lib/AsmParser/LLParser.cpp45
-rw-r--r--llvm/lib/AsmParser/LLParser.h6
-rw-r--r--llvm/lib/AsmParser/LLToken.h1
-rw-r--r--llvm/lib/Bitcode/Reader/BitcodeReader.cpp6
-rw-r--r--llvm/lib/Bitcode/Writer/BitcodeWriter.cpp2
-rw-r--r--llvm/lib/IR/AttributeImpl.h4
-rw-r--r--llvm/lib/IR/Attributes.cpp78
-rw-r--r--llvm/lib/IR/Function.cpp18
-rw-r--r--llvm/lib/IR/Value.cpp27
11 files changed, 177 insertions, 13 deletions
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index cedf076497e..e6d09f4e31f 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -2086,7 +2086,7 @@ bool llvm::isKnownNonNull(const Value *V, const TargetLibraryInfo *TLI) {
return !GV->hasExternalWeakLinkage();
if (ImmutableCallSite CS = V)
- if (CS.paramHasAttr(0, Attribute::NonNull))
+ if (CS.isReturnNonNull())
return true;
// operator new never returns null.
diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index 1e5bcdd930c..962298fcd54 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -612,6 +612,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(byval);
KEYWORD(inalloca);
KEYWORD(cold);
+ KEYWORD(dereferenceable);
KEYWORD(inlinehint);
KEYWORD(inreg);
KEYWORD(jumptable);
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index be55ac6481f..ac6e0e512fe 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -1052,6 +1052,7 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
"invalid use of attribute on a function");
break;
case lltok::kw_byval:
+ case lltok::kw_dereferenceable:
case lltok::kw_inalloca:
case lltok::kw_nest:
case lltok::kw_noalias:
@@ -1212,6 +1213,16 @@ bool LLParser::ParseUInt32(unsigned &Val) {
return false;
}
+/// ParseUInt64
+/// ::= uint64
+bool LLParser::ParseUInt64(uint64_t &Val) {
+ if (Lex.getKind() != lltok::APSInt || Lex.getAPSIntVal().isSigned())
+ return TokError("expected integer");
+ Val = Lex.getAPSIntVal().getLimitedValue();
+ Lex.Lex();
+ return false;
+}
+
/// ParseTLSModel
/// := 'localdynamic'
/// := 'initialexec'
@@ -1284,6 +1295,13 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) {
continue;
}
case lltok::kw_byval: B.addAttribute(Attribute::ByVal); break;
+ case lltok::kw_dereferenceable: {
+ uint64_t Bytes;
+ if (ParseOptionalDereferenceableBytes(Bytes))
+ return true;
+ B.addDereferenceableAttr(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;
@@ -1341,6 +1359,13 @@ bool LLParser::ParseOptionalReturnAttrs(AttrBuilder &B) {
switch (Token) {
default: // End of attributes.
return HaveError;
+ case lltok::kw_dereferenceable: {
+ uint64_t Bytes;
+ if (ParseOptionalDereferenceableBytes(Bytes))
+ return true;
+ B.addDereferenceableAttr(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;
@@ -1606,6 +1631,26 @@ bool LLParser::ParseOptionalAlignment(unsigned &Alignment) {
return false;
}
+/// ParseOptionalDereferenceableBytes
+/// ::= /* empty */
+/// ::= 'dereferenceable' '(' 4 ')'
+bool LLParser::ParseOptionalDereferenceableBytes(uint64_t &Bytes) {
+ Bytes = 0;
+ if (!EatIfPresent(lltok::kw_dereferenceable))
+ return false;
+ LocTy ParenLoc = Lex.getLoc();
+ if (!EatIfPresent(lltok::lparen))
+ return Error(ParenLoc, "expected '('");
+ LocTy DerefLoc = Lex.getLoc();
+ if (ParseUInt64(Bytes)) return true;
+ ParenLoc = Lex.getLoc();
+ if (!EatIfPresent(lltok::rparen))
+ return Error(ParenLoc, "expected ')'");
+ if (!Bytes)
+ return Error(DerefLoc, "dereferenceable bytes must be non-zero");
+ return false;
+}
+
/// ParseOptionalCommaAlign
/// ::=
/// ::= ',' align 4
diff --git a/llvm/lib/AsmParser/LLParser.h b/llvm/lib/AsmParser/LLParser.h
index 2efb260d66b..7203bb245d0 100644
--- a/llvm/lib/AsmParser/LLParser.h
+++ b/llvm/lib/AsmParser/LLParser.h
@@ -202,6 +202,11 @@ namespace llvm {
Loc = Lex.getLoc();
return ParseUInt32(Val);
}
+ bool ParseUInt64(uint64_t &Val);
+ bool ParseUInt64(uint64_t &Val, LocTy &Loc) {
+ Loc = Lex.getLoc();
+ return ParseUInt64(Val);
+ }
bool ParseTLSModel(GlobalVariable::ThreadLocalMode &TLM);
bool ParseOptionalThreadLocal(GlobalVariable::ThreadLocalMode &TLM);
@@ -219,6 +224,7 @@ namespace llvm {
bool ParseOptionalDLLStorageClass(unsigned &DLLStorageClass);
bool ParseOptionalCallingConv(CallingConv::ID &CC);
bool ParseOptionalAlignment(unsigned &Alignment);
+ bool ParseOptionalDereferenceableBytes(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 534d82415fd..2f02606f93e 100644
--- a/llvm/lib/AsmParser/LLToken.h
+++ b/llvm/lib/AsmParser/LLToken.h
@@ -106,6 +106,7 @@ namespace lltok {
kw_byval,
kw_inalloca,
kw_cold,
+ kw_dereferenceable,
kw_inlinehint,
kw_inreg,
kw_jumptable,
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 4a0484777cf..47a39539e20 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -588,6 +588,8 @@ static Attribute::AttrKind GetAttrFromCode(uint64_t Code) {
return Attribute::NonLazyBind;
case bitc::ATTR_KIND_NON_NULL:
return Attribute::NonNull;
+ case bitc::ATTR_KIND_DEREFERENCEABLE:
+ return Attribute::Dereferenceable;
case bitc::ATTR_KIND_NO_RED_ZONE:
return Attribute::NoRedZone;
case bitc::ATTR_KIND_NO_RETURN:
@@ -689,8 +691,10 @@ std::error_code BitcodeReader::ParseAttributeGroupBlock() {
return EC;
if (Kind == Attribute::Alignment)
B.addAlignmentAttr(Record[++i]);
- else
+ else if (Kind == Attribute::StackAlignment)
B.addStackAlignmentAttr(Record[++i]);
+ else if (Kind == Attribute::Dereferenceable)
+ B.addDereferenceableAttr(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 67710472a15..b2e49486d70 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -201,6 +201,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_NON_LAZY_BIND;
case Attribute::NonNull:
return bitc::ATTR_KIND_NON_NULL;
+ case Attribute::Dereferenceable:
+ return bitc::ATTR_KIND_DEREFERENCEABLE;
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 999a803c037..cc6d557ab4c 100644
--- a/llvm/lib/IR/AttributeImpl.h
+++ b/llvm/lib/IR/AttributeImpl.h
@@ -116,7 +116,8 @@ public:
IntAttributeImpl(Attribute::AttrKind Kind, uint64_t Val)
: EnumAttributeImpl(IntAttrEntry, Kind), Val(Val) {
assert(
- (Kind == Attribute::Alignment || Kind == Attribute::StackAlignment) &&
+ (Kind == Attribute::Alignment || Kind == Attribute::StackAlignment ||
+ Kind == Attribute::Dereferenceable) &&
"Wrong kind for int attribute!");
}
@@ -164,6 +165,7 @@ public:
unsigned getAlignment() const;
unsigned getStackAlignment() const;
+ uint64_t getDereferenceableBytes() const;
std::string getAsString(bool InAttrGrp) const;
typedef const Attribute *iterator;
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index 3ee622b31ba..04545ea919a 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -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
//===----------------------------------------------------------------------===//
@@ -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 "";
@@ -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"
@@ -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");
}
@@ -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) {
@@ -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);
}
@@ -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)));
}
@@ -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);
@@ -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;
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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
@@ -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)
@@ -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(),
@@ -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) {
@@ -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;
@@ -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)
diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp
index 14435711bb6..de59b26ec92 100644
--- a/llvm/lib/IR/Function.cpp
+++ b/llvm/lib/IR/Function.cpp
@@ -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
@@ -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 {
diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp
index 999685e15eb..efdd6a7ed6e 100644
--- a/llvm/lib/IR/Value.cpp
+++ b/llvm/lib/IR/Value.cpp
@@ -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"
@@ -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)) {
OpenPOWER on IntegriCloud