Skip to content

Commit 7472477

Browse files
committed
[Clang]: Enable speculative devirtualization
1 parent 5a6c69b commit 7472477

File tree

10 files changed

+56
-18
lines changed

10 files changed

+56
-18
lines changed

clang/docs/UsersManual.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2319,6 +2319,13 @@ are listed below.
23192319
This enables better devirtualization. Turned off by default, because it is
23202320
still experimental.
23212321

2322+
.. option:: -fdevirtualize-speculatively
2323+
2324+
Enable speculative devirtualization optimization, such as single-implementation
2325+
devirtualization. This optimization is used out of LTO mode for now.
2326+
Turned off by default.
2327+
TODO: Enable for LTO mode.
2328+
23222329
.. option:: -fwhole-program-vtables
23232330

23242331
Enable whole-program vtable optimizations, such as single-implementation
@@ -5207,6 +5214,8 @@ Execute ``clang-cl /?`` to see a list of supported options:
52075214
-fstandalone-debug Emit full debug info for all types used by the program
52085215
-fstrict-aliasing Enable optimizations based on strict aliasing rules
52095216
-fsyntax-only Run the preprocessor, parser and semantic analysis stages
5217+
-fdevirtualize-speculatively
5218+
Enables speculative devirtualization optimization.
52105219
-fwhole-program-vtables Enables whole-program vtable optimization. Requires -flto
52115220
-gcodeview-ghash Emit type record hashes in a .debug$H section
52125221
-gcodeview Generate CodeView debug information

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,8 @@ VALUE_CODEGENOPT(WarnStackSize , 32, UINT_MAX, Benign) ///< Set via -fwarn-s
362362
CODEGENOPT(NoStackArgProbe, 1, 0, Benign) ///< Set when -mno-stack-arg-probe is used
363363
CODEGENOPT(EmitLLVMUseLists, 1, 0, Benign) ///< Control whether to serialize use-lists.
364364

365+
CODEGENOPT(DevirtualizeSpeculatively, 1, 0, Benign) ///< Whether to apply the speculative
366+
/// devirtualization optimization.
365367
CODEGENOPT(WholeProgramVTables, 1, 0, Benign) ///< Whether to apply whole-program
366368
/// vtable optimization.
367369

clang/include/clang/Driver/Options.td

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4475,6 +4475,13 @@ defm new_infallible : BoolFOption<"new-infallible",
44754475
BothFlags<[], [ClangOption, CC1Option],
44764476
" treating throwing global C++ operator new as always returning valid memory "
44774477
"(annotates with __attribute__((returns_nonnull)) and throw()). This is detectable in source.">>;
4478+
defm devirtualize_speculatively
4479+
: BoolFOption<"devirtualize-speculatively",
4480+
CodeGenOpts<"DevirtualizeSpeculatively">, DefaultFalse,
4481+
PosFlag<SetTrue, [], [],
4482+
"Enables speculative devirtualization optimization.">,
4483+
NegFlag<SetFalse>,
4484+
BothFlags<[], [ClangOption, CLOption, CC1Option]>>;
44784485
defm whole_program_vtables : BoolFOption<"whole-program-vtables",
44794486
CodeGenOpts<"WholeProgramVTables">, DefaultFalse,
44804487
PosFlag<SetTrue, [], [ClangOption, CC1Option],
@@ -7070,9 +7077,8 @@ defm variable_expansion_in_unroller : BooleanFFlag<"variable-expansion-in-unroll
70707077
Group<clang_ignored_gcc_optimization_f_Group>;
70717078
defm web : BooleanFFlag<"web">, Group<clang_ignored_gcc_optimization_f_Group>;
70727079
defm whole_program : BooleanFFlag<"whole-program">, Group<clang_ignored_gcc_optimization_f_Group>;
7073-
defm devirtualize : BooleanFFlag<"devirtualize">, Group<clang_ignored_gcc_optimization_f_Group>;
7074-
defm devirtualize_speculatively : BooleanFFlag<"devirtualize-speculatively">,
7075-
Group<clang_ignored_gcc_optimization_f_Group>;
7080+
defm devirtualize : BooleanFFlag<"devirtualize">,
7081+
Group<clang_ignored_gcc_optimization_f_Group>;
70767082

70777083
// Generic gfortran options.
70787084
def A_DASH : Joined<["-"], "A-">, Group<gfortran_Group>;

clang/lib/CodeGen/BackendUtil.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,7 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
938938
// non-integrated assemblers don't recognize .cgprofile section.
939939
PTO.CallGraphProfile = !CodeGenOpts.DisableIntegratedAS;
940940
PTO.UnifiedLTO = CodeGenOpts.UnifiedLTO;
941+
PTO.DevirtualizeSpeculatively = CodeGenOpts.DevirtualizeSpeculatively;
941942

942943
LoopAnalysisManager LAM;
943944
FunctionAnalysisManager FAM;

clang/lib/CodeGen/CGClass.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2827,10 +2827,11 @@ void CodeGenFunction::EmitTypeMetadataCodeForVCall(const CXXRecordDecl *RD,
28272827
SourceLocation Loc) {
28282828
if (SanOpts.has(SanitizerKind::CFIVCall))
28292829
EmitVTablePtrCheckForCall(RD, VTable, CodeGenFunction::CFITCK_VCall, Loc);
2830-
else if (CGM.getCodeGenOpts().WholeProgramVTables &&
2831-
// Don't insert type test assumes if we are forcing public
2832-
// visibility.
2833-
!CGM.AlwaysHasLTOVisibilityPublic(RD)) {
2830+
else if ((CGM.getCodeGenOpts().WholeProgramVTables &&
2831+
// Don't insert type test assumes if we are forcing public
2832+
// visibility.
2833+
!CGM.AlwaysHasLTOVisibilityPublic(RD)) ||
2834+
CGM.getCodeGenOpts().DevirtualizeSpeculatively) {
28342835
CanQualType Ty = CGM.getContext().getCanonicalTagType(RD);
28352836
llvm::Metadata *MD = CGM.CreateMetadataIdentifierForType(Ty);
28362837
llvm::Value *TypeId =
@@ -2988,8 +2989,9 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
29882989
}
29892990

29902991
bool CodeGenFunction::ShouldEmitVTableTypeCheckedLoad(const CXXRecordDecl *RD) {
2991-
if (!CGM.getCodeGenOpts().WholeProgramVTables ||
2992-
!CGM.HasHiddenLTOVisibility(RD))
2992+
if ((!CGM.getCodeGenOpts().WholeProgramVTables ||
2993+
!CGM.HasHiddenLTOVisibility(RD)) &&
2994+
!CGM.getCodeGenOpts().DevirtualizeSpeculatively)
29932995
return false;
29942996

29952997
if (CGM.getCodeGenOpts().VirtualFunctionElimination)

clang/lib/CodeGen/CGVTables.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,10 +1358,12 @@ llvm::GlobalObject::VCallVisibility CodeGenModule::GetVCallVisibilityLevel(
13581358
void CodeGenModule::EmitVTableTypeMetadata(const CXXRecordDecl *RD,
13591359
llvm::GlobalVariable *VTable,
13601360
const VTableLayout &VTLayout) {
1361-
// Emit type metadata on vtables with LTO or IR instrumentation.
1361+
// Emit type metadata on vtables with LTO or IR instrumentation or
1362+
// speculative devirtualization.
13621363
// In IR instrumentation, the type metadata is used to find out vtable
13631364
// definitions (for type profiling) among all global variables.
1364-
if (!getCodeGenOpts().LTOUnit && !getCodeGenOpts().hasProfileIRInstr())
1365+
if (!getCodeGenOpts().LTOUnit && !getCodeGenOpts().hasProfileIRInstr() &&
1366+
!getCodeGenOpts().DevirtualizeSpeculatively)
13651367
return;
13661368

13671369
CharUnits ComponentWidth = GetTargetTypeStoreSize(getVTableComponentType());

clang/lib/CodeGen/ItaniumCXXABI.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -717,9 +717,10 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
717717
bool ShouldEmitVFEInfo = CGM.getCodeGenOpts().VirtualFunctionElimination &&
718718
CGM.HasHiddenLTOVisibility(RD);
719719
bool ShouldEmitWPDInfo =
720-
CGM.getCodeGenOpts().WholeProgramVTables &&
721-
// Don't insert type tests if we are forcing public visibility.
722-
!CGM.AlwaysHasLTOVisibilityPublic(RD);
720+
(CGM.getCodeGenOpts().WholeProgramVTables &&
721+
// Don't insert type tests if we are forcing public visibility.
722+
!CGM.AlwaysHasLTOVisibilityPublic(RD)) ||
723+
CGM.getCodeGenOpts().DevirtualizeSpeculatively;
723724
llvm::Value *VirtualFn = nullptr;
724725

725726
{
@@ -2114,13 +2115,15 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
21142115
// definitions to ensure we associate derived classes with base classes
21152116
// defined in headers but with a strong definition only in a shared library.
21162117
if (!VTable->isDeclarationForLinker() ||
2117-
CGM.getCodeGenOpts().WholeProgramVTables) {
2118+
CGM.getCodeGenOpts().WholeProgramVTables ||
2119+
CGM.getCodeGenOpts().DevirtualizeSpeculatively) {
21182120
CGM.EmitVTableTypeMetadata(RD, VTable, VTLayout);
21192121
// For available_externally definitions, add the vtable to
21202122
// @llvm.compiler.used so that it isn't deleted before whole program
21212123
// analysis.
21222124
if (VTable->isDeclarationForLinker()) {
2123-
assert(CGM.getCodeGenOpts().WholeProgramVTables);
2125+
assert(CGM.getCodeGenOpts().WholeProgramVTables ||
2126+
CGM.getCodeGenOpts().DevirtualizeSpeculatively);
21242127
CGM.addCompilerUsedGlobal(VTable);
21252128
}
21262129
}

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7731,6 +7731,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
77317731

77327732
addOpenMPHostOffloadingArgs(C, JA, Args, CmdArgs);
77337733

7734+
// Temporarily disable this for LTO if it's not explicitly enabled.
7735+
// TODO: enable it by default for LTO also.
7736+
if (Args.hasFlag(options::OPT_fdevirtualize_speculatively,
7737+
options::OPT_fno_devirtualize_speculatively,
7738+
/*Default value*/ false))
7739+
CmdArgs.push_back("-fdevirtualize-speculatively");
7740+
77347741
bool VirtualFunctionElimination =
77357742
Args.hasFlag(options::OPT_fvirtual_function_elimination,
77367743
options::OPT_fno_virtual_function_elimination, false);

clang/test/CodeGenCXX/type-metadata.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
// RUN: %clang_cc1 -O2 -flto -flto-unit -triple x86_64-unknown-linux -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=ITANIUM-OPT --check-prefix=ITANIUM-OPT-LAYOUT %s
1515
// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-pc-windows-msvc -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=MS --check-prefix=MS-TYPEMETADATA --check-prefix=TT-MS %s
1616

17+
// Test for the speculative devirtualization feature in nonlto mode:
18+
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fdevirtualize-speculatively -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=TT-ITANIUM-DEFAULT-NOLTO-SPECULATIVE-DEVIRT %s
19+
1720
// Tests for cfi + whole-program-vtables:
1821
// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -fvisibility=hidden -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-VT --check-prefix=ITANIUM-HIDDEN --check-prefix=ITANIUM-COMMON-MD --check-prefix=TC-ITANIUM --check-prefix=ITANIUM-NO-RV-MD %s
1922
// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-pc-windows-msvc -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-VT --check-prefix=MS --check-prefix=MS-TYPEMETADATA --check-prefix=TC-MS %s
@@ -178,6 +181,7 @@ void af(A *a) {
178181
// TT-ITANIUM-HIDDEN: [[P:%[^ ]*]] = call i1 @llvm.type.test(ptr [[VT:%[^ ]*]], metadata !"_ZTS1A")
179182
// TT-ITANIUM-DEFAULT: [[P:%[^ ]*]] = call i1 @llvm.public.type.test(ptr [[VT:%[^ ]*]], metadata !"_ZTS1A")
180183
// TT-MS: [[P:%[^ ]*]] = call i1 @llvm.type.test(ptr [[VT:%[^ ]*]], metadata !"?AUA@@")
184+
// TT-ITANIUM-DEFAULT-NOLTO-SPECULATIVE-DEVIRT: [[P:%[^ ]*]] = call i1 @llvm.public.type.test(ptr [[VT:%[^ ]*]], metadata !"_ZTS1A")
181185
// TC-ITANIUM: [[PAIR:%[^ ]*]] = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata !"_ZTS1A")
182186
// TC-ITANIUM-RV: [[PAIR:%[^ ]*]] = call { ptr, i1 } @llvm.type.checked.load.relative(ptr {{%[^ ]*}}, i32 0, metadata !"_ZTS1A")
183187
// TC-MS: [[PAIR:%[^ ]*]] = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata !"?AUA@@")
@@ -212,6 +216,7 @@ void df1(D *d) {
212216
// TT-ITANIUM-HIDDEN: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
213217
// TT-ITANIUM-DEFAULT: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
214218
// TT-MS: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata !"?AUA@@")
219+
// TT-ITANIUM-DEFAULT-NOLTO-SPECULATIVE-DEVIRT: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
215220
// TC-ITANIUM: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata ![[DTYPE:[0-9]+]])
216221
// TC-ITANIUM-RV: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load.relative(ptr {{%[^ ]*}}, i32 0, metadata ![[DTYPE:[0-9]+]])
217222
// TC-MS: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata !"?AUA@@")
@@ -224,6 +229,7 @@ void dg1(D *d) {
224229
// TT-ITANIUM-HIDDEN: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata !"_ZTS1B")
225230
// TT-ITANIUM-DEFAULT: {{%[^ ]*}} = call i1 @llvm.public.type.test(ptr {{%[^ ]*}}, metadata !"_ZTS1B")
226231
// TT-MS: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata !"?AUB@@")
232+
// TT-ITANIUM-DEFAULT-NOLTO-SPECULATIVE-DEVIRT: {{%[^ ]*}} = call i1 @llvm.public.type.test(ptr {{%[^ ]*}}, metadata !"_ZTS1B")
227233
// TC-ITANIUM: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 8, metadata !"_ZTS1B")
228234
// TC-ITANIUM-RV: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load.relative(ptr {{%[^ ]*}}, i32 4, metadata !"_ZTS1B")
229235
// TC-MS: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata !"?AUB@@")
@@ -236,6 +242,7 @@ void dh1(D *d) {
236242
// TT-ITANIUM-HIDDEN: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata ![[DTYPE]])
237243
// TT-ITANIUM-DEFAULT: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata ![[DTYPE]])
238244
// TT-MS: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
245+
// TT-ITANIUM-DEFAULT-NOLTO-SPECULATIVE-DEVIRT: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata ![[DTYPE]])
239246
// TC-ITANIUM: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 16, metadata ![[DTYPE]])
240247
// TC-ITANIUM-RV: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load.relative(ptr {{%[^ ]*}}, i32 8, metadata ![[DTYPE]])
241248
// TC-MS: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 8, metadata ![[DTYPE:[0-9]+]])
@@ -297,6 +304,7 @@ void f(D *d) {
297304
// TT-ITANIUM-HIDDEN: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata !"_ZTSN5test21DE")
298305
// TT-ITANIUM-DEFAULT: {{%[^ ]*}} = call i1 @llvm.public.type.test(ptr {{%[^ ]*}}, metadata !"_ZTSN5test21DE")
299306
// TT-MS: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata !"?AUA@test2@@")
307+
// TT-ITANIUM-DEFAULT-NOLTO-SPECULATIVE-DEVIRT: {{%[^ ]*}} = call i1 @llvm.public.type.test(ptr {{%[^ ]*}}, metadata !"_ZTSN5test21DE")
300308
// TC-ITANIUM: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 8, metadata !"_ZTSN5test21DE")
301309
// TC-ITANIUM-RV: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load.relative(ptr {{%[^ ]*}}, i32 4, metadata !"_ZTSN5test21DE")
302310
// TC-MS: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata !"?AUA@test2@@")

clang/test/Driver/clang_f_opts.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,6 @@
377377
// RUN: -ftree-ter \
378378
// RUN: -ftree-vrp \
379379
// RUN: -fno-devirtualize \
380-
// RUN: -fno-devirtualize-speculatively \
381380
// RUN: -fslp-vectorize-aggressive \
382381
// RUN: -fno-slp-vectorize-aggressive \
383382
// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-WARNING %s
@@ -436,7 +435,6 @@
436435
// CHECK-WARNING-DAG: optimization flag '-ftree-ter' is not supported
437436
// CHECK-WARNING-DAG: optimization flag '-ftree-vrp' is not supported
438437
// CHECK-WARNING-DAG: optimization flag '-fno-devirtualize' is not supported
439-
// CHECK-WARNING-DAG: optimization flag '-fno-devirtualize-speculatively' is not supported
440438
// CHECK-WARNING-DAG: the flag '-fslp-vectorize-aggressive' has been deprecated and will be ignored
441439
// CHECK-WARNING-DAG: the flag '-fno-slp-vectorize-aggressive' has been deprecated and will be ignored
442440

0 commit comments

Comments
 (0)