forked from OSchip/llvm-project
[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 (cd0a1226b5
) 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
This commit is contained in:
parent
3b0a9e7b39
commit
b40a2a533a
|
@ -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>
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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">,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
Loading…
Reference in New Issue