steplong updated this revision to Diff 436443.
steplong added a comment.

- Add llvm::Attribute::MinSize when OptimizeAttr::Oz
- Add test for checking minsize


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D126984/new/

https://reviews.llvm.org/D126984

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/CodeGen/CGCall.cpp
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/lib/CodeGen/CodeGenModule.h
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/CodeGen/attr-optimize.c
  clang/test/Misc/pragma-attribute-supported-attributes-list.test
  clang/test/Sema/attr-optimize.c

Index: clang/test/Sema/attr-optimize.c
===================================================================
--- /dev/null
+++ clang/test/Sema/attr-optimize.c
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s
+
+__attribute__((optimize(a))) // expected-error {{use of undeclared identifier 'a'}}
+void
+f1() {}
+
+int b = 1;
+__attribute__((optimize(b))) // expected-error {{'optimize' attribute requires a string}}
+void
+f2() {}
+
+__attribute__((optimize("O0", "O1"))) // expected-error {{'optimize' attribute takes one argument}}
+void
+f3() {}
+
+__attribute__((optimize("Og"))) // expected-no-error
+void
+f4() {}
+
+__attribute__((optimize("O-1"))) // expected-warning {{invalid optimization level 'O-1' specified; the argument to '-O' should be a non-negative integer, '-Os', '-Oz', '-Og', or '-Ofast'; attribute ignored}}
+void
+f5() {}
+
+__attribute__((optimize("O+1"))) // expected-warning {{invalid optimization level 'O+1' specified; the argument to '-O' should be a non-negative integer, '-Os', '-Oz', '-Og', or '-Ofast'; attribute ignored}}
+void
+f6() {}
+
+__attribute__((optimize("O0"))) // expected-no-error
+void
+f7() {}
+
+__attribute__((optimize("Os"))) // expected-no-error
+void
+f8() {}
+
+__attribute__((optimize("O44"))) // expected-no-error
+void
+f9() {}
+
+__attribute__((optimize("Oz"))) // expected-no-error
+void
+f10() {}
+
+__attribute__((optimize("Ofast"))) // expected-no-error
+void
+f11() {}
+
+__attribute__((optimize("O"))) // expected-no-error
+void
+f12() {}
+
+__attribute__((optimize("O0"))) // expected-error {{expected identifier or '('}}
Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test
===================================================================
--- clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -142,6 +142,7 @@
 // CHECK-NEXT: ObjCSubclassingRestricted (SubjectMatchRule_objc_interface)
 // CHECK-NEXT: OpenCLIntelReqdSubGroupSize (SubjectMatchRule_function)
 // CHECK-NEXT: OpenCLNoSVM (SubjectMatchRule_variable)
+// CHECK-NEXT: Optimize (SubjectMatchRule_function)
 // CHECK-NEXT: OptimizeNone (SubjectMatchRule_function, SubjectMatchRule_objc_method)
 // CHECK-NEXT: Overloadable (SubjectMatchRule_function)
 // CHECK-NEXT: Owner (SubjectMatchRule_record_not_is_union)
Index: clang/test/CodeGen/attr-optimize.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/attr-optimize.c
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -O2 -S -emit-llvm %s -o - | FileCheck %s --check-prefix=O2
+// RUN: %clang_cc1 -O0 -S -emit-llvm %s -o - | FileCheck %s --check-prefix=O0
+
+__attribute__((optimize("O0"))) void f1(void) {}
+// O2: @f1{{.*}}[[ATTR_OPTNONE:#[0-9]+]]
+// O0: @f1{{.*}}[[ATTR_OPTNONE:#[0-9]+]]
+
+__attribute__((optimize("Os"))) void f2(void) {}
+// O2: @f2{{.*}}[[ATTR_OPTSIZE:#[0-9]+]]
+// O0: @f2{{.*}}[[ATTR_OPTNONE]]
+
+__attribute__((optimize("Og"))) void f3(void) {}
+// O2: @f3{{.*}}[[ATTR_OPTSIZE]]
+// O0: @f3{{.*}}[[ATTR_OPTNONE]]
+
+__attribute__((optimize("Oz"))) void f4(void) {}
+// O2: @f4{{.*}}[[ATTR_MINSIZE:#[0-9]+]]
+// O0: @f4{{.*}}[[ATTR_OPTNONE]]
+
+__attribute__((optimize("Ofast"))) void f5(void) {}
+// O2: @f5{{.*}}[[ATTR_OPTSIZE]]
+// O0: @f5{{.*}}[[ATTR_OPTNONE]]
+
+// O2: attributes [[ATTR_OPTNONE]] = { {{.*}}optnone{{.*}} }
+// O2: attributes [[ATTR_OPTSIZE]] = { {{.*}}optsize{{.*}} }
+// O2: attributes [[ATTR_MINSIZE]] = { {{.*}}minsize{{.*}}optsize{{.*}} }
+
+// Check that O0 overrides the attribute
+// O0: attributes [[ATTR_OPTNONE]] = { {{.*}}optnone{{.*}} }
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -4833,6 +4833,46 @@
     D->addAttr(Optnone);
 }
 
+static void handleOptimizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+  StringRef Arg;
+  if (!S.checkStringLiteralArgumentAttr(AL, 0, Arg))
+    return;
+
+  StringRef Level;
+  // Check if argument is prefixed with "-O" or "O"
+  if (Arg.str().rfind("-O", 0) == 0)
+    Level = Arg.substr(2);
+  else if (Arg.str().rfind("O", 0) == 0)
+    Level = Arg.substr(1);
+  else
+    S.Diag(AL.getLoc(), diag::warn_invalid_optimize_attr_level) << Arg;
+
+  llvm::StringMap<OptimizeAttr::OptLevelKind> StrToKind = {
+      {"", OptimizeAttr::O0},  {"s", OptimizeAttr::Os},
+      {"g", OptimizeAttr::Og}, {"fast", OptimizeAttr::Ofast},
+      {"z", OptimizeAttr::Oz}, {"0", OptimizeAttr::O0},
+      {"1", OptimizeAttr::O1}, {"2", OptimizeAttr::O2},
+      {"3", OptimizeAttr::O3}, {"4", OptimizeAttr::O4},
+  };
+
+  auto It = StrToKind.find(Level.str());
+  if (It != StrToKind.end()) {
+    D->addAttr(::new (S.Context) OptimizeAttr(S.Context, AL, Arg, It->second));
+    return;
+  }
+
+  llvm::APInt Num;
+  if (!Level.getAsInteger(10, Num)) {
+    // Limit level to -O4 if higher.
+    std::string Level = std::to_string(Num.getLimitedValue(4));
+    D->addAttr(::new (S.Context)
+                   OptimizeAttr(S.Context, AL, Arg, StrToKind[Level]));
+    return;
+  }
+
+  S.Diag(AL.getLoc(), diag::warn_invalid_optimize_attr_level) << Arg;
+}
+
 static void handleConstantAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   const auto *VD = cast<VarDecl>(D);
   if (VD->hasLocalStorage()) {
@@ -8525,6 +8565,9 @@
   case ParsedAttr::AT_OptimizeNone:
     handleOptimizeNoneAttr(S, D, AL);
     break;
+  case ParsedAttr::AT_Optimize:
+    handleOptimizeAttr(S, D, AL);
+    break;
   case ParsedAttr::AT_EnumExtensibility:
     handleEnumExtensibilityAttr(S, D, AL);
     break;
Index: clang/lib/CodeGen/CodeGenModule.h
===================================================================
--- clang/lib/CodeGen/CodeGenModule.h
+++ clang/lib/CodeGen/CodeGenModule.h
@@ -1654,6 +1654,7 @@
   /// addDefaultFunctionDefinitionAttributes.  Builds a set of function
   /// attributes to add to a function with the given properties.
   void getDefaultFunctionAttributes(StringRef Name, bool HasOptnone,
+                                    bool HasOptsize, bool HasMinsize,
                                     bool AttrOnCallSite,
                                     llvm::AttrBuilder &FuncAttrs);
 
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -1928,8 +1928,13 @@
   ShouldAddOptNone &= !D->hasAttr<MinSizeAttr>();
   ShouldAddOptNone &= !D->hasAttr<AlwaysInlineAttr>();
 
+  bool HasOptimizeAttrO0 = false;
+  if (const auto *OA = D->getAttr<OptimizeAttr>())
+    HasOptimizeAttrO0 = OA->getOptLevel() == OptimizeAttr::O0;
+
   // Add optnone, but do so only if the function isn't always_inline.
-  if ((ShouldAddOptNone || D->hasAttr<OptimizeNoneAttr>()) &&
+  if ((ShouldAddOptNone || D->hasAttr<OptimizeNoneAttr>() ||
+       HasOptimizeAttrO0) &&
       !F->hasFnAttribute(llvm::Attribute::AlwaysInline)) {
     B.addAttribute(llvm::Attribute::OptimizeNone);
 
@@ -1950,7 +1955,8 @@
     B.addAttribute(llvm::Attribute::NoInline);
   } else if (D->hasAttr<NoDuplicateAttr>()) {
     B.addAttribute(llvm::Attribute::NoDuplicate);
-  } else if (D->hasAttr<NoInlineAttr>() && !F->hasFnAttribute(llvm::Attribute::AlwaysInline)) {
+  } else if (D->hasAttr<NoInlineAttr>() &&
+             !F->hasFnAttribute(llvm::Attribute::AlwaysInline)) {
     // Add noinline if the function isn't always_inline.
     B.addAttribute(llvm::Attribute::NoInline);
   } else if (D->hasAttr<AlwaysInlineAttr>() &&
Index: clang/lib/CodeGen/CGCall.cpp
===================================================================
--- clang/lib/CodeGen/CGCall.cpp
+++ clang/lib/CodeGen/CGCall.cpp
@@ -1792,15 +1792,14 @@
   return ReturnType.isTriviallyCopyableType(Context);
 }
 
-void CodeGenModule::getDefaultFunctionAttributes(StringRef Name,
-                                                 bool HasOptnone,
-                                                 bool AttrOnCallSite,
-                                               llvm::AttrBuilder &FuncAttrs) {
+void CodeGenModule::getDefaultFunctionAttributes(
+    StringRef Name, bool HasOptnone, bool HasOptsize, bool HasMinsize,
+    bool AttrOnCallSite, llvm::AttrBuilder &FuncAttrs) {
   // OptimizeNoneAttr takes precedence over -Os or -Oz. No warning needed.
   if (!HasOptnone) {
-    if (CodeGenOpts.OptimizeSize)
+    if (CodeGenOpts.OptimizeSize || HasOptsize)
       FuncAttrs.addAttribute(llvm::Attribute::OptimizeForSize);
-    if (CodeGenOpts.OptimizeSize == 2)
+    if (CodeGenOpts.OptimizeSize == 2 || HasMinsize)
       FuncAttrs.addAttribute(llvm::Attribute::MinSize);
   }
 
@@ -1945,7 +1944,8 @@
 
 void CodeGenModule::addDefaultFunctionDefinitionAttributes(llvm::Function &F) {
   llvm::AttrBuilder FuncAttrs(F.getContext());
-  getDefaultFunctionAttributes(F.getName(), F.hasOptNone(),
+  getDefaultFunctionAttributes(F.getName(), F.hasOptNone(), F.hasOptSize(),
+                               F.hasMinSize(),
                                /* AttrOnCallSite = */ false, FuncAttrs);
   // TODO: call GetCPUAndFeaturesAttributes?
   F.addFnAttrs(FuncAttrs);
@@ -1954,6 +1954,7 @@
 void CodeGenModule::addDefaultFunctionDefinitionAttributes(
                                                    llvm::AttrBuilder &attrs) {
   getDefaultFunctionAttributes(/*function name*/ "", /*optnone*/ false,
+                               /*optsize*/ false, /*minsize*/ false,
                                /*for call*/ false, attrs);
   GetCPUAndFeaturesAttributes(GlobalDecl(), attrs);
 }
@@ -2088,6 +2089,8 @@
   AddAttributesFromAssumes(FuncAttrs, TargetDecl);
 
   bool HasOptnone = false;
+  bool HasOptsize = false;
+  bool HasMinsize = false;
   // The NoBuiltinAttr attached to the target FunctionDecl.
   const NoBuiltinAttr *NBA = nullptr;
 
@@ -2164,6 +2167,13 @@
       FuncAttrs.addAttribute(llvm::Attribute::NoCallback);
 
     HasOptnone = TargetDecl->hasAttr<OptimizeNoneAttr>();
+    if (const auto *OA = TargetDecl->getAttr<OptimizeAttr>()) {
+      OptimizeAttr::OptLevelKind Kind = OA->getOptLevel();
+      HasOptnone = HasOptnone || (Kind == OptimizeAttr::O0);
+      HasOptsize = Kind == OptimizeAttr::Os || Kind == OptimizeAttr::Og ||
+                   Kind == OptimizeAttr::Ofast || Kind == OptimizeAttr::Oz;
+      HasMinsize = Kind == OptimizeAttr::Oz;
+    }
     if (auto *AllocSize = TargetDecl->getAttr<AllocSizeAttr>()) {
       Optional<unsigned> NumElemsParam;
       if (AllocSize->getNumElemsParam().isValid())
@@ -2197,7 +2207,8 @@
   addNoBuiltinAttributes(FuncAttrs, getLangOpts(), NBA);
 
   // Collect function IR attributes based on global settiings.
-  getDefaultFunctionAttributes(Name, HasOptnone, AttrOnCallSite, FuncAttrs);
+  getDefaultFunctionAttributes(Name, HasOptnone, HasOptsize, HasMinsize,
+                               AttrOnCallSite, FuncAttrs);
 
   // Override some default IR attributes based on declaration-specific
   // information.
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3016,6 +3016,10 @@
   "%0 attribute takes no more than %1 argument%s1">;
 def err_attribute_too_few_arguments : Error<
   "%0 attribute takes at least %1 argument%s1">;
+def warn_invalid_optimize_attr_level : Warning <
+   "invalid optimization level '%0' specified; the argument to '-O' should be a non-negative integer, "
+   "'-Os', '-Oz', '-Og', or '-Ofast'; attribute ignored">,
+   InGroup<IgnoredAttributes>;
 def err_attribute_invalid_vector_type : Error<"invalid vector element type %0">;
 def err_attribute_invalid_matrix_type : Error<"invalid matrix element type %0">;
 def err_attribute_bad_neon_vector_size : Error<
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -3456,6 +3456,20 @@
   }];
 }
 
+def OptimizeDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+The ``optimize`` attribute, when attached to a function, indicates that the
+function should be compiled with a different optimization level than specified
+on the command line. See the Function Attributes documentation on GCC's docs for
+more information. Currently, the attribute differs from GCC in that Clang only
+supports one argument, doesn't support ``-f`` arguments, and also doesn't
+support expressions or integers as arguments.
+
+Refer to: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html
+  }];
+}
+
 def LoopHintDocs : Documentation {
   let Category = DocCatStmt;
   let Heading = "#pragma clang loop";
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -2260,6 +2260,17 @@
   let Documentation = [OptnoneDocs];
 }
 
+def Optimize : InheritableAttr {
+  let Spellings = [GCC<"optimize">];
+  let Args = [StringArgument<"Level">,
+              EnumArgument<"OptLevel", "OptLevelKind",
+                           ["Ofast", "Og", "Oz", "Os", "O0", "O1", "O2", "O3", "O4"],
+                           ["Ofast", "Og", "Oz", "Os", "O0", "O1", "O2", "O3", "O4"],
+                           /*optional*/0, /*fake*/1>];
+  let Subjects = SubjectList<[Function]>;
+  let Documentation = [OptimizeDocs];
+}
+
 def Overloadable : Attr {
   let Spellings = [Clang<"overloadable">];
   let Subjects = SubjectList<[Function], ErrorDiag>;
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -328,6 +328,10 @@
   builtins (corresponding to the specific names listed in the attribute) in the
   body of the function the attribute is on.
 
+- Added preliminary support for GCC's attribute ``optimize``, which allows
+  functions to be compiled with different optimization options than what was
+  specified on the command line.
+
 Windows Support
 ---------------
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to