aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Serialization/ASTWriter.cpp
AgeCommit message (Collapse)AuthorFilesLines
2024-08-05[OpenMP] OpenMP 5.1 "assume" directive parsing support (#92731)Julian Brown1-0/+28
This is a minimal patch to support parsing for "omp assume" directives. These are meant to be hints to a compiler's optimisers: as such, it is legitimate (if not very useful) to ignore them. The patch builds on top of the existing support for "omp assumes" directives (note spelling!). Unlike the "omp [begin/end] assumes" directives, "omp assume" is associated with a compound statement, i.e. it can appear within a function. The "holds" assumption could (theoretically) be mapped onto the existing builtin "__builtin_assume", though the latter applies to a single point in the program, and the former to a range (i.e. the whole of the associated compound statement). This patch fixes sollve's OpenMP 5.1 "omp assume"-based tests.
2024-08-04[clang] Construct SmallVector with ArrayRef (NFC) (#101898)Kazu Hirata1-1/+1
2024-07-30[clang][OpenMP] Rename `varlists` to `varlist`, NFC (#101058)Krzysztof Parzyszek1-27/+27
It returns a range of variables (via Expr*), not a range of lists.
2024-07-18[C++20] [Modules] Write ODRHash for decls in GMFChuanqi Xu1-8/+3
Previously, we skipped calculating ODRHash for decls in GMF when writing them to .pcm files as an optimization. But actually, it is not true that this will be a pure optimization. Whether or not it is beneficial depends on the use cases. For example, if we're writing a function `a` in module and there are 10 consumers of `a` in other TUs, then the other TUs will pay for the cost to calculate the ODR hash for `a` ten times. Then this optimization doesn't work. However, if all the consumers of the module didn't touch `a`, then we can save the cost to calculate the ODR hash of `a` for 1 times. And the assumption to make it was: generally, the consumers of a module may only consume a small part of the imported module. This is the reason why we tried to load declarations, types and identifiers lazily. Then it looks good to do the similar thing for calculating ODR hashs. It works fine for a long time, until we started to look into the support of modules in clangd. Then we meet multiple issue reports complaining we're calculating ODR hash in the wrong place. To workaround these issue reports, I decided to always write the ODRhash for decls in GMF. In my local test, I only observed less than 1% compile time regression after doing this. So it should be fine.
2024-07-10Revert "[C++20] [Modules] [Itanium ABI] Generate the vtable in the module ↵Chuanqi Xu1-29/+4
unit of dynamic classes (#75912)" This reverts commit 18f3bcbb13ca83d33223b00761d8cddf463e9ffb, 15bb02650e26875c48889053d6a9697444583721 and 99873b35da7ecb905143c8a6b8deca4d4416f1a9. See the post commit message in https://github.com/llvm/llvm-project/pull/75912 to see the reasons.
2024-07-08[clang][modules] Fix use-after-free in header serialization (#96356)Jan Svoboda1-2/+8
With the pruning of unused module map files disabled (`-fno-modules-prune-non-affecting-module-map-files`), `HeaderFileInfo` no longer gets deserialized before `ASTWriter::WriteHeaderSearch()`. This function then interleaves the stores of references to `KnownHeader` with their lazy deserialization. Lazy deserialization may cause reallocation of `ModuleMap::Headers` entries (including its `SmallVector<KnownHeader, 1>` values) thus making previously-stored `ArrayRef<KnownHeader>` dangling. This patch fixes that situation by storing a copy instead.
2024-06-25[C++20] [Modules] [Serialization] Don't reuse type ID and identifier ID from ↵Chuanqi Xu1-0/+24
imported modules To support no-transitive-change model for named modules, we can't reuse type ID and identifier ID from imported modules arbitrarily. Since the theory for no-transitive-change model is, for a user of a named module, the user can only access the indirectly imported decls via the directly imported module. So that it is possible to control what matters to the users when writing the module. And it will be unsafe to do so if the users can reuse the type IDs and identifier IDs from the indirectly imported modules not via the directly imported modules. So in this patch, we don't reuse the type ID and identifier ID in the AST writer to avoid the problematic case.
2024-06-24[Serialization] Register Speical types before register declsChuanqi Xu1-11/+11
We will only regsiter top level types and decls in ASTWriter and we will register the sub types and decls during the process of writing types and decls. So that the ID for the types in the sub level can be different if the writing decl process changes the order of the to-be- emitted type queues. This is not ideal since it causes unnecessary changes especially in no transitive changes model. This patch migrates the issue by regsitering special types before regsitering decls. This make sure that the special types in the 2nd top level can be registered early than the decls. But it might still be problematic if there are more levels in the special types. Luckily we just don't have such special types.
2024-06-22[Serialization] Change input file content hash from size_t to uint64_tFangrui Song1-7/+3
https://reviews.llvm.org/D67249 added content hash (see -fvalidate-ast-input-files-content) using llvm::hash_code (size_t). The hash value is 32-bit on 32-bit systems, which was unintentional. Fix #96379: #96136 switched the hash function to xxh3_64bit but did not update the ContentHash type, leading to mismatch between ASTReader and ASTWriter.
2024-06-21[Serialization] Register identifiers in ahead and don't emit predefined declsChuanqi Xu1-36/+58
See the added test for the motivation example. In that example, we add a new function declaration in `a.cppm` and this is not used in the reduced BMI of `b.cppm`. We expect that the change won't affect the BMI of `b.cppm`. But it is the not the case. There are 2 reason for unexpected result: 1. We would register the interesting identifiers in a pretty late phase. This may cause some some predefined identifier ID change due to we insert other identifiers during emitting decls and types. 2. In `GenerateNameLookup`, we would generate information for predefined decls. This may not be intended. Since every predefined decl doesn't belong to any module. And this patch solves the first issue by registering the identifiers in the very early posititon to make sure the ID won't get affected by the process to emit decls and types. And we solve the second question by filtering predefined decls simply.
2024-06-20[Serialization] Use stable hash functionsFangrui Song1-2/+5
clangSerialization currently uses hash_combine/hash_value from Hashing.h, which are not guaranteed to be deterministic. Replace these uses with xxh3_64bits. Pull Request: https://github.com/llvm/llvm-project/pull/96136
2024-06-21[serialization] No transitive type change (#92511)Chuanqi Xu1-17/+24
Following of https://github.com/llvm/llvm-project/pull/92085. #### motivation The motivation is still cutting of the unnecessary change in the dependency chain. See the above link (recursively) for details. And this will be the last patch of the `no-transitive-*-change` series. If there are any following patches, they might be C++20 Named modules specific to handle special grammars like `ADL` (See the reply in https://discourse.llvm.org/t/rfc-c-20-modules-introduce-thin-bmi-and-decls-hash/74755/53 for example). So they won't affect the whole serialization part as the series patch did. #### example After this patch, finally we are able to cut of unnecessary change of types. For example, ``` //--- m-partA.cppm export module m:partA; //--- m-partA.v1.cppm export module m:partA; namespace NS { class A { public: int getValue() { return 43; } }; } //--- m-partB.cppm export module m:partB; export inline int getB() { return 430; } //--- m.cppm export module m; export import :partA; export import :partB; //--- useBOnly.cppm export module useBOnly; import m; export inline int get() { return getB(); } ``` The BMI of `useBOnly.cppm` is expected to not change if we only add a new class in `m:partA`. This will be pretty useful in practice. #### implementation details The key idea of this patch is similar with the previous patches: extend the 32bits type ID to 64bits so that we can store the module file index in the higher bits. Then the encoding of the type ID is independent on the imported modules. But there are two differences from the previous patches: - TypeID is not completely an index of serialized types. We used the lower 3 bits to store the qualifiers. - TypeID won't take part in any lookup process. So the uses of TypeID is much less than the previous patches. The first difference make we have some more slightly complex bit operations. And the second difference makes the patch much simpler than the previous ones.
2024-06-20[Serialization] No transitive identifier change (#92085)Chuanqi Xu1-19/+37
Following of https://github.com/llvm/llvm-project/pull/92083 The motivation is still cutting of the unnecessary change in the dependency chain. See the above link (recursively) for details. After this patch, (and the above patch), we can already do something pretty interesting. For example, #### Motivation example ``` //--- m-partA.cppm export module m:partA; export inline int getA() { return 43; } export class A { public: int getMem(); }; export template <typename T> class ATempl { public: T getT(); }; //--- m-partA.v1.cppm export module m:partA; export inline int getA() { return 43; } // Now we add a new declaration without introducing a new type. // The consuming module which didn't use m:partA completely is expected to be // not changed. export inline int getA2() { return 88; } export class A { public: int getMem(); // Now we add a new declaration without introducing a new type. // The consuming module which didn't use m:partA completely is expected to be // not changed. int getMem2(); }; export template <typename T> class ATempl { public: T getT(); // Add a new declaration without introducing a new type. T getT2(); }; //--- m-partB.cppm export module m:partB; export inline int getB() { return 430; } //--- m.cppm export module m; export import :partA; export import :partB; //--- useBOnly.cppm export module useBOnly; import m; export inline int get() { return getB(); } ``` In this example, module `m` exports two partitions `:partA` and `:partB`. And a consumer `useBOnly` only consumes the entities from `:partB`. So we don't hope the BMI of `useBOnly` changes if only `:partA` changes. After this patch, we can make it if the change of `:partA` doesn't introduce new types. (And we can get rid of this if we make no-transitive-type-change). As the example shows, when we change the implementation of `:partA` from `m-partA.cppm` to `m-partA.v1.cppm`, we add new function declaration `getA2()` at the global namespace, add a new member function `getMem2()` to class `A` and add a new member function to `getT2()` to class template `ATempl`. And since `:partA` is not used by `useBOnly` completely, the BMI of `useBOnly` won't change after we made above changes. #### Design details Method used in this patch is similar with https://github.com/llvm/llvm-project/pull/92083 and https://github.com/llvm/llvm-project/pull/86912. It extends the 32 bit IdentifierID to 64 bits and use the higher 32 bits to store the module file index. So that the encoding of the identifier won't get affected by other modules. #### Overhead Similar with https://github.com/llvm/llvm-project/pull/92083 and https://github.com/llvm/llvm-project/pull/86912. The change is only expected to increase the size of the on-disk .pcm files and not affect the compile-time performances. And from my experiment, the size of the on-disk change only increase 1%+ and observe no compile-time impacts. #### Future Plans I'll try to do the same thing for type ids. IIRC, it won't change the dependency graph if we add a new type in an unused units. I do think this is a significant win. And this will be a pretty good answer to "why modules are better than headers."
2024-06-20[HeaderSearch] Introduce LazyIdentifierInfoPtr for Controlling Macro in ↵Chuanqi Xu1-3/+4
HeaderFileInfo This patch is helpful to reduce 32 bits for HeaderFileInfo by combining a uint32_t and pointer into a tagged pointer. This is reviewed as part of https://github.com/llvm/llvm-project/pull/92085 and required to be split as a separate commit
2024-06-19[NFC] [Serialization] Unify how LocalDeclID can be createdChuanqi Xu1-6/+6
Now we can create a LocalDeclID directly with an integer without verifying. It may be hard to refactor if we want to change the way we serialize DeclIDs (See https://github.com/llvm/llvm-project/pull/95897). Also it is hard for us to debug if someday someone construct a LocalDeclID with an incorrect value. So in this patch, I tried to unify the way we can construct a LocalDeclID in ASTReader, where we will construct the LocalDeclID from the serialized data. Also, now we can verify the constructed LocalDeclID sooner in the new interface.
2024-06-17[C++20] [Modules] [Itanium ABI] Generate the vtable in the module unit of ↵Chuanqi Xu1-0/+23
dynamic classes (#75912) Close https://github.com/llvm/llvm-project/issues/70585 and reflect https://github.com/itanium-cxx-abi/cxx-abi/issues/170. The significant change of the patch is: for dynamic classes attached to module units, we generate the vtable to the attached module units directly and the key functions for such classes is meaningless.
2024-06-13[Safe Buffers] Serialize unsafe_buffer_usage pragmas (#92031)Ziqing Luo1-0/+7
The commit adds serialization and de-serialization implementations for the stored regions. Basically, the serialized representation of the regions of a PP is a (ordered) sequence of source location encodings. For de-serialization, regions from loaded files are stored by their ASTs. When later one queries if a loaded location L is in an opt-out region, PP looks up the regions of the loaded AST where L is at. (Background if helps: a pair of `#pragma clang unsafe_buffer_usage begin/end` pragmas marks a warning-opt-out region. The begin and end locations (opt-out regions) are stored in preprocessor instances (PP) and will be queried by the `-Wunsafe-buffer-usage` analyzer.) The reported issue at upstream: https://github.com/llvm/llvm-project/issues/90501 rdar://124035402
2024-06-07[serialization] no transitive decl change (#92083)Chuanqi Xu1-6/+1
Following of https://github.com/llvm/llvm-project/pull/86912 The motivation of the patch series is that, for a module interface unit `X`, when the dependent modules of `X` changes, if the changes is not relevant with `X`, we hope the BMI of `X` won't change. For the specific patch, we hope if the changes was about irrelevant declaration changes, we hope the BMI of `X` won't change. **However**, I found the patch itself is not very useful in practice, since the adding or removing declarations, will change the state of identifiers and types in most cases. That said, for the most simple example, ``` // partA.cppm export module m:partA; // partA.v1.cppm export module m:partA; export void a() {} // partB.cppm export module m:partB; export void b() {} // m.cppm export module m; export import :partA; export import :partB; // onlyUseB; export module onlyUseB; import m; export inline void onluUseB() { b(); } ``` the BMI of `onlyUseB` will change after we change the implementation of `partA.cppm` to `partA.v1.cppm`. Since `partA.v1.cppm` introduces new identifiers and types (the function prototype). So in this patch, we have to write the tests as: ``` // partA.cppm export module m:partA; export int getA() { ... } export int getA2(int) { ... } // partA.v1.cppm export module m:partA; export int getA() { ... } export int getA(int) { ... } export int getA2(int) { ... } // partB.cppm export module m:partB; export void b() {} // m.cppm export module m; export import :partA; export import :partB; // onlyUseB; export module onlyUseB; import m; export inline void onluUseB() { b(); } ``` so that the new introduced declaration `int getA(int)` doesn't introduce new identifiers and types, then the BMI of `onlyUseB` can keep unchanged. While it looks not so great, the patch should be the base of the patch to erase the transitive change for identifiers and types since I don't know how can we introduce new types and identifiers without introducing new declarations. Given how tightly the relationship between declarations, types and identifiers, I think we can only reach the ideal state after we made the series for all of the three entties. The design of the patch is similar to https://github.com/llvm/llvm-project/pull/86912, which extends the 32-bit DeclID to 64-bit and use the higher bits to store the module file index and the lower bits to store the Local Decl ID. A slight difference is that we only use 48 bits to store the new DeclID since we try to use the higher 16 bits to store the module ID in the prefix of Decl class. Previously, we use 32 bits to store the module ID and 32 bits to store the DeclID. I don't want to allocate additional space so I tried to make the additional space the same as 64 bits. An potential interesting thing here is about the relationship between the module ID and the module file index. I feel we can get the module file index by the module ID. But I didn't prove it or implement it. Since I want to make the patch itself as small as possible. We can make it in the future if we want. Another change in the patch is the new concept Decl Index, which means the index of the very big array `DeclsLoaded` in ASTReader. Previously, the index of a loaded declaration is simply the Decl ID minus PREDEFINED_DECL_NUMs. So there are some places they got used ambiguously. But this patch tried to split these two concepts. As https://github.com/llvm/llvm-project/pull/86912 did, the change will increase the on-disk PCM file sizes. As the declaration ID may be the most IDs in the PCM file, this can have the biggest impact on the size. In my experiments, this change will bring 6.6% increase of the on-disk PCM size. No compile-time performance regression observed. Given the benefits in the motivation example, I think the cost is worthwhile.
2024-06-07Revert "[serialization] no transitive decl change (#92083)"Chuanqi Xu1-1/+6
This reverts commit 5c104879c1a98eeb845c03e7c45206bd48e88f0c. The ArmV7 bot is complaining the change breaks the alignment.
2024-06-07[serialization] no transitive decl change (#92083)Chuanqi Xu1-6/+1
Following of https://github.com/llvm/llvm-project/pull/86912 The motivation of the patch series is that, for a module interface unit `X`, when the dependent modules of `X` changes, if the changes is not relevant with `X`, we hope the BMI of `X` won't change. For the specific patch, we hope if the changes was about irrelevant declaration changes, we hope the BMI of `X` won't change. **However**, I found the patch itself is not very useful in practice, since the adding or removing declarations, will change the state of identifiers and types in most cases. That said, for the most simple example, ``` // partA.cppm export module m:partA; // partA.v1.cppm export module m:partA; export void a() {} // partB.cppm export module m:partB; export void b() {} // m.cppm export module m; export import :partA; export import :partB; // onlyUseB; export module onlyUseB; import m; export inline void onluUseB() { b(); } ``` the BMI of `onlyUseB` will change after we change the implementation of `partA.cppm` to `partA.v1.cppm`. Since `partA.v1.cppm` introduces new identifiers and types (the function prototype). So in this patch, we have to write the tests as: ``` // partA.cppm export module m:partA; export int getA() { ... } export int getA2(int) { ... } // partA.v1.cppm export module m:partA; export int getA() { ... } export int getA(int) { ... } export int getA2(int) { ... } // partB.cppm export module m:partB; export void b() {} // m.cppm export module m; export import :partA; export import :partB; // onlyUseB; export module onlyUseB; import m; export inline void onluUseB() { b(); } ``` so that the new introduced declaration `int getA(int)` doesn't introduce new identifiers and types, then the BMI of `onlyUseB` can keep unchanged. While it looks not so great, the patch should be the base of the patch to erase the transitive change for identifiers and types since I don't know how can we introduce new types and identifiers without introducing new declarations. Given how tightly the relationship between declarations, types and identifiers, I think we can only reach the ideal state after we made the series for all of the three entties. The design of the patch is similar to https://github.com/llvm/llvm-project/pull/86912, which extends the 32-bit DeclID to 64-bit and use the higher bits to store the module file index and the lower bits to store the Local Decl ID. A slight difference is that we only use 48 bits to store the new DeclID since we try to use the higher 16 bits to store the module ID in the prefix of Decl class. Previously, we use 32 bits to store the module ID and 32 bits to store the DeclID. I don't want to allocate additional space so I tried to make the additional space the same as 64 bits. An potential interesting thing here is about the relationship between the module ID and the module file index. I feel we can get the module file index by the module ID. But I didn't prove it or implement it. Since I want to make the patch itself as small as possible. We can make it in the future if we want. Another change in the patch is the new concept Decl Index, which means the index of the very big array `DeclsLoaded` in ASTReader. Previously, the index of a loaded declaration is simply the Decl ID minus PREDEFINED_DECL_NUMs. So there are some places they got used ambiguously. But this patch tried to split these two concepts. As https://github.com/llvm/llvm-project/pull/86912 did, the change will increase the on-disk PCM file sizes. As the declaration ID may be the most IDs in the PCM file, this can have the biggest impact on the size. In my experiments, this change will bring 6.6% increase of the on-disk PCM size. No compile-time performance regression observed. Given the benefits in the motivation example, I think the cost is worthwhile.
2024-06-06Revert "[serialization] no transitive decl change (#92083)"Chuanqi Xu1-1/+6
This reverts commit 97c866f6c86456b3316006e6beff47e68a81c00a. This fails on 32bit machines. See https://github.com/llvm/llvm-project/pull/92083
2024-06-06[serialization] no transitive decl change (#92083)Chuanqi Xu1-6/+1
Following of https://github.com/llvm/llvm-project/pull/86912 The motivation of the patch series is that, for a module interface unit `X`, when the dependent modules of `X` changes, if the changes is not relevant with `X`, we hope the BMI of `X` won't change. For the specific patch, we hope if the changes was about irrelevant declaration changes, we hope the BMI of `X` won't change. **However**, I found the patch itself is not very useful in practice, since the adding or removing declarations, will change the state of identifiers and types in most cases. That said, for the most simple example, ``` // partA.cppm export module m:partA; // partA.v1.cppm export module m:partA; export void a() {} // partB.cppm export module m:partB; export void b() {} // m.cppm export module m; export import :partA; export import :partB; // onlyUseB; export module onlyUseB; import m; export inline void onluUseB() { b(); } ``` the BMI of `onlyUseB` will change after we change the implementation of `partA.cppm` to `partA.v1.cppm`. Since `partA.v1.cppm` introduces new identifiers and types (the function prototype). So in this patch, we have to write the tests as: ``` // partA.cppm export module m:partA; export int getA() { ... } export int getA2(int) { ... } // partA.v1.cppm export module m:partA; export int getA() { ... } export int getA(int) { ... } export int getA2(int) { ... } // partB.cppm export module m:partB; export void b() {} // m.cppm export module m; export import :partA; export import :partB; // onlyUseB; export module onlyUseB; import m; export inline void onluUseB() { b(); } ``` so that the new introduced declaration `int getA(int)` doesn't introduce new identifiers and types, then the BMI of `onlyUseB` can keep unchanged. While it looks not so great, the patch should be the base of the patch to erase the transitive change for identifiers and types since I don't know how can we introduce new types and identifiers without introducing new declarations. Given how tightly the relationship between declarations, types and identifiers, I think we can only reach the ideal state after we made the series for all of the three entties. The design of the patch is similar to https://github.com/llvm/llvm-project/pull/86912, which extends the 32-bit DeclID to 64-bit and use the higher bits to store the module file index and the lower bits to store the Local Decl ID. A slight difference is that we only use 48 bits to store the new DeclID since we try to use the higher 16 bits to store the module ID in the prefix of Decl class. Previously, we use 32 bits to store the module ID and 32 bits to store the DeclID. I don't want to allocate additional space so I tried to make the additional space the same as 64 bits. An potential interesting thing here is about the relationship between the module ID and the module file index. I feel we can get the module file index by the module ID. But I didn't prove it or implement it. Since I want to make the patch itself as small as possible. We can make it in the future if we want. Another change in the patch is the new concept Decl Index, which means the index of the very big array `DeclsLoaded` in ASTReader. Previously, the index of a loaded declaration is simply the Decl ID minus PREDEFINED_DECL_NUMs. So there are some places they got used ambiguously. But this patch tried to split these two concepts. As https://github.com/llvm/llvm-project/pull/86912 did, the change will increase the on-disk PCM file sizes. As the declaration ID may be the most IDs in the PCM file, this can have the biggest impact on the size. In my experiments, this change will bring 6.6% increase of the on-disk PCM size. No compile-time performance regression observed. Given the benefits in the motivation example, I think the cost is worthwhile.
2024-06-05[OpenACC] Implement auto/seq/independent clause Sema for 'loop'erichkeane1-3/+6
These three clauses are all quite trivial, as they take no parameters. They are mutually exclusive, and 'seq' has some other exclusives that are implemented here. The ONE thing that isn't implemented is 2.9's restriction (line 2010): 'A loop associated with a 'loop' construct that does not have a 'seq' clause must be written to meet all the following conditions'. Future clauses will require similar work, so it'll be done as a followup.
2024-06-04[NFC] [AST] Introduce Decl::isInAnotherModuleUnit and ↵Chuanqi Xu1-4/+6
Decl::shouldEmitInExternalSource Motivated by the review process in https://github.com/llvm/llvm-project/pull/75912. This can also help to simplify the code slightly.
2024-06-04Revert "[serialization] no transitive decl change (#92083)"Chuanqi Xu1-1/+6
This reverts commit d8ec452db016f359feeec28994f6560b30b49824. This fails on LLDB macOS CI. See https://github.com/llvm/llvm-project/pull/92083 for details.
2024-06-04[NFC] [Serialization] Avoid unnecessary check for if Identifier from ASTChuanqi Xu1-2/+1
Inspired by the review process in https://github.com/llvm/llvm-project/pull/92085. The check `ID >= FirstIdentID` can cover the following check `!II->isFromAST()`.
2024-06-04[serialization] no transitive decl change (#92083)Chuanqi Xu1-6/+1
Following of https://github.com/llvm/llvm-project/pull/86912 The motivation of the patch series is that, for a module interface unit `X`, when the dependent modules of `X` changes, if the changes is not relevant with `X`, we hope the BMI of `X` won't change. For the specific patch, we hope if the changes was about irrelevant declaration changes, we hope the BMI of `X` won't change. **However**, I found the patch itself is not very useful in practice, since the adding or removing declarations, will change the state of identifiers and types in most cases. That said, for the most simple example, ``` // partA.cppm export module m:partA; // partA.v1.cppm export module m:partA; export void a() {} // partB.cppm export module m:partB; export void b() {} // m.cppm export module m; export import :partA; export import :partB; // onlyUseB; export module onlyUseB; import m; export inline void onluUseB() { b(); } ``` the BMI of `onlyUseB` will change after we change the implementation of `partA.cppm` to `partA.v1.cppm`. Since `partA.v1.cppm` introduces new identifiers and types (the function prototype). So in this patch, we have to write the tests as: ``` // partA.cppm export module m:partA; export int getA() { ... } export int getA2(int) { ... } // partA.v1.cppm export module m:partA; export int getA() { ... } export int getA(int) { ... } export int getA2(int) { ... } // partB.cppm export module m:partB; export void b() {} // m.cppm export module m; export import :partA; export import :partB; // onlyUseB; export module onlyUseB; import m; export inline void onluUseB() { b(); } ``` so that the new introduced declaration `int getA(int)` doesn't introduce new identifiers and types, then the BMI of `onlyUseB` can keep unchanged. While it looks not so great, the patch should be the base of the patch to erase the transitive change for identifiers and types since I don't know how can we introduce new types and identifiers without introducing new declarations. Given how tightly the relationship between declarations, types and identifiers, I think we can only reach the ideal state after we made the series for all of the three entties. The design of the patch is similar to https://github.com/llvm/llvm-project/pull/86912, which extends the 32-bit DeclID to 64-bit and use the higher bits to store the module file index and the lower bits to store the Local Decl ID. A slight difference is that we only use 48 bits to store the new DeclID since we try to use the higher 16 bits to store the module ID in the prefix of Decl class. Previously, we use 32 bits to store the module ID and 32 bits to store the DeclID. I don't want to allocate additional space so I tried to make the additional space the same as 64 bits. An potential interesting thing here is about the relationship between the module ID and the module file index. I feel we can get the module file index by the module ID. But I didn't prove it or implement it. Since I want to make the patch itself as small as possible. We can make it in the future if we want. Another change in the patch is the new concept Decl Index, which means the index of the very big array `DeclsLoaded` in ASTReader. Previously, the index of a loaded declaration is simply the Decl ID minus PREDEFINED_DECL_NUMs. So there are some places they got used ambiguously. But this patch tried to split these two concepts. As https://github.com/llvm/llvm-project/pull/86912 did, the change will increase the on-disk PCM file sizes. As the declaration ID may be the most IDs in the PCM file, this can have the biggest impact on the size. In my experiments, this change will bring 6.6% increase of the on-disk PCM size. No compile-time performance regression observed. Given the benefits in the motivation example, I think the cost is worthwhile.
2024-06-03Revert "[serialization] no transitive decl change (#92083)"Chuanqi Xu1-1/+6
This reverts commit ccb73e882b2d727877cfda42a14a6979cfd31f04. It looks like there are some bots complaining about the patch. See the post commit comment in https://github.com/llvm/llvm-project/pull/92083 to track it.
2024-06-03[serialization] no transitive decl change (#92083)Chuanqi Xu1-6/+1
Following of https://github.com/llvm/llvm-project/pull/86912 #### Motivation Example The motivation of the patch series is that, for a module interface unit `X`, when the dependent modules of `X` changes, if the changes is not relevant with `X`, we hope the BMI of `X` won't change. For the specific patch, we hope if the changes was about irrelevant declaration changes, we hope the BMI of `X` won't change. **However**, I found the patch itself is not very useful in practice, since the adding or removing declarations, will change the state of identifiers and types in most cases. That said, for the most simple example, ``` // partA.cppm export module m:partA; // partA.v1.cppm export module m:partA; export void a() {} // partB.cppm export module m:partB; export void b() {} // m.cppm export module m; export import :partA; export import :partB; // onlyUseB; export module onlyUseB; import m; export inline void onluUseB() { b(); } ``` the BMI of `onlyUseB` will change after we change the implementation of `partA.cppm` to `partA.v1.cppm`. Since `partA.v1.cppm` introduces new identifiers and types (the function prototype). So in this patch, we have to write the tests as: ``` // partA.cppm export module m:partA; export int getA() { ... } export int getA2(int) { ... } // partA.v1.cppm export module m:partA; export int getA() { ... } export int getA(int) { ... } export int getA2(int) { ... } // partB.cppm export module m:partB; export void b() {} // m.cppm export module m; export import :partA; export import :partB; // onlyUseB; export module onlyUseB; import m; export inline void onluUseB() { b(); } ``` so that the new introduced declaration `int getA(int)` doesn't introduce new identifiers and types, then the BMI of `onlyUseB` can keep unchanged. While it looks not so great, the patch should be the base of the patch to erase the transitive change for identifiers and types since I don't know how can we introduce new types and identifiers without introducing new declarations. Given how tightly the relationship between declarations, types and identifiers, I think we can only reach the ideal state after we made the series for all of the three entties. #### Design details The design of the patch is similar to https://github.com/llvm/llvm-project/pull/86912, which extends the 32-bit DeclID to 64-bit and use the higher bits to store the module file index and the lower bits to store the Local Decl ID. A slight difference is that we only use 48 bits to store the new DeclID since we try to use the higher 16 bits to store the module ID in the prefix of Decl class. Previously, we use 32 bits to store the module ID and 32 bits to store the DeclID. I don't want to allocate additional space so I tried to make the additional space the same as 64 bits. An potential interesting thing here is about the relationship between the module ID and the module file index. I feel we can get the module file index by the module ID. But I didn't prove it or implement it. Since I want to make the patch itself as small as possible. We can make it in the future if we want. Another change in the patch is the new concept Decl Index, which means the index of the very big array `DeclsLoaded` in ASTReader. Previously, the index of a loaded declaration is simply the Decl ID minus PREDEFINED_DECL_NUMs. So there are some places they got used ambiguously. But this patch tried to split these two concepts. #### Overhead As https://github.com/llvm/llvm-project/pull/86912 did, the change will increase the on-disk PCM file sizes. As the declaration ID may be the most IDs in the PCM file, this can have the biggest impact on the size. In my experiments, this change will bring 6.6% increase of the on-disk PCM size. No compile-time performance regression observed. Given the benefits in the motivation example, I think the cost is worthwhile.
2024-06-02Use llvm::less_first (NFC) (#94136)Kazu Hirata1-3/+1
2024-05-28[OpenACC] Correct serialization of certain clause sub-expressionserichkeane1-7/+7
For some reason I was using writeStmtRef when I meant writeStmt, so this corrects that.
2024-05-28[NFC] [Serialization] Emit Name for DECL_EXPORTChuanqi Xu1-0/+1
2024-05-28[C++20] [Modules] Don't record implicitly declarations to BMI by default ↵Chuanqi Xu1-2/+11
(#93459) I found we may insert unused implciit declarations like AArch SVE declarations by default on AArch64 due to we will insert that by default. But it should be completely redundant and this patch tries to remove that.
2024-05-21[OpenACC] Implement 'reduction' sema for compute constructs (#92808)Erich Keane1-1/+7
'reduction' has a few restrictions over normal 'var-list' clauses: 1- On parallel, a num_gangs can only have 1 argument when combined with reduction. These two aren't able to be combined on any other of the compute constructs however. 2- The vars all must be 'numerical data types' types of some sort, or a 'composite of numerical data types'. A list of types is given in the standard as a minimum, so we choose 'isScalar', which covers all of these types and keeps types that are actually numeric. Other compilers don't seem to implement the 'composite of numerical data types', though we do. 3- Because of the above restrictions, member-of-composite is not allowed, so any access via a memberexpr is disallowed. Array-element and sub-arrays (aka array sections) are both permitted, so long as they meet the requirements of #2. This patch implements all of these for compute constructs.
2024-05-20[NFC] Remove unused ASTWriter::getTypeIDChuanqi Xu1-13/+25
As the title suggests, the `ASTWriter:getTypeID` method is not used. This patch removes it.
2024-05-18[clang][NFC] Further improvements to const-correctnessVlad Serebrennikov1-12/+11
2024-05-16[clang] Drop explicit conversions of string literals to StringRef (NFC)Kazu Hirata1-1/+1
We routinely rely on implicit conversions of string literals to StringRef so that we can use operator==(StringRef, StringRef). The LHS here are all known to be of StringRef.
2024-05-13[clang] Introduce `SemaObjC` (#89086)Vlad Serebrennikov1-6/+8
This is continuation of efforts to split `Sema` up, following the example of OpenMP, OpenACC, etc. Context can be found in https://github.com/llvm/llvm-project/pull/82217 and https://github.com/llvm/llvm-project/pull/84184. I split formatting changes into a separate commit to help reviewing the actual changes.
2024-05-13Reapply "[OpenACC] device_type clause Sema for Compute constructs"erichkeane1-2/+13
device_type, also spelled as dtype, specifies the applicability of the clauses following it, and takes a series of identifiers representing the architectures it applies to. As we don't have a source for the valid architectures yet, this patch just accepts all. Semantically, this also limits the list of clauses that can be applied after the device_type, so this implements that as well. This reverts commit 06f04b2e27f2586d3db2204ed4e54f8b78fea74e. This reapplies commit c4a9a374749deb5f2a932a7d4ef9321be1b2ae5d. The build failures were caused by the patch depending on the order of evaluation of arguments to a function. This reapplication separates out the capture of one of the values.
2024-05-13Revert "[OpenACC] device_type clause Sema for Compute constructs"erichkeane1-13/+2
This reverts commit c4a9a374749deb5f2a932a7d4ef9321be1b2ae5d. This and the followup patch keep hitting an assert I wrote on the build bots in a way that isn't clear. Reverting so I can fix it without a rush.
2024-05-13[OpenACC] device_type clause Sema for Compute constructserichkeane1-2/+13
device_type, also spelled as dtype, specifies the applicability of the clauses following it, and takes a series of identifiers representing the architectures it applies to. As we don't have a source for the valid architectures yet, this patch just accepts all. Semantically, this also limits the list of clauses that can be applied after the device_type, so this implements that as well.
2024-05-13[NFC] [Serialization] Merge IdentID with IdentifierIDChuanqi Xu1-9/+9
In ASTBitCodes.h, there are two type alias for the ID type of Identifiers with the same underlying type. It is confusing. This patch tries to merge the `IdentID` to `IdentifierID` to erase such confusion.
2024-05-10[OpenACC][NFC] Fix isa behavior for OpenACC typeserichkeane1-1/+1
I discovered while working on a different patch that I'd not implemented the 'classof' for any of the Clauses, which resulted in 'isa' always returning 'true' for all of the types. This patch goes through all the existing clauses and adds 'classof' such that it will work correctly. Additionally, in doing this, I found a bug where I was doing a cast to the wrong type in the ASTWriter, so this fixes that problem as well.
2024-05-09[OpenACC] 'wait' clause for compute construct semaerichkeane1-1/+17
'wait' takes a few int-exprs (well, a series of async-arguments, but those are effectively just an int-expr), plus a pair of tags. This patch adds the support for this to the AST, and does the appropriate semantic analysis for them.
2024-05-07[OpenACC] Implement 'async' clause sema for compute constructserichkeane1-1/+8
This is a pretty simple clause, it takes an 'async-argument', which effectively needs to be just parsed as an 'int' argument, since it can be an arbitrarly integer at runtime (and negative values are legal for implementation defined values). This patch also cleans up the async-argument parsing, so 'wait' got some minor quality-of-life improvements for parsing (both clause and construct).
2024-05-07[C++20] [Modules] [Reduced BMI] Combine the signature of used modulesChuanqi Xu1-1/+30
into the current module Following of https://github.com/llvm/llvm-project/pull/86912. After https://github.com/llvm/llvm-project/pull/86912, with reduced BMI, the BMI can keep unchange if the dependent modules only changes the implementation (without introduing new decls). However, this is not strictly correct. For example: ``` // a.cppm export module a; export inline int a() { ... } // b.cppm export module b; import a; export inline int b() { return a(); } ``` Since both `a()` and `b()` are inline, we need to make sure the BMI of `b.pcm` will change after the implementation of `a()` changes. We can't get that naturally since we won't record the body of `a()` during the writing process. We can't reuse ODRHash here since ODRHash won't calculate the called function recursively. So ODRHash will be problematic if `a()` calls other inline functions. Probably we can solve this by a new hash mechanism. But the safety and efficiency may a problem too. Here we just combine the hash value of the used modules conservatively.
2024-05-06[OpenACC] Implement 'deviceptr' and 'attach' sema for compute constructserichkeane1-2/+12
These two are very similar to the other 'var-list' variants, except they require that the type of the variable be a pointer. This patch implements that restriction.
2024-05-06Reland "[Modules] No transitive source location change (#86912)"Chuanqi Xu1-8/+35
This relands 6c31104. The patch was reverted due to incorrectly introduced alignment. And the patch was re-commited after fixing the alignment issue. Following off are the original message: This is part of "no transitive change" patch series, "no transitive source location change". I talked this with @Bigcheese in the tokyo's WG21 meeting. The idea comes from @jyknight posted on LLVM discourse. That for: ``` // A.cppm export module A; ... // B.cppm export module B; import A; ... //--- C.cppm export module C; import C; ``` Almost every time A.cppm changes, we need to recompile `B`. Due to we think the source location is significant to the semantics. But it may be good if we can avoid recompiling `C` if the change from `A` wouldn't change the BMI of B. This patch only cares source locations. So let's focus on source location's example. We can see the full example from the attached test. ``` //--- A.cppm export module A; export template <class T> struct C { T func() { return T(43); } }; export int funcA() { return 43; } //--- A.v1.cppm export module A; export template <class T> struct C { T func() { return T(43); } }; export int funcA() { return 43; } //--- B.cppm export module B; import A; export int funcB() { return funcA(); } //--- C.cppm export module C; import A; export void testD() { C<int> c; c.func(); } ``` Here the only difference between `A.cppm` and `A.v1.cppm` is that `A.v1.cppm` has an additional blank line. Then the test shows that two BMI of `B.cppm`, one specified `-fmodule-file=A=A.pcm` and the other specified `-fmodule-file=A=A.v1.pcm`, should have the bit-wise same contents. However, it is a different story for C, since C instantiates templates from A, and the instantiation records the source information from module A, which is different from `A` and `A.v1`, so it is expected that the BMI `C.pcm` and `C.v1.pcm` can and should differ. To fully understand the patch, we need to understand how we encodes source locations and how we serialize and deserialize them. For source locations, we encoded them as: ``` | | | _____ base offset of an imported module | | | |_____ base offset of another imported module | | | | | ___ 0 ``` As the diagram shows, we encode the local (unloaded) source location from 0 to higher bits. And we allocate the space for source locations from the loaded modules from high bits to 0. Then the source locations from the loaded modules will be mapped to our source location space according to the allocated offset. For example, for, ``` // a.cppm export module a; ... // b.cppm export module b; import a; ... ``` Assuming the offset of a source location (let's name the location as `S`) in a.cppm is 45 and we will record the value `45` into the BMI `a.pcm`. Then in b.cppm, when we import a, the source manager will allocate a space for module 'a' (according to the recorded number of source locations) as the base offset of module 'a' in the current source location spaces. Let's assume the allocated base offset as 90 in this example. Then when we want to get the location in the current source location space for `S`, we can get it simply by adding `45` to `90` to `135`. Finally we can get the source location for `S` in module B as `135`. And when we want to write module `b`, we would also write the source location of `S` as `135` directly in the BMI. And to clarify the location `S` comes from module `a`, we also need to record the base offset of module `a`, 90 in the BMI of `b`. Then the problem comes. Since the base offset of module 'a' is computed by the number source locations in module 'a'. In module 'b', the recorded base offset of module 'a' will change every time the number of source locations in module 'a' increase or decrease. In other words, the contents of BMI of B will change every time the number of locations in module 'a' changes. This is pretty sensitive. Almost every change will change the number of locations. So this is the problem this patch want to solve. Let's continue with the existing design to understand what's going on. Another interesting case is: ``` // c.cppm export module c; import whatever; import a; import b; ... ``` In `c.cppm`, when we import `a`, we still need to allocate a base location offset for it, let's say the value becomes to `200` somehow. Then when we reach the location `S` recorded in module `b`, we need to translate it into the current source location space. The solution is quite simple, we can get it by `135 + (200 - 90) = 245`. In another word, the offset of a source location in current module can be computed as `Recorded Offset + Base Offset of the its module file - Recorded Base Offset`. Then we're almost done about how we handle the offset of source locations in serializers. From the abstract level, what we want to do is to remove the hardcoded base offset of imported modules and remain the ability to calculate the source location in a new module unit. To achieve this, we need to be able to find the module file owning a source location from the encoding of the source location. So in this patch, for each source location, we will store the local offset of the location and the module file index. For the above example, in `b.pcm`, the source location of `S` will be recorded as `135` directly. And in the new design, the source location of `S` will be recorded as `<1, 45>`. Here `1` stands for the module file index of `a` in module `b`. And `45` means the offset of `S` to the base offset of module `a`. So the trade-off here is that, to make the BMI more independent, we need to record more abstract information. And I feel it is worthy. The recompilation problem of modules is really annoying and there are still people complaining this. But if we can make this (including stopping other changes transitively), I think this may be a killer feature for modules. And from @Bigcheese , this should be helpful for clang explicit modules too. And the benchmarking side, I tested this patch against https://github.com/alibaba/async_simple/tree/CXX20Modules. No significant change on compilation time. The size of .pcm files becomes to 204M from 200M. I think the trade-off is pretty fair. I didn't use another slot to record the module file index. I tried to use the higher 32 bits of the existing source location encodings to store that information. This design may be safe. Since we use `unsigned` to store source locations but we use uint64_t in serialization. And generally `unsigned` is 32 bit width in most platforms. So it might not be a safe problem. Since all the bits we used to store the module file index is not used before. So the new encodings may be: ``` |-----------------------|-----------------------| | A | B | C | * A: 32 bit. The index of the module file in the module manager + 1. * The +1 here is necessary since we wish 0 stands for the current module file. * B: 31 bit. The offset of the source location to the module file * containing it. * C: The macro bit. We rotate it to the lowest bit so that we can save * some space in case the index of the module file is 0. ``` (The B and C is the existing raw encoding for source locations) Another reason to reuse the same slot of the source location is to reduce the impact of the patch. Since there are a lot of places assuming we can store and get a source location from a slot. And if I tried to add another slot, a lot of codes breaks. I don't feel it is worhty. Another impact of this decision is that, the existing small optimizations for encoding source location may be invalided. The key of the optimization is that we can turn large values into small values then we can use VBR6 format to reduce the size. But if we decided to put the module file index into the higher bits, then maybe it simply doesn't work. An example may be the `SourceLocationSequence` optimization. This will only affect the size of on-disk .pcm files. I don't expect this impact the speed and memory use of compilations. And seeing my small experiments above, I feel this trade off is worthy. The mental model for handling source location offsets is not so complex and I believe we can solve it by adding module file index to each stored source location. For the practical side, since the source location is pretty sensitive, and the patch can pass all the in-tree tests and a small scale projects, I feel it should be correct. I'll continue to work on no transitive decl change and no transitive identifier change (if matters) to achieve the goal to stop the propagation of unnecessary changes. But all of this depends on this patch. Since, clearly, the source locations are the most sensitive thing. --- The release nots and documentation will be added seperately.
2024-05-05[clang][Modules] Make `Module::Requirement` a struct (NFC) (#67900)David Stone1-2/+2
`Module::Requirement` was defined as a `std::pair<std::string, bool>`. This required a comment to explain what the data members mean and makes the usage harder to understand. Replace this with a struct with two members, `FeatureName` and `RequiredState`. --------- Co-authored-by: cor3ntin <corentinjabot@gmail.com>
2024-05-03[OpenACC] Implement copyin, copyout, create clauses for compute constructerichkeane1-3/+27
Like 'copy', these also have alternate names, so this implements that as well. Additionally, these have an optional tag of either 'readonly' or 'zero' depending on the clause. Otherwise, this is a pretty rote implementation of the clause, as there aren't any special rules for it.