summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2015-03-24 21:18:10 +0000
committerChandler Carruth <chandlerc@gmail.com>2015-03-24 21:18:10 +0000
commit885e78cb22dcfd882c1d54082569573cc17de6c7 (patch)
treeb91ca7210bd9295d26c5f98c5073f3c5cf0b2e0a
parentd0aa59f77f3a8db0cabbe796e5d7ed68ae713d22 (diff)
downloadbcm5719-llvm-885e78cb22dcfd882c1d54082569573cc17de6c7.tar.gz
bcm5719-llvm-885e78cb22dcfd882c1d54082569573cc17de6c7.zip
[Modules] Start making explicit modules produce deterministic output.
There are two aspects of non-determinism fixed here, which was the minimum required to cause at least an empty module to be deterministic. First, the random number signature is only inserted into the module when we are building modules implicitly. The use case for these random signatures is to work around the very fact that modules are not deterministic in their output when working with the implicitly built and populated module cache. Eventually this should go away entirely when we're confident that Clang is producing deterministic output. Second, the on-disk hash table is populated based on the order of iteration over a DenseMap. Instead, use a MapVector so that we can walk it in insertion order. I've added a test that an empty module, when built twice, produces the same binary PCM file. llvm-svn: 233115
-rw-r--r--clang/include/clang/Serialization/ASTWriter.h2
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp29
-rw-r--r--clang/test/Modules/Inputs/empty/empty.h1
-rw-r--r--clang/test/Modules/empty.modulemap15
4 files changed, 33 insertions, 14 deletions
diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h
index 678ba687cb8..1d872a8c051 100644
--- a/clang/include/clang/Serialization/ASTWriter.h
+++ b/clang/include/clang/Serialization/ASTWriter.h
@@ -225,7 +225,7 @@ private:
/// The ID numbers for identifiers are consecutive (in order of
/// discovery), starting at 1. An ID of zero refers to a NULL
/// IdentifierInfo.
- llvm::DenseMap<const IdentifierInfo *, serialization::IdentID> IdentifierIDs;
+ llvm::MapVector<const IdentifierInfo *, serialization::IdentID> IdentifierIDs;
/// \brief The first ID number we can use for our own macros.
serialization::MacroID FirstMacroID;
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index cc6e2cff402..5b8d8b7d0e4 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -1160,12 +1160,17 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record,
getClangFullRepositoryVersion());
- // Signature
- Record.clear();
- Record.push_back(getSignature());
- Stream.EmitRecord(SIGNATURE, Record);
-
if (WritingModule) {
+ // For implicit modules we output a signature that we can use to ensure
+ // duplicate module builds don't collide in the cache as their output order
+ // is non-deterministic.
+ // FIXME: Remove this when output is deterministic.
+ if (Context.getLangOpts().ImplicitModules) {
+ Record.clear();
+ Record.push_back(getSignature());
+ Stream.EmitRecord(SIGNATURE, Record);
+ }
+
// Module name
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(MODULE_NAME));
@@ -3507,14 +3512,12 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP,
// Create the on-disk hash table representation. We only store offsets
// for identifiers that appear here for the first time.
IdentifierOffsets.resize(NextIdentID - FirstIdentID);
- for (llvm::DenseMap<const IdentifierInfo *, IdentID>::iterator
- ID = IdentifierIDs.begin(), IDEnd = IdentifierIDs.end();
- ID != IDEnd; ++ID) {
- assert(ID->first && "NULL identifier in identifier table");
- if (!Chain || !ID->first->isFromAST() ||
- ID->first->hasChangedSinceDeserialization())
- Generator.insert(const_cast<IdentifierInfo *>(ID->first), ID->second,
- Trait);
+ for (auto IdentIDPair : IdentifierIDs) {
+ IdentifierInfo *II = const_cast<IdentifierInfo *>(IdentIDPair.first);
+ IdentID ID = IdentIDPair.second;
+ assert(II && "NULL identifier in identifier table");
+ if (!Chain || !II->isFromAST() || II->hasChangedSinceDeserialization())
+ Generator.insert(II, ID, Trait);
}
// Create the on-disk hash table in a buffer.
diff --git a/clang/test/Modules/Inputs/empty/empty.h b/clang/test/Modules/Inputs/empty/empty.h
new file mode 100644
index 00000000000..e26b0ab556c
--- /dev/null
+++ b/clang/test/Modules/Inputs/empty/empty.h
@@ -0,0 +1 @@
+// This file intentionally left empty.
diff --git a/clang/test/Modules/empty.modulemap b/clang/test/Modules/empty.modulemap
new file mode 100644
index 00000000000..ef1d4a80ecf
--- /dev/null
+++ b/clang/test/Modules/empty.modulemap
@@ -0,0 +1,15 @@
+// RUN: rm -rf %t
+//
+// RUN: %clang_cc1 -fmodules -x c++ -fmodules-cache-path=%t \
+// RUN: -fno-implicit-modules -fno-modules-implicit-maps \
+// RUN: -emit-module -fmodule-name=empty -o %t/base.pcm \
+// RUN: %s
+//
+// RUN: %clang_cc1 -fmodules -x c++ -fmodules-cache-path=%t \
+// RUN: -fno-implicit-modules -fno-modules-implicit-maps \
+// RUN: -emit-module -fmodule-name=empty -o %t/check.pcm \
+// RUN: %s
+//
+// RUN: diff %t/base.pcm %t/check.pcm
+
+module empty { header "Inputs/empty.h" export * }
OpenPOWER on IntegriCloud