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
======================================
- 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.
- ...
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">,
SourceLocation PragmaLocation);
bool HandlePragmaMSAllocText(StringRef PragmaName,
SourceLocation PragmaLocation);
+ bool HandlePragmaMSOptimize(StringRef PragmaName,
+ SourceLocation PragmaLocation);
/// Handle the annotation token produced for
/// #pragma align...
/// 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;
/// 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,
/// 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.
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") {}
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());
}
.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
}
// #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(
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()) {
}
}
+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.
AddRangeBasedOptnone(NewFD);
AddImplicitMSFunctionNoBuiltinAttr(NewFD);
AddSectionMSAllocText(NewFD);
+ ModifyFnAttributesMSPragmaOptimize(NewFD);
}
// If this is the first declaration of an extern C variable, update
--- /dev/null
+// 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{{.*}}}
#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'}}