forked from OSchip/llvm-project
[CodeGen][mips] Support `long_call/far/near` attributes
This patch adds support for the `long_call`, `far`, and `near` attributes for MIPS targets. The `long_call` and `far` attributes are synonyms. All these attributes override `-mlong-calls` / `-mno-long-calls` command line options for particular function. Differential revision: https://reviews.llvm.org/D35479 llvm-svn: 308667
This commit is contained in:
parent
39aa5dbbf5
commit
1a116db120
|
@ -1188,6 +1188,18 @@ def MicroMips : InheritableAttr, TargetSpecificAttr<TargetMips> {
|
|||
let Documentation = [MicroMipsDocs];
|
||||
}
|
||||
|
||||
def MipsLongCall : InheritableAttr, TargetSpecificAttr<TargetMips> {
|
||||
let Spellings = [GCC<"long_call">, GCC<"far">];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let Documentation = [MipsCallStyleDocs];
|
||||
}
|
||||
|
||||
def MipsShortCall : InheritableAttr, TargetSpecificAttr<TargetMips> {
|
||||
let Spellings = [GCC<"near">];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let Documentation = [MipsCallStyleDocs];
|
||||
}
|
||||
|
||||
def Mode : Attr {
|
||||
let Spellings = [GCC<"mode">];
|
||||
let Subjects = SubjectList<[Var, Enum, TypedefName, Field], ErrorDiag,
|
||||
|
|
|
@ -1323,6 +1323,26 @@ on the command line.
|
|||
}];
|
||||
}
|
||||
|
||||
def MipsCallStyleDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
Clang supports the ``__attribute__((long_call))``, ``__attribute__((far))``,
|
||||
and ``__attribute__((near))`` attributes on MIPS targets. These attributes may
|
||||
only be added to function declarations and change the code generated
|
||||
by the compiler when directly calling the function. The ``near`` attribute
|
||||
allows calls to the function to be made using the ``jal`` instruction, which
|
||||
requires the function to be located in the same naturally aligned 256MB
|
||||
segment as the caller. The ``long_call`` and ``far`` attributes are synonyms
|
||||
and require the use of a different call sequence that works regardless
|
||||
of the distance between the functions.
|
||||
|
||||
These attributes have no effect for position-independent code.
|
||||
|
||||
These attributes take priority over command line switches such
|
||||
as ``-mlong-calls`` and ``-mno-long-calls``.
|
||||
}];
|
||||
}
|
||||
|
||||
def AVRInterruptDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
|
|
|
@ -1080,7 +1080,7 @@ void CodeGenModule::setNonAliasAttributes(const Decl *D,
|
|||
GO->setSection(SA->getName());
|
||||
}
|
||||
|
||||
getTargetCodeGenInfo().setTargetAttributes(D, GO, *this);
|
||||
getTargetCodeGenInfo().setTargetAttributes(D, GO, *this, ForDefinition);
|
||||
}
|
||||
|
||||
void CodeGenModule::SetInternalFunctionAttributes(const Decl *D,
|
||||
|
@ -1147,7 +1147,9 @@ void CodeGenModule::CreateFunctionTypeMetadata(const FunctionDecl *FD,
|
|||
|
||||
void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
|
||||
bool IsIncompleteFunction,
|
||||
bool IsThunk) {
|
||||
bool IsThunk,
|
||||
ForDefinition_t IsForDefinition) {
|
||||
|
||||
if (llvm::Intrinsic::ID IID = F->getIntrinsicID()) {
|
||||
// If this is an intrinsic function, set the function's attributes
|
||||
// to the intrinsic's attributes.
|
||||
|
@ -1157,8 +1159,13 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
|
|||
|
||||
const auto *FD = cast<FunctionDecl>(GD.getDecl());
|
||||
|
||||
if (!IsIncompleteFunction)
|
||||
if (!IsIncompleteFunction) {
|
||||
SetLLVMFunctionAttributes(FD, getTypes().arrangeGlobalDeclaration(GD), F);
|
||||
// Setup target-specific attributes.
|
||||
if (!IsForDefinition)
|
||||
getTargetCodeGenInfo().setTargetAttributes(FD, F, *this,
|
||||
NotForDefinition);
|
||||
}
|
||||
|
||||
// Add the Returned attribute for "this", except for iOS 5 and earlier
|
||||
// where substantial code, including the libstdc++ dylib, was compiled with
|
||||
|
@ -2123,7 +2130,8 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
|
|||
|
||||
assert(F->getName() == MangledName && "name was uniqued!");
|
||||
if (D)
|
||||
SetFunctionAttributes(GD, F, IsIncompleteFunction, IsThunk);
|
||||
SetFunctionAttributes(GD, F, IsIncompleteFunction, IsThunk,
|
||||
IsForDefinition);
|
||||
if (ExtraAttrs.hasAttributes(llvm::AttributeList::FunctionIndex)) {
|
||||
llvm::AttrBuilder B(ExtraAttrs, llvm::AttributeList::FunctionIndex);
|
||||
F->addAttributes(llvm::AttributeList::FunctionIndex, B);
|
||||
|
|
|
@ -1239,7 +1239,8 @@ private:
|
|||
|
||||
/// Set function attributes for a function declaration.
|
||||
void SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
|
||||
bool IsIncompleteFunction, bool IsThunk);
|
||||
bool IsIncompleteFunction, bool IsThunk,
|
||||
ForDefinition_t IsForDefinition);
|
||||
|
||||
void EmitGlobalDefinition(GlobalDecl D, llvm::GlobalValue *GV = nullptr);
|
||||
|
||||
|
|
|
@ -1037,7 +1037,8 @@ public:
|
|||
const llvm::Triple &Triple, const CodeGenOptions &Opts);
|
||||
|
||||
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &CGM) const override;
|
||||
CodeGen::CodeGenModule &CGM,
|
||||
ForDefinition_t IsForDefinition) const override;
|
||||
|
||||
int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override {
|
||||
// Darwin uses different dwarf register numbers for EH.
|
||||
|
@ -1904,9 +1905,11 @@ bool X86_32TargetCodeGenInfo::isStructReturnInRegABI(
|
|||
}
|
||||
}
|
||||
|
||||
void X86_32TargetCodeGenInfo::setTargetAttributes(const Decl *D,
|
||||
llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &CGM) const {
|
||||
void X86_32TargetCodeGenInfo::setTargetAttributes(
|
||||
const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM,
|
||||
ForDefinition_t IsForDefinition) const {
|
||||
if (!IsForDefinition)
|
||||
return;
|
||||
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
|
||||
if (FD->hasAttr<X86ForceAlignArgPointerAttr>()) {
|
||||
// Get the LLVM function.
|
||||
|
@ -2266,7 +2269,10 @@ public:
|
|||
}
|
||||
|
||||
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &CGM) const override {
|
||||
CodeGen::CodeGenModule &CGM,
|
||||
ForDefinition_t IsForDefinition) const override {
|
||||
if (!IsForDefinition)
|
||||
return;
|
||||
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
|
||||
if (FD->hasAttr<AnyX86InterruptAttr>()) {
|
||||
llvm::Function *Fn = cast<llvm::Function>(GV);
|
||||
|
@ -2314,7 +2320,8 @@ public:
|
|||
Win32StructABI, NumRegisterParameters, false) {}
|
||||
|
||||
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &CGM) const override;
|
||||
CodeGen::CodeGenModule &CGM,
|
||||
ForDefinition_t IsForDefinition) const override;
|
||||
|
||||
void getDependentLibraryOption(llvm::StringRef Lib,
|
||||
llvm::SmallString<24> &Opt) const override {
|
||||
|
@ -2342,11 +2349,12 @@ static void addStackProbeSizeTargetAttribute(const Decl *D,
|
|||
}
|
||||
}
|
||||
|
||||
void WinX86_32TargetCodeGenInfo::setTargetAttributes(const Decl *D,
|
||||
llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &CGM) const {
|
||||
X86_32TargetCodeGenInfo::setTargetAttributes(D, GV, CGM);
|
||||
|
||||
void WinX86_32TargetCodeGenInfo::setTargetAttributes(
|
||||
const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM,
|
||||
ForDefinition_t IsForDefinition) const {
|
||||
X86_32TargetCodeGenInfo::setTargetAttributes(D, GV, CGM, IsForDefinition);
|
||||
if (!IsForDefinition)
|
||||
return;
|
||||
addStackProbeSizeTargetAttribute(D, GV, CGM);
|
||||
}
|
||||
|
||||
|
@ -2357,7 +2365,8 @@ public:
|
|||
: TargetCodeGenInfo(new WinX86_64ABIInfo(CGT)) {}
|
||||
|
||||
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &CGM) const override;
|
||||
CodeGen::CodeGenModule &CGM,
|
||||
ForDefinition_t IsForDefinition) const override;
|
||||
|
||||
int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override {
|
||||
return 7;
|
||||
|
@ -2386,11 +2395,12 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
void WinX86_64TargetCodeGenInfo::setTargetAttributes(const Decl *D,
|
||||
llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &CGM) const {
|
||||
TargetCodeGenInfo::setTargetAttributes(D, GV, CGM);
|
||||
|
||||
void WinX86_64TargetCodeGenInfo::setTargetAttributes(
|
||||
const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM,
|
||||
ForDefinition_t IsForDefinition) const {
|
||||
TargetCodeGenInfo::setTargetAttributes(D, GV, CGM, IsForDefinition);
|
||||
if (!IsForDefinition)
|
||||
return;
|
||||
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
|
||||
if (FD->hasAttr<AnyX86InterruptAttr>()) {
|
||||
llvm::Function *Fn = cast<llvm::Function>(GV);
|
||||
|
@ -5475,7 +5485,10 @@ public:
|
|||
}
|
||||
|
||||
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &CGM) const override {
|
||||
CodeGen::CodeGenModule &CGM,
|
||||
ForDefinition_t IsForDefinition) const override {
|
||||
if (!IsForDefinition)
|
||||
return;
|
||||
const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
|
||||
if (!FD)
|
||||
return;
|
||||
|
@ -5517,7 +5530,8 @@ public:
|
|||
: ARMTargetCodeGenInfo(CGT, K) {}
|
||||
|
||||
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &CGM) const override;
|
||||
CodeGen::CodeGenModule &CGM,
|
||||
ForDefinition_t IsForDefinition) const override;
|
||||
|
||||
void getDependentLibraryOption(llvm::StringRef Lib,
|
||||
llvm::SmallString<24> &Opt) const override {
|
||||
|
@ -5531,8 +5545,11 @@ public:
|
|||
};
|
||||
|
||||
void WindowsARMTargetCodeGenInfo::setTargetAttributes(
|
||||
const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const {
|
||||
ARMTargetCodeGenInfo::setTargetAttributes(D, GV, CGM);
|
||||
const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM,
|
||||
ForDefinition_t IsForDefinition) const {
|
||||
ARMTargetCodeGenInfo::setTargetAttributes(D, GV, CGM, IsForDefinition);
|
||||
if (!IsForDefinition)
|
||||
return;
|
||||
addStackProbeSizeTargetAttribute(D, GV, CGM);
|
||||
}
|
||||
}
|
||||
|
@ -6061,7 +6078,9 @@ public:
|
|||
: TargetCodeGenInfo(new NVPTXABIInfo(CGT)) {}
|
||||
|
||||
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &M) const override;
|
||||
CodeGen::CodeGenModule &M,
|
||||
ForDefinition_t IsForDefinition) const override;
|
||||
|
||||
private:
|
||||
// Adds a NamedMDNode with F, Name, and Operand as operands, and adds the
|
||||
// resulting MDNode to the nvvm.annotations MDNode.
|
||||
|
@ -6115,9 +6134,11 @@ Address NVPTXABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
|
|||
llvm_unreachable("NVPTX does not support varargs");
|
||||
}
|
||||
|
||||
void NVPTXTargetCodeGenInfo::
|
||||
setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &M) const{
|
||||
void NVPTXTargetCodeGenInfo::setTargetAttributes(
|
||||
const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M,
|
||||
ForDefinition_t IsForDefinition) const {
|
||||
if (!IsForDefinition)
|
||||
return;
|
||||
const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
|
||||
if (!FD) return;
|
||||
|
||||
|
@ -6553,14 +6574,17 @@ public:
|
|||
MSP430TargetCodeGenInfo(CodeGenTypes &CGT)
|
||||
: TargetCodeGenInfo(new DefaultABIInfo(CGT)) {}
|
||||
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &M) const override;
|
||||
CodeGen::CodeGenModule &M,
|
||||
ForDefinition_t IsForDefinition) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void MSP430TargetCodeGenInfo::setTargetAttributes(const Decl *D,
|
||||
llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &M) const {
|
||||
void MSP430TargetCodeGenInfo::setTargetAttributes(
|
||||
const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M,
|
||||
ForDefinition_t IsForDefinition) const {
|
||||
if (!IsForDefinition)
|
||||
return;
|
||||
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
|
||||
if (const MSP430InterruptAttr *attr = FD->getAttr<MSP430InterruptAttr>()) {
|
||||
// Handle 'interrupt' attribute:
|
||||
|
@ -6619,10 +6643,21 @@ public:
|
|||
}
|
||||
|
||||
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &CGM) const override {
|
||||
CodeGen::CodeGenModule &CGM,
|
||||
ForDefinition_t IsForDefinition) const override {
|
||||
const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
|
||||
if (!FD) return;
|
||||
llvm::Function *Fn = cast<llvm::Function>(GV);
|
||||
|
||||
if (FD->hasAttr<MipsLongCallAttr>())
|
||||
Fn->addFnAttr("long-call");
|
||||
else if (FD->hasAttr<MipsShortCallAttr>())
|
||||
Fn->addFnAttr("short-call");
|
||||
|
||||
// Other attributes do not have a meaning for declarations.
|
||||
if (!IsForDefinition)
|
||||
return;
|
||||
|
||||
if (FD->hasAttr<Mips16Attr>()) {
|
||||
Fn->addFnAttr("mips16");
|
||||
}
|
||||
|
@ -6992,7 +7027,10 @@ public:
|
|||
: TargetCodeGenInfo(new DefaultABIInfo(CGT)) { }
|
||||
|
||||
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &CGM) const override {
|
||||
CodeGen::CodeGenModule &CGM,
|
||||
ForDefinition_t IsForDefinition) const override {
|
||||
if (!IsForDefinition)
|
||||
return;
|
||||
const auto *FD = dyn_cast_or_null<FunctionDecl>(D);
|
||||
if (!FD) return;
|
||||
auto *Fn = cast<llvm::Function>(GV);
|
||||
|
@ -7020,11 +7058,15 @@ public:
|
|||
: DefaultTargetCodeGenInfo(CGT) {}
|
||||
|
||||
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &M) const override;
|
||||
CodeGen::CodeGenModule &M,
|
||||
ForDefinition_t IsForDefinition) const override;
|
||||
};
|
||||
|
||||
void TCETargetCodeGenInfo::setTargetAttributes(
|
||||
const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const {
|
||||
const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M,
|
||||
ForDefinition_t IsForDefinition) const {
|
||||
if (!IsForDefinition)
|
||||
return;
|
||||
const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
|
||||
if (!FD) return;
|
||||
|
||||
|
@ -7364,7 +7406,8 @@ public:
|
|||
AMDGPUTargetCodeGenInfo(CodeGenTypes &CGT)
|
||||
: TargetCodeGenInfo(new AMDGPUABIInfo(CGT)) {}
|
||||
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &M) const override;
|
||||
CodeGen::CodeGenModule &M,
|
||||
ForDefinition_t IsForDefinition) const override;
|
||||
unsigned getOpenCLKernelCallingConv() const override;
|
||||
|
||||
llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM,
|
||||
|
@ -7380,9 +7423,10 @@ public:
|
|||
}
|
||||
|
||||
void AMDGPUTargetCodeGenInfo::setTargetAttributes(
|
||||
const Decl *D,
|
||||
llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &M) const {
|
||||
const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M,
|
||||
ForDefinition_t IsForDefinition) const {
|
||||
if (!IsForDefinition)
|
||||
return;
|
||||
const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
|
||||
if (!FD)
|
||||
return;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#ifndef LLVM_CLANG_LIB_CODEGEN_TARGETINFO_H
|
||||
#define LLVM_CLANG_LIB_CODEGEN_TARGETINFO_H
|
||||
|
||||
#include "CodeGenModule.h"
|
||||
#include "CGValue.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
|
@ -34,7 +35,6 @@ class Decl;
|
|||
namespace CodeGen {
|
||||
class ABIInfo;
|
||||
class CallArgList;
|
||||
class CodeGenModule;
|
||||
class CodeGenFunction;
|
||||
class CGFunctionInfo;
|
||||
|
||||
|
@ -55,7 +55,8 @@ public:
|
|||
/// setTargetAttributes - Provides a convenient hook to handle extra
|
||||
/// target-specific attributes for the given global.
|
||||
virtual void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &M) const {}
|
||||
CodeGen::CodeGenModule &M,
|
||||
ForDefinition_t IsForDefinition) const {}
|
||||
|
||||
/// emitTargetMD - Provides a convenient hook to handle extra
|
||||
/// target-specific metadata for the given global.
|
||||
|
|
|
@ -5986,6 +5986,14 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
|
|||
case AttributeList::AT_NoMicroMips:
|
||||
handleSimpleAttribute<NoMicroMipsAttr>(S, D, Attr);
|
||||
break;
|
||||
case AttributeList::AT_MipsLongCall:
|
||||
handleSimpleAttributeWithExclusions<MipsLongCallAttr, MipsShortCallAttr>(
|
||||
S, D, Attr);
|
||||
break;
|
||||
case AttributeList::AT_MipsShortCall:
|
||||
handleSimpleAttributeWithExclusions<MipsShortCallAttr, MipsLongCallAttr>(
|
||||
S, D, Attr);
|
||||
break;
|
||||
case AttributeList::AT_AMDGPUFlatWorkGroupSize:
|
||||
handleAMDGPUFlatWorkGroupSizeAttr(S, D, Attr);
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
// RUN: %clang_cc1 -triple mips-linux-gnu -emit-llvm -o - %s | FileCheck %s
|
||||
|
||||
void __attribute__((long_call)) foo1 (void);
|
||||
|
||||
void __attribute__((far)) foo2 (void) {}
|
||||
|
||||
// CHECK: define void @foo2() [[FAR:#[0-9]+]]
|
||||
|
||||
void __attribute__((near)) foo3 (void) { foo1(); }
|
||||
|
||||
// CHECK: define void @foo3() [[NEAR:#[0-9]+]]
|
||||
|
||||
// CHECK: declare void @foo1() [[LONGDECL:#[0-9]+]]
|
||||
|
||||
// CHECK: attributes [[FAR]] = { {{.*}} "long-call" {{.*}} }
|
||||
// CHECK: attributes [[NEAR]] = { {{.*}} "short-call" {{.*}} }
|
||||
// CHECK: attributes [[LONGDECL]] = { {{.*}} "long-call" {{.*}} }
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
// The number of supported attributes should never go down!
|
||||
|
||||
// CHECK: #pragma clang attribute supports 62 attributes:
|
||||
// CHECK: #pragma clang attribute supports 64 attributes:
|
||||
// CHECK-NEXT: AMDGPUFlatWorkGroupSize (SubjectMatchRule_function)
|
||||
// CHECK-NEXT: AMDGPUNumSGPR (SubjectMatchRule_function)
|
||||
// CHECK-NEXT: AMDGPUNumVGPR (SubjectMatchRule_function)
|
||||
|
@ -31,6 +31,8 @@
|
|||
// CHECK-NEXT: InternalLinkage (SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_record)
|
||||
// CHECK-NEXT: LTOVisibilityPublic (SubjectMatchRule_record)
|
||||
// CHECK-NEXT: MicroMips (SubjectMatchRule_function)
|
||||
// CHECK-NEXT: MipsLongCall (SubjectMatchRule_function)
|
||||
// CHECK-NEXT: MipsShortCall (SubjectMatchRule_function)
|
||||
// CHECK-NEXT: NoDebug (SubjectMatchRule_hasType_functionType, SubjectMatchRule_objc_method, SubjectMatchRule_variable_not_is_parameter)
|
||||
// CHECK-NEXT: NoDuplicate (SubjectMatchRule_function)
|
||||
// CHECK-NEXT: NoMicroMips (SubjectMatchRule_function)
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
// RUN: %clang_cc1 -triple mips-linux-gnu -fsyntax-only -verify %s
|
||||
|
||||
__attribute__((long_call(0))) void foo1(); // expected-error {{'long_call' attribute takes no arguments}}
|
||||
__attribute__((far(0))) void foo2(); // expected-error {{'far' attribute takes no arguments}}
|
||||
__attribute__((near(0))) void foo3(); // expected-error {{'near' attribute takes no arguments}}
|
||||
|
||||
__attribute((long_call)) int a; // expected-warning {{attribute only applies to functions}}
|
||||
__attribute((far)) int a; // expected-warning {{attribute only applies to functions}}
|
||||
__attribute((near)) int a; // expected-warning {{attribute only applies to functions}}
|
||||
|
||||
__attribute((long_call)) void foo4();
|
||||
__attribute((far)) void foo5();
|
||||
__attribute((near)) void foo6();
|
||||
|
||||
__attribute((long_call, far)) void foo7();
|
||||
|
||||
__attribute((far, near)) void foo8(); // expected-error {{'far' and 'near' attributes are not compatible}} \
|
||||
// expected-note {{conflicting attribute is here}}
|
Loading…
Reference in New Issue