Skip to content

Commit

Permalink
Added support for the Builtin attribute.
Browse files Browse the repository at this point in the history
The Builtin attribute is an attribute that can be placed on function call site that signal that even though a function is declared as being a builtin,

rdar://problem/13727199

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@185049 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
gottesmm committed Jun 27, 2013
1 parent 9367c79 commit 2253a2f
Show file tree
Hide file tree
Showing 15 changed files with 154 additions and 23 deletions.
16 changes: 11 additions & 5 deletions docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,12 @@ example:
computing edge weights, basic blocks post-dominated by a cold
function call are also considered to be cold; and, thus, given low
weight.
``builtin``
This indicates that the callee function at a call site should be
recognized as a built-in function, even though the function's declaration
uses the ``nobuiltin'' attribute. This is only valid at call sites for
direct calls to functions which are declared with the ``nobuiltin``
attribute.
``nonlazybind``
This attribute suppresses lazy symbol binding for the function. This
may make calls to the function faster, at the cost of extra program
Expand All @@ -835,11 +841,11 @@ example:
This attribute disables prologue / epilogue emission for the
function. This can have very system-specific consequences.
``nobuiltin``
This indicates that the callee function at a call site is not
recognized as a built-in function. LLVM will retain the original call
and not replace it with equivalent code based on the semantics of the
built-in function. This is only valid at call sites, not on function
declarations or definitions.
This indicates that the callee function at a call site is not recognized as
a built-in function. LLVM will retain the original call and not replace it
with equivalent code based on the semantics of the built-in function, unless
the call site uses the ``builtin`` attribute. This is valid at call sites
and on function declarations and definitions.
``noduplicate``
This attribute indicates that calls to the function cannot be
duplicated. A call to a ``noduplicate`` function may be moved
Expand Down
2 changes: 2 additions & 0 deletions include/llvm/IR/Attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ class Attribute {
///< stored as log2 of alignment with +1 bias
///< 0 means unaligned (different from align(1))
AlwaysInline, ///< inline=always
Builtin, ///< Callee is recognized as a builtin, despite
///< nobuiltin attribute on its declaration.
ByVal, ///< Pass structure by value
Cold, ///< Marks function as being in a cold path.
InlineHint, ///< Source said inlining was desirable
Expand Down
33 changes: 31 additions & 2 deletions include/llvm/IR/Instructions.h
Original file line number Diff line number Diff line change
Expand Up @@ -1278,7 +1278,11 @@ class CallInst : public Instruction {
void removeAttribute(unsigned i, Attribute attr);

/// \brief Determine whether this call has the given attribute.
bool hasFnAttr(Attribute::AttrKind A) const;
bool hasFnAttr(Attribute::AttrKind A) const {
assert(A != Attribute::NoBuiltin &&
"Use CallInst::isNoBuiltin() to check for Attribute::NoBuiltin");
return hasFnAttrImpl(A);
}

/// \brief Determine whether the call or the callee has the given attributes.
bool paramHasAttr(unsigned i, Attribute::AttrKind A) const;
Expand All @@ -1288,6 +1292,13 @@ class CallInst : public Instruction {
return AttributeList.getParamAlignment(i);
}

/// \brief Return true if the call should not be treated as a call to a
/// builtin.
bool isNoBuiltin() const {
return hasFnAttrImpl(Attribute::NoBuiltin) &&
!hasFnAttrImpl(Attribute::Builtin);
}

/// \brief Return true if the call should not be inlined.
bool isNoInline() const { return hasFnAttr(Attribute::NoInline); }
void setIsNoInline() {
Expand Down Expand Up @@ -1378,6 +1389,9 @@ class CallInst : public Instruction {
return isa<Instruction>(V) && classof(cast<Instruction>(V));
}
private:

bool hasFnAttrImpl(Attribute::AttrKind A) const;

// Shadow Instruction::setInstructionSubclassData with a private forwarding
// method so that subclasses cannot accidentally use it.
void setInstructionSubclassData(unsigned short D) {
Expand Down Expand Up @@ -3021,7 +3035,11 @@ class InvokeInst : public TerminatorInst {
void removeAttribute(unsigned i, Attribute attr);

/// \brief Determine whether this call has the NoAlias attribute.
bool hasFnAttr(Attribute::AttrKind A) const;
bool hasFnAttr(Attribute::AttrKind A) const {
assert(A != Attribute::NoBuiltin &&
"Use CallInst::isNoBuiltin() to check for Attribute::NoBuiltin");
return hasFnAttrImpl(A);
}

/// \brief Determine whether the call or the callee has the given attributes.
bool paramHasAttr(unsigned i, Attribute::AttrKind A) const;
Expand All @@ -3031,6 +3049,15 @@ class InvokeInst : public TerminatorInst {
return AttributeList.getParamAlignment(i);
}

/// \brief Return true if the call should not be treated as a call to a
/// builtin.
bool isNoBuiltin() const {
// We assert in hasFnAttr if one passes in Attribute::NoBuiltin, so we have
// to check it by hand.
return hasFnAttrImpl(Attribute::NoBuiltin) &&
!hasFnAttrImpl(Attribute::Builtin);
}

/// \brief Return true if the call should not be inlined.
bool isNoInline() const { return hasFnAttr(Attribute::NoInline); }
void setIsNoInline() {
Expand Down Expand Up @@ -3137,6 +3164,8 @@ class InvokeInst : public TerminatorInst {
virtual unsigned getNumSuccessorsV() const;
virtual void setSuccessorV(unsigned idx, BasicBlock *B);

bool hasFnAttrImpl(Attribute::AttrKind A) const;

// Shadow Instruction::setInstructionSubclassData with a private forwarding
// method so that subclasses cannot accidentally use it.
void setInstructionSubclassData(unsigned short D) {
Expand Down
6 changes: 6 additions & 0 deletions include/llvm/Support/CallSite.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,12 @@ class CallSiteBase {
CALLSITE_DELEGATE_GETTER(getParamAlignment(i));
}

/// \brief Return true if the call should not be treated as a call to a
/// builtin.
bool isNoBuiltin() const {
CALLSITE_DELEGATE_GETTER(isNoBuiltin());
}

/// @brief Return true if the call should not be inlined.
bool isNoInline() const {
CALLSITE_DELEGATE_GETTER(isNoInline());
Expand Down
2 changes: 1 addition & 1 deletion lib/Analysis/MemoryBuiltins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ static Function *getCalledFunction(const Value *V, bool LookThroughBitCast) {
if (!CS.getInstruction())
return 0;

if (CS.hasFnAttr(Attribute::NoBuiltin))
if (CS.isNoBuiltin())
return 0;

Function *Callee = CS.getCalledFunction();
Expand Down
1 change: 1 addition & 0 deletions lib/AsmParser/LLLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(attributes);

KEYWORD(alwaysinline);
KEYWORD(builtin);
KEYWORD(byval);
KEYWORD(cold);
KEYWORD(inlinehint);
Expand Down
25 changes: 14 additions & 11 deletions lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -810,13 +810,13 @@ bool LLParser::ParseUnnamedAttrGrp() {
assert(Lex.getKind() == lltok::AttrGrpID);
unsigned VarID = Lex.getUIntVal();
std::vector<unsigned> unused;
LocTy NoBuiltinLoc;
LocTy BuiltinLoc;
Lex.Lex();

if (ParseToken(lltok::equal, "expected '=' here") ||
ParseToken(lltok::lbrace, "expected '{' here") ||
ParseFnAttributeValuePairs(NumberedAttrBuilders[VarID], unused, true,
NoBuiltinLoc) ||
BuiltinLoc) ||
ParseToken(lltok::rbrace, "expected end of attribute group"))
return true;

Expand All @@ -830,15 +830,15 @@ bool LLParser::ParseUnnamedAttrGrp() {
/// ::= <attr> | <attr> '=' <value>
bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
std::vector<unsigned> &FwdRefAttrGrps,
bool inAttrGrp, LocTy &NoBuiltinLoc) {
bool inAttrGrp, LocTy &BuiltinLoc) {
bool HaveError = false;

B.clear();

while (true) {
lltok::Kind Token = Lex.getKind();
if (Token == lltok::kw_nobuiltin)
NoBuiltinLoc = Lex.getLoc();
if (Token == lltok::kw_builtin)
BuiltinLoc = Lex.getLoc();
switch (Token) {
default:
if (!inAttrGrp) return HaveError;
Expand Down Expand Up @@ -909,6 +909,7 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
continue;
}
case lltok::kw_alwaysinline: B.addAttribute(Attribute::AlwaysInline); break;
case lltok::kw_builtin: B.addAttribute(Attribute::Builtin); break;
case lltok::kw_cold: B.addAttribute(Attribute::Cold); break;
case lltok::kw_inlinehint: B.addAttribute(Attribute::InlineHint); break;
case lltok::kw_minsize: B.addAttribute(Attribute::MinSize); break;
Expand Down Expand Up @@ -1165,6 +1166,7 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) {

case lltok::kw_alignstack:
case lltok::kw_alwaysinline:
case lltok::kw_builtin:
case lltok::kw_inlinehint:
case lltok::kw_minsize:
case lltok::kw_naked:
Expand Down Expand Up @@ -1223,6 +1225,7 @@ bool LLParser::ParseOptionalReturnAttrs(AttrBuilder &B) {

case lltok::kw_alignstack:
case lltok::kw_alwaysinline:
case lltok::kw_builtin:
case lltok::kw_cold:
case lltok::kw_inlinehint:
case lltok::kw_minsize:
Expand Down Expand Up @@ -2983,7 +2986,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
bool isVarArg;
AttrBuilder FuncAttrs;
std::vector<unsigned> FwdRefAttrGrps;
LocTy NoBuiltinLoc;
LocTy BuiltinLoc;
std::string Section;
unsigned Alignment;
std::string GC;
Expand All @@ -2994,16 +2997,16 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
ParseOptionalToken(lltok::kw_unnamed_addr, UnnamedAddr,
&UnnamedAddrLoc) ||
ParseFnAttributeValuePairs(FuncAttrs, FwdRefAttrGrps, false,
NoBuiltinLoc) ||
BuiltinLoc) ||
(EatIfPresent(lltok::kw_section) &&
ParseStringConstant(Section)) ||
ParseOptionalAlignment(Alignment) ||
(EatIfPresent(lltok::kw_gc) &&
ParseStringConstant(GC)))
return true;

if (FuncAttrs.contains(Attribute::NoBuiltin))
return Error(NoBuiltinLoc, "'nobuiltin' attribute not valid on function");
if (FuncAttrs.contains(Attribute::Builtin))
return Error(BuiltinLoc, "'builtin' attribute not valid on function");

// If the alignment was parsed as an attribute, move to the alignment field.
if (FuncAttrs.hasAlignmentAttr()) {
Expand Down Expand Up @@ -3927,7 +3930,7 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS,
bool isTail) {
AttrBuilder RetAttrs, FnAttrs;
std::vector<unsigned> FwdRefAttrGrps;
LocTy NoBuiltinLoc;
LocTy BuiltinLoc;
CallingConv::ID CC;
Type *RetType = 0;
LocTy RetTypeLoc;
Expand All @@ -3942,7 +3945,7 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS,
ParseValID(CalleeID) ||
ParseParameterList(ArgList, PFS) ||
ParseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false,
NoBuiltinLoc))
BuiltinLoc))
return true;

// If RetType is a non-function pointer type, then this is the short syntax
Expand Down
2 changes: 1 addition & 1 deletion lib/AsmParser/LLParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ namespace llvm {
bool ParseUnnamedAttrGrp();
bool ParseFnAttributeValuePairs(AttrBuilder &B,
std::vector<unsigned> &FwdRefAttrGrps,
bool inAttrGrp, LocTy &NoBuiltinLoc);
bool inAttrGrp, LocTy &BuiltinLoc);

// Type Parsing.
bool ParseType(Type *&Result, bool AllowVoid = false);
Expand Down
1 change: 1 addition & 0 deletions lib/AsmParser/LLToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ namespace lltok {
kw_attributes,
kw_alwaysinline,
kw_sanitize_address,
kw_builtin,
kw_byval,
kw_cold,
kw_inlinehint,
Expand Down
3 changes: 3 additions & 0 deletions lib/IR/Attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
return "sanitize_address";
if (hasAttribute(Attribute::AlwaysInline))
return "alwaysinline";
if (hasAttribute(Attribute::Builtin))
return "builtin";
if (hasAttribute(Attribute::ByVal))
return "byval";
if (hasAttribute(Attribute::InlineHint))
Expand Down Expand Up @@ -399,6 +401,7 @@ uint64_t AttributeImpl::getAttrMask(Attribute::AttrKind Val) {
case Attribute::NoBuiltin: return 1ULL << 38;
case Attribute::Returned: return 1ULL << 39;
case Attribute::Cold: return 1ULL << 40;
case Attribute::Builtin: return 1ULL << 41;
}
llvm_unreachable("Unsupported attribute type");
}
Expand Down
4 changes: 2 additions & 2 deletions lib/IR/Instructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ void CallInst::removeAttribute(unsigned i, Attribute attr) {
setAttributes(PAL);
}

bool CallInst::hasFnAttr(Attribute::AttrKind A) const {
bool CallInst::hasFnAttrImpl(Attribute::AttrKind A) const {
if (AttributeList.hasAttribute(AttributeSet::FunctionIndex, A))
return true;
if (const Function *F = getCalledFunction())
Expand Down Expand Up @@ -574,7 +574,7 @@ void InvokeInst::setSuccessorV(unsigned idx, BasicBlock *B) {
return setSuccessor(idx, B);
}

bool InvokeInst::hasFnAttr(Attribute::AttrKind A) const {
bool InvokeInst::hasFnAttrImpl(Attribute::AttrKind A) const {
if (AttributeList.hasAttribute(AttributeSet::FunctionIndex, A))
return true;
if (const Function *F = getCalledFunction())
Expand Down
16 changes: 16 additions & 0 deletions lib/IR/Verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,7 @@ void Verifier::VerifyAttributeTypes(AttributeSet Attrs, unsigned Idx,
I->getKindAsEnum() == Attribute::SanitizeMemory ||
I->getKindAsEnum() == Attribute::MinSize ||
I->getKindAsEnum() == Attribute::NoDuplicate ||
I->getKindAsEnum() == Attribute::Builtin ||
I->getKindAsEnum() == Attribute::NoBuiltin ||
I->getKindAsEnum() == Attribute::Cold) {
if (!isFunction)
Expand Down Expand Up @@ -877,6 +878,13 @@ void Verifier::visitFunction(Function &F) {
// Check function attributes.
VerifyFunctionAttrs(FT, Attrs, &F);

// On function declarations/definitions, we do not support the builtin
// attribute. We do not check this in VerifyFunctionAttrs since that is
// checking for Attributes that can/can not ever be on functions.
Assert1(!Attrs.hasAttribute(AttributeSet::FunctionIndex,
Attribute::Builtin),
"Attribute 'builtin' can only be applied to a callsite.", &F);

// Check that this function meets the restrictions on this calling convention.
switch (F.getCallingConv()) {
default:
Expand Down Expand Up @@ -1435,6 +1443,14 @@ void Verifier::VerifyCallSite(CallSite CS) {
"Function has metadata parameter but isn't an intrinsic", I);
}

// If the call site has the 'builtin' attribute, verify that it's applied to a
// direct call to a function with the 'nobuiltin' attribute.
if (CS.hasFnAttr(Attribute::Builtin))
Assert1(CS.getCalledFunction() &&
CS.getCalledFunction()->hasFnAttribute(Attribute::NoBuiltin),
"Attribute 'builtin' can only be used in a call to a function with "
"the 'nobuiltin' attribute.", I);

visitInstruction(*I);
}

Expand Down
2 changes: 1 addition & 1 deletion lib/Transforms/Utils/SimplifyLibCalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1940,7 +1940,7 @@ LibCallSimplifier::~LibCallSimplifier() {
}

Value *LibCallSimplifier::optimizeCall(CallInst *CI) {
if (CI->hasFnAttr(Attribute::NoBuiltin)) return 0;
if (CI->isNoBuiltin()) return 0;
return Impl->optimizeCall(CI);
}

Expand Down
Loading

0 comments on commit 2253a2f

Please sign in to comment.