Hash the various compiler version, target, preprocessor, and

header-search options into the module hash. We're just using
ADT/Hashing.hpp for this, which isn't as cryptographically strong as
I'd like, but it'll do. If someone contributes (say) and MD4
implementation, we'd happily switch to that.

llvm-svn: 167397
This commit is contained in:
Douglas Gregor 2012-11-05 19:45:09 +00:00
parent 339d0597d3
commit 7fd0849bc3
1 changed files with 31 additions and 34 deletions

View File

@ -11,6 +11,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/Version.h"
#include "clang/Basic/FileManager.h"
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Options.h"
@ -20,6 +21,7 @@
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/LangStandard.h"
#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
@ -1511,54 +1513,49 @@ llvm::APInt ModuleSignature::getAsInteger() const {
}
std::string CompilerInvocation::getModuleHash() const {
ModuleSignature Signature;
using llvm::hash_code;
using llvm::hash_value;
using llvm::hash_combine;
// Start the signature with the compiler version.
// FIXME: The full version string can be quite long. Omit it from the
// module hash for now to avoid failures where the path name becomes too
// long. An MD5 or similar checksum would work well here.
// Signature.add(getClangFullRepositoryVersion());
// FIXME: We'd rather use something more cryptographically sound that
// CityHash, but this will do for now.
hash_code code = hash_value(getClangFullRepositoryVersion());
// Extend the signature with the language options
#define LANGOPT(Name, Bits, Default, Description) \
Signature.add(LangOpts->Name, Bits);
code = hash_combine(code, LangOpts->Name);
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
Signature.add(static_cast<unsigned>(LangOpts->get##Name()), Bits);
code = hash_combine(code, 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"
// Extend the signature with the target triple
// FIXME: Add target options.
llvm::Triple T(TargetOpts->Triple);
Signature.add((unsigned)T.getArch(), 5);
Signature.add((unsigned)T.getVendor(), 4);
Signature.add((unsigned)T.getOS(), 5);
Signature.add((unsigned)T.getEnvironment(), 4);
// Extend the signature with the target options.
code = hash_combine(code, TargetOpts->Triple, TargetOpts->CPU,
TargetOpts->ABI, TargetOpts->CXXABI,
TargetOpts->LinkerVersion);
for (unsigned i = 0, n = TargetOpts->FeaturesAsWritten.size(); i != n; ++i)
code = hash_combine(code, TargetOpts->FeaturesAsWritten[i]);
// Extend the signature with preprocessor options.
Signature.add(getPreprocessorOpts().UsePredefines, 1);
Signature.add(getPreprocessorOpts().DetailedRecord, 1);
// Hash the preprocessor defines.
// FIXME: This is terrible. Use an MD5 sum of the preprocessor defines.
const PreprocessorOptions &ppOpts = getPreprocessorOpts();
code = hash_combine(code, ppOpts.UsePredefines, ppOpts.DetailedRecord);
std::vector<StringRef> MacroDefs;
for (std::vector<std::pair<std::string, bool/*isUndef*/> >::const_iterator
I = getPreprocessorOpts().Macros.begin(),
IEnd = getPreprocessorOpts().Macros.end();
I != IEnd; ++I) {
if (!I->second)
MacroDefs.push_back(I->first);
code = hash_combine(code, I->first, I->second);
}
llvm::array_pod_sort(MacroDefs.begin(), MacroDefs.end());
unsigned PPHashResult = 0;
for (unsigned I = 0, N = MacroDefs.size(); I != N; ++I)
PPHashResult = llvm::HashString(MacroDefs[I], PPHashResult);
Signature.add(PPHashResult, 32);
// We've generated the signature. Treat it as one large APInt that we'll
// encode in base-36 and return.
Signature.flush();
return Signature.getAsInteger().toString(36, /*Signed=*/false);
// Extend the signature with the sysroot.
const HeaderSearchOptions &hsOpts = getHeaderSearchOpts();
code = hash_combine(code, hsOpts.Sysroot, hsOpts.UseBuiltinIncludes,
hsOpts.UseStandardSystemIncludes,
hsOpts.UseStandardCXXIncludes,
hsOpts.UseLibcxx);
return llvm::APInt(64, code).toString(36, /*Signed=*/false);
}