From 143d46476cdcf5b88b9ee18ebd799e5820a2db0e Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 22 Feb 2013 00:12:35 +0000 Subject: [PATCH] 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 --- docs/LangRef.rst | 5 +++++ include/llvm/IR/Attributes.h | 27 ++----------------------- lib/AsmParser/LLLexer.cpp | 1 + lib/AsmParser/LLParser.cpp | 27 +++++++++++++++++++------ lib/AsmParser/LLParser.h | 2 +- lib/AsmParser/LLToken.h | 1 + lib/IR/Attributes.cpp | 32 +++++++++++++++++++++++++++++- lib/IR/Verifier.cpp | 3 ++- lib/Transforms/Scalar/SimplifyLibCalls.cpp | 2 +- lib/Transforms/Utils/SimplifyLibCalls.cpp | 1 + 10 files changed, 66 insertions(+), 35 deletions(-) diff --git a/docs/LangRef.rst b/docs/LangRef.rst index cf9a8c0aed8..c86309029eb 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -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 `. 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: diff --git a/include/llvm/IR/Attributes.h b/include/llvm/IR/Attributes.h index 380bc6a3e05..f207ad6f751 100644 --- a/include/llvm/IR/Attributes.h +++ b/include/llvm/IR/Attributes.h @@ -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) { diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp index 35108af24a0..2b14559f3e5 100644 --- a/lib/AsmParser/LLLexer.cpp +++ b/lib/AsmParser/LLLexer.cpp @@ -571,6 +571,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(naked); KEYWORD(nest); KEYWORD(noalias); + KEYWORD(nobuiltin); KEYWORD(nocapture); KEYWORD(noduplicate); KEYWORD(noimplicitfloat); diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index 86e2fd980e9..bde18cd9fcc 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -810,11 +810,13 @@ bool LLParser::ParseUnnamedAttrGrp() { assert(Lex.getKind() == lltok::AttrGrpID); unsigned VarID = Lex.getUIntVal(); std::vector 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() { /// ::= | '=' bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B, std::vector &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 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 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 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 diff --git a/lib/AsmParser/LLParser.h b/lib/AsmParser/LLParser.h index 42cdbd51227..1f2879e948d 100644 --- a/lib/AsmParser/LLParser.h +++ b/lib/AsmParser/LLParser.h @@ -242,7 +242,7 @@ namespace llvm { bool ParseUnnamedAttrGrp(); bool ParseFnAttributeValuePairs(AttrBuilder &B, std::vector &FwdRefAttrGrps, - bool inAttrGrp); + bool inAttrGrp, LocTy &NoBuiltinLoc); // Type Parsing. bool ParseType(Type *&Result, bool AllowVoid = false); diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h index 97429b8ce5d..a51dadacf06 100644 --- a/lib/AsmParser/LLToken.h +++ b/lib/AsmParser/LLToken.h @@ -102,6 +102,7 @@ namespace lltok { kw_naked, kw_nest, kw_noalias, + kw_nobuiltin, kw_nocapture, kw_noduplicate, kw_noimplicitfloat, diff --git a/lib/IR/Attributes.cpp b/lib/IR/Attributes.cpp index d89ebc503a3..96b17c31e52 100644 --- a/lib/IR/Attributes.cpp +++ b/lib/IR/Attributes.cpp @@ -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; diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index 02c209660bf..33e8ec651dd 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -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); diff --git a/lib/Transforms/Scalar/SimplifyLibCalls.cpp b/lib/Transforms/Scalar/SimplifyLibCalls.cpp index d5cefa35a0c..916b37d4a8b 100644 --- a/lib/Transforms/Scalar/SimplifyLibCalls.cpp +++ b/lib/Transforms/Scalar/SimplifyLibCalls.cpp @@ -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(I++); - if (!CI) continue; + if (!CI || CI->hasFnAttr(Attribute::NoBuiltin)) continue; // Ignore indirect calls and calls to non-external functions. Function *Callee = CI->getCalledFunction(); diff --git a/lib/Transforms/Utils/SimplifyLibCalls.cpp b/lib/Transforms/Utils/SimplifyLibCalls.cpp index cccf0a67a64..8ad566c893c 100644 --- a/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -1889,6 +1889,7 @@ LibCallSimplifier::~LibCallSimplifier() { } Value *LibCallSimplifier::optimizeCall(CallInst *CI) { + if (CI->hasFnAttr(Attribute::NoBuiltin)) return 0; return Impl->optimizeCall(CI); } -- 2.11.0