Implement the NoBuiltin attribute.

The 'nobuiltin' attribute is applied to call sites to indicate that LLVM should
not treat the callee function as a built-in function. I.e., it shouldn't try to
replace that function with different code.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@175835 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Bill Wendling 2013-02-22 00:12:35 +00:00
parent a931a12e04
commit 143d46476c
10 changed files with 66 additions and 35 deletions

View File

@ -720,6 +720,11 @@ Currently, only the following parameter attributes are defined:
This indicates that the pointer parameter can be excised using the
:ref:`trampoline intrinsics <int_trampoline>`. This is not a valid
attribute for return values.
``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.
.. _gc:

View File

@ -75,6 +75,7 @@ public:
Naked, ///< Naked function
Nest, ///< Nested function static chain
NoAlias, ///< Considered to not alias after call
NoBuiltin, ///< Callee isn't recognized as a builtin
NoCapture, ///< Function creates no aliases of pointer
NoDuplicate, ///< Call cannot be duplicated
NoImplicitFloat, ///< Disable implicit floating point insts
@ -473,31 +474,7 @@ public:
bool td_empty() const { return TargetDepAttrs.empty(); }
/// \brief Remove attributes that are used on functions only.
void removeFunctionOnlyAttrs() {
removeAttribute(Attribute::NoReturn)
.removeAttribute(Attribute::NoUnwind)
.removeAttribute(Attribute::ReadNone)
.removeAttribute(Attribute::ReadOnly)
.removeAttribute(Attribute::NoInline)
.removeAttribute(Attribute::AlwaysInline)
.removeAttribute(Attribute::OptimizeForSize)
.removeAttribute(Attribute::StackProtect)
.removeAttribute(Attribute::StackProtectReq)
.removeAttribute(Attribute::StackProtectStrong)
.removeAttribute(Attribute::NoRedZone)
.removeAttribute(Attribute::NoImplicitFloat)
.removeAttribute(Attribute::Naked)
.removeAttribute(Attribute::InlineHint)
.removeAttribute(Attribute::StackAlignment)
.removeAttribute(Attribute::UWTable)
.removeAttribute(Attribute::NonLazyBind)
.removeAttribute(Attribute::ReturnsTwice)
.removeAttribute(Attribute::AddressSafety)
.removeAttribute(Attribute::ThreadSafety)
.removeAttribute(Attribute::UninitializedChecks)
.removeAttribute(Attribute::MinSize)
.removeAttribute(Attribute::NoDuplicate);
}
void removeFunctionOnlyAttrs();
bool operator==(const AttrBuilder &B);
bool operator!=(const AttrBuilder &B) {

View File

@ -571,6 +571,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(naked);
KEYWORD(nest);
KEYWORD(noalias);
KEYWORD(nobuiltin);
KEYWORD(nocapture);
KEYWORD(noduplicate);
KEYWORD(noimplicitfloat);

View File

@ -810,11 +810,13 @@ bool LLParser::ParseUnnamedAttrGrp() {
assert(Lex.getKind() == lltok::AttrGrpID);
unsigned VarID = Lex.getUIntVal();
std::vector<unsigned> unused;
LocTy NoBuiltinLoc;
Lex.Lex();
if (ParseToken(lltok::equal, "expected '=' here") ||
ParseToken(lltok::lbrace, "expected '{' here") ||
ParseFnAttributeValuePairs(NumberedAttrBuilders[VarID], unused, true) ||
ParseFnAttributeValuePairs(NumberedAttrBuilders[VarID], unused, true,
NoBuiltinLoc) ||
ParseToken(lltok::rbrace, "expected end of attribute group"))
return true;
@ -828,13 +830,15 @@ bool LLParser::ParseUnnamedAttrGrp() {
/// ::= <attr> | <attr> '=' <value>
bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
std::vector<unsigned> &FwdRefAttrGrps,
bool inAttrGrp) {
bool inAttrGrp, LocTy &NoBuiltinLoc) {
bool HaveError = false;
B.clear();
while (true) {
lltok::Kind Token = Lex.getKind();
if (Token == lltok::kw_nobuiltin)
NoBuiltinLoc = Lex.getLoc();
switch (Token) {
default:
if (!inAttrGrp) return HaveError;
@ -908,6 +912,7 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
case lltok::kw_inlinehint: B.addAttribute(Attribute::InlineHint); break;
case lltok::kw_minsize: B.addAttribute(Attribute::MinSize); break;
case lltok::kw_naked: B.addAttribute(Attribute::Naked); break;
case lltok::kw_nobuiltin: B.addAttribute(Attribute::NoBuiltin); break;
case lltok::kw_noduplicate: B.addAttribute(Attribute::NoDuplicate); break;
case lltok::kw_noimplicitfloat: B.addAttribute(Attribute::NoImplicitFloat); break;
case lltok::kw_noinline: B.addAttribute(Attribute::NoInline); break;
@ -1164,7 +1169,7 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) {
case lltok::kw_naked: case lltok::kw_nonlazybind:
case lltok::kw_address_safety: case lltok::kw_minsize:
case lltok::kw_alignstack: case lltok::kw_thread_safety:
case lltok::kw_uninitialized_checks:
case lltok::kw_nobuiltin: case lltok::kw_uninitialized_checks:
HaveError |= Error(Lex.getLoc(), "invalid use of function-only attribute");
break;
}
@ -1207,6 +1212,7 @@ bool LLParser::ParseOptionalReturnAttrs(AttrBuilder &B) {
case lltok::kw_minsize: case lltok::kw_alignstack:
case lltok::kw_align: case lltok::kw_noduplicate:
case lltok::kw_thread_safety: case lltok::kw_uninitialized_checks:
case lltok::kw_nobuiltin:
HaveError |= Error(Lex.getLoc(), "invalid use of function-only attribute");
break;
}
@ -2944,6 +2950,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
bool isVarArg;
AttrBuilder FuncAttrs;
std::vector<unsigned> FwdRefAttrGrps;
LocTy NoBuiltinLoc;
std::string Section;
unsigned Alignment;
std::string GC;
@ -2953,7 +2960,8 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
if (ParseArgumentList(ArgList, isVarArg) ||
ParseOptionalToken(lltok::kw_unnamed_addr, UnnamedAddr,
&UnnamedAddrLoc) ||
ParseFnAttributeValuePairs(FuncAttrs, FwdRefAttrGrps, false) ||
ParseFnAttributeValuePairs(FuncAttrs, FwdRefAttrGrps, false,
NoBuiltinLoc) ||
(EatIfPresent(lltok::kw_section) &&
ParseStringConstant(Section)) ||
ParseOptionalAlignment(Alignment) ||
@ -2961,6 +2969,9 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
ParseStringConstant(GC)))
return true;
if (FuncAttrs.contains(Attribute::NoBuiltin))
return Error(NoBuiltinLoc, "'nobuiltin' attribute not valid on function");
// If the alignment was parsed as an attribute, move to the alignment field.
if (FuncAttrs.hasAlignmentAttr()) {
Alignment = FuncAttrs.getAlignment();
@ -3474,6 +3485,7 @@ bool LLParser::ParseInvoke(Instruction *&Inst, PerFunctionState &PFS) {
LocTy CallLoc = Lex.getLoc();
AttrBuilder RetAttrs, FnAttrs;
std::vector<unsigned> FwdRefAttrGrps;
LocTy NoBuiltinLoc;
CallingConv::ID CC;
Type *RetType = 0;
LocTy RetTypeLoc;
@ -3486,7 +3498,8 @@ bool LLParser::ParseInvoke(Instruction *&Inst, PerFunctionState &PFS) {
ParseType(RetType, RetTypeLoc, true /*void allowed*/) ||
ParseValID(CalleeID) ||
ParseParameterList(ArgList, PFS) ||
ParseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false) ||
ParseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false,
NoBuiltinLoc) ||
ParseToken(lltok::kw_to, "expected 'to' in invoke") ||
ParseTypeAndBasicBlock(NormalBB, PFS) ||
ParseToken(lltok::kw_unwind, "expected 'unwind' in invoke") ||
@ -3881,6 +3894,7 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS,
bool isTail) {
AttrBuilder RetAttrs, FnAttrs;
std::vector<unsigned> FwdRefAttrGrps;
LocTy NoBuiltinLoc;
CallingConv::ID CC;
Type *RetType = 0;
LocTy RetTypeLoc;
@ -3894,7 +3908,8 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS,
ParseType(RetType, RetTypeLoc, true /*void allowed*/) ||
ParseValID(CalleeID) ||
ParseParameterList(ArgList, PFS) ||
ParseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false))
ParseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false,
NoBuiltinLoc))
return true;
// If RetType is a non-function pointer type, then this is the short syntax

View File

@ -242,7 +242,7 @@ namespace llvm {
bool ParseUnnamedAttrGrp();
bool ParseFnAttributeValuePairs(AttrBuilder &B,
std::vector<unsigned> &FwdRefAttrGrps,
bool inAttrGrp);
bool inAttrGrp, LocTy &NoBuiltinLoc);
// Type Parsing.
bool ParseType(Type *&Result, bool AllowVoid = false);

View File

@ -102,6 +102,7 @@ namespace lltok {
kw_naked,
kw_nest,
kw_noalias,
kw_nobuiltin,
kw_nocapture,
kw_noduplicate,
kw_noimplicitfloat,

View File

@ -171,6 +171,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
return "nest";
if (hasAttribute(Attribute::NoAlias))
return "noalias";
if (hasAttribute(Attribute::NoBuiltin))
return "nobuiltin";
if (hasAttribute(Attribute::NoCapture))
return "nocapture";
if (hasAttribute(Attribute::NoDuplicate))
@ -354,6 +356,8 @@ bool AttributeImpl::operator<(const AttributeImpl &AI) const {
uint64_t AttributeImpl::getAttrMask(Attribute::AttrKind Val) {
// FIXME: Remove this.
switch (Val) {
default:
llvm_unreachable("Unsupported attribute type");
case Attribute::EndAttrKinds:
llvm_unreachable("Synthetic enumerators which should never get here");
@ -391,7 +395,6 @@ uint64_t AttributeImpl::getAttrMask(Attribute::AttrKind Val) {
case Attribute::ThreadSafety: return 1ULL << 36;
case Attribute::UninitializedChecks: return 1ULL << 37;
}
llvm_unreachable("Unsupported attribute type");
}
//===----------------------------------------------------------------------===//
@ -1097,6 +1100,33 @@ bool AttrBuilder::operator==(const AttrBuilder &B) {
return Alignment == B.Alignment && StackAlignment == B.StackAlignment;
}
void AttrBuilder::removeFunctionOnlyAttrs() {
removeAttribute(Attribute::NoReturn)
.removeAttribute(Attribute::NoUnwind)
.removeAttribute(Attribute::ReadNone)
.removeAttribute(Attribute::ReadOnly)
.removeAttribute(Attribute::NoInline)
.removeAttribute(Attribute::AlwaysInline)
.removeAttribute(Attribute::OptimizeForSize)
.removeAttribute(Attribute::StackProtect)
.removeAttribute(Attribute::StackProtectReq)
.removeAttribute(Attribute::StackProtectStrong)
.removeAttribute(Attribute::NoRedZone)
.removeAttribute(Attribute::NoImplicitFloat)
.removeAttribute(Attribute::Naked)
.removeAttribute(Attribute::InlineHint)
.removeAttribute(Attribute::StackAlignment)
.removeAttribute(Attribute::UWTable)
.removeAttribute(Attribute::NonLazyBind)
.removeAttribute(Attribute::ReturnsTwice)
.removeAttribute(Attribute::AddressSafety)
.removeAttribute(Attribute::ThreadSafety)
.removeAttribute(Attribute::UninitializedChecks)
.removeAttribute(Attribute::MinSize)
.removeAttribute(Attribute::NoDuplicate)
.removeAttribute(Attribute::NoBuiltin);
}
AttrBuilder &AttrBuilder::addRawValue(uint64_t Val) {
// FIXME: Remove this in 4.0.
if (!Val) return *this;

View File

@ -653,7 +653,8 @@ void Verifier::VerifyParameterAttrs(AttributeSet Attrs, uint64_t Idx, Type *Ty,
!Attrs.hasAttribute(Idx, Attribute::AddressSafety) &&
!Attrs.hasAttribute(Idx, Attribute::ThreadSafety) &&
!Attrs.hasAttribute(Idx, Attribute::UninitializedChecks) &&
!Attrs.hasAttribute(Idx, Attribute::MinSize),
!Attrs.hasAttribute(Idx, Attribute::MinSize) &&
!Attrs.hasAttribute(Idx, Attribute::NoBuiltin),
"Some attributes in '" + Attrs.getAsString(Idx) +
"' only apply to functions!", V);

View File

@ -165,7 +165,7 @@ bool SimplifyLibCalls::runOnFunction(Function &F) {
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) {
// Ignore non-calls.
CallInst *CI = dyn_cast<CallInst>(I++);
if (!CI) continue;
if (!CI || CI->hasFnAttr(Attribute::NoBuiltin)) continue;
// Ignore indirect calls and calls to non-external functions.
Function *Callee = CI->getCalledFunction();

View File

@ -1889,6 +1889,7 @@ LibCallSimplifier::~LibCallSimplifier() {
}
Value *LibCallSimplifier::optimizeCall(CallInst *CI) {
if (CI->hasFnAttr(Attribute::NoBuiltin)) return 0;
return Impl->optimizeCall(CI);
}