From 4ece68258609ddfa5a4b7ceac1427c2626925230 Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Mon, 24 Nov 2014 20:51:42 +0000 Subject: [PATCH] Correctly remove OptimizeForSize from functions marked OptimizeNone. This allows using __attribute__((optnone)) and the -Os/-Oz options. Fixes PR21604. llvm-svn: 222683 --- clang/lib/CodeGen/CodeGenModule.cpp | 25 ++++---- clang/test/CodeGen/attr-optnone.c | 10 +++- clang/test/CodeGenCXX/optnone-def-decl.cpp | 94 ++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 11 deletions(-) create mode 100644 clang/test/CodeGenCXX/optnone-def-decl.cpp diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index b35e81c..497aac5 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -715,10 +715,6 @@ 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()) { - // OptimizeNone implies noinline; we should not be inlining such functions. - B.addAttribute(llvm::Attribute::OptimizeNone); - B.addAttribute(llvm::Attribute::NoInline); } else if (D->hasAttr()) { B.addAttribute(llvm::Attribute::NoDuplicate); } else if (D->hasAttr()) { @@ -738,12 +734,6 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, if (D->hasAttr()) B.addAttribute(llvm::Attribute::MinSize); - if (D->hasAttr()) { - // 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) @@ -772,6 +762,21 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::AttributeSet::get( F->getContext(), llvm::AttributeSet::FunctionIndex, B)); + if (D->hasAttr()) { + // OptimizeNone implies noinline; we should not be inlining such functions. + F->addFnAttr(llvm::Attribute::OptimizeNone); + F->addFnAttr(llvm::Attribute::NoInline); + + // OptimizeNone wins over OptimizeForSize, MinSize, AlwaysInline. + F->removeFnAttr(llvm::Attribute::OptimizeForSize); + F->removeFnAttr(llvm::Attribute::MinSize); + F->removeFnAttr(llvm::Attribute::AlwaysInline); + + // Attribute 'inlinehint' has no effect on 'optnone' functions. + // Explicitly remove it from the set of function attributes. + F->removeFnAttr(llvm::Attribute::InlineHint); + } + if (isa(D) || isa(D)) F->setUnnamedAddr(true); else if (const auto *MD = dyn_cast(D)) diff --git a/clang/test/CodeGen/attr-optnone.c b/clang/test/CodeGen/attr-optnone.c index e7069b1..2a6e0d1 100644 --- a/clang/test/CodeGen/attr-optnone.c +++ b/clang/test/CodeGen/attr-optnone.c @@ -1,10 +1,13 @@ // RUN: %clang_cc1 -emit-llvm < %s > %t // RUN: FileCheck %s --check-prefix=PRESENT < %t // RUN: FileCheck %s --check-prefix=ABSENT < %t +// RUN: %clang_cc1 -emit-llvm -Os < %s > %t +// RUN: FileCheck %s --check-prefix=PRESENT < %t +// RUN: FileCheck %s --check-prefix=OPTSIZE < %t __attribute__((always_inline)) int test2() { return 0; } -// PRESENT-DAG: @test2{{.*}}[[ATTR2:#[0-9]+]] +// OPTSIZE: @test2{{.*}}[[ATTR2:#[0-9]+]] __attribute__((optnone)) __attribute__((minsize)) int test3() { return 0; } @@ -23,3 +26,8 @@ int test4() { return test2(); } // Check that no 'optsize' or 'minsize' attributes appear. // ABSENT-NOT: optsize // ABSENT-NOT: minsize + +// With -Os, check that 'optsize' appears only on test2. +// OPTSIZE-NOT: optsize +// OPTSIZE: attributes [[ATTR2]] = { {{.*}}optsize{{.*}} } +// OPTSIZE-NOT: optsize diff --git a/clang/test/CodeGenCXX/optnone-def-decl.cpp b/clang/test/CodeGenCXX/optnone-def-decl.cpp new file mode 100644 index 0000000..6037201 --- /dev/null +++ b/clang/test/CodeGenCXX/optnone-def-decl.cpp @@ -0,0 +1,94 @@ +// RUN: %clang_cc1 %s -triple %itanium_abi_triple -fms-extensions -emit-llvm -o - | FileCheck %s + +// Test optnone on both function declarations and function definitions. +// Verify also that we don't generate invalid IR functions with +// both alwaysinline and noinline. (optnone implies noinline and wins +// over alwaysinline, in all cases.) + +// Test optnone on extern declaration only. +extern int decl_only(int a) __attribute__((optnone)); + +// This function should be marked 'optnone'. +int decl_only(int a) { + return a + a + a + a; +} + +// CHECK: define i32 @_Z9decl_onlyi(i32 %a) [[OPTNONE:#[0-9]+]] + +// Test optnone on definition but not extern declaration. +extern int def_only(int a); + +__attribute__((optnone)) +int def_only(int a) { + return a + a + a + a; +} + +// Function def_only is a optnone function and therefore it should not be +// inlined inside 'user_of_def_only'. +int user_of_def_only() { + return def_only(5); +} + +// CHECK: define i32 @_Z8def_onlyi(i32 %a) [[OPTNONE]] +// CHECK: define i32 @_Z16user_of_def_onlyv() [[NORMAL:#[0-9]+]] + +// Test optnone on both definition and declaration. +extern int def_and_decl(int a) __attribute__((optnone)); + +__attribute__((optnone)) +int def_and_decl(int a) { + return a + a + a + a; +} + +// CHECK: define i32 @_Z12def_and_decli(i32 %a) [[OPTNONE]] + +// Check that optnone wins over always_inline. + +// Test optnone on definition and always_inline on declaration. +extern int always_inline_function(int a) __attribute__((always_inline)); + +__attribute__((optnone)) +extern int always_inline_function(int a) { + return a + a + a + a; +} +// CHECK: define i32 @_Z22always_inline_functioni(i32 %a) [[OPTNONE]] + +int user_of_always_inline_function() { + return always_inline_function(4); +} + +// CHECK: define i32 @_Z30user_of_always_inline_functionv() [[NORMAL]] + +// Test optnone on declaration and always_inline on definition. +extern int optnone_function(int a) __attribute__((optnone)); + +__attribute__((always_inline)) +int optnone_function(int a) { + return a + a + a + a; +} +// CHECK: define i32 @_Z16optnone_functioni(i32 %a) [[OPTNONE]] + +int user_of_optnone_function() { + return optnone_function(4); +} + +// CHECK: define i32 @_Z24user_of_optnone_functionv() [[NORMAL]] + +// Test the combination of optnone with forceinline (optnone wins). +extern __forceinline int forceinline_optnone_function(int a, int b); + +__attribute__((optnone)) +extern int forceinline_optnone_function(int a, int b) { + return a + b; +} + +int user_of_forceinline_optnone_function() { + return forceinline_optnone_function(4,5); +} + +// CHECK: @_Z36user_of_forceinline_optnone_functionv() [[NORMAL]] +// CHECK: @_Z28forceinline_optnone_functionii(i32 %a, i32 %b) [[OPTNONE]] + +// CHECK: attributes [[OPTNONE]] = { noinline nounwind optnone {{.*}} } +// CHECK: attributes [[NORMAL]] = { nounwind {{.*}} } + -- 2.7.4