Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -353,6 +353,9 @@ - When the ``weak`` attribute is applied to a const qualified variable clang no longer tells the backend it is allowed to optimize based on initializer value. +- New function attribute ``optsize`` can be used to perform optimizations designed to reduce + code size as long as they do not significantly impact runtime performance. + Windows Support --------------- Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -2260,6 +2260,12 @@ let Documentation = [OptnoneDocs]; } +def OptSize : InheritableAttr { + let Spellings = [Clang<"optsize">]; + let Subjects = SubjectList<[Function, ObjCMethod]>; + let Documentation = [OptSizeDocs]; +} + def Overloadable : Attr { let Spellings = [Clang<"overloadable">]; let Subjects = SubjectList<[Function], ErrorDiag>; Index: clang/include/clang/Basic/AttrDocs.td =================================================================== --- clang/include/clang/Basic/AttrDocs.td +++ clang/include/clang/Basic/AttrDocs.td @@ -3456,6 +3456,16 @@ }]; } +def OptSizeDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +This function attribute indicates that optimization passes and code generator +passes make choices that keep the function code size low. The compiler also does +optimizations to reduce code size as long as they do not significantly impact +runtime performance. + }]; +} + def LoopHintDocs : Documentation { let Category = DocCatStmt; let Heading = "#pragma clang loop"; Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -3482,6 +3482,7 @@ const AttributeCommonInfo &CI, const IdentifierInfo *Ident); MinSizeAttr *mergeMinSizeAttr(Decl *D, const AttributeCommonInfo &CI); + OptSizeAttr *mergeOptSizeAttr(Decl *D, const AttributeCommonInfo &CI); SwiftNameAttr *mergeSwiftNameAttr(Decl *D, const SwiftNameAttr &SNA, StringRef Name); OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D, Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -1923,6 +1923,7 @@ !CodeGenOpts.DisableO0ImplyOptNone && CodeGenOpts.OptimizationLevel == 0; // We can't add optnone in the following cases, it won't pass the verifier. ShouldAddOptNone &= !D->hasAttr(); + ShouldAddOptNone &= !D->hasAttr(); ShouldAddOptNone &= !D->hasAttr(); // Add optnone, but do so only if the function isn't always_inline. @@ -1998,6 +1999,8 @@ B.addAttribute(llvm::Attribute::Hot); if (D->hasAttr()) B.addAttribute(llvm::Attribute::MinSize); + if (D->hasAttr()) + B.addAttribute(llvm::Attribute::OptimizeForSize); } F->addFnAttrs(B); Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -4792,6 +4792,19 @@ return ::new (Context) MinSizeAttr(Context, CI); } +OptSizeAttr *Sema::mergeOptSizeAttr(Decl *D, const AttributeCommonInfo &CI) { + if (OptimizeNoneAttr *Optnone = D->getAttr()) { + Diag(CI.getLoc(), diag::warn_attribute_ignored) << "'optsize'"; + Diag(Optnone->getLocation(), diag::note_conflicting_attribute); + return nullptr; + } + + if (D->hasAttr()) + return nullptr; + + return ::new (Context) OptSizeAttr(Context, CI); +} + SwiftNameAttr *Sema::mergeSwiftNameAttr(Decl *D, const SwiftNameAttr &SNA, StringRef Name) { if (const auto *PrevSNA = D->getAttr()) { @@ -4836,6 +4849,11 @@ D->addAttr(MinSize); } +static void handleOptSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (OptSizeAttr *OptSize = S.mergeOptSizeAttr(D, AL)) + D->addAttr(OptSize); +} + static void handleOptimizeNoneAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (OptimizeNoneAttr *Optnone = S.mergeOptimizeNoneAttr(D, AL)) D->addAttr(Optnone); @@ -8533,6 +8551,9 @@ case ParsedAttr::AT_OptimizeNone: handleOptimizeNoneAttr(S, D, AL); break; + case ParsedAttr::AT_OptSize: + handleOptSizeAttr(S, D, AL); + break; case ParsedAttr::AT_EnumExtensibility: handleEnumExtensibilityAttr(S, D, AL); break; Index: clang/test/CodeGen/attr-optsize.cpp =================================================================== --- /dev/null +++ clang/test/CodeGen/attr-optsize.cpp @@ -0,0 +1,79 @@ +// RUN: %clang_cc1 -Os -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s -check-prefix=Os +// RUN: %clang_cc1 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER +// RUN: %clang_cc1 -O1 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER +// RUN: %clang_cc1 -O2 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER +// RUN: %clang_cc1 -O3 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER +// Check that we set the optsize attribute on each function +// when Os optimization level is set. + +__attribute__((optsize)) +int test1() { + return 42; +// Os: @{{.*}}test1{{.*}}[[OPTSIZE:#[0-9]+]] +// OTHER: @{{.*}}test1{{.*}}[[MS:#[0-9]+]] +} + +int test2() { + return 42; +// Os: @{{.*}}test2{{.*}}[[OPTSIZE]] +// Os: ret +// OTHER: @{{.*}}test2 +// OTHER-NOT: [[MS]] +// OTHER: ret +} + +int test3() { + return 42; +// Os: @{{.*}}test3{{.*}}[[OPTSIZE]] +// Os: ret +// OTHER: @{{.*}}test3 +// OTHER-NOT: [[MS]] +// OTHER: ret +} + +// Check that the optsize attribute is well propagated through +// template instantiation + +template +__attribute__((optsize)) +void test4(T arg) { + return; +} + +template +void test4(int arg); +// Os: define{{.*}}void @{{.*}}test4 +// Os: [[OPTSIZE]] +// OTHER: define{{.*}}void @{{.*}}test4 +// OTHER: [[MS]] + +template +void test4(float arg); +// Os: define{{.*}}void @{{.*}}test4 +// Os: [[OPTSIZE]] +// OTHER: define{{.*}}void @{{.*}}test4 +// OTHER: [[MS]] + +template +void test5(T arg) { + return; +} + +template +void test5(int arg); +// Os: define{{.*}}void @{{.*}}test5 +// Os: [[OPTSIZE]] +// OTHER: define{{.*}}void @{{.*}}test5 +// OTHER-NOT: define{{.*}}void @{{.*}}test5{{.*}}[[MS]] + +template +void test5(float arg); +// Os: define{{.*}}void @{{.*}}test5 +// Os: [[OPTSIZE]] +// OTHER: define{{.*}}void @{{.*}}test5 +// OTHER-NOT: define{{.*}}void @{{.*}}test5{{.*}}[[MS]] + +// Os: attributes [[OPTSIZE]] = { {{.*}} optsize {{.*}} } + +// OTHER: attributes [[MS]] = { {{.*}} optsize {{.*}} } + Index: clang/test/CodeGenObjC/attr-optsize.m =================================================================== --- /dev/null +++ clang/test/CodeGenObjC/attr-optsize.m @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +@interface Test +- (void)test; +@end + +@implementation Test +- (void)test __attribute__((optsize)) { + // CHECK: define{{.*}}Test test + // CHECK: optsize +} +@end Index: clang/test/Sema/attr-optsize.c =================================================================== --- /dev/null +++ clang/test/Sema/attr-optsize.c @@ -0,0 +1,5 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +int foo(void) __attribute__((__optsize__)); + +int var1 __attribute__((__optsize__)); // expected-warning{{'__optsize__' attribute only applies to functions and Objective-C methods}}