Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -456,6 +456,18 @@ let Documentation = [ARMInterruptDocs]; } +def ARMLongCall : InheritableAttr, TargetSpecificAttr { + let Spellings = [GNU<"long_call">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [ARMLongCallDocs]; +} + +def ARMShortCall : InheritableAttr, TargetSpecificAttr { + let Spellings = [GNU<"short_call">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [ARMLongCallDocs]; +} + def AsmLabel : InheritableAttr { let Spellings = [Keyword<"asm">, Keyword<"__asm__">]; let Args = [StringArgument<"Label">]; Index: include/clang/Basic/AttrDocs.td =================================================================== --- include/clang/Basic/AttrDocs.td +++ include/clang/Basic/AttrDocs.td @@ -908,6 +908,15 @@ }]; } +def ARMLongCallDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Clang supports the GNU style long-call/short-call attribute on ARM targets. +These attributes overrides the command line options of -mlong-calls/-mno-long-calls +for individual functions. + }]; +} + def MipsInterruptDocs : Documentation { let Category = DocCatFunction; let Content = [{ Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -1596,6 +1596,18 @@ FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); } +static bool hasExtraTargetAttr(const FunctionDecl *FD) { + return FD->hasAttr() || FD->hasAttr(); +} + +static void addExtraTargetAttr(const FunctionDecl *FD, + std::vector &FS) { + if (FD->hasAttr()) + FS.push_back("+long-calls"); + if (FD->hasAttr()) + FS.push_back("-long-calls"); +} + void CodeGenModule::ConstructAttributeList( StringRef Name, const CGFunctionInfo &FI, CGCalleeInfo CalleeInfo, AttributeListType &PAL, unsigned &CallingConv, bool AttrOnCallSite) { @@ -1720,7 +1732,7 @@ // parse that and add it to the feature set. StringRef TargetCPU = getTarget().getTargetOpts().CPU; const FunctionDecl *FD = dyn_cast_or_null(TargetDecl); - if (FD && FD->hasAttr()) { + if (FD && (FD->hasAttr() || hasExtraTargetAttr(FD))) { llvm::StringMap FeatureMap; getFunctionFeatureMap(FeatureMap, FD); @@ -1730,15 +1742,17 @@ ie = FeatureMap.end(); it != ie; ++it) Features.push_back((it->second ? "+" : "-") + it->first().str()); - + addExtraTargetAttr(FD, Features); // Now add the target-cpu and target-features to the function. // While we populated the feature map above, we still need to // get and parse the target attribute so we can get the cpu for // the function. const auto *TD = FD->getAttr(); - TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse(); - if (ParsedAttr.second != "") - TargetCPU = ParsedAttr.second; + if (TD) { + TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse(); + if (ParsedAttr.second != "") + TargetCPU = ParsedAttr.second; + } if (TargetCPU != "") FuncAttrs.addAttribute("target-cpu", TargetCPU); if (!Features.empty()) { Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -5366,6 +5366,12 @@ case AttributeList::AT_Interrupt: handleInterruptAttr(S, D, Attr); break; + case AttributeList::AT_ARMLongCall: + handleSimpleAttribute(S, D, Attr); + break; + case AttributeList::AT_ARMShortCall: + handleSimpleAttribute(S, D, Attr); + break; case AttributeList::AT_X86ForceAlignArgPointer: handleX86ForceAlignArgPointerAttr(S, D, Attr); break; Index: test/CodeGen/arm-longcall-attr.c =================================================================== --- /dev/null +++ test/CodeGen/arm-longcall-attr.c @@ -0,0 +1,32 @@ +// RUN: %clang -target arm-linux-gnueabi -S -emit-llvm -o - %s | FileCheck %s --check-prefix=NOFLAG --check-prefix=COMMON +// RUN: %clang -target arm-linux-gnueabi -S -emit-llvm -mlong-calls -o - %s | FileCheck %s --check-prefix=FLAG_LONG --check-prefix=COMMON +// RUN: %clang -target arm-linux-gnueabi -S -emit-llvm -mno-long-calls -o - %s | FileCheck %s --check-prefix=FLAG_SHORT --check-prefix=COMMON + +__attribute__((long_call)) extern void foo_long(); + +__attribute__((short_call)) extern void foo_short(); + +extern void foo_default(); + +void bar() { + foo_default(); + foo_long(); + foo_short(); +} +// COMMON: define void @bar() [[CALLER_ATTR:#[0-9]+]] { +// COMMON: declare void @foo_default(...) [[NOFLAG_ATTR:#[0-9]+]] +// COMMON: declare void @foo_long(...) [[LONG_ATTR:#[0-9]+]] +// COMMON: declare void @foo_short(...) [[SHORT_ATTR:#[0-9]+]] + +//NOFLAG-NOT: attributes [[CALLER_ATTR]] = { {{.*}} long-calls +//FLAG_LONG: attributes [[CALLER_ATTR]] = { {{.*}}"target-features"="{{.*}}+long-calls +//FLAG_SHORT-NOT: attributes [[CALLER_ATTR]] = { {{.*}} long-calls + +//NOFLAG-NOT: attributes [[NOFLAG_ATTR]] = { {{.*}} long-calls +//FLAG_LONG: attributes [[NOFLAG_ATTR]] = { {{.*}} "target-features"="{{.*}}+long-calls +//FLAG_SHORT-NOT: attributes [[NOFLAG_ATTR]] = { {{.*}} long-calls + +//COMMON: attributes [[LONG_ATTR]] = { {{.*}} "target-features"={{.*}}+long-calls + +//COMMON: attributes [[SHORT_ATTR]] = { {{.*}} "target-features"={{.*}}-long-calls +