[clang] b40a2a5 - [clang] Add support for optional flag -fnew-infallible to restrict exception propagation

via cfe-commits cfe-commits at lists.llvm.org
Mon Aug 2 15:47:32 PDT 2021


Author: modimo
Date: 2021-08-02T15:45:06-07:00
New Revision: b40a2a533a9dfb8dd5afb1f3b7d277da1e19f235

URL: https://github.com/llvm/llvm-project/commit/b40a2a533a9dfb8dd5afb1f3b7d277da1e19f235
DIFF: https://github.com/llvm/llvm-project/commit/b40a2a533a9dfb8dd5afb1f3b7d277da1e19f235.diff

LOG: [clang] Add support for optional flag -fnew-infallible to restrict exception propagation

The declaration for the global new function in C++ is generated in the compiler front-end. When examining exception propagation, we found that this is the largest root throw site propagator requiring unwind code to be generated for callers up the stack. Allowing this to be handled immediately with termination stops upward propagation and leads to significantly less landing pads generated. This in turns leads to a performance and .text size win.

With `-fnew-infallible` this annotates the declaration with `throw()` and `__attribute__((returns_nonnull))`.  `throw()` allows the compiler to assume exceptions do not propagate out of new and eliminate it as a root throw site. Note that the definition of global new is user-replaceable so users should ensure that the one used follows these semantics.

Measuring internally, we're seeing at 0.5% CPU win in one of our large internal FB workload. Measuring on clang self-build (cd0a1226b50081e86eb75a89d01e8782423971a0) we get:

thinlto/

        "dwarfehprepare.NumCleanupLandingPadsRemaining": 153494,
        "dwarfehprepare.NumNoUnwind": 26309,
thinlto_newinfallible/

        "dwarfehprepare.NumCleanupLandingPadsRemaining": 143660,
        "dwarfehprepare.NumNoUnwind": 28744,

a 1-143660/153494 = 6.4% reduction in landing pads and a 28744/26309 = 9.3% increase in the number of nounwind functions.

Testing:
ninja check-all
new test case to make sure these attributes are added correctly to global new.

Reviewed By: urnathan

Differential Revision: https://reviews.llvm.org/D105225

Added: 
    clang/test/CodeGenCXX/new-infallible.cpp

Modified: 
    clang/docs/ClangCommandLineReference.rst
    clang/include/clang/Basic/LangOptions.def
    clang/include/clang/Driver/Options.td
    clang/lib/Driver/ToolChains/Clang.cpp
    clang/lib/Sema/SemaExprCXX.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ClangCommandLineReference.rst b/clang/docs/ClangCommandLineReference.rst
index 41f2dc70c052f..798e85fb58c8e 100644
--- a/clang/docs/ClangCommandLineReference.rst
+++ b/clang/docs/ClangCommandLineReference.rst
@@ -1941,6 +1941,10 @@ Microsoft compiler version number to report in \_MSC\_VER (0 = don't define it (
 
 Specifies the largest alignment guaranteed by '::operator new(size\_t)'
 
+.. option:: -fnew-infallible
+
+Treats throwing global C++ operator new as always returning valid memory (annotates with \_\_attribute\_\_((returns\_nonnull)) and throw()). This is detectable in source.
+
 .. option:: -fnext-runtime
 
 .. option:: -fno-builtin-<arg>

diff  --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 61a4dbdf856a8..4a91e2c20dc58 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -280,6 +280,7 @@ BENIGN_LANGOPT(VisibilityInlinesHiddenStaticLocalVar, 1, 0,
                "hidden visibility for static local variables in inline C++ "
                "methods when -fvisibility-inlines hidden is enabled")
 LANGOPT(GlobalAllocationFunctionVisibilityHidden , 1, 0, "hidden visibility for global operator new and delete declaration")
+LANGOPT(NewInfallible , 1, 0, "Treats throwing global C++ operator new as always returning valid memory (annotates with __attribute__((returns_nonnull)) and throw()). This is detectable in source.")
 BENIGN_LANGOPT(ParseUnknownAnytype, 1, 0, "__unknown_anytype")
 BENIGN_LANGOPT(DebuggerSupport , 1, 0, "debugger support")
 BENIGN_LANGOPT(DebuggerCastResultToId, 1, 0, "for 'po' in the debugger, cast the result to id if it is of unknown type")

diff  --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 8c562a6c06128..af01f620a94f9 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2730,6 +2730,10 @@ def fvisibility_ms_compat : Flag<["-"], "fvisibility-ms-compat">, Group<f_Group>
 def fvisibility_global_new_delete_hidden : Flag<["-"], "fvisibility-global-new-delete-hidden">, Group<f_Group>,
   HelpText<"Give global C++ operator new and delete declarations hidden visibility">, Flags<[CC1Option]>,
   MarshallingInfoFlag<LangOpts<"GlobalAllocationFunctionVisibilityHidden">>;
+def fnew_infallible : Flag<["-"], "fnew-infallible">, Group<f_Group>,
+  HelpText<"Treats throwing global C++ operator new as always returning valid memory "
+  "(annotates with __attribute__((returns_nonnull)) and throw()). This is detectable in source.">,
+  Flags<[CC1Option]>, MarshallingInfoFlag<LangOpts<"NewInfallible">>;
 defm whole_program_vtables : BoolFOption<"whole-program-vtables",
   CodeGenOpts<"WholeProgramVTables">, DefaultFalse,
   PosFlag<SetTrue, [CC1Option], "Enables whole-program vtable optimization. Requires -flto">,

diff  --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 863e5a17bc47f..3de54e248f248 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5711,7 +5711,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden_static_local_var,
                            options::OPT_fno_visibility_inlines_hidden_static_local_var);
   Args.AddLastArg(CmdArgs, options::OPT_fvisibility_global_new_delete_hidden);
-
+  Args.AddLastArg(CmdArgs, options::OPT_fnew_infallible);
   Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ);
 
   if (Args.hasFlag(options::OPT_fno_operator_names,

diff  --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 14484147e0414..ba2e17c4a6313 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -3049,6 +3049,9 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
       EPI.ExceptionSpec.Type = EST_Dynamic;
       EPI.ExceptionSpec.Exceptions = llvm::makeArrayRef(BadAllocType);
     }
+    if (getLangOpts().NewInfallible) {
+      EPI.ExceptionSpec.Type = EST_DynamicNone;
+    }
   } else {
     EPI.ExceptionSpec =
         getLangOpts().CPlusPlus11 ? EST_BasicNoexcept : EST_DynamicNone;
@@ -3064,6 +3067,10 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
     // Global allocation functions should always be visible.
     Alloc->setVisibleDespiteOwningModule();
 
+    if (HasBadAllocExceptionSpec && getLangOpts().NewInfallible)
+      Alloc->addAttr(
+          ReturnsNonNullAttr::CreateImplicit(Context, Alloc->getLocation()));
+
     Alloc->addAttr(VisibilityAttr::CreateImplicit(
         Context, LangOpts.GlobalAllocationFunctionVisibilityHidden
                      ? VisibilityAttr::Hidden

diff  --git a/clang/test/CodeGenCXX/new-infallible.cpp b/clang/test/CodeGenCXX/new-infallible.cpp
new file mode 100644
index 0000000000000..94bcc886d3966
--- /dev/null
+++ b/clang/test/CodeGenCXX/new-infallible.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-linux-gnu -fnew-infallible -o - %s | FileCheck %s
+
+// CHECK: call noalias nonnull i8* @_Znwm(i64 4)
+
+// CHECK: ; Function Attrs: nobuiltin nounwind allocsize(0)
+// CHECK-NEXT: declare nonnull i8* @_Znwm(i64)
+int *new_infallible = new int;


        


More information about the cfe-commits mailing list