[llvm][EmbedBitcodePass] Prevent modifying the module with ThinLTO (#139999)

Since ThinLTOBitcodeWriterPass handles many things for CFI and WPD, like
updating vtable linkage, we need to prevent those changes from
persisting in the non-LTO object code we will compile under FatLTO.

The only non-invasive way to do that is to clone the module when
serializing the module in ThinLTOBitcodeWriterPass. We may be able to
avoid cloning in the future with additional infrastructure to restore
the IR to its original state.

Fixes #139440
This commit is contained in:
Paul Kirth 2025-05-29 13:42:48 -07:00 committed by GitHub
parent bedbc65871
commit 55c7d5cdad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 9 additions and 4 deletions

View File

@ -16,6 +16,7 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Triple.h"
#include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include <string>
@ -33,8 +34,11 @@ PreservedAnalyses EmbedBitcodePass::run(Module &M, ModuleAnalysisManager &AM) {
std::string Data;
raw_string_ostream OS(Data);
// Clone the module with Thin LTO, since ThinLTOBitcodeWriterPass changes
// vtable linkage that would break the non-lto object code for FatLTO.
if (IsThinLTO)
ThinLTOBitcodeWriterPass(OS, /*ThinLinkOS=*/nullptr).run(M, AM);
ThinLTOBitcodeWriterPass(OS, /*ThinLinkOS=*/nullptr)
.run(*llvm::CloneModule(M), AM);
else
BitcodeWriterPass(OS, /*ShouldPreserveUseListOrder=*/false, EmitLTOSummary)
.run(M, AM);

View File

@ -1,12 +1,13 @@
; RUN: opt --mtriple x86_64-unknown-linux-gnu < %s -passes="embed-bitcode<thinlto>" -S | FileCheck %s
; CHECK-NOT: $_ZTV3Foo = comdat any
; CHECK: $_ZTV3Foo = comdat any
$_ZTV3Foo = comdat any
$_ZTI3Foo = comdat any
; CHECK: @_ZTV3Foo = external hidden unnamed_addr constant { [5 x ptr] }, align 8
; CHECK: @_ZTI3Foo = linkonce_odr hidden constant { ptr, ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2), ptr @_ZTS3Foo, ptr @_ZTISt13runtime_error }, comdat, align 8
;; ThinLTOBitcodeWriter will remove the vtable for Foo, and make it an external symbol
; CHECK: @_ZTV3Foo = linkonce_odr hidden unnamed_addr constant { [5 x ptr] } { [5 x ptr] [ptr null, ptr @_ZTI3Foo, ptr @_ZN3FooD2Ev, ptr @_ZN3FooD0Ev, ptr @_ZNKSt13runtime_error4whatEv] }, comdat, align 8, !type !0, !type !1, !type !2, !type !3, !type !4, !type !5
; CHECK-NOT: @foo = external unnamed_addr constant { [5 x ptr] }, align 8
; CHECK: @llvm.embedded.object = private constant {{.*}}, section ".llvm.lto", align 1
; CHECK: @llvm.compiler.used = appending global [1 x ptr] [ptr @llvm.embedded.object], section "llvm.metadata"
@_ZTV3Foo = linkonce_odr hidden unnamed_addr constant { [5 x ptr] } { [5 x ptr] [ptr null, ptr @_ZTI3Foo, ptr @_ZN3FooD2Ev, ptr @_ZN3FooD0Ev, ptr @_ZNKSt13runtime_error4whatEv] }, comdat, align 8, !type !0, !type !1, !type !2, !type !3, !type !4, !type !5