diff options
author | Michael Gottesman <mgottesman@apple.com> | 2013-06-27 00:25:01 +0000 |
---|---|---|
committer | Michael Gottesman <mgottesman@apple.com> | 2013-06-27 00:25:01 +0000 |
commit | 2253a2f52f3c46ae75cd05f5885acb987bd1d6b6 (patch) | |
tree | 483f06fa8a9b2981c441c49dde73b45eb724c03d | |
parent | 9367c79e62307421f28ba92174f3792a6360f37b (diff) | |
download | external_llvm-2253a2f52f3c46ae75cd05f5885acb987bd1d6b6.zip external_llvm-2253a2f52f3c46ae75cd05f5885acb987bd1d6b6.tar.gz external_llvm-2253a2f52f3c46ae75cd05f5885acb987bd1d6b6.tar.bz2 |
Added support for the Builtin attribute.
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
-rw-r--r-- | docs/LangRef.rst | 16 | ||||
-rw-r--r-- | include/llvm/IR/Attributes.h | 2 | ||||
-rw-r--r-- | include/llvm/IR/Instructions.h | 33 | ||||
-rw-r--r-- | include/llvm/Support/CallSite.h | 6 | ||||
-rw-r--r-- | lib/Analysis/MemoryBuiltins.cpp | 2 | ||||
-rw-r--r-- | lib/AsmParser/LLLexer.cpp | 1 | ||||
-rw-r--r-- | lib/AsmParser/LLParser.cpp | 25 | ||||
-rw-r--r-- | lib/AsmParser/LLParser.h | 2 | ||||
-rw-r--r-- | lib/AsmParser/LLToken.h | 1 | ||||
-rw-r--r-- | lib/IR/Attributes.cpp | 3 | ||||
-rw-r--r-- | lib/IR/Instructions.cpp | 4 | ||||
-rw-r--r-- | lib/IR/Verifier.cpp | 16 | ||||
-rw-r--r-- | lib/Transforms/Utils/SimplifyLibCalls.cpp | 2 | ||||
-rw-r--r-- | test/Assembler/attribute-builtin.ll | 52 | ||||
-rw-r--r-- | test/Transforms/InstCombine/simplify-libcalls.ll | 12 |
15 files changed, 154 insertions, 23 deletions
diff --git a/docs/LangRef.rst b/docs/LangRef.rst index cd72cc9..b98332b 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -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 @@ -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 diff --git a/include/llvm/IR/Attributes.h b/include/llvm/IR/Attributes.h index 0d14709..0bf59cf 100644 --- a/include/llvm/IR/Attributes.h +++ b/include/llvm/IR/Attributes.h @@ -67,6 +67,8 @@ public: ///< 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 diff --git a/include/llvm/IR/Instructions.h b/include/llvm/IR/Instructions.h index 3a8738f..e05c3a8 100644 --- a/include/llvm/IR/Instructions.h +++ b/include/llvm/IR/Instructions.h @@ -1278,7 +1278,11 @@ public: 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; @@ -1288,6 +1292,13 @@ public: 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() { @@ -1378,6 +1389,9 @@ public: 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) { @@ -3021,7 +3035,11 @@ public: 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; @@ -3031,6 +3049,15 @@ public: 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() { @@ -3137,6 +3164,8 @@ private: 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) { diff --git a/include/llvm/Support/CallSite.h b/include/llvm/Support/CallSite.h index d80d9d8..961c38e 100644 --- a/include/llvm/Support/CallSite.h +++ b/include/llvm/Support/CallSite.h @@ -198,6 +198,12 @@ public: 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()); diff --git a/lib/Analysis/MemoryBuiltins.cpp b/lib/Analysis/MemoryBuiltins.cpp index 1660347..39ec965 100644 --- a/lib/Analysis/MemoryBuiltins.cpp +++ b/lib/Analysis/MemoryBuiltins.cpp @@ -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(); diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp index 82d9975..1b5422e 100644 --- a/lib/AsmParser/LLLexer.cpp +++ b/lib/AsmParser/LLLexer.cpp @@ -563,6 +563,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(attributes); KEYWORD(alwaysinline); + KEYWORD(builtin); KEYWORD(byval); KEYWORD(cold); KEYWORD(inlinehint); diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index b22d251f..9349007 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -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; @@ -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; @@ -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; @@ -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: @@ -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: @@ -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; @@ -2994,7 +2997,7 @@ 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) || @@ -3002,8 +3005,8 @@ 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 (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()) { @@ -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; @@ -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 diff --git a/lib/AsmParser/LLParser.h b/lib/AsmParser/LLParser.h index 1f2879e..594281e 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<unsigned> &FwdRefAttrGrps, - bool inAttrGrp, LocTy &NoBuiltinLoc); + bool inAttrGrp, LocTy &BuiltinLoc); // Type Parsing. bool ParseType(Type *&Result, bool AllowVoid = false); diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h index e889a2b..bbe6de0 100644 --- a/lib/AsmParser/LLToken.h +++ b/lib/AsmParser/LLToken.h @@ -95,6 +95,7 @@ namespace lltok { kw_attributes, kw_alwaysinline, kw_sanitize_address, + kw_builtin, kw_byval, kw_cold, kw_inlinehint, diff --git a/lib/IR/Attributes.cpp b/lib/IR/Attributes.cpp index e48ebb1..2160ea2 100644 --- a/lib/IR/Attributes.cpp +++ b/lib/IR/Attributes.cpp @@ -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)) @@ -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"); } diff --git a/lib/IR/Instructions.cpp b/lib/IR/Instructions.cpp index d58877e..5878f77 100644 --- a/lib/IR/Instructions.cpp +++ b/lib/IR/Instructions.cpp @@ -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()) @@ -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()) diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index 1b1b3b8..7123eaf 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -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) @@ -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: @@ -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); } diff --git a/lib/Transforms/Utils/SimplifyLibCalls.cpp b/lib/Transforms/Utils/SimplifyLibCalls.cpp index 1b5b55d..094c201 100644 --- a/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -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); } diff --git a/test/Assembler/attribute-builtin.ll b/test/Assembler/attribute-builtin.ll new file mode 100644 index 0000000..0b322aa --- /dev/null +++ b/test/Assembler/attribute-builtin.ll @@ -0,0 +1,52 @@ + +; Make sure that llvm-as/llvm-dis properly assembly/disassembly the 'builtin' +; attribute. +; +; rdar://13727199 + +; RUN: llvm-as -disable-verify < %s | \ +; llvm-dis -disable-verify | \ +; llvm-as -disable-verify | \ +; llvm-dis -disable-verify | \ +; FileCheck -check-prefix=ASSEMBLES %s + +; CHECK-ASSEMBLES: declare i8* @foo(i8*) [[NOBUILTIN:#[0-9]+]] +; CHECK-ASSEMBLES: call i8* @foo(i8* %x) [[BUILTIN:#[0-9]+]] +; CHECK-ASSEMBLES: attributes [[NOBUILTIN]] = { nobuiltin } +; CHECK-ASSEMBLES: attributes [[BUILTIN]] = { builtin } + +declare i8* @foo(i8*) #1 +define i8* @bar(i8* %x) { + %y = call i8* @foo(i8* %x) #0 + ret i8* %y +} + +; Make sure that we do not accept the 'builtin' attribute on function +; definitions, function declarations, and on call sites that call functions +; which do not have nobuiltin on them. +; rdar://13727199 + +; RUN: not llvm-as <%s 2>&1 | FileCheck -check-prefix=BAD %s + +; CHECK-BAD: Attribute 'builtin' can only be used in a call to a function with the 'nobuiltin' attribute. +; CHECK-BAD-NEXT: %y = call i8* @lar(i8* %x) #1 +; CHECK-BAD: Attribute 'builtin' can only be applied to a callsite. +; CHECK-BAD-NEXT: i8* (i8*)* @car +; CHECK-BAD: Attribute 'builtin' can only be applied to a callsite. +; CHECK-BAD-NEXT: i8* (i8*)* @mar + +declare i8* @lar(i8*) + +define i8* @har(i8* %x) { + %y = call i8* @lar(i8* %x) #0 + ret i8* %y +} + +define i8* @car(i8* %x) #0 { + ret i8* %x +} + +declare i8* @mar(i8*) #0 + +attributes #0 = { builtin } +attributes #1 = { nobuiltin } diff --git a/test/Transforms/InstCombine/simplify-libcalls.ll b/test/Transforms/InstCombine/simplify-libcalls.ll index 4f3a506..ad29a44 100644 --- a/test/Transforms/InstCombine/simplify-libcalls.ll +++ b/test/Transforms/InstCombine/simplify-libcalls.ll @@ -130,3 +130,15 @@ define i32 @MemCpy() { } declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i32, i1) nounwind + +declare i32 @strcmp(i8*, i8*) #0 + +define void @test9(i8* %x) { +; CHECK: @test9 +; CHECK-NOT: strcmp + %y = call i32 @strcmp(i8* %x, i8* %x) #1 + ret void +} + +attributes #0 = { nobuiltin } +attributes #1 = { builtin } |