Implement the 'optnone' attribute, which suppresses most optimizations

on a function.

llvm-svn: 205255
This commit is contained in:
Paul Robinson 2014-03-31 22:29:15 +00:00
parent e117992f00
commit f067435026
7 changed files with 129 additions and 1 deletions

View File

@ -975,6 +975,12 @@ def ObjCDesignatedInitializer : Attr {
let Documentation = [Undocumented];
}
def OptimizeNone : InheritableAttr {
let Spellings = [GNU<"optnone">, CXX11<"clang", "optnone">];
let Subjects = SubjectList<[Function, ObjCMethod]>;
let Documentation = [OptnoneDocs];
}
def Overloadable : Attr {
let Spellings = [GNU<"overloadable">];
let Subjects = SubjectList<[Function], ErrorDiag>;

View File

@ -952,3 +952,19 @@ an error:
struct S {};
}];
}
def OptnoneDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
The ``optnone`` attribute suppresses essentially all optimizations
on a function or method, regardless of the optimization level applied to
the compilation unit as a whole. This is particularly useful when you
need to debug a particular function, but it is infeasible to build the
entire application without optimization. Avoiding optimization on the
specified function can improve the quality of the debugging information
for that function.
This attribute is incompatible with the ``always_inline`` attribute.
}];
}

View File

@ -660,6 +660,10 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
// Naked implies noinline: we should not be inlining such functions.
B.addAttribute(llvm::Attribute::Naked);
B.addAttribute(llvm::Attribute::NoInline);
} else if (D->hasAttr<OptimizeNoneAttr>()) {
// OptimizeNone implies noinline; we should not be inlining such functions.
B.addAttribute(llvm::Attribute::OptimizeNone);
B.addAttribute(llvm::Attribute::NoInline);
} else if (D->hasAttr<NoDuplicateAttr>()) {
B.addAttribute(llvm::Attribute::NoDuplicate);
} else if (D->hasAttr<NoInlineAttr>()) {
@ -679,6 +683,12 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
if (D->hasAttr<MinSizeAttr>())
B.addAttribute(llvm::Attribute::MinSize);
if (D->hasAttr<OptimizeNoneAttr>()) {
// OptimizeNone wins over OptimizeForSize and MinSize.
B.removeAttribute(llvm::Attribute::OptimizeForSize);
B.removeAttribute(llvm::Attribute::MinSize);
}
if (LangOpts.getStackProtector() == LangOptions::SSPOn)
B.addAttribute(llvm::Attribute::StackProtect);
else if (LangOpts.getStackProtector() == LangOptions::SSPStrong)

View File

@ -2972,6 +2972,26 @@ static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Attr.getAttributeSpellingListIndex()));
}
static void handleAlwaysInlineAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
if (checkAttrMutualExclusion<OptimizeNoneAttr>(S, D, Attr))
return;
D->addAttr(::new (S.Context)
AlwaysInlineAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
}
static void handleOptimizeNoneAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
if (checkAttrMutualExclusion<AlwaysInlineAttr>(S, D, Attr))
return;
D->addAttr(::new (S.Context)
OptimizeNoneAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
}
static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) {
FunctionDecl *FD = cast<FunctionDecl>(D);
if (!FD->getReturnType()->isVoidType()) {
@ -4042,7 +4062,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleAlignedAttr(S, D, Attr);
break;
case AttributeList::AT_AlwaysInline:
handleSimpleAttribute<AlwaysInlineAttr>(S, D, Attr);
handleAlwaysInlineAttr(S, D, Attr);
break;
case AttributeList::AT_AnalyzerNoReturn:
handleAnalyzerNoReturnAttr(S, D, Attr);
@ -4086,6 +4106,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_MinSize:
handleSimpleAttribute<MinSizeAttr>(S, D, Attr);
break;
case AttributeList::AT_OptimizeNone:
handleOptimizeNoneAttr(S, D, Attr);
break;
case AttributeList::AT_Format:
handleFormatAttr(S, D, Attr);
break;

View File

@ -0,0 +1,25 @@
// RUN: %clang_cc1 -emit-llvm < %s > %t
// RUN: FileCheck %s --check-prefix=PRESENT < %t
// RUN: FileCheck %s --check-prefix=ABSENT < %t
__attribute__((always_inline))
int test2() { return 0; }
// PRESENT-DAG: @test2{{.*}}[[ATTR2:#[0-9]+]]
__attribute__((optnone)) __attribute__((minsize))
int test3() { return 0; }
// PRESENT-DAG: @test3{{.*}}[[ATTR3:#[0-9]+]]
__attribute__((optnone)) __attribute__((cold))
int test4() { return test2(); }
// PRESENT-DAG: @test4{{.*}}[[ATTR4:#[0-9]+]]
// Also check that test2 is inlined into test4 (always_inline still works).
// PRESENT-DAG-NOT: call i32 @test2
// Check for both noinline and optnone on each optnone function.
// PRESENT-DAG: attributes [[ATTR3]] = { {{.*}}noinline{{.*}}optnone{{.*}} }
// PRESENT-DAG: attributes [[ATTR4]] = { {{.*}}noinline{{.*}}optnone{{.*}} }
// Check that no 'optsize' or 'minsize' attributes appear.
// ABSENT-NOT: optsize
// ABSENT-NOT: minsize

View File

@ -0,0 +1,47 @@
// RUN: %clang_cc1 -std=c++11 -fms-compatibility -fsyntax-only -verify %s
int foo() __attribute__((optnone));
int bar() __attribute__((optnone)) __attribute__((noinline));
int baz() __attribute__((always_inline)) __attribute__((optnone)); // expected-error{{'always_inline' and 'optnone' attributes are not compatible}}
int quz() __attribute__((optnone)) __attribute__((always_inline)); // expected-error{{'optnone' and 'always_inline' attributes are not compatible}}
__forceinline __attribute__((optnone)) int bax(); // expected-error{{'__forceinline' and 'optnone' attributes are not compatible}}
__attribute__((optnone)) __forceinline int qux(); // expected-error{{'optnone' and '__forceinline' attributes are not compatible}}
int globalVar __attribute__((optnone)); // expected-warning{{'optnone' attribute only applies to functions}}
int fubar(int __attribute__((optnone)), int); // expected-warning{{'optnone' attribute only applies to functions}}
struct A {
int aField __attribute__((optnone)); // expected-warning{{'optnone' attribute only applies to functions}}
};
struct B {
void foo() __attribute__((optnone));
static void bar() __attribute__((optnone));
};
// Verify that we can specify the [[clang::optnone]] syntax as well.
[[clang::optnone]]
int foo2();
[[clang::optnone]]
int bar2() __attribute__((noinline));
[[clang::optnone]]
int baz2() __attribute__((always_inline)); // expected-error{{'always_inline' and 'optnone' attributes are not compatible}}
[[clang::optnone]] int globalVar2; //expected-warning{{'optnone' attribute only applies to functions}}
struct A2 {
[[clang::optnone]] int aField; // expected-warning{{'optnone' attribute only applies to functions}}
};
struct B2 {
[[clang::optnone]]
void foo();
[[clang::optnone]]
static void bar();
};

View File

@ -8,6 +8,7 @@
-(void) m0 __attribute__((noreturn));
-(void) m1 __attribute__((unused));
-(void) m2 __attribute__((stdcall));
-(void) m3 __attribute__((optnone));
@end