[clang] 186bea3 - [MSVC] Add initial support for MSVC pragma optimize
Stephen Long via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 24 08:04:03 PDT 2022
Author: Stephen Long
Date: 2022-06-24T08:03:42-07:00
New Revision: 186bea3750d6b349de0e71044d95e2a42e087b4c
URL: https://github.com/llvm/llvm-project/commit/186bea3750d6b349de0e71044d95e2a42e087b4c
DIFF: https://github.com/llvm/llvm-project/commit/186bea3750d6b349de0e71044d95e2a42e087b4c.diff
LOG: [MSVC] Add initial support for MSVC pragma optimize
MSVC's pragma optimize turns optimizations on or off based on the list
passed. At the moment, we only support an empty optimization list.
i.e. `#pragma optimize("", on | off)`
>From MSVC's docs:
| Parameter | Type of optimization |
|-----------|--------------------------------------------------|
| g | Enable global optimizations. Deprecated |
| s or t | Specify short or fast sequences of machine code |
| y | Generate frame pointers on the program stack |
https://docs.microsoft.com/en-us/cpp/preprocessor/optimize?view=msvc-170
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D125723
Added:
clang/test/CodeGen/pragma-msvc-optimize.c
Modified:
clang/docs/LanguageExtensions.rst
clang/docs/ReleaseNotes.rst
clang/include/clang/Basic/DiagnosticParseKinds.td
clang/include/clang/Parse/Parser.h
clang/include/clang/Sema/Sema.h
clang/lib/Parse/ParsePragma.cpp
clang/lib/Sema/SemaAttr.cpp
clang/lib/Sema/SemaDecl.cpp
clang/test/Preprocessor/pragma_microsoft.c
Removed:
################################################################################
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index a69b798f31ee4..59c9889df9622 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -3813,6 +3813,43 @@ it causes the instantiation of ``twice`` and ``thrice`` with an ``int`` type; of
these two instantiations, ``twice`` will be optimized (because its definition
was outside the region) and ``thrice`` will not be optimized.
+Clang also implements MSVC's range-based pragma,
+``#pragma optimize("[optimization-list]", on | off)``. At the moment, Clang only
+supports an empty optimization list, whereas MSVC supports the arguments, ``s``,
+``g``, ``t``, and ``y``. Currently, the implementation of ``pragma optimize`` behaves
+the same as ``#pragma clang optimize``. All functions
+between ``off`` and ``on`` will be decorated with the ``optnone`` attribute.
+
+.. code-block:: c++
+
+ #pragma optimize("", off)
+ // This function will be decorated with optnone.
+ void f1() {}
+
+ #pragma optimize("", on)
+ // This function will be optimized with whatever was specified on
+ // the commandline.
+ void f2() {}
+
+ // This will warn with Clang's current implementation.
+ #pragma optimize("g", on)
+ void f3() {}
+
+For MSVC, an empty optimization list and ``off`` parameter will turn off
+all optimizations, ``s``, ``g``, ``t``, and ``y``. An empty optimization and
+``on`` parameter will reset the optimizations to the ones specified on the
+commandline.
+
+.. list-table:: Parameters (unsupported by Clang)
+ * - Parameter
+ - Type of optimization
+ * - g
+ - Deprecated
+ * - s or t
+ - Short or fast sequences of machine code
+ * - y
+ - Enable frame pointers
+
Extensions for loop hint optimizations
======================================
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 1b0bd5e52b8fb..c884f745b8fc9 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -336,6 +336,10 @@ New Pragmas in Clang
- Added support for MSVC's ``#pragma alloc_text``. The pragma names the code
section functions are placed in. The pragma only applies to functions with
C linkage.
+- Added support for an empty optimization list for MSVC's ``#pragma optimize``.
+ The pragma takes a list of optimizations to turn on or off which applies to
+ all functions following the pragma. At the moment, only an empty list is
+ supported.
- ...
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index b0abe2aa517e7..352a050ba5cf1 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1169,10 +1169,6 @@ def warn_pragma_pack_malformed : Warning<
def warn_pragma_intrinsic_builtin : Warning<
"%0 is not a recognized builtin%select{|; consider including <intrin.h> to access non-builtin intrinsics}1">,
InGroup<IgnoredPragmaIntrinsic>;
-// - #pragma optimize
-def warn_pragma_optimize : Warning<
- "'#pragma optimize' is not supported">,
- InGroup<IgnoredPragmaOptimize>;
// - #pragma unused
def warn_pragma_unused_expected_var : Warning<
"expected '#pragma unused' argument to be a variable name">,
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 0eb6f7104a55b..76e1c9db5284e 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -728,6 +728,8 @@ class Parser : public CodeCompletionHandler {
SourceLocation PragmaLocation);
bool HandlePragmaMSAllocText(StringRef PragmaName,
SourceLocation PragmaLocation);
+ bool HandlePragmaMSOptimize(StringRef PragmaName,
+ SourceLocation PragmaLocation);
/// Handle the annotation token produced for
/// #pragma align...
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 22ebdfe0bfbb4..587ddac8ad1a6 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -758,6 +758,13 @@ class Sema final {
/// optimizations are currently "on", this is set to an invalid location.
SourceLocation OptimizeOffPragmaLocation;
+ /// The "on" or "off" argument passed by \#pragma optimize, that denotes
+ /// whether the optimizations in the list passed to the pragma should be
+ /// turned off or on. This boolean is true by default because command line
+ /// options are honored when `#pragma optimize("", on)`.
+ /// (i.e. `ModifyFnAttributeMSPragmaOptimze()` does nothing)
+ bool MSPragmaOptimizeIsOn = true;
+
/// Set of no-builtin functions listed by \#pragma function.
llvm::SmallSetVector<StringRef, 4> MSFunctionNoBuiltins;
@@ -10363,6 +10370,9 @@ class Sema final {
/// Called on well formed \#pragma clang optimize.
void ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc);
+ /// #pragma optimize("[optimization-list]", on | off).
+ void ActOnPragmaMSOptimize(SourceLocation Loc, bool IsOn);
+
/// Call on well formed \#pragma function.
void
ActOnPragmaMSFunction(SourceLocation Loc,
@@ -10389,6 +10399,11 @@ class Sema final {
/// attribute to be added (usually because of a pragma).
void AddOptnoneAttributeIfNoConflicts(FunctionDecl *FD, SourceLocation Loc);
+ /// Only called on function definitions; if there is a MSVC #pragma optimize
+ /// in scope, consider changing the function's attributes based on the
+ /// optimization list passed to the pragma.
+ void ModifyFnAttributesMSPragmaOptimize(FunctionDecl *FD);
+
/// Only called on function definitions; if there is a pragma in scope
/// with the effect of a range-based no_builtin, consider marking the function
/// with attribute no_builtin.
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index d69081cbecedc..6ca98876b8fc8 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -255,12 +255,6 @@ struct PragmaMSIntrinsicHandler : public PragmaHandler {
Token &FirstToken) override;
};
-struct PragmaMSOptimizeHandler : public PragmaHandler {
- PragmaMSOptimizeHandler() : PragmaHandler("optimize") {}
- void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
- Token &FirstToken) override;
-};
-
// "\#pragma fenv_access (on)".
struct PragmaMSFenvAccessHandler : public PragmaHandler {
PragmaMSFenvAccessHandler() : PragmaHandler("fenv_access") {}
@@ -449,12 +443,12 @@ void Parser::initializePragmaHandlers() {
PP.AddPragmaHandler(MSFunction.get());
MSAllocText = std::make_unique<PragmaMSPragma>("alloc_text");
PP.AddPragmaHandler(MSAllocText.get());
+ MSOptimize = std::make_unique<PragmaMSPragma>("optimize");
+ PP.AddPragmaHandler(MSOptimize.get());
MSRuntimeChecks = std::make_unique<PragmaMSRuntimeChecksHandler>();
PP.AddPragmaHandler(MSRuntimeChecks.get());
MSIntrinsic = std::make_unique<PragmaMSIntrinsicHandler>();
PP.AddPragmaHandler(MSIntrinsic.get());
- MSOptimize = std::make_unique<PragmaMSOptimizeHandler>();
- PP.AddPragmaHandler(MSOptimize.get());
MSFenvAccess = std::make_unique<PragmaMSFenvAccessHandler>();
PP.AddPragmaHandler(MSFenvAccess.get());
}
@@ -923,7 +917,8 @@ void Parser::HandlePragmaMSPragma() {
.Case("section", &Parser::HandlePragmaMSSection)
.Case("init_seg", &Parser::HandlePragmaMSInitSeg)
.Case("function", &Parser::HandlePragmaMSFunction)
- .Case("alloc_text", &Parser::HandlePragmaMSAllocText);
+ .Case("alloc_text", &Parser::HandlePragmaMSAllocText)
+ .Case("optimize", &Parser::HandlePragmaMSOptimize);
if (!(this->*Handler)(PragmaName, PragmaLocation)) {
// Pragma handling failed, and has been diagnosed. Slurp up the tokens
@@ -3645,57 +3640,64 @@ bool Parser::HandlePragmaMSFunction(StringRef PragmaName,
}
// #pragma optimize("gsty", on|off)
-void PragmaMSOptimizeHandler::HandlePragma(Preprocessor &PP,
- PragmaIntroducer Introducer,
- Token &Tok) {
- SourceLocation StartLoc = Tok.getLocation();
- PP.Lex(Tok);
-
- if (Tok.isNot(tok::l_paren)) {
- PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "optimize";
- return;
- }
- PP.Lex(Tok);
+bool Parser::HandlePragmaMSOptimize(StringRef PragmaName,
+ SourceLocation PragmaLocation) {
+ Token FirstTok = Tok;
+ if (ExpectAndConsume(tok::l_paren, diag::warn_pragma_expected_lparen,
+ PragmaName))
+ return false;
if (Tok.isNot(tok::string_literal)) {
- PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_string) << "optimize";
- return;
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_string) << PragmaName;
+ return false;
}
- // We could syntax check the string but it's probably not worth the effort.
- PP.Lex(Tok);
-
- if (Tok.isNot(tok::comma)) {
- PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_comma) << "optimize";
- return;
+ ExprResult StringResult = ParseStringLiteralExpression();
+ if (StringResult.isInvalid())
+ return false; // Already diagnosed.
+ StringLiteral *OptimizationList = cast<StringLiteral>(StringResult.get());
+ if (OptimizationList->getCharByteWidth() != 1) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string)
+ << PragmaName;
+ return false;
}
- PP.Lex(Tok);
- if (Tok.is(tok::eod) || Tok.is(tok::r_paren)) {
- PP.Diag(Tok.getLocation(), diag::warn_pragma_missing_argument)
- << "optimize" << /*Expected=*/true << "'on' or 'off'";
- return;
+ if (ExpectAndConsume(tok::comma, diag::warn_pragma_expected_comma,
+ PragmaName))
+ return false;
+
+ if (Tok.is(tok::eof) || Tok.is(tok::r_paren)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_missing_argument)
+ << PragmaName << /*Expected=*/true << "'on' or 'off'";
+ return false;
}
IdentifierInfo *II = Tok.getIdentifierInfo();
if (!II || (!II->isStr("on") && !II->isStr("off"))) {
- PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_argument)
- << PP.getSpelling(Tok) << "optimize" << /*Expected=*/true
+ PP.Diag(PragmaLocation, diag::warn_pragma_invalid_argument)
+ << PP.getSpelling(Tok) << PragmaName << /*Expected=*/true
<< "'on' or 'off'";
- return;
+ return false;
}
+ bool IsOn = II->isStr("on");
PP.Lex(Tok);
- if (Tok.isNot(tok::r_paren)) {
- PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) << "optimize";
- return;
- }
- PP.Lex(Tok);
+ if (ExpectAndConsume(tok::r_paren, diag::warn_pragma_expected_rparen,
+ PragmaName))
+ return false;
- if (Tok.isNot(tok::eod)) {
- PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
- << "optimize";
- return;
+ // TODO: Add support for "sgty"
+ if (!OptimizationList->getString().empty()) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_invalid_argument)
+ << OptimizationList->getString() << PragmaName << /*Expected=*/true
+ << "\"\"";
+ return false;
}
- PP.Diag(StartLoc, diag::warn_pragma_optimize);
+
+ if (ExpectAndConsume(tok::eof, diag::warn_pragma_extra_tokens_at_eol,
+ PragmaName))
+ return false;
+
+ Actions.ActOnPragmaMSOptimize(FirstTok.getLocation(), IsOn);
+ return true;
}
void PragmaForceCUDAHostDeviceHandler::HandlePragma(
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 8e6f029726bce..c7e62e5895533 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -1144,6 +1144,15 @@ void Sema::ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc) {
OptimizeOffPragmaLocation = PragmaLoc;
}
+void Sema::ActOnPragmaMSOptimize(SourceLocation Loc, bool IsOn) {
+ if (!CurContext->getRedeclContext()->isFileContext()) {
+ Diag(Loc, diag::err_pragma_expected_file_scope) << "optimize";
+ return;
+ }
+
+ MSPragmaOptimizeIsOn = IsOn;
+}
+
void Sema::ActOnPragmaMSFunction(
SourceLocation Loc, const llvm::SmallVectorImpl<StringRef> &NoBuiltins) {
if (!CurContext->getRedeclContext()->isFileContext()) {
@@ -1177,6 +1186,13 @@ void Sema::AddSectionMSAllocText(FunctionDecl *FD) {
}
}
+void Sema::ModifyFnAttributesMSPragmaOptimize(FunctionDecl *FD) {
+ // Don't modify the function attributes if it's "on". "on" resets the
+ // optimizations to the ones listed on the command line
+ if (!MSPragmaOptimizeIsOn)
+ AddOptnoneAttributeIfNoConflicts(FD, FD->getBeginLoc());
+}
+
void Sema::AddOptnoneAttributeIfNoConflicts(FunctionDecl *FD,
SourceLocation Loc) {
// Don't add a conflicting attribute. No diagnostic is needed.
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index a5870efdfa303..2e0620785b551 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -10197,6 +10197,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
AddRangeBasedOptnone(NewFD);
AddImplicitMSFunctionNoBuiltinAttr(NewFD);
AddSectionMSAllocText(NewFD);
+ ModifyFnAttributesMSPragmaOptimize(NewFD);
}
// If this is the first declaration of an extern C variable, update
diff --git a/clang/test/CodeGen/pragma-msvc-optimize.c b/clang/test/CodeGen/pragma-msvc-optimize.c
new file mode 100644
index 0000000000000..17ba40de0a304
--- /dev/null
+++ b/clang/test/CodeGen/pragma-msvc-optimize.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -O2 -emit-llvm -fms-extensions -o - %s | FileCheck %s
+
+#pragma optimize("", off)
+
+// CHECK: define{{.*}} void @f0(){{.*}} #[[OPTNONE:[0-9]+]]
+void f0() {}
+
+// CHECK: define{{.*}} void @f1(){{.*}} #[[OPTNONE]]
+void f1() {}
+
+#pragma optimize("", on)
+
+// CHECK: define{{.*}} void @f2(){{.*}} #[[NO_OPTNONE:[0-9]+]]
+void f2() {}
+
+// CHECK: define{{.*}} void @f3(){{.*}} #[[NO_OPTNONE]]
+void f3() {}
+
+// CHECK: attributes #[[OPTNONE]] = {{{.*}}optnone{{.*}}}
+// CHECK-NOT: attributes #[[NO_OPTNONE]] = {{{.*}}optnone{{.*}}}
diff --git a/clang/test/Preprocessor/pragma_microsoft.c b/clang/test/Preprocessor/pragma_microsoft.c
index ab60902783573..057f5ea006e86 100644
--- a/clang/test/Preprocessor/pragma_microsoft.c
+++ b/clang/test/Preprocessor/pragma_microsoft.c
@@ -228,7 +228,13 @@ void pragma_function_foo() {
#pragma optimize("g" // expected-warning{{expected ',' in '#pragma optimize'}}
#pragma optimize("g", // expected-warning{{missing argument to '#pragma optimize'; expected 'on' or 'off'}}
#pragma optimize("g",xyz // expected-warning{{unexpected argument 'xyz' to '#pragma optimize'; expected 'on' or 'off'}}
-#pragma optimize("g",on) // expected-warning{{#pragma optimize' is not supported}}
+#pragma optimize("g",on) // expected-warning{{unexpected argument 'g' to '#pragma optimize'; expected ""}}
+#pragma optimize("",on) // no-warning
+#pragma optimize("", on) asdf // expected-warning{{extra tokens at end of '#pragma optimize'}}
+
+void pragma_optimize_foo() {
+#pragma optimize("", on) // expected-error {{'#pragma optimize' can only appear at file scope}}
+}
#pragma execution_character_set // expected-warning {{expected '('}}
#pragma execution_character_set( // expected-warning {{expected 'push' or 'pop'}}
More information about the cfe-commits
mailing list