mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-14 16:33:28 +00:00
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
This commit is contained in:
parent
9367c79e62
commit
2253a2f52f
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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());
|
||||
|
@ -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();
|
||||
|
@ -563,6 +563,7 @@ lltok::Kind LLLexer::LexIdentifier() {
|
||||
KEYWORD(attributes);
|
||||
|
||||
KEYWORD(alwaysinline);
|
||||
KEYWORD(builtin);
|
||||
KEYWORD(byval);
|
||||
KEYWORD(cold);
|
||||
KEYWORD(inlinehint);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -95,6 +95,7 @@ namespace lltok {
|
||||
kw_attributes,
|
||||
kw_alwaysinline,
|
||||
kw_sanitize_address,
|
||||
kw_builtin,
|
||||
kw_byval,
|
||||
kw_cold,
|
||||
kw_inlinehint,
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
52
test/Assembler/attribute-builtin.ll
Normal file
52
test/Assembler/attribute-builtin.ll
Normal file
@ -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 }
|
@ -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 }
|
||||
|
Loading…
x
Reference in New Issue
Block a user