aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Frontend/CompilerInvocation.cpp
diff options
context:
space:
mode:
authorAlexandre Rames <arames@apple.com>2021-09-03 11:12:27 -0700
committerAlexandre Rames <arames@apple.com>2021-09-03 11:13:36 -0700
commit655bea4226b401a11164f99c6344e38d8742b8e4 (patch)
tree07fbd0a7320c70d74612e9e3fbcb3a2a790f9430 /clang/lib/Frontend/CompilerInvocation.cpp
parent830c0b9023cd0cf91955900e0d96283e7a8c3711 (diff)
downloadllvm-655bea4226b401a11164f99c6344e38d8742b8e4.zip
llvm-655bea4226b401a11164f99c6344e38d8742b8e4.tar.gz
llvm-655bea4226b401a11164f99c6344e38d8742b8e4.tar.bz2
[modules] Use `HashBuilder` and `MD5` for the module hash.
Per the comments, `hash_code` values "are not stable to save or persist", so are unsuitable for the module hash, which must persist across compilations for the implicit module hashes to match. Note that in practice, today, `hash_code` are stable. But this is an implementation detail, with a clear `FIXME` indicating we should switch to a per-execution seed. The stability of `MD5` also allows modules cross-compilation use-cases. The `size_t` underlying storage for `hash_code` varying across platforms could cause mismatching hashes when cross-compiling from a 64bit target to a 32bit target. Note that native endianness is still used for the hash computation. So hashes will differ between platforms of different endianness. Reviewed By: jansvoboda11 Differential Revision: https://reviews.llvm.org/D102943
Diffstat (limited to 'clang/lib/Frontend/CompilerInvocation.cpp')
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp100
1 files changed, 42 insertions, 58 deletions
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 0da2cb3e..014595c 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -78,6 +78,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/HashBuilder.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -4476,116 +4477,99 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Invocation,
}
std::string CompilerInvocation::getModuleHash() const {
+ // FIXME: Consider using SHA1 instead of MD5.
+ llvm::HashBuilder<llvm::MD5, llvm::support::endianness::native> HBuilder;
+
// Note: For QoI reasons, the things we use as a hash here should all be
// dumped via the -module-info flag.
- using llvm::hash_code;
- using llvm::hash_value;
- using llvm::hash_combine;
- using llvm::hash_combine_range;
// Start the signature with the compiler version.
- // FIXME: We'd rather use something more cryptographically sound than
- // CityHash, but this will do for now.
- hash_code code = hash_value(getClangFullRepositoryVersion());
+ HBuilder.add(getClangFullRepositoryVersion());
// Also include the serialization version, in case LLVM_APPEND_VC_REV is off
// and getClangFullRepositoryVersion() doesn't include git revision.
- code = hash_combine(code, serialization::VERSION_MAJOR,
- serialization::VERSION_MINOR);
+ HBuilder.add(serialization::VERSION_MAJOR, serialization::VERSION_MINOR);
// Extend the signature with the language options
-#define LANGOPT(Name, Bits, Default, Description) \
- code = hash_combine(code, LangOpts->Name);
-#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
- code = hash_combine(code, static_cast<unsigned>(LangOpts->get##Name()));
+#define LANGOPT(Name, Bits, Default, Description) HBuilder.add(LangOpts->Name);
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ HBuilder.add(static_cast<unsigned>(LangOpts->get##Name()));
#define BENIGN_LANGOPT(Name, Bits, Default, Description)
#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
#include "clang/Basic/LangOptions.def"
- for (StringRef Feature : LangOpts->ModuleFeatures)
- code = hash_combine(code, Feature);
+ HBuilder.addRange(LangOpts->ModuleFeatures);
- code = hash_combine(code, LangOpts->ObjCRuntime);
- const auto &BCN = LangOpts->CommentOpts.BlockCommandNames;
- code = hash_combine(code, hash_combine_range(BCN.begin(), BCN.end()));
+ HBuilder.add(LangOpts->ObjCRuntime);
+ HBuilder.addRange(LangOpts->CommentOpts.BlockCommandNames);
// Extend the signature with the target options.
- code = hash_combine(code, TargetOpts->Triple, TargetOpts->CPU,
- TargetOpts->TuneCPU, TargetOpts->ABI);
- for (const auto &FeatureAsWritten : TargetOpts->FeaturesAsWritten)
- code = hash_combine(code, FeatureAsWritten);
+ HBuilder.add(TargetOpts->Triple, TargetOpts->CPU, TargetOpts->TuneCPU,
+ TargetOpts->ABI);
+ HBuilder.addRange(TargetOpts->FeaturesAsWritten);
// Extend the signature with preprocessor options.
const PreprocessorOptions &ppOpts = getPreprocessorOpts();
- const HeaderSearchOptions &hsOpts = getHeaderSearchOpts();
- code = hash_combine(code, ppOpts.UsePredefines, ppOpts.DetailedRecord);
+ HBuilder.add(ppOpts.UsePredefines, ppOpts.DetailedRecord);
- for (const auto &I : getPreprocessorOpts().Macros) {
+ const HeaderSearchOptions &hsOpts = getHeaderSearchOpts();
+ for (const auto &Macro : getPreprocessorOpts().Macros) {
// If we're supposed to ignore this macro for the purposes of modules,
// don't put it into the hash.
if (!hsOpts.ModulesIgnoreMacros.empty()) {
// Check whether we're ignoring this macro.
- StringRef MacroDef = I.first;
+ StringRef MacroDef = Macro.first;
if (hsOpts.ModulesIgnoreMacros.count(
llvm::CachedHashString(MacroDef.split('=').first)))
continue;
}
- code = hash_combine(code, I.first, I.second);
+ HBuilder.add(Macro);
}
// Extend the signature with the sysroot and other header search options.
- code = hash_combine(code, hsOpts.Sysroot,
- hsOpts.ModuleFormat,
- hsOpts.UseDebugInfo,
- hsOpts.UseBuiltinIncludes,
- hsOpts.UseStandardSystemIncludes,
- hsOpts.UseStandardCXXIncludes,
- hsOpts.UseLibcxx,
- hsOpts.ModulesValidateDiagnosticOptions);
- code = hash_combine(code, hsOpts.ResourceDir);
+ HBuilder.add(hsOpts.Sysroot, hsOpts.ModuleFormat, hsOpts.UseDebugInfo,
+ hsOpts.UseBuiltinIncludes, hsOpts.UseStandardSystemIncludes,
+ hsOpts.UseStandardCXXIncludes, hsOpts.UseLibcxx,
+ hsOpts.ModulesValidateDiagnosticOptions);
+ HBuilder.add(hsOpts.ResourceDir);
if (hsOpts.ModulesStrictContextHash) {
- hash_code SHPC = hash_combine_range(hsOpts.SystemHeaderPrefixes.begin(),
- hsOpts.SystemHeaderPrefixes.end());
- hash_code UEC = hash_combine_range(hsOpts.UserEntries.begin(),
- hsOpts.UserEntries.end());
- code = hash_combine(code, hsOpts.SystemHeaderPrefixes.size(), SHPC,
- hsOpts.UserEntries.size(), UEC);
+ HBuilder.addRange(hsOpts.SystemHeaderPrefixes);
+ HBuilder.addRange(hsOpts.UserEntries);
const DiagnosticOptions &diagOpts = getDiagnosticOpts();
- #define DIAGOPT(Name, Bits, Default) \
- code = hash_combine(code, diagOpts.Name);
- #define ENUM_DIAGOPT(Name, Type, Bits, Default) \
- code = hash_combine(code, diagOpts.get##Name());
- #include "clang/Basic/DiagnosticOptions.def"
- #undef DIAGOPT
- #undef ENUM_DIAGOPT
+#define DIAGOPT(Name, Bits, Default) HBuilder.add(diagOpts.Name);
+#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
+ HBuilder.add(diagOpts.get##Name());
+#include "clang/Basic/DiagnosticOptions.def"
+#undef DIAGOPT
+#undef ENUM_DIAGOPT
}
// Extend the signature with the user build path.
- code = hash_combine(code, hsOpts.ModuleUserBuildPath);
+ HBuilder.add(hsOpts.ModuleUserBuildPath);
// Extend the signature with the module file extensions.
- const FrontendOptions &frontendOpts = getFrontendOpts();
- for (const auto &ext : frontendOpts.ModuleFileExtensions) {
- code = ext->hashExtension(code);
- }
+ for (const auto &ext : getFrontendOpts().ModuleFileExtensions)
+ ext->hashExtension(HBuilder);
// When compiling with -gmodules, also hash -fdebug-prefix-map as it
// affects the debug info in the PCM.
if (getCodeGenOpts().DebugTypeExtRefs)
- for (const auto &KeyValue : getCodeGenOpts().DebugPrefixMap)
- code = hash_combine(code, KeyValue.first, KeyValue.second);
+ HBuilder.addRange(getCodeGenOpts().DebugPrefixMap);
// Extend the signature with the enabled sanitizers, if at least one is
// enabled. Sanitizers which cannot affect AST generation aren't hashed.
SanitizerSet SanHash = LangOpts->Sanitize;
SanHash.clear(getPPTransparentSanitizers());
if (!SanHash.empty())
- code = hash_combine(code, SanHash.Mask);
+ HBuilder.add(SanHash.Mask);
- return toString(llvm::APInt(64, code), 36, /*Signed=*/false);
+ llvm::MD5::MD5Result Result;
+ HBuilder.getHasher().final(Result);
+ uint64_t Hash = Result.high() ^ Result.low();
+ return toString(llvm::APInt(64, Hash), 36, /*Signed=*/false);
}
void CompilerInvocation::generateCC1CommandLine(