Serialize TargetOptions into an AST file, and make sure that we keep

target options around so they can be accessed at any point (rather
than keeping them transient).

llvm-svn: 166072
This commit is contained in:
Douglas Gregor 2012-10-16 23:40:58 +00:00
parent 1ee6352788
commit cb177f15e7
13 changed files with 156 additions and 83 deletions

View File

@ -25,9 +25,13 @@ def err_fe_pch_file_modified : Error<
def err_fe_pch_file_overridden : Error<
"file '%0' from the precompiled header has been overridden">;
def warn_pch_target_triple : Error<
"PCH file was compiled for the target '%0' but the current translation "
"unit is being compiled for target '%1'">;
def err_pch_targetopt_mismatch : Error<
"PCH file was compiled for the %0 '%1' but the current translation "
"unit is being compiled for target '%2'">;
def err_pch_targetopt_feature_mismatch : Error<
"%select{AST file|current translation unit}0 was compiled with the target "
"feature'%1' but the %select{current translation unit is|AST file was}0 "
"not">;
def err_pch_langopt_mismatch : Error<"%0 was %select{disabled|enabled}1 in "
"PCH file but is currently %select{disabled|enabled}2">;
def err_pch_langopt_value_mismatch : Error<

View File

@ -23,6 +23,7 @@
#include "llvm/ADT/Triple.h"
#include "llvm/Support/DataTypes.h"
#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/VersionTuple.h"
#include "clang/Basic/Specifiers.h"
#include <cassert>
@ -39,7 +40,6 @@ class LangOptions;
class MacroBuilder;
class SourceLocation;
class SourceManager;
class TargetOptions;
namespace Builtin { struct Info; }
@ -62,7 +62,7 @@ enum TargetCXXABI {
/// \brief Exposes information about the current target.
///
class TargetInfo : public RefCountedBase<TargetInfo> {
TargetOptions *TargetOpts;
llvm::IntrusiveRefCntPtr<TargetOptions> TargetOpts;
llvm::Triple Triple;
protected:
// Target values set by the ctor of the actual target implementation. Default

View File

@ -15,13 +15,14 @@
#ifndef LLVM_CLANG_FRONTEND_TARGETOPTIONS_H
#define LLVM_CLANG_FRONTEND_TARGETOPTIONS_H
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include <string>
#include <vector>
namespace clang {
/// \brief Options for controlling the target.
class TargetOptions {
class TargetOptions : public RefCountedBase<TargetOptions> {
public:
/// If given, the name of the target triple to compile for. If not given the
/// target will be selected to match the host.
@ -40,6 +41,9 @@ public:
/// If given, the version string of the linker in use.
std::string LinkerVersion;
/// \brief The list of target specific features to enable or disable, as written on the command line.
std::vector<std::string> FeaturesAsWritten;
/// The list of target specific features to enable or disable -- this should
/// be a list of strings starting with by '+' or '-'.
std::vector<std::string> Features;

View File

@ -71,8 +71,8 @@ private:
IntrusiveRefCntPtr<TargetInfo> Target;
IntrusiveRefCntPtr<Preprocessor> PP;
IntrusiveRefCntPtr<ASTContext> Ctx;
IntrusiveRefCntPtr<TargetOptions> TargetOpts;
ASTReader *Reader;
TargetOptions TargetOpts;
struct ASTWriterData;
OwningPtr<ASTWriterData> WriterData;
@ -91,13 +91,6 @@ private:
/// LoadFromCommandLine available.
IntrusiveRefCntPtr<CompilerInvocation> Invocation;
/// \brief The set of target features.
///
/// FIXME: each time we reparse, we need to restore the set of target
/// features from this vector, because TargetInfo::CreateTargetInfo()
/// mangles the target options in place. Yuck!
std::vector<std::string> TargetFeatures;
// OnlyLocalDecls - when true, walking this AST should only visit declarations
// that come from the AST itself, not from included precompiled headers.
// FIXME: This is temporary; eventually, CIndex will always do this.

View File

@ -52,6 +52,9 @@ class CompilerInvocationBase : public RefCountedBase<CompilerInvocation> {
protected:
/// Options controlling the language variant.
IntrusiveRefCntPtr<LangOptions> LangOpts;
/// Options controlling the target.
IntrusiveRefCntPtr<TargetOptions> TargetOpts;
public:
CompilerInvocationBase();
@ -59,6 +62,11 @@ public:
LangOptions *getLangOpts() { return LangOpts.getPtr(); }
const LangOptions *getLangOpts() const { return LangOpts.getPtr(); }
TargetOptions &getTargetOpts() { return *TargetOpts.getPtr(); }
const TargetOptions &getTargetOpts() const {
return *TargetOpts.getPtr();
}
};
/// \brief Helper class for holding the data necessary to invoke the compiler.
@ -96,9 +104,6 @@ class CompilerInvocation : public CompilerInvocationBase {
/// Options controlling preprocessed output.
PreprocessorOutputOptions PreprocessorOutputOpts;
/// Options controlling the target.
TargetOptions TargetOpts;
public:
CompilerInvocation() : AnalyzerOpts(new AnalyzerOptions()) {}
@ -199,11 +204,6 @@ public:
return PreprocessorOutputOpts;
}
TargetOptions &getTargetOpts() { return TargetOpts; }
const TargetOptions &getTargetOpts() const {
return TargetOpts;
}
/// @}
};

View File

@ -82,6 +82,7 @@ class ASTStmtReader;
class TypeLocReader;
struct HeaderFileInfo;
class VersionTuple;
class TargetOptions;
struct PCHPredefinesBlock {
/// \brief The file ID for this predefines buffer in a PCH file.
@ -110,11 +111,12 @@ public:
return false;
}
/// \brief Receives the target triple.
/// \brief Receives the target options.
///
/// \returns true to indicate the target triple is invalid or false otherwise.
virtual bool ReadTargetTriple(const serialization::ModuleFile &M,
StringRef Triple) {
/// \returns true to indicate the target options are invalid, or false
/// otherwise.
virtual bool ReadTargetOptions(const serialization::ModuleFile &M,
const TargetOptions &TargetOpts) {
return false;
}
@ -158,8 +160,8 @@ public:
virtual bool ReadLanguageOptions(const serialization::ModuleFile &M,
const LangOptions &LangOpts);
virtual bool ReadTargetTriple(const serialization::ModuleFile &M,
StringRef Triple);
virtual bool ReadTargetOptions(const serialization::ModuleFile &M,
const TargetOptions &TargetOpts);
virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
StringRef OriginalFileName,
std::string &SuggestedPredefines,

View File

@ -4635,8 +4635,10 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
// Apply the user specified deltas.
// First the enables.
for (std::vector<std::string>::const_iterator it = Opts.Features.begin(),
ie = Opts.Features.end(); it != ie; ++it) {
for (std::vector<std::string>::const_iterator
it = Opts.FeaturesAsWritten.begin(),
ie = Opts.FeaturesAsWritten.end();
it != ie; ++it) {
const char *Name = it->c_str();
if (Name[0] != '+')
@ -4650,8 +4652,10 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
}
// Then the disables.
for (std::vector<std::string>::const_iterator it = Opts.Features.begin(),
ie = Opts.Features.end(); it != ie; ++it) {
for (std::vector<std::string>::const_iterator
it = Opts.FeaturesAsWritten.begin(),
ie = Opts.FeaturesAsWritten.end();
it != ie; ++it) {
const char *Name = it->c_str();
if (Name[0] == '+')

View File

@ -503,7 +503,7 @@ class ASTInfoCollector : public ASTReaderListener {
ASTContext &Context;
LangOptions &LangOpt;
HeaderSearch &HSI;
TargetOptions &TargetOpts;
IntrusiveRefCntPtr<TargetOptions> &TargetOpts;
IntrusiveRefCntPtr<TargetInfo> &Target;
std::string &Predefines;
unsigned &Counter;
@ -513,7 +513,8 @@ class ASTInfoCollector : public ASTReaderListener {
bool InitializedLanguage;
public:
ASTInfoCollector(Preprocessor &PP, ASTContext &Context, LangOptions &LangOpt,
HeaderSearch &HSI, TargetOptions &TargetOpts,
HeaderSearch &HSI,
IntrusiveRefCntPtr<TargetOptions> &TargetOpts,
IntrusiveRefCntPtr<TargetInfo> &Target,
std::string &Predefines,
unsigned &Counter)
@ -536,21 +537,18 @@ public:
return false;
}
virtual bool ReadTargetTriple(const serialization::ModuleFile &M,
StringRef Triple) {
virtual bool ReadTargetOptions(const serialization::ModuleFile &M,
const TargetOptions &TargetOpts) {
// If we've already initialized the target, don't do it again.
if (Target)
return false;
assert(M.Kind == serialization::MK_MainFile);
// FIXME: This is broken, we should store the TargetOptions in the AST file.
TargetOpts.ABI = "";
TargetOpts.CXXABI = "";
TargetOpts.CPU = "";
TargetOpts.Features.clear();
TargetOpts.Triple = Triple;
Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(), TargetOpts);
this->TargetOpts = new TargetOptions(TargetOpts);
Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(),
*this->TargetOpts);
updated();
return false;
@ -1098,7 +1096,6 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
Clang->setDiagnostics(&getDiagnostics());
// Create the target instance.
Clang->getTargetOpts().Features = TargetFeatures;
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
Clang->getTargetOpts()));
if (!Clang->hasTarget()) {
@ -1568,7 +1565,6 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
Clang->setDiagnostics(&getDiagnostics());
// Create the target instance.
Clang->getTargetOpts().Features = TargetFeatures;
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
Clang->getTargetOpts()));
if (!Clang->hasTarget()) {
@ -1777,9 +1773,6 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
CI->getFrontendOpts().DisableFree = false;
ProcessWarningOptions(AST->getDiagnostics(), CI->getDiagnosticOpts());
// Save the target features.
AST->TargetFeatures = CI->getTargetOpts().Features;
// Create the compiler instance to use for building the AST.
OwningPtr<CompilerInstance> Clang(new CompilerInstance());
@ -1795,7 +1788,6 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
Clang->setDiagnostics(&AST->getDiagnostics());
// Create the target instance.
Clang->getTargetOpts().Features = AST->TargetFeatures;
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
Clang->getTargetOpts()));
if (!Clang->hasTarget())
@ -1884,9 +1876,6 @@ bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) {
Invocation->getFrontendOpts().DisableFree = false;
ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
// Save the target features.
TargetFeatures = Invocation->getTargetOpts().Features;
llvm::MemoryBuffer *OverrideMainBuffer = 0;
if (PrecompilePreamble) {
PreambleRebuildCounter = 2;
@ -2396,7 +2385,6 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
StoredDiagnostics);
// Create the target instance.
Clang->getTargetOpts().Features = TargetFeatures;
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
Clang->getTargetOpts()));
if (!Clang->hasTarget()) {

View File

@ -35,11 +35,12 @@ using namespace clang;
//===----------------------------------------------------------------------===//
CompilerInvocationBase::CompilerInvocationBase()
: LangOpts(new LangOptions()) {}
: LangOpts(new LangOptions()), TargetOpts(new TargetOptions()) {}
CompilerInvocationBase::CompilerInvocationBase(const CompilerInvocationBase &X)
: RefCountedBase<CompilerInvocation>(),
LangOpts(new LangOptions(*X.getLangOpts())) {}
LangOpts(new LangOptions(*X.getLangOpts())),
TargetOpts(new TargetOptions(X.getTargetOpts())) {}
//===----------------------------------------------------------------------===//
// Utility functions.
@ -927,8 +928,8 @@ static void TargetOptsToArgs(const TargetOptions &Opts,
Res.push_back("-target-linker-version", Opts.LinkerVersion);
if (!Opts.CXXABI.empty())
Res.push_back("-cxx-abi", Opts.CXXABI);
for (unsigned i = 0, e = Opts.Features.size(); i != e; ++i)
Res.push_back("-target-feature", Opts.Features[i]);
for (unsigned i = 0, e = Opts.FeaturesAsWritten.size(); i != e; ++i)
Res.push_back("-target-feature", Opts.FeaturesAsWritten[i]);
}
void CompilerInvocation::toArgs(std::vector<std::string> &Res) const {
@ -2285,7 +2286,7 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) {
Opts.ABI = Args.getLastArgValue(OPT_target_abi);
Opts.CXXABI = Args.getLastArgValue(OPT_cxx_abi);
Opts.CPU = Args.getLastArgValue(OPT_target_cpu);
Opts.Features = Args.getAllArgValues(OPT_target_feature);
Opts.FeaturesAsWritten = Args.getAllArgValues(OPT_target_feature);
Opts.LinkerVersion = Args.getLastArgValue(OPT_target_linker_version);
Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple));
@ -2431,7 +2432,8 @@ std::string CompilerInvocation::getModuleHash() const {
#include "clang/Basic/LangOptions.def"
// Extend the signature with the target triple
llvm::Triple T(TargetOpts.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);

View File

@ -37,6 +37,7 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemStatCache.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/Version.h"
#include "clang/Basic/VersionTuple.h"
#include "llvm/ADT/StringExtras.h"
@ -101,15 +102,68 @@ PCHValidator::ReadLanguageOptions(const ModuleFile &M,
return false;
}
bool PCHValidator::ReadTargetTriple(const ModuleFile &M, StringRef Triple) {
if (Triple == PP.getTargetInfo().getTriple().str())
return false;
bool PCHValidator::ReadTargetOptions(const ModuleFile &M,
const TargetOptions &TargetOpts) {
const TargetOptions &ExistingTargetOpts = PP.getTargetInfo().getTargetOpts();
Reader.Diag(diag::warn_pch_target_triple)
<< Triple << PP.getTargetInfo().getTriple().str();
#define CHECK_TARGET_OPT(Field, Name) \
if (TargetOpts.Field != ExistingTargetOpts.Field) { \
Reader.Diag(diag::err_pch_targetopt_mismatch) \
<< Name << TargetOpts.Field << ExistingTargetOpts.Field; \
return true; \
}
CHECK_TARGET_OPT(Triple, "target");
CHECK_TARGET_OPT(CPU, "target CPU");
CHECK_TARGET_OPT(ABI, "target ABI");
CHECK_TARGET_OPT(CXXABI, "target C++ ABI");
CHECK_TARGET_OPT(LinkerVersion, "target linker version");
#undef CHECK_TARGET_OPT
// Compare feature sets.
SmallVector<StringRef, 4> ExistingFeatures(
ExistingTargetOpts.FeaturesAsWritten.begin(),
ExistingTargetOpts.FeaturesAsWritten.end());
SmallVector<StringRef, 4> ReadFeatures(TargetOpts.FeaturesAsWritten.begin(),
TargetOpts.FeaturesAsWritten.end());
std::sort(ExistingFeatures.begin(), ExistingFeatures.end());
std::sort(ReadFeatures.begin(), ReadFeatures.end());
unsigned ExistingIdx = 0, ExistingN = ExistingFeatures.size();
unsigned ReadIdx = 0, ReadN = ReadFeatures.size();
while (ExistingIdx < ExistingN && ReadIdx < ReadN) {
if (ExistingFeatures[ExistingIdx] == ReadFeatures[ReadIdx]) {
++ExistingIdx;
++ReadIdx;
continue;
}
if (ReadFeatures[ReadIdx] < ExistingFeatures[ExistingIdx]) {
Reader.Diag(diag::err_pch_targetopt_feature_mismatch)
<< false << ReadFeatures[ReadIdx];
return true;
}
Reader.Diag(diag::err_pch_targetopt_feature_mismatch)
<< true << ExistingFeatures[ExistingIdx];
return true;
}
if (ExistingIdx < ExistingN) {
Reader.Diag(diag::err_pch_targetopt_feature_mismatch)
<< true << ExistingFeatures[ExistingIdx];
return true;
}
if (ReadIdx < ReadN) {
Reader.Diag(diag::err_pch_targetopt_feature_mismatch)
<< false << ReadFeatures[ReadIdx];
return true;
}
return false;
}
namespace {
struct EmptyStringRef {
bool operator ()(StringRef r) const { return r.empty(); }
@ -1846,8 +1900,21 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
RelocatablePCH = Record[4];
if (Listener) {
std::string TargetTriple(BlobStart, BlobLen);
if (Listener->ReadTargetTriple(F, TargetTriple))
unsigned Idx = 6;
TargetOptions TargetOpts;
TargetOpts.Triple = ReadString(Record, Idx);
TargetOpts.CPU = ReadString(Record, Idx);
TargetOpts.ABI = ReadString(Record, Idx);
TargetOpts.CXXABI = ReadString(Record, Idx);
TargetOpts.LinkerVersion = ReadString(Record, Idx);
for (unsigned N = Record[Idx++]; N; --N) {
TargetOpts.FeaturesAsWritten.push_back(ReadString(Record, Idx));
}
for (unsigned N = Record[Idx++]; N; --N) {
TargetOpts.Features.push_back(ReadString(Record, Idx));
}
if (Listener->ReadTargetOptions(F, TargetOpts))
return IgnorePCH;
}
break;

View File

@ -35,6 +35,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceManagerInternals.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/Version.h"
#include "clang/Basic/VersionTuple.h"
#include "llvm/ADT/APFloat.h"
@ -984,27 +985,28 @@ void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot,
// Metadata
const TargetInfo &Target = Context.getTargetInfo();
BitCodeAbbrev *MetaAbbrev = new BitCodeAbbrev();
MetaAbbrev->Add(BitCodeAbbrevOp(METADATA));
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // AST major
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // AST minor
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang major
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang minor
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Has errors
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Target triple
unsigned MetaAbbrevCode = Stream.EmitAbbrev(MetaAbbrev);
const TargetOptions &TargetOpts = Target.getTargetOpts();
RecordData Record;
Record.push_back(METADATA);
Record.push_back(VERSION_MAJOR);
Record.push_back(VERSION_MINOR);
Record.push_back(CLANG_VERSION_MAJOR);
Record.push_back(CLANG_VERSION_MINOR);
Record.push_back(!isysroot.empty());
Record.push_back(ASTHasCompilerErrors);
const std::string &Triple = Target.getTriple().getTriple();
Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, Triple);
AddString(TargetOpts.Triple, Record);
AddString(TargetOpts.CPU, Record);
AddString(TargetOpts.ABI, Record);
AddString(TargetOpts.CXXABI, Record);
AddString(TargetOpts.LinkerVersion, Record);
Record.push_back(TargetOpts.FeaturesAsWritten.size());
for (unsigned I = 0, N = TargetOpts.FeaturesAsWritten.size(); I != N; ++I) {
AddString(TargetOpts.FeaturesAsWritten[I], Record);
}
Record.push_back(TargetOpts.Features.size());
for (unsigned I = 0, N = TargetOpts.Features.size(); I != N; ++I) {
AddString(TargetOpts.Features[I], Record);
}
Stream.EmitRecord(METADATA, Record);
if (Chain) {
serialization::ModuleManager &Mgr = Chain->getModuleManager();

View File

@ -0,0 +1,5 @@
// RUN: %clang_cc1 -triple=x86_64-apple-darwin9 -emit-pch -o %t.pch %S/target-options.h
// RUN: not %clang_cc1 -triple=x86_64-unknown-freebsd7.0 -include-pch %t.pch %s -emit-llvm -o - > %t.err 2>&1
// RUN: FileCheck %s < %t.err
// CHECK: for the target

View File

@ -0,0 +1,2 @@
enum { apple_cc = __APPLE_CC__ };