Skip to content

Commit e1e6e78

Browse files
ChuanqiXu9yuxuanchen1997
authored andcommitted
[Doc] Update documentation for no-transitive-change (#96453)
Summary: (Some backgrounds, not required to read: https://discourse.llvm.org/t/rfc-c-20-modules-introduce-thin-bmi-and-decls-hash/74755) This is the document part for the no-transitive-change (#86912, #92083, #92085, #92511) to provide the ability for build system to skip some unnecessary recompilations. See the patch for examples. Test Plan: Reviewers: Subscribers: Tasks: Tags: Differential Revision: https://phabricator.intern.facebook.com/D60251509
1 parent c815fe2 commit e1e6e78

File tree

2 files changed

+150
-0
lines changed

2 files changed

+150
-0
lines changed

clang/docs/ReleaseNotes.rst

+7
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,13 @@ here. Generic improvements to Clang as a whole or to its underlying
174174
infrastructure are described first, followed by language-specific
175175
sections with improvements to Clang's support for those languages.
176176

177+
- Implemented improvements to BMIs for C++20 Modules that can reduce
178+
the number of rebuilds during incremental recompilation. We are seeking
179+
feedback from Build System authors and other interested users, especially
180+
when you feel Clang changes the BMI and misses an opportunity to avoid
181+
recompilations or causes correctness issues. See StandardCPlusPlusModules
182+
`StandardCPlusPlusModules <StandardCPlusPlusModules.html>`_ for more details.
183+
177184
- The ``\par`` documentation comment command now supports an optional
178185
argument, which denotes the header of the paragraph started by
179186
an instance of the ``\par`` command comment. The implementation

clang/docs/StandardCPlusPlusModules.rst

+143
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,149 @@ in the future. The expected roadmap for Reduced BMIs as of Clang 19.x is:
652652
comes, the term BMI will refer to the Reduced BMI and the Full BMI will only
653653
be meaningful to build systems which elect to support two-phase compilation.
654654

655+
Experimental Non-Cascading Changes
656+
----------------------------------
657+
658+
This section is primarily for build system vendors. For end compiler users,
659+
if you don't want to read it all, this is helpful to reduce recompilations.
660+
We encourage build system vendors and end users try this out and bring feedback.
661+
662+
Before Clang 19, a change in BMI of any (transitive) dependency would cause the
663+
outputs of the BMI to change. Starting with Clang 19, changes to non-direct
664+
dependencies should not directly affect the output BMI, unless they affect the
665+
results of the compilations. We expect that there are many more opportunities
666+
for this optimization than we currently have realized and would appreaciate
667+
feedback about missed optimization opportunities. For example,
668+
669+
.. code-block:: c++
670+
671+
// m-partA.cppm
672+
export module m:partA;
673+
674+
// m-partB.cppm
675+
export module m:partB;
676+
export int getB() { return 44; }
677+
678+
// m.cppm
679+
export module m;
680+
export import :partA;
681+
export import :partB;
682+
683+
// useBOnly.cppm
684+
export module useBOnly;
685+
import m;
686+
export int B() {
687+
return getB();
688+
}
689+
690+
// Use.cc
691+
import useBOnly;
692+
int get() {
693+
return B();
694+
}
695+
696+
To compile the project (for brevity, some commands are omitted.):
697+
698+
.. code-block:: console
699+
700+
$ clang++ -std=c++20 m-partA.cppm --precompile -o m-partA.pcm
701+
$ clang++ -std=c++20 m-partB.cppm --precompile -o m-partB.pcm
702+
$ clang++ -std=c++20 m.cppm --precompile -o m.pcm -fprebuilt-module-path=.
703+
$ clang++ -std=c++20 useBOnly.cppm --precompile -o useBOnly.pcm -fprebuilt-module-path=.
704+
$ md5sum useBOnly.pcm
705+
07656bf4a6908626795729295f9608da useBOnly.pcm
706+
707+
If the interface of ``m-partA.cppm`` is changed to:
708+
709+
.. code-block:: c++
710+
711+
// m-partA.v1.cppm
712+
export module m:partA;
713+
export int getA() { return 43; }
714+
715+
and the BMI for ``useBOnly`` is recompiled as in:
716+
717+
.. code-block:: console
718+
719+
$ clang++ -std=c++20 m-partA.cppm --precompile -o m-partA.pcm
720+
$ clang++ -std=c++20 m-partB.cppm --precompile -o m-partB.pcm
721+
$ clang++ -std=c++20 m.cppm --precompile -o m.pcm -fprebuilt-module-path=.
722+
$ clang++ -std=c++20 useBOnly.cppm --precompile -o useBOnly.pcm -fprebuilt-module-path=.
723+
$ md5sum useBOnly.pcm
724+
07656bf4a6908626795729295f9608da useBOnly.pcm
725+
726+
then the contents of ``useBOnly.pcm`` remain unchanged.
727+
Consequently, if the build system only bases recompilation decisions on directly imported modules,
728+
it becomes possible to skip the recompilation of ``Use.cc``.
729+
It should be fine because the altered interfaces do not affect ``Use.cc`` in any way;
730+
the changes do not cascade.
731+
732+
When ``Clang`` generates a BMI, it records the hash values of all potentially contributory BMIs
733+
for the BMI being produced. This ensures that build systems are not required to consider
734+
transitively imported modules when deciding whether to recompile.
735+
736+
What is considered to be a potential contributory BMIs is currently unspecified.
737+
However, it is a severe bug for a BMI to remain unchanged following an observable change
738+
that affects its consumers.
739+
740+
Build systems may utilize this optimization by doing an update-if-changed operation to the BMI
741+
that is consumed from the BMI that is output by the compiler.
742+
743+
We encourage build systems to add an experimental mode that
744+
reuses the cached BMI when **direct** dependencies did not change,
745+
even if **transitive** dependencies did change.
746+
747+
Given there are potential compiler bugs, we recommend that build systems
748+
support this feature as a configurable option so that users
749+
can go back to the transitive change mode safely at any time.
750+
751+
Interactions with Reduced BMI
752+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
753+
754+
With reduced BMI, non-cascading changes can be more powerful. For example,
755+
756+
.. code-block:: c++
757+
758+
// A.cppm
759+
export module A;
760+
export int a() { return 44; }
761+
762+
// B.cppm
763+
export module B;
764+
import A;
765+
export int b() { return a(); }
766+
767+
.. code-block:: console
768+
769+
$ clang++ -std=c++20 A.cppm -c -fmodule-output=A.pcm -fexperimental-modules-reduced-bmi -o A.o
770+
$ clang++ -std=c++20 B.cppm -c -fmodule-output=B.pcm -fexperimental-modules-reduced-bmi -o B.o -fmodule-file=A=A.pcm
771+
$ md5sum B.pcm
772+
6c2bd452ca32ab418bf35cd141b060b9 B.pcm
773+
774+
And let's change the implementation for ``A.cppm`` into:
775+
776+
.. code-block:: c++
777+
778+
export module A;
779+
int a_impl() { return 99; }
780+
export int a() { return a_impl(); }
781+
782+
and recompile the example:
783+
784+
.. code-block:: console
785+
786+
$ clang++ -std=c++20 A.cppm -c -fmodule-output=A.pcm -fexperimental-modules-reduced-bmi -o A.o
787+
$ clang++ -std=c++20 B.cppm -c -fmodule-output=B.pcm -fexperimental-modules-reduced-bmi -o B.o -fmodule-file=A=A.pcm
788+
$ md5sum B.pcm
789+
6c2bd452ca32ab418bf35cd141b060b9 B.pcm
790+
791+
We should find the contents of ``B.pcm`` remains the same. In this case, the build system is
792+
allowed to skip recompilations of TUs which solely and directly depend on module ``B``.
793+
794+
This only happens with a reduced BMI. With reduced BMIs, we won't record the function body
795+
of ``int b()`` in the BMI for ``B`` so that the module ``A`` doesn't contribute to the BMI of ``B``
796+
and we have less dependencies.
797+
655798
Performance Tips
656799
----------------
657800

0 commit comments

Comments
 (0)