From: Daniel Dunbar Date: Wed, 6 May 2009 03:16:41 +0000 (+0000) Subject: Improve handling of (X86) target features. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=868bd0aa9281929ef50d2e9a8c82a036906f53f5;p=clang Improve handling of (X86) target features. - This is a WIP... - This adds -march= handling to the driver, and fixes the defaulting of -mcpu on Darwin (which was using the wrong test). Instead of handling -m{sse, ...} in the driver, pass them to clang-cc as -target-feature [+-]name In clang-cc, communicate with the (clang) target to discover the legal features of a target, and the features which are enabled based on -mcpu. This is currently hardcoded just enough to not be a feature regression, we need to get this information from the backend's TableGen information somehow. This is used to construct the full list of features which are being used, which is in turn used to initialize the predefines. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71061 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index 94fa0d4aea..ce54db7581 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -14,6 +14,8 @@ #ifndef LLVM_CLANG_BASIC_TARGETINFO_H #define LLVM_CLANG_BASIC_TARGETINFO_H +// FIXME: Daniel isn't smart enough to use a prototype for this. +#include "llvm/ADT/StringMap.h" #include "llvm/Support/DataTypes.h" #include #include @@ -334,22 +336,16 @@ public: /// options. virtual void getDefaultLangOptions(LangOptions &Opts) {} - /// HandleTargetFeatures - Handle target-specific options like -mattr=+sse2 - /// and friends. An array of arguments is passed in: if they are all valid, - /// this should handle them and return -1. If there is an error, the index of - /// the invalid argument should be returned along with an optional error - /// string. - /// - /// Note that the driver should have already consolidated all the - /// target-feature settings and passed them to us in the -mattr list. The - /// -mattr list is treated by the code generator as a diff against the -mcpu - /// setting, but the driver should pass all enabled options as "+" settings. - /// This means that the target should only look at + settings. - virtual int HandleTargetFeatures(std::string *StrArray, unsigned NumStrs, - std::string &ErrorReason) { - if (NumStrs == 0) - return -1; - return 0; + /// getDefaultFeatures - Get the default set of target features for + /// the \args CPU; this should include all legal feature strings on + /// the target. + virtual void getDefaultFeatures(const std::string &CPU, + llvm::StringMap &Features) { + } + + /// HandleTargetOptions - Perform initialization based on the user + /// configured set of features. + virtual void HandleTargetFeatures(const llvm::StringMap &Features) { } // getRegParmMax - Returns maximal number of args passed in registers. diff --git a/include/clang/Driver/Options.def b/include/clang/Driver/Options.def index 5d35602e5b..cf077be969 100644 --- a/include/clang/Driver/Options.def +++ b/include/clang/Driver/Options.def @@ -108,6 +108,7 @@ OPTION("", g_Group, Group, INVALID, INVALID, "", 0, 0, 0) OPTION("", i_Group, Group, INVALID, INVALID, "", 0, 0, 0) OPTION("", clang_i_Group, Group, i_Group, INVALID, "", 0, 0, 0) OPTION("", m_Group, Group, INVALID, INVALID, "", 0, 0, 0) +OPTION("", m_x86_Features_Group, Group, INVALID, INVALID, "", 0, 0, 0) OPTION("", u_Group, Group, INVALID, INVALID, "", 0, 0, 0) OPTION("", pedantic_Group, Group, INVALID, INVALID, "", 0, 0, 0) @@ -477,41 +478,42 @@ OPTION("-i", i, Joined, i_Group, INVALID, "", 0, 0, 0) OPTION("-keep_private_externs", keep__private__externs, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-l", l, JoinedOrSeparate, INVALID, INVALID, "l", 0, 0, 0) OPTION("-m32", m32, Flag, m_Group, INVALID, "d", 0, 0, 0) -OPTION("-m3dnowa", m3dnowa, Flag, m_Group, INVALID, "", 0, 0, 0) -OPTION("-m3dnow", m3dnow, Flag, m_Group, INVALID, "", 0, 0, 0) +OPTION("-m3dnowa", m3dnowa, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-m3dnow", m3dnow, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) OPTION("-m64", m64, Flag, m_Group, INVALID, "d", 0, 0, 0) +OPTION("-march=", march_EQ, Joined, m_Group, INVALID, "d", 0, 0, 0) OPTION("-mconstant-cfstrings", mconstant_cfstrings, Flag, clang_ignored_m_Group, INVALID, "", 0, 0, 0) OPTION("-mdynamic-no-pic", mdynamic_no_pic, Joined, m_Group, INVALID, "q", 0, 0, 0) OPTION("-mfix-and-continue", mfix_and_continue, Flag, clang_ignored_m_Group, INVALID, "", 0, 0, 0) OPTION("-miphoneos-version-min=", miphoneos_version_min_EQ, Joined, m_Group, INVALID, "", 0, 0, 0) OPTION("-mkernel", mkernel, Flag, m_Group, INVALID, "", 0, 0, 0) OPTION("-mmacosx-version-min=", mmacosx_version_min_EQ, Joined, m_Group, INVALID, "", 0, 0, 0) -OPTION("-mmmx", mmmx, Flag, m_Group, INVALID, "", 0, 0, 0) -OPTION("-mno-3dnowa", mno_3dnowa, Flag, m_Group, INVALID, "", 0, 0, 0) -OPTION("-mno-3dnow", mno_3dnow, Flag, m_Group, INVALID, "", 0, 0, 0) +OPTION("-mmmx", mmmx, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-3dnowa", mno_3dnowa, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-3dnow", mno_3dnow, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) OPTION("-mno-constant-cfstrings", mno_constant_cfstrings, Flag, m_Group, INVALID, "", 0, 0, 0) -OPTION("-mno-mmx", mno_mmx, Flag, m_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-mmx", mno_mmx, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) OPTION("-mno-pascal-strings", mno_pascal_strings, Flag, m_Group, INVALID, "", 0, 0, 0) OPTION("-mno-red-zone", mno_red_zone, Flag, m_Group, INVALID, "", 0, 0, 0) OPTION("-mno-soft-float", mno_soft_float, Flag, m_Group, INVALID, "", 0, 0, 0) -OPTION("-mno-sse2", mno_sse2, Flag, m_Group, INVALID, "", 0, 0, 0) -OPTION("-mno-sse3", mno_sse3, Flag, m_Group, INVALID, "", 0, 0, 0) -OPTION("-mno-sse41", mno_sse41, Flag, m_Group, INVALID, "", 0, 0, 0) -OPTION("-mno-sse42", mno_sse42, Flag, m_Group, INVALID, "", 0, 0, 0) -OPTION("-mno-sse4a", mno_sse4a, Flag, m_Group, INVALID, "", 0, 0, 0) -OPTION("-mno-sse", mno_sse, Flag, m_Group, INVALID, "", 0, 0, 0) -OPTION("-mno-ssse3", mno_ssse3, Flag, m_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-sse2", mno_sse2, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-sse3", mno_sse3, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-sse41", mno_sse41, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-sse42", mno_sse42, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-sse4a", mno_sse4a, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-sse", mno_sse, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mno-ssse3", mno_ssse3, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) OPTION("-mno-warn-nonportable-cfstrings", mno_warn_nonportable_cfstrings, Flag, m_Group, INVALID, "", 0, 0, 0) OPTION("-mpascal-strings", mpascal_strings, Flag, m_Group, INVALID, "", 0, 0, 0) OPTION("-mred-zone", mred_zone, Flag, m_Group, INVALID, "", 0, 0, 0) OPTION("-msoft-float", msoft_float, Flag, m_Group, INVALID, "", 0, 0, 0) -OPTION("-msse2", msse2, Flag, m_Group, INVALID, "", 0, 0, 0) -OPTION("-msse3", msse3, Flag, m_Group, INVALID, "", 0, 0, 0) -OPTION("-msse41", msse41, Flag, m_Group, INVALID, "", 0, 0, 0) -OPTION("-msse42", msse42, Flag, m_Group, INVALID, "", 0, 0, 0) -OPTION("-msse4a", msse4a, Flag, m_Group, INVALID, "", 0, 0, 0) -OPTION("-msse", msse, Flag, m_Group, INVALID, "", 0, 0, 0) -OPTION("-mssse3", mssse3, Flag, m_Group, INVALID, "", 0, 0, 0) +OPTION("-msse2", msse2, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-msse3", msse3, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-msse41", msse41, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-msse42", msse42, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-msse4a", msse4a, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-msse", msse, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) +OPTION("-mssse3", mssse3, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0) OPTION("-mtune=", mtune_EQ, Joined, m_Group, INVALID, "", 0, 0, 0) OPTION("-multi_module", multi__module, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-multiply_defined_unused", multiply__defined__unused, Separate, INVALID, INVALID, "", 0, 0, 0) diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index e0db82d2a8..bb568b149b 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -503,10 +503,7 @@ class X86TargetInfo : public TargetInfo { } SSELevel; public: X86TargetInfo(const std::string& triple) - : TargetInfo(triple), - // FIXME: hard coding to SSE2 for now. This should change to NoMMXSSE so - // that the driver controls this. - SSELevel(SSE2) { + : TargetInfo(triple), SSELevel(NoMMXSSE) { LongDoubleFormat = &llvm::APFloat::x87DoubleExtended; } virtual void getTargetBuiltins(const Builtin::Info *&Records, @@ -536,49 +533,59 @@ public: virtual void getTargetDefines(const LangOptions &Opts, std::vector &Defines) const; - virtual int HandleTargetFeatures(std::string *StrArray, unsigned NumStrs, - std::string &ErrorReason); + virtual void getDefaultFeatures(const std::string &CPU, + llvm::StringMap &Features); + virtual void HandleTargetFeatures(const llvm::StringMap &Features); }; -/// HandleTargetOptions - Handle target-specific options like -msse2 and -/// friends. An array of arguments is passed in: if they are all valid, this -/// should handle them and return -1. If there is an error, the index of the -/// invalid argument should be returned along with an optional error string. -int X86TargetInfo::HandleTargetFeatures(std::string *StrArray, unsigned NumStrs, - std::string &ErrorReason) { - for (unsigned i = 0; i != NumStrs; ++i) { - const std::string &Feature = StrArray[i]; - if (Feature.size() < 2) return i; - // Ignore explicitly disabled features. - if (Feature[0] == '-') continue; - - // Feature strings are of the form "+feature". - if (Feature[0] != '+') return i; - - // The set of supported subtarget features is defined in - // lib/Target/X86/X86.td. Here we recognize and map onto our internal - // state. - if (Feature == "+mmx") - SSELevel = std::max(SSELevel, MMX); - else if (Feature == "+sse") - SSELevel = std::max(SSELevel, SSE1); - else if (Feature == "+sse2") - SSELevel = std::max(SSELevel, SSE2); - else if (Feature == "+sse3") - SSELevel = std::max(SSELevel, SSE3); - else if (Feature == "+ssse3") - SSELevel = std::max(SSELevel, SSSE3); - else if (Feature == "+sse41") - SSELevel = std::max(SSELevel, SSE41); - else if (Feature == "+sse42") - SSELevel = std::max(SSELevel, SSE42); - else if (Feature == "+64bit" || Feature == "+slow-bt-mem") - // Ignore these features. - continue; - else - return i; - } - return -1; +void X86TargetInfo::getDefaultFeatures(const std::string &CPU, + llvm::StringMap &Features) { + // FIXME: This should not be here. + Features["3dnow"] = false; + Features["3dnowa"] = false; + Features["mmx"] = false; + Features["sse"] = false; + Features["sse2"] = false; + Features["sse3"] = false; + Features["ssse3"] = false; + Features["sse41"] = false; + Features["sse42"] = false; + + // LLVM does not currently recognize this. + // Features["sse4a"] = false; + + // FIXME: This *really* should not be here. + + // X86_64 always has SSE2. + if (PointerWidth == 64) + Features["sse2"] = Features["sse"] = Features["mmx"] = true; + + // FIXME: LLVM says core2 has SSSE3, but gcc doesn't define + // __SSSE3__ with it? What else is going on here? + if (CPU == "core2") + Features["ssse3"] = Features["sse3"] = Features["sse2"] = Features["sse"] = + Features["mmx"] = true; + else if (CPU == "pentium4") + Features["sse2"] = Features["sse"] = Features["mmx"] = true; +} + +/// HandleTargetOptions - Perform initialization based on the user +/// configured set of features. +void X86TargetInfo::HandleTargetFeatures(const llvm::StringMap&Features) { + if (Features.lookup("sse42")) + SSELevel = SSE42; + else if (Features.lookup("sse41")) + SSELevel = SSE41; + else if (Features.lookup("ssse3")) + SSELevel = SSSE3; + else if (Features.lookup("sse3")) + SSELevel = SSE3; + else if (Features.lookup("sse2")) + SSELevel = SSE2; + else if (Features.lookup("sse")) + SSELevel = SSE1; + else if (Features.lookup("mmx")) + SSELevel = MMX; } /// X86TargetInfo::getTargetDefines - Return a set of the X86-specific #defines diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 2a959b3c55..a52498dc95 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -31,6 +31,13 @@ using namespace clang::driver; using namespace clang::driver::tools; +static const char *MakeFormattedString(const ArgList &Args, + const llvm::format_object_base &Fmt) { + std::string Str; + llvm::raw_string_ostream(Str) << Fmt; + return Args.MakeArgString(Str.c_str()); +} + void Clang::AddPreprocessingOptions(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs, @@ -318,52 +325,48 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, false)) CmdArgs.push_back("--soft-float"); - // FIXME: Need target hooks. - if (memcmp(getToolChain().getPlatform().c_str(), "darwin", 6) == 0) { - if (getToolChain().getArchName() == "x86_64") - CmdArgs.push_back("--mcpu=core2"); - else if (getToolChain().getArchName() == "i386") - CmdArgs.push_back("--mcpu=yonah"); - } - - // FIXME: Ignores ordering. Also, we need to find a realistic - // solution for this. - static const struct { - options::ID Pos, Neg; - const char *Name; - } FeatureOptions[] = { - { options::OPT_mmmx, options::OPT_mno_mmx, "mmx" }, - { options::OPT_msse, options::OPT_mno_sse, "sse" }, - { options::OPT_msse2, options::OPT_mno_sse2, "sse2" }, - { options::OPT_msse3, options::OPT_mno_sse3, "sse3" }, - { options::OPT_mssse3, options::OPT_mno_ssse3, "ssse3" }, - { options::OPT_msse41, options::OPT_mno_sse41, "sse41" }, - { options::OPT_msse42, options::OPT_mno_sse42, "sse42" }, - { options::OPT_msse4a, options::OPT_mno_sse4a, "sse4a" }, - { options::OPT_m3dnow, options::OPT_mno_3dnow, "3dnow" }, - { options::OPT_m3dnowa, options::OPT_mno_3dnowa, "3dnowa" } - }; - const unsigned NumFeatureOptions = - sizeof(FeatureOptions)/sizeof(FeatureOptions[0]); - - // FIXME: Avoid std::string - std::string Attrs; - for (unsigned i=0; i < NumFeatureOptions; ++i) { - if (Args.hasArg(FeatureOptions[i].Pos)) { - if (!Attrs.empty()) - Attrs += ','; - Attrs += '+'; - Attrs += FeatureOptions[i].Name; - } else if (Args.hasArg(FeatureOptions[i].Neg)) { - if (!Attrs.empty()) - Attrs += ','; - Attrs += '-'; - Attrs += FeatureOptions[i].Name; + // FIXME: Handle -mtune=. + (void) Args.hasArg(options::OPT_mtune_EQ); + + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { + // FIXME: We made need some translation here from the options gcc + // takes to names the LLVM backend understand? + CmdArgs.push_back("-mcpu"); + CmdArgs.push_back(A->getValue(Args)); + } else { + // Select default CPU. + + // FIXME: Need target hooks. + if (memcmp(getToolChain().getOS().c_str(), "darwin", 6) == 0) { + if (getToolChain().getArchName() == "x86_64") + CmdArgs.push_back("--mcpu=core2"); + else if (getToolChain().getArchName() == "i386") + CmdArgs.push_back("--mcpu=pentium4"); } } - if (!Attrs.empty()) { - CmdArgs.push_back("--mattr"); - CmdArgs.push_back(Args.MakeArgString(Attrs.c_str())); + + // FIXME: Use iterator. + for (ArgList::const_iterator + it = Args.begin(), ie = Args.end(); it != ie; ++it) { + const Arg *A = *it; + if (A->getOption().matches(options::OPT_m_x86_Features_Group)) { + const char *Name = A->getOption().getName(); + + // Skip over "-m". + assert(Name[0] == '-' && Name[1] == 'm' && "Invalid feature name."); + Name += 2; + + bool IsNegative = memcmp(Name, "no-", 3) == 0; + if (IsNegative) + Name += 3; + + A->claim(); + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back(MakeFormattedString(Args, + llvm::format("%c%s", + IsNegative ? '-' : '+', + Name))); + } } if (Args.hasFlag(options::OPT_fmath_errno, @@ -1215,13 +1218,6 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, Dest.addCommand(new Command(Exec, CmdArgs)); } -static const char *MakeFormattedString(const ArgList &Args, - const llvm::format_object_base &Fmt) { - std::string Str; - llvm::raw_string_ostream(Str) << Fmt; - return Args.MakeArgString(Str.c_str()); -} - /// Helper routine for seeing if we should use dsymutil; this is a /// gcc compatible hack, we should remove it and use the input /// type information. diff --git a/test/CodeGen/mmintrin-test.c b/test/CodeGen/mmintrin-test.c index 97f3b3b67c..2a9ab56723 100644 --- a/test/CodeGen/mmintrin-test.c +++ b/test/CodeGen/mmintrin-test.c @@ -1,6 +1,6 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm -o %t %s && +// RUN: clang-cc -triple i386-apple-darwin9 -mcpu=pentium4 -emit-llvm -o %t %s && // RUN: grep define %t | count 1 && -// RUN: clang-cc -triple i386-apple-darwin9 -g -emit-llvm -o %t %s && +// RUN: clang-cc -triple i386-apple-darwin9 -mcpu=pentium4 -g -emit-llvm -o %t %s && // RUN: grep define %t | count 1 #include diff --git a/test/Driver/analyze.c b/test/Driver/analyze.c index f82199d356..338c6148c1 100644 --- a/test/Driver/analyze.c +++ b/test/Driver/analyze.c @@ -4,6 +4,6 @@ // RUN: clang -ccc-host-triple i386-apple-darwin9 -### --analyze -o /dev/null %s -msse 2> %t.log && // RUN: grep '"-analyze"' %t.log && // RUN: grep '"--fmath-errno=0"' %t.log && -// RUN: grep '"--mattr" "+sse"' %t.log && +// RUN: grep '"-target-feature" "+sse"' %t.log && // RUN: grep '"-mmacosx-version-min=10.5.0"' %t.log diff --git a/test/Driver/clang-translation.c b/test/Driver/clang-translation.c index 2421bd1f3a..6d523954c7 100644 --- a/test/Driver/clang-translation.c +++ b/test/Driver/clang-translation.c @@ -9,4 +9,8 @@ // RUN: grep '"-Os"' %t.log && // RUN: grep '"-o" .*clang-translation\.c\.out\.tmp\.s' %t.log && // RUN: grep '"--asm-verbose"' %t.log && +// RUN: clang -ccc-host-triple i386-apple-darwin9 -### -S %s -o %t.s 2> %t.log +// RUN: grep '"--mcpu=pentium4"' %t.log && +// RUN: clang -ccc-host-triple x86_64-apple-darwin9 -### -S %s -o %t.s 2> %t.log +// RUN: grep '"--mcpu=core2"' %t.log && // RUN: true diff --git a/test/Sema/carbon-pth.c b/test/Sema/carbon-pth.c index ebc8840545..c956d2a7a1 100644 --- a/test/Sema/carbon-pth.c +++ b/test/Sema/carbon-pth.c @@ -1,6 +1,6 @@ -// RUN: clang-cc -emit-pth -o %t %s && -// RUN: clang-cc -token-cache %t %s && -// RUN: clang-cc -token-cache %t %s -E %s -o /dev/null +// RUN: clang-cc -mcpu=pentium4 -emit-pth -o %t %s && +// RUN: clang-cc -mcpu=pentium4 -token-cache %t %s && +// RUN: clang-cc -mcpu=pentium4 -token-cache %t %s -E %s -o /dev/null #ifdef __APPLE__ #include #endif diff --git a/test/Sema/carbon.c b/test/Sema/carbon.c index 8e6837f125..5eda4385ac 100644 --- a/test/Sema/carbon.c +++ b/test/Sema/carbon.c @@ -1,5 +1,4 @@ -// RUN: clang-cc %s -print-stats && -// RUN: clang-cc %s -disable-free +// RUN: clang-cc -mcpu=pentium4 %s -print-stats #ifdef __APPLE__ #include #endif diff --git a/test/SemaCXX/carbon.cpp b/test/SemaCXX/carbon.cpp index 983a000b2c..0e7570f335 100644 --- a/test/SemaCXX/carbon.cpp +++ b/test/SemaCXX/carbon.cpp @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -fsyntax-only -print-stats +// RUN: clang-cc -mcpu=pentium4 %s -fsyntax-only -print-stats #ifdef __APPLE__ #include #endif diff --git a/test/SemaObjC/cocoa-pth.m b/test/SemaObjC/cocoa-pth.m index 24b0579a24..dc806dfb7c 100644 --- a/test/SemaObjC/cocoa-pth.m +++ b/test/SemaObjC/cocoa-pth.m @@ -1,6 +1,6 @@ -// RUN: clang-cc -emit-pth -o %t %s && -// RUN: clang-cc -token-cache %t %s && -// RUN: clang-cc -token-cache %t %s -E %s -o /dev/null +// RUN: clang-cc -mcpu=pentium4 -emit-pth -o %t %s && +// RUN: clang-cc -mcpu=pentium4 -token-cache %t %s && +// RUN: clang-cc -mcpu=pentium4 -token-cache %t %s -E %s -o /dev/null #ifdef __APPLE__ #include #endif diff --git a/test/SemaObjC/cocoa.m b/test/SemaObjC/cocoa.m index 153c46e103..b73b3c4ccd 100644 --- a/test/SemaObjC/cocoa.m +++ b/test/SemaObjC/cocoa.m @@ -1,5 +1,4 @@ -// RUN: clang-cc %s -print-stats && -// RUN: clang-cc %s -disable-free +// RUN: clang-cc -mcpu=pentium4 %s -print-stats #ifdef __APPLE__ #include #endif diff --git a/test/SemaObjCXX/cocoa.mm b/test/SemaObjCXX/cocoa.mm index dd9684ce06..c061d4e096 100644 --- a/test/SemaObjCXX/cocoa.mm +++ b/test/SemaObjCXX/cocoa.mm @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -print-stats +// RUN: clang-cc -mcpu=pentium4 %s -print-stats #ifdef __APPLE__ #include #endif diff --git a/tools/clang-cc/clang-cc.cpp b/tools/clang-cc/clang-cc.cpp index 17eeac776c..3726f1c738 100644 --- a/tools/clang-cc/clang-cc.cpp +++ b/tools/clang-cc/clang-cc.cpp @@ -50,6 +50,7 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Config/config.h" #include "llvm/Support/CommandLine.h" @@ -663,10 +664,6 @@ NeXTRuntime("fnext-runtime", static llvm::cl::opt Trigraphs("trigraphs", llvm::cl::desc("Process trigraph sequences")); -static llvm::cl::list -TargetFeatures("mattr", llvm::cl::CommaSeparated, - llvm::cl::desc("Target specific attributes (-mattr=help for details)")); - static llvm::cl::opt TemplateDepth("ftemplate-depth", llvm::cl::init(99), llvm::cl::desc("Maximum depth of recursive template " @@ -711,30 +708,14 @@ static llvm::cl::opt StaticDefine("static-define", llvm::cl::desc("Should __STATIC__ be defined")); static void InitializeLanguageStandard(LangOptions &Options, LangKind LK, - TargetInfo *Target) { + TargetInfo *Target, + const llvm::StringMap &Features) { // Allow the target to set the default the langauge options as it sees fit. Target->getDefaultLangOptions(Options); - - // If there are any -mattr options, pass them to the target for validation and - // processing. The driver should have already consolidated all the - // target-feature settings and passed them to us in the -mattr list. The - // -mattr list is treated by the code generator as a diff against the -mcpu - // setting, but the driver should pass all enabled options as "+" settings. - // This means that the target should only look at + settings. - if (!TargetFeatures.empty()) { - std::string ErrorStr; - int Opt = Target->HandleTargetFeatures(&TargetFeatures[0], - TargetFeatures.size(), ErrorStr); - if (Opt != -1) { - if (ErrorStr.empty()) - fprintf(stderr, "invalid feature '%s'\n", - TargetFeatures[Opt].c_str()); - else - fprintf(stderr, "feature '%s': %s\n", - TargetFeatures[Opt].c_str(), ErrorStr.c_str()); - exit(1); - } - } + + // Pass the map of target features to the target for validation and + // processing. + Target->HandleTargetFeatures(Features); if (LangStd == lang_unspecified) { // Based on the base language, pick one. @@ -1429,8 +1410,47 @@ static llvm::cl::opt TargetCPU("mcpu", llvm::cl::desc("Target a specific cpu type (-mcpu=help for details)")); +static llvm::cl::list +TargetFeatures("target-feature", llvm::cl::desc("Target specific attributes")); + +/// ComputeTargetFeatures - Recompute the target feature list to only +/// be the list of things that are enabled, based on the target cpu +/// and feature list. +static void ComputeFeatureMap(TargetInfo *Target, + llvm::StringMap &Features) { + assert(Features.empty() && "invalid map"); + + // Initialize the feature map based on the target. + Target->getDefaultFeatures(TargetCPU, Features); + + // Apply the user specified deltas. + for (llvm::cl::list::iterator it = TargetFeatures.begin(), + ie = TargetFeatures.end(); it != ie; ++it) { + const char *Name = it->c_str(); + + // FIXME: Don't handle errors like this. + if (Name[0] != '-' && Name[0] != '+') { + fprintf(stderr, "error: clang-cc: invalid target feature string: %s\n", + Name); + exit(1); + } + + llvm::StringMap::iterator it = Features.find(Name + 1); + if (it == Features.end()) { + fprintf(stderr, "error: clang-cc: invalid target feature string: %s\n", + Name); + exit(1); + } + + // FIXME: Actually, we need to apply all the features implied by + // this feature. + it->second = (Name[0] == '+'); + } +} + static void InitializeCompileOptions(CompileOptions &Opts, - const LangOptions &LangOpts) { + const LangOptions &LangOpts, + const llvm::StringMap &Features) { Opts.OptimizeSize = OptSize; Opts.DebugInfo = GenerateDebugInfo; if (OptSize) { @@ -1451,8 +1471,15 @@ static void InitializeCompileOptions(CompileOptions &Opts, #endif Opts.CPU = TargetCPU; - Opts.Features.insert(Opts.Features.end(), - TargetFeatures.begin(), TargetFeatures.end()); + Opts.Features.clear(); + for (llvm::StringMap::const_iterator it = Features.begin(), + ie = Features.end(); it != ie; ++it) { + // FIXME: If we are completely confident that we have the right + // set, we only need to pass the minuses. + std::string Name(it->second ? "+" : "-"); + Name += it->first(); + Opts.Features.push_back(Name); + } Opts.NoCommon = NoCommon | LangOpts.CPlusPlus; @@ -1556,6 +1583,7 @@ static void SetUpBuildDumpLog(unsigned argc, char **argv, static ASTConsumer *CreateASTConsumer(const std::string& InFile, Diagnostic& Diag, FileManager& FileMgr, const LangOptions& LangOpts, + const llvm::StringMap& Features, Preprocessor *PP, PreprocessorFactory *PPF) { switch (ProgAction) { @@ -1598,7 +1626,7 @@ static ASTConsumer *CreateASTConsumer(const std::string& InFile, Act = Backend_EmitBC; CompileOptions Opts; - InitializeCompileOptions(Opts, LangOpts); + InitializeCompileOptions(Opts, LangOpts, Features); return CreateBackendConsumer(Act, Diag, LangOpts, Opts, InFile, OutputFile); } @@ -1620,7 +1648,8 @@ static ASTConsumer *CreateASTConsumer(const std::string& InFile, /// ProcessInputFile - Process a single input file with the specified state. /// static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF, - const std::string &InFile, ProgActions PA) { + const std::string &InFile, ProgActions PA, + const llvm::StringMap &Features) { llvm::OwningPtr Consumer; bool ClearSourceMgr = false; FixItRewriter *FixItRewrite = 0; @@ -1630,7 +1659,7 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF, default: Consumer.reset(CreateASTConsumer(InFile, PP.getDiagnostics(), PP.getFileManager(), PP.getLangOptions(), - &PP, &PPF)); + Features, &PP, &PPF)); if (!Consumer) { fprintf(stderr, "Unexpected program action!\n"); @@ -1999,6 +2028,10 @@ int main(int argc, char **argv) { // Create a file manager object to provide access to and cache the filesystem. FileManager FileMgr; + // Compute the feature set, unfortunately this effects the language! + llvm::StringMap Features; + ComputeFeatureMap(Target.get(), Features); + for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) { const std::string &InFile = InputFilenames[i]; @@ -2016,7 +2049,7 @@ int main(int argc, char **argv) { InitializeBaseLanguage(); LangKind LK = GetLanguage(InFile); InitializeLangOptions(LangInfo, LK); - InitializeLanguageStandard(LangInfo, LK, Target.get()); + InitializeLanguageStandard(LangInfo, LK, Target.get(), Features); // Process the -I options and set them in the HeaderInfo. HeaderSearch HeaderInfo(FileMgr); @@ -2041,7 +2074,7 @@ int main(int argc, char **argv) { ((PathDiagnosticClient*)DiagClient.get())->SetPreprocessor(PP.get()); // Process the source file. - ProcessInputFile(*PP, PPFactory, InFile, ProgAction); + ProcessInputFile(*PP, PPFactory, InFile, ProgAction, Features); HeaderInfo.ClearFileInfo(); DiagClient->setLangOptions(0);