This is an archive of the discontinued LLVM Phabricator instance.

[C++20] [Modules] Don't generate global ctors/dtors for variables which are available externally
ClosedPublic

Authored by ChuanqiXu on Jan 2 2023, 7:47 PM.

Details

Summary

Closes https://github.com/llvm/llvm-project/issues/59765.

Currently we will generate the global ctor/dtor for variables in importing modules. It will cause multiple initialization/destructions. It makes no sense. This patch tries to not generate global ctor/dtor for variables which are available externally. Note that the variables in header units and clang modules won't be available externally by default.

Diff Detail

Event Timeline

ChuanqiXu created this revision.Jan 2 2023, 7:47 PM
Herald added a project: Restricted Project. · View Herald TranscriptJan 2 2023, 7:47 PM
ChuanqiXu requested review of this revision.Jan 2 2023, 7:47 PM
iains added a comment.Jan 3 2023, 1:42 AM

your test case only covers itanium ABI - does the process still work properly for non-itanium ABIs?
.. if I remember correctly, the ctor/dtors are all run from the top level module (i.e. it pulls in the imported ones and constructs a composite ctor),

your test case only covers itanium ABI - does the process still work properly for non-itanium ABIs?

Yeah, CodeGenModule::EmitGlobalVarDefinition should be ABI independent. But we only support the initializer for modules in itanium ABI.

.. if I remember correctly, the ctor/dtors are all run from the top level module (i.e. it pulls in the imported ones and constructs a composite ctor),

Yes, the ctor/dtors are run from the top level. (To avoid confusing, given A import B and B import C, let's call C as the top level module).

iains added a comment.Jan 4 2023, 3:15 AM

OK. So I've been thinking about this some more and ISTM that if the external source represents a Header Unit, then that has no stand-alone object or initialiser.

Header Units are permitted to contain (implicitly exported) declarations with internal linkage (although after D140261 we should reject exported definitions with external linkage).

Did we not fix a problem where ctors for static objects in headers were allowed (the issue with iostream?)

ISTM that if we permit static objects at file scope with dynamic inits, to appear in a header unit - then we would have to special-case external sources that are header units or those ctors would not be run (and we would again break iostream). Perhaps my memory is not right on this tho.

ChuanqiXu updated this revision to Diff 486449.Jan 4 2023, 7:16 PM
ChuanqiXu retitled this revision from [C++20] [Modules] Don't generate global ctors/dtors for variables from external sources to [C++20] [Modules] Don't generate global ctors/dtors for variables which are available externally.
ChuanqiXu edited the summary of this revision. (Show Details)

Rewording external sources to available externally.

ChuanqiXu added a comment.EditedJan 4 2023, 7:25 PM

@iains Oh, I used the incorrect word. I should use available externally. Header Units are external sources but the declarations in header units won't be available externally. I added a test to show this.


(following off is about the idea of available externally. You can ignore it if you are not interested)

The idea of available externally is originally the idea of LLVM. It means that we import a definition from another LLVM Module and the definition is available externally to current LLVM Modules. So that the optimizer can optimize away the available external definitions at any time.

Then modules in clang borrow the idea of available externally to speedup compilation. When clang generate codes, if clang found a definition is defined in a named modules (or object pcm file, which is another extension mode of clang modules. I am not sure if this mode is used or maintained), clang will mark the definition as available externally. So simply, the declarations in normal clang modules and header units won't be available externally. So this patch won't affect normal clang modules and header units.

iains accepted this revision.Jan 5 2023, 12:24 AM

@iains Oh, I used the incorrect word. I should use available externally. Header Units are external sources but the declarations in header units won't be available externally. I added a test to show this.

Yeah, that explains it and the patch LGTM (but please allow @dblaikie a few days to comment, if he wants to)


(following off is about the idea of available externally. You can ignore it if you are not interested)

The idea of available externally is originally the idea of LLVM. It means that we import a definition from another LLVM Module and the definition is available externally to current LLVM Modules. So that the optimizer can optimize away the available external definitions at any time.

Then modules in clang borrow the idea of available externally to speedup compilation. When clang generate codes, if clang found a definition is defined in a named modules (or object pcm file, which is another extension mode of clang modules. I am not sure if this mode is used or maintained), clang will mark the definition as available externally. So simply, the declarations in normal clang modules and header units won't be available externally. So this patch won't affect normal clang modules and header units.

sure, I am familiar with the externally available process, we should probably check on the cases that might not be maintained.

This revision is now accepted and ready to land.Jan 5 2023, 12:24 AM

sure, I am familiar with the externally available process, we should probably check on the cases that might not be maintained.

Yeah, it looks like @dblaikie bring the object pcm mode to clang. If it is not used now, I think we can remove the mode.

sure, I am familiar with the externally available process, we should probably check on the cases that might not be maintained.

Yeah, it looks like @dblaikie bring the object pcm mode to clang. If it is not used now, I think we can remove the mode.

Modular code generation/debug info for Clang Header modules? It was never deployed, but I think it's probably worth keeping around for experimentation/further investigation. I think it might be valuable with some heuristics tweaks to not try to home/available_externally generated code like protobufs, maybe.

sure, I am familiar with the externally available process, we should probably check on the cases that might not be maintained.

Yeah, it looks like @dblaikie bring the object pcm mode to clang. If it is not used now, I think we can remove the mode.

Modular code generation/debug info for Clang Header modules? It was never deployed, but I think it's probably worth keeping around for experimentation/further investigation. I think it might be valuable with some heuristics tweaks to not try to home/available_externally generated code like protobufs, maybe.

Got it.

This revision was landed with ongoing or failed builds.Jan 8 2023, 6:49 PM
This revision was automatically updated to reflect the committed changes.
Herald added a project: Restricted Project. · View Herald TranscriptJan 8 2023, 6:49 PM
Herald added a subscriber: cfe-commits. · View Herald Transcript

I fixed the failure by restricting the targets in https://github.com/llvm/llvm-project/commit/9cb1298dcc85c357eb97ed0bdc3c82c5d011f6f6. And the best approach is to add a separate test for AIX but I don't have an AIX machine. You can add it if you are interested.

Jake-Egan added a comment.EditedJan 10 2023, 10:12 AM

I fixed the failure by restricting the targets in https://github.com/llvm/llvm-project/commit/9cb1298dcc85c357eb97ed0bdc3c82c5d011f6f6. And the best approach is to add a separate test for AIX but I don't have an AIX machine. You can add it if you are interested.

Thanks for looking into it. Unfortunately the test is still failing on AIX after this commit. Which is odd because your fix does make sense to me. I'm not sure why the test is still being run on AIX. https://lab.llvm.org/buildbot/#/builders/214/builds/5267

I fixed the failure by restricting the targets in https://github.com/llvm/llvm-project/commit/9cb1298dcc85c357eb97ed0bdc3c82c5d011f6f6. And the best approach is to add a separate test for AIX but I don't have an AIX machine. You can add it if you are interested.

Thanks for looking into it. Unfortunately the test is still failing on AIX after this commit. Which is odd because your fix does make sense to me. I'm not sure why the test is still being run on AIX. https://lab.llvm.org/buildbot/#/builders/214/builds/5267

Weird. I compiled PowerPC target locally and change the test into:

// RUN: %clang_cc1 -std=c++20 --target=powerpc-ibm-aix-xcoff %t/M.cppm -triple %itanium_abi_triple -emit-module-interface -o %t/M.pcm
// RUN: %clang_cc1 -std=c++20 --target=powerpc-ibm-aix-xcoff %t/M.pcm -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %t/M.cppm
// RUN: %clang_cc1 -std=c++20 --target=powerpc-ibm-aix-xcoff %t/Use.cpp -fprebuilt-module-path=%t -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %t/Use.cpp

Then when I run the test, it tells me it is unsupported (as expect).

Would you like to take a double look?

Would you like to take a double look?

Yes, it still fails on the bot and on my local machine. I've added an XFAIL to the test for now just to get the AIX bot green.

Would you like to take a double look?

Yes, it still fails on the bot and on my local machine. I've added an XFAIL to the test for now just to get the AIX bot green.

Weird. Maybe you can find a method by adding REQUIRES or NOT-SUPPORTED and test it locally. If it goes well then you can upstream the change.

Would you like to take a double look?

Yes, it still fails on the bot and on my local machine. I've added an XFAIL to the test for now just to get the AIX bot green.

Weird. Maybe you can find a method by adding REQUIRES or NOT-SUPPORTED and test it locally. If it goes well then you can upstream the change.

It seems that it's because the test fails when running on AIX - not just when it's being targeted.

// REQUIRES: x86-registered-target,aarch64-registered-target

The above doesn't stop the test from being run on AIX. So, I can add:

// UNSUPPORTED: system-aix

But do you want to keep the REQUIRES for other targets?

Would you like to take a double look?

Yes, it still fails on the bot and on my local machine. I've added an XFAIL to the test for now just to get the AIX bot green.

Weird. Maybe you can find a method by adding REQUIRES or NOT-SUPPORTED and test it locally. If it goes well then you can upstream the change.

It seems that it's because the test fails when running on AIX - not just when it's being targeted.

// REQUIRES: x86-registered-target,aarch64-registered-target

The above doesn't stop the test from being run on AIX. So, I can add:

// UNSUPPORTED: system-aix

But do you want to keep the REQUIRES for other targets?

The REQUIRES are added for AIX, so maybe it is ok to abandon them temporarily and add them back once we find other similar failures.