Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lld] lld incorrectly marking functions available_externally while linking Destructors with Mixed Comdats #125155

Open
pranav-159 opened this issue Jan 31, 2025 · 0 comments
Labels

Comments

@pranav-159
Copy link

when compiling the project ZenDNN with LLVM faced an error similar to that of given below

Alias must point to a definition
ptr @_ZN1AIiED1Ev
LLVM ERROR: Broken module found, compilation aborted!

A simple test case demonstrating the issue:

; RUN: rm -rf %t.dir && split-file %s %t.dir && cd %t.dir
; RUN: llvm-as a.ll -o a.bc && llvm-as b.ll -o b.bc
; RUN: ld.lld -shared a.bc b.bc -o out.so

;--- a.ll
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

$_ZN1AIiED0Ev = comdat any

define linkonce_odr void @_ZN1AIiED0Ev(ptr noundef nonnull %this) unnamed_addr comdat {
  call void @_ZdlPv(ptr noundef %this)
  ret void
}
declare void @_ZdlPv(ptr noundef)

;--- b.ll
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

$_ZN1AIiED5Ev = comdat any

@_ZN1AIiED1Ev = weak_odr unnamed_addr alias void (ptr), ptr @_ZN1AIiED2Ev

define weak_odr void @_ZN1AIiED2Ev(ptr noundef nonnull %this) unnamed_addr comdat($_ZN1AIiED5Ev) {
  ret void
}

define weak_odr void @_ZN1AIiED0Ev(ptr noundef nonnull %this) unnamed_addr comdat($_ZN1AIiED5Ev) {
entry:
  call void @_ZN1AIiED1Ev(ptr noundef nonnull %this)
  call void @_ZdlPv(ptr noundef %this)
  ret void
}

declare void @_ZdlPv(ptr noundef)

and the C code reproducer:

// RUN: split-file %s %t
// RUN: %clang -fPIC -shared -O3 -flto %t/implicit.cpp %t/explicit.cpp

//--- test.h
#include <iostream>

struct Base {
    Base() { std::cout << "Base Constructor\n"; }
    virtual ~Base() { std::cout << "Base Destructor\n"; }
};

template<class T>
struct Derived : public Base {
    Derived() { std::cout << "Derived Constructor\n"; }
    ~Derived() {};
};

//--- explicit.cpp
#include "test.h"

template struct Derived<int>;

void foo() {
    Base* obj = new Derived<int>();
    delete obj;
}

//--- implicit.cpp
#include "test.h"

void bar() {
    Base* obj = new Derived<int>();
    delete obj;
}

while analyzing the issue found that opt inlines D2 destructor into D0 destructor in a.ll (implicit instantiation), hence it contains only D0 function in D0 comdat whereas b.ll (explicit instantiation) contains all D0/D1/D2 destructors in D5 comdat.
In this IR with mixed comdats, D0 of a.ll is marked prevailing whereas D0 in b.ll is marked non-prevailing. As lld tries to remove D0 from b.ll and its COMDAT D5 (which is marked as non-prevailing because of D0), it marks D2 as available_externally, even though it is prevailing. Since D1 alias D2, which is not considered as real definition as its linkage type is available_externally, IR-Verifier pass throws the above-mentioned error.

In thinLTO flow this issue not observed, it may be because of this commit [12050a3] (12050a3#diff-56a1bc22385a365b144c1ecc9d53128cb8f16dad12cc6f13b8ddf293a6c583b3) and its corresponding test case can be found at llvm/test/ThinLTO/X86/ctor-dtor-alias2.ll .

Can we fix it similarly by not marking its comdat as non-prevailing, if the symbols name and comdat's name doesn't match? thereby leaving other symbols in comdat intact.

diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp
index 0f53c6085121..d66846756842 100644
--- a/llvm/lib/LTO/LTO.cpp
+++ b/llvm/lib/LTO/LTO.cpp
@@ -928,7 +928,7 @@ LTO::addRegularLTO(BitcodeModule BM, ArrayRef<InputFile::Symbol> Syms,
         // module (in linkRegularLTO), based on whether it is undefined.
         Mod.Keep.push_back(GV);
         GV->setLinkage(GlobalValue::AvailableExternallyLinkage);
-        if (GV->hasComdat())
+        if (GV->getComdat()->getName() == GV->getName())
           NonPrevailingComdats.insert(GV->getComdat());
         cast<GlobalObject>(GV)->setComdat(nullptr);
       }
@llvmbot llvmbot added the lld label Jan 31, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants