xref: /freebsd-src/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===--- X86.cpp - X86 Helpers for Tools ------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "X86.h"
100b57cec5SDimitry Andric #include "ToolChains/CommonArgs.h"
110b57cec5SDimitry Andric #include "clang/Driver/Driver.h"
120b57cec5SDimitry Andric #include "clang/Driver/DriverDiagnostic.h"
130b57cec5SDimitry Andric #include "clang/Driver/Options.h"
14349cc55cSDimitry Andric #include "llvm/ADT/StringExtras.h"
15349cc55cSDimitry Andric #include "llvm/ADT/StringMap.h"
160b57cec5SDimitry Andric #include "llvm/Option/ArgList.h"
1706c3fb27SDimitry Andric #include "llvm/TargetParser/Host.h"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric using namespace clang::driver;
200b57cec5SDimitry Andric using namespace clang::driver::tools;
210b57cec5SDimitry Andric using namespace clang;
220b57cec5SDimitry Andric using namespace llvm::opt;
230b57cec5SDimitry Andric 
24349cc55cSDimitry Andric std::string x86::getX86TargetCPU(const Driver &D, const ArgList &Args,
250b57cec5SDimitry Andric                                  const llvm::Triple &Triple) {
260b57cec5SDimitry Andric   if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) {
27e8d8bef9SDimitry Andric     StringRef CPU = A->getValue();
28e8d8bef9SDimitry Andric     if (CPU != "native")
29e8d8bef9SDimitry Andric       return std::string(CPU);
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric     // FIXME: Reject attempts to use -march=native unless the target matches
320b57cec5SDimitry Andric     // the host.
33e8d8bef9SDimitry Andric     CPU = llvm::sys::getHostCPUName();
340b57cec5SDimitry Andric     if (!CPU.empty() && CPU != "generic")
35e8d8bef9SDimitry Andric       return std::string(CPU);
360b57cec5SDimitry Andric   }
370b57cec5SDimitry Andric 
38349cc55cSDimitry Andric   if (const Arg *A = Args.getLastArg(options::OPT__SLASH_arch)) {
390b57cec5SDimitry Andric     // Mapping built by looking at lib/Basic's X86TargetInfo::initFeatureMap().
40349cc55cSDimitry Andric     // The keys are case-sensitive; this matches link.exe.
41349cc55cSDimitry Andric     // 32-bit and 64-bit /arch: flags.
42349cc55cSDimitry Andric     llvm::StringMap<StringRef> ArchMap({
43349cc55cSDimitry Andric         {"AVX", "sandybridge"},
44349cc55cSDimitry Andric         {"AVX2", "haswell"},
45349cc55cSDimitry Andric         {"AVX512F", "knl"},
46349cc55cSDimitry Andric         {"AVX512", "skylake-avx512"},
47349cc55cSDimitry Andric     });
48349cc55cSDimitry Andric     if (Triple.getArch() == llvm::Triple::x86) {
49349cc55cSDimitry Andric       // 32-bit-only /arch: flags.
50349cc55cSDimitry Andric       ArchMap.insert({
51349cc55cSDimitry Andric           {"IA32", "i386"},
52349cc55cSDimitry Andric           {"SSE", "pentium3"},
53349cc55cSDimitry Andric           {"SSE2", "pentium4"},
54349cc55cSDimitry Andric       });
550b57cec5SDimitry Andric     }
56349cc55cSDimitry Andric     StringRef CPU = ArchMap.lookup(A->getValue());
57349cc55cSDimitry Andric     if (CPU.empty()) {
58349cc55cSDimitry Andric       std::vector<StringRef> ValidArchs{ArchMap.keys().begin(),
59349cc55cSDimitry Andric                                         ArchMap.keys().end()};
60349cc55cSDimitry Andric       sort(ValidArchs);
61349cc55cSDimitry Andric       D.Diag(diag::warn_drv_invalid_arch_name_with_suggestion)
62349cc55cSDimitry Andric           << A->getValue() << (Triple.getArch() == llvm::Triple::x86)
63349cc55cSDimitry Andric           << join(ValidArchs, ", ");
640b57cec5SDimitry Andric     }
65e8d8bef9SDimitry Andric     return std::string(CPU);
660b57cec5SDimitry Andric   }
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric   // Select the default CPU if none was given (or detection failed).
690b57cec5SDimitry Andric 
70480093f4SDimitry Andric   if (!Triple.isX86())
71e8d8bef9SDimitry Andric     return ""; // This routine is only handling x86 targets.
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   bool Is64Bit = Triple.getArch() == llvm::Triple::x86_64;
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric   // FIXME: Need target hooks.
760b57cec5SDimitry Andric   if (Triple.isOSDarwin()) {
770b57cec5SDimitry Andric     if (Triple.getArchName() == "x86_64h")
780b57cec5SDimitry Andric       return "core-avx2";
790b57cec5SDimitry Andric     // macosx10.12 drops support for all pre-Penryn Macs.
800b57cec5SDimitry Andric     // Simulators can still run on 10.11 though, like Xcode.
810b57cec5SDimitry Andric     if (Triple.isMacOSX() && !Triple.isOSVersionLT(10, 12))
820b57cec5SDimitry Andric       return "penryn";
8381ad6265SDimitry Andric 
8481ad6265SDimitry Andric     if (Triple.isDriverKit())
8581ad6265SDimitry Andric       return "nehalem";
8681ad6265SDimitry Andric 
870b57cec5SDimitry Andric     // The oldest x86_64 Macs have core2/Merom; the oldest x86 Macs have Yonah.
880b57cec5SDimitry Andric     return Is64Bit ? "core2" : "yonah";
890b57cec5SDimitry Andric   }
900b57cec5SDimitry Andric 
9181ad6265SDimitry Andric   // Set up default CPU name for PS4/PS5 compilers.
9281ad6265SDimitry Andric   if (Triple.isPS4())
930b57cec5SDimitry Andric     return "btver2";
9481ad6265SDimitry Andric   if (Triple.isPS5())
9581ad6265SDimitry Andric     return "znver2";
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric   // On Android use targets compatible with gcc
980b57cec5SDimitry Andric   if (Triple.isAndroid())
990b57cec5SDimitry Andric     return Is64Bit ? "x86-64" : "i686";
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   // Everything else goes to x86-64 in 64-bit mode.
1020b57cec5SDimitry Andric   if (Is64Bit)
1030b57cec5SDimitry Andric     return "x86-64";
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric   switch (Triple.getOS()) {
1060b57cec5SDimitry Andric   case llvm::Triple::NetBSD:
1070b57cec5SDimitry Andric     return "i486";
1080b57cec5SDimitry Andric   case llvm::Triple::Haiku:
10975b4d546SDimitry Andric   case llvm::Triple::OpenBSD:
1100b57cec5SDimitry Andric     return "i586";
11175b4d546SDimitry Andric   case llvm::Triple::FreeBSD:
11275b4d546SDimitry Andric     return "i686";
1130b57cec5SDimitry Andric   default:
1140b57cec5SDimitry Andric     // Fallback to p4.
1150b57cec5SDimitry Andric     return "pentium4";
1160b57cec5SDimitry Andric   }
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
1200b57cec5SDimitry Andric                                const ArgList &Args,
1210b57cec5SDimitry Andric                                std::vector<StringRef> &Features) {
12206c3fb27SDimitry Andric   // Claim and report unsupported -mabi=. Note: we don't support "sysv_abi" or
12306c3fb27SDimitry Andric   // "ms_abi" as default function attributes.
12406c3fb27SDimitry Andric   if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mabi_EQ)) {
12506c3fb27SDimitry Andric     StringRef DefaultAbi = Triple.isOSWindows() ? "ms" : "sysv";
12606c3fb27SDimitry Andric     if (A->getValue() != DefaultAbi)
12706c3fb27SDimitry Andric       D.Diag(diag::err_drv_unsupported_opt_for_target)
12806c3fb27SDimitry Andric           << A->getSpelling() << Triple.getTriple();
12906c3fb27SDimitry Andric   }
13006c3fb27SDimitry Andric 
1310b57cec5SDimitry Andric   // If -march=native, autodetect the feature list.
1320b57cec5SDimitry Andric   if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) {
1330b57cec5SDimitry Andric     if (StringRef(A->getValue()) == "native") {
134*0fca6ea1SDimitry Andric       for (auto &F : llvm::sys::getHostCPUFeatures())
1350b57cec5SDimitry Andric         Features.push_back(
1360b57cec5SDimitry Andric             Args.MakeArgString((F.second ? "+" : "-") + F.first()));
1370b57cec5SDimitry Andric     }
1380b57cec5SDimitry Andric   }
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric   if (Triple.getArchName() == "x86_64h") {
1410b57cec5SDimitry Andric     // x86_64h implies quite a few of the more modern subtarget features
1420b57cec5SDimitry Andric     // for Haswell class CPUs, but not all of them. Opt-out of a few.
1430b57cec5SDimitry Andric     Features.push_back("-rdrnd");
1440b57cec5SDimitry Andric     Features.push_back("-aes");
1450b57cec5SDimitry Andric     Features.push_back("-pclmul");
1460b57cec5SDimitry Andric     Features.push_back("-rtm");
1470b57cec5SDimitry Andric     Features.push_back("-fsgsbase");
1480b57cec5SDimitry Andric   }
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric   const llvm::Triple::ArchType ArchType = Triple.getArch();
1510b57cec5SDimitry Andric   // Add features to be compatible with gcc for Android.
1520b57cec5SDimitry Andric   if (Triple.isAndroid()) {
1530b57cec5SDimitry Andric     if (ArchType == llvm::Triple::x86_64) {
1540b57cec5SDimitry Andric       Features.push_back("+sse4.2");
1550b57cec5SDimitry Andric       Features.push_back("+popcnt");
1560b57cec5SDimitry Andric       Features.push_back("+cx16");
1570b57cec5SDimitry Andric     } else
1580b57cec5SDimitry Andric       Features.push_back("+ssse3");
1590b57cec5SDimitry Andric   }
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric   // Translate the high level `-mretpoline` flag to the specific target feature
1620b57cec5SDimitry Andric   // flags. We also detect if the user asked for retpoline external thunks but
1630b57cec5SDimitry Andric   // failed to ask for retpolines themselves (through any of the different
1640b57cec5SDimitry Andric   // flags). This is a bit hacky but keeps existing usages working. We should
1650b57cec5SDimitry Andric   // consider deprecating this and instead warn if the user requests external
1660b57cec5SDimitry Andric   // retpoline thunks and *doesn't* request some form of retpolines.
1670946e70aSDimitry Andric   auto SpectreOpt = clang::driver::options::ID::OPT_INVALID;
1680b57cec5SDimitry Andric   if (Args.hasArgNoClaim(options::OPT_mretpoline, options::OPT_mno_retpoline,
1690b57cec5SDimitry Andric                          options::OPT_mspeculative_load_hardening,
1700b57cec5SDimitry Andric                          options::OPT_mno_speculative_load_hardening)) {
1710b57cec5SDimitry Andric     if (Args.hasFlag(options::OPT_mretpoline, options::OPT_mno_retpoline,
1720b57cec5SDimitry Andric                      false)) {
1730b57cec5SDimitry Andric       Features.push_back("+retpoline-indirect-calls");
1740b57cec5SDimitry Andric       Features.push_back("+retpoline-indirect-branches");
1750946e70aSDimitry Andric       SpectreOpt = options::OPT_mretpoline;
1760b57cec5SDimitry Andric     } else if (Args.hasFlag(options::OPT_mspeculative_load_hardening,
1770b57cec5SDimitry Andric                             options::OPT_mno_speculative_load_hardening,
1780b57cec5SDimitry Andric                             false)) {
1790b57cec5SDimitry Andric       // On x86, speculative load hardening relies on at least using retpolines
1800b57cec5SDimitry Andric       // for indirect calls.
1810b57cec5SDimitry Andric       Features.push_back("+retpoline-indirect-calls");
1820946e70aSDimitry Andric       SpectreOpt = options::OPT_mspeculative_load_hardening;
1830b57cec5SDimitry Andric     }
1840b57cec5SDimitry Andric   } else if (Args.hasFlag(options::OPT_mretpoline_external_thunk,
1850b57cec5SDimitry Andric                           options::OPT_mno_retpoline_external_thunk, false)) {
1860b57cec5SDimitry Andric     // FIXME: Add a warning about failing to specify `-mretpoline` and
1870b57cec5SDimitry Andric     // eventually switch to an error here.
1880b57cec5SDimitry Andric     Features.push_back("+retpoline-indirect-calls");
1890b57cec5SDimitry Andric     Features.push_back("+retpoline-indirect-branches");
1900946e70aSDimitry Andric     SpectreOpt = options::OPT_mretpoline_external_thunk;
1910946e70aSDimitry Andric   }
1920946e70aSDimitry Andric 
1930946e70aSDimitry Andric   auto LVIOpt = clang::driver::options::ID::OPT_INVALID;
1940946e70aSDimitry Andric   if (Args.hasFlag(options::OPT_mlvi_hardening, options::OPT_mno_lvi_hardening,
1950946e70aSDimitry Andric                    false)) {
1960946e70aSDimitry Andric     Features.push_back("+lvi-load-hardening");
1970946e70aSDimitry Andric     Features.push_back("+lvi-cfi"); // load hardening implies CFI protection
1980946e70aSDimitry Andric     LVIOpt = options::OPT_mlvi_hardening;
1990946e70aSDimitry Andric   } else if (Args.hasFlag(options::OPT_mlvi_cfi, options::OPT_mno_lvi_cfi,
2000946e70aSDimitry Andric                           false)) {
2010946e70aSDimitry Andric     Features.push_back("+lvi-cfi");
2020946e70aSDimitry Andric     LVIOpt = options::OPT_mlvi_cfi;
2030946e70aSDimitry Andric   }
2040946e70aSDimitry Andric 
2055ffd83dbSDimitry Andric   if (Args.hasFlag(options::OPT_m_seses, options::OPT_mno_seses, false)) {
2065ffd83dbSDimitry Andric     if (LVIOpt == options::OPT_mlvi_hardening)
2075ffd83dbSDimitry Andric       D.Diag(diag::err_drv_argument_not_allowed_with)
2085ffd83dbSDimitry Andric           << D.getOpts().getOptionName(options::OPT_mlvi_hardening)
2095ffd83dbSDimitry Andric           << D.getOpts().getOptionName(options::OPT_m_seses);
2105ffd83dbSDimitry Andric 
2115ffd83dbSDimitry Andric     if (SpectreOpt != clang::driver::options::ID::OPT_INVALID)
2125ffd83dbSDimitry Andric       D.Diag(diag::err_drv_argument_not_allowed_with)
2135ffd83dbSDimitry Andric           << D.getOpts().getOptionName(SpectreOpt)
2145ffd83dbSDimitry Andric           << D.getOpts().getOptionName(options::OPT_m_seses);
2155ffd83dbSDimitry Andric 
2165ffd83dbSDimitry Andric     Features.push_back("+seses");
2175ffd83dbSDimitry Andric     if (!Args.hasArg(options::OPT_mno_lvi_cfi)) {
2185ffd83dbSDimitry Andric       Features.push_back("+lvi-cfi");
2195ffd83dbSDimitry Andric       LVIOpt = options::OPT_mlvi_cfi;
2205ffd83dbSDimitry Andric     }
2215ffd83dbSDimitry Andric   }
2225ffd83dbSDimitry Andric 
2230946e70aSDimitry Andric   if (SpectreOpt != clang::driver::options::ID::OPT_INVALID &&
2240946e70aSDimitry Andric       LVIOpt != clang::driver::options::ID::OPT_INVALID) {
2250946e70aSDimitry Andric     D.Diag(diag::err_drv_argument_not_allowed_with)
2260946e70aSDimitry Andric         << D.getOpts().getOptionName(SpectreOpt)
2270946e70aSDimitry Andric         << D.getOpts().getOptionName(LVIOpt);
2280b57cec5SDimitry Andric   }
2290b57cec5SDimitry Andric 
2305f757f3fSDimitry Andric   for (const Arg *A : Args.filtered(options::OPT_m_x86_AVX10_Features_Group)) {
2315f757f3fSDimitry Andric     StringRef Name = A->getOption().getName();
2325f757f3fSDimitry Andric     A->claim();
2335f757f3fSDimitry Andric 
2345f757f3fSDimitry Andric     // Skip over "-m".
2355f757f3fSDimitry Andric     assert(Name.starts_with("m") && "Invalid feature name.");
2365f757f3fSDimitry Andric     Name = Name.substr(1);
2375f757f3fSDimitry Andric 
238647cbc5dSDimitry Andric     bool IsNegative = Name.consume_front("no-");
2395f757f3fSDimitry Andric 
2405f757f3fSDimitry Andric #ifndef NDEBUG
2415f757f3fSDimitry Andric     assert(Name.starts_with("avx10.") && "Invalid AVX10 feature name.");
2425f757f3fSDimitry Andric     StringRef Version, Width;
2435f757f3fSDimitry Andric     std::tie(Version, Width) = Name.substr(6).split('-');
2445f757f3fSDimitry Andric     assert(Version == "1" && "Invalid AVX10 feature name.");
2455f757f3fSDimitry Andric     assert((Width == "256" || Width == "512") && "Invalid AVX10 feature name.");
2465f757f3fSDimitry Andric #endif
2475f757f3fSDimitry Andric 
2485f757f3fSDimitry Andric     Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
2495f757f3fSDimitry Andric   }
2505f757f3fSDimitry Andric 
2510b57cec5SDimitry Andric   // Now add any that the user explicitly requested on the command line,
2520b57cec5SDimitry Andric   // which may override the defaults.
253fe6060f1SDimitry Andric   for (const Arg *A : Args.filtered(options::OPT_m_x86_Features_Group,
254fe6060f1SDimitry Andric                                     options::OPT_mgeneral_regs_only)) {
255fe6060f1SDimitry Andric     StringRef Name = A->getOption().getName();
256fe6060f1SDimitry Andric     A->claim();
257fe6060f1SDimitry Andric 
258fe6060f1SDimitry Andric     // Skip over "-m".
2595f757f3fSDimitry Andric     assert(Name.starts_with("m") && "Invalid feature name.");
260fe6060f1SDimitry Andric     Name = Name.substr(1);
261fe6060f1SDimitry Andric 
262fe6060f1SDimitry Andric     // Replace -mgeneral-regs-only with -x87, -mmx, -sse
263fe6060f1SDimitry Andric     if (A->getOption().getID() == options::OPT_mgeneral_regs_only) {
264fe6060f1SDimitry Andric       Features.insert(Features.end(), {"-x87", "-mmx", "-sse"});
265fe6060f1SDimitry Andric       continue;
266fe6060f1SDimitry Andric     }
267fe6060f1SDimitry Andric 
2685f757f3fSDimitry Andric     bool IsNegative = Name.starts_with("no-");
2695f757f3fSDimitry Andric     if (A->getOption().matches(options::OPT_mapx_features_EQ) ||
2705f757f3fSDimitry Andric         A->getOption().matches(options::OPT_mno_apx_features_EQ)) {
2715f757f3fSDimitry Andric 
2725f757f3fSDimitry Andric       for (StringRef Value : A->getValues()) {
2735f757f3fSDimitry Andric         if (Value == "egpr" || Value == "push2pop2" || Value == "ppx" ||
274*0fca6ea1SDimitry Andric             Value == "ndd" || Value == "ccmp" || Value == "nf" ||
275*0fca6ea1SDimitry Andric             Value == "cf" || Value == "zu") {
2765f757f3fSDimitry Andric           Features.push_back(
2775f757f3fSDimitry Andric               Args.MakeArgString((IsNegative ? "-" : "+") + Value));
2785f757f3fSDimitry Andric           continue;
2795f757f3fSDimitry Andric         }
2805f757f3fSDimitry Andric         D.Diag(clang::diag::err_drv_unsupported_option_argument)
2815f757f3fSDimitry Andric             << A->getSpelling() << Value;
2825f757f3fSDimitry Andric       }
2835f757f3fSDimitry Andric       continue;
2845f757f3fSDimitry Andric     }
285fe6060f1SDimitry Andric     if (IsNegative)
286fe6060f1SDimitry Andric       Name = Name.substr(3);
287fe6060f1SDimitry Andric     Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
288fe6060f1SDimitry Andric   }
28981ad6265SDimitry Andric 
29081ad6265SDimitry Andric   // Enable/disable straight line speculation hardening.
29181ad6265SDimitry Andric   if (Arg *A = Args.getLastArg(options::OPT_mharden_sls_EQ)) {
29281ad6265SDimitry Andric     StringRef Scope = A->getValue();
29381ad6265SDimitry Andric     if (Scope == "all") {
29481ad6265SDimitry Andric       Features.push_back("+harden-sls-ijmp");
29581ad6265SDimitry Andric       Features.push_back("+harden-sls-ret");
29681ad6265SDimitry Andric     } else if (Scope == "return") {
29781ad6265SDimitry Andric       Features.push_back("+harden-sls-ret");
29881ad6265SDimitry Andric     } else if (Scope == "indirect-jmp") {
29981ad6265SDimitry Andric       Features.push_back("+harden-sls-ijmp");
30081ad6265SDimitry Andric     } else if (Scope != "none") {
30181ad6265SDimitry Andric       D.Diag(diag::err_drv_unsupported_option_argument)
302bdd1243dSDimitry Andric           << A->getSpelling() << Scope;
30381ad6265SDimitry Andric     }
30481ad6265SDimitry Andric   }
3058a4dda33SDimitry Andric 
3068a4dda33SDimitry Andric   // -mno-gather, -mno-scatter support
3078a4dda33SDimitry Andric   if (Args.hasArg(options::OPT_mno_gather))
3088a4dda33SDimitry Andric     Features.push_back("+prefer-no-gather");
3098a4dda33SDimitry Andric   if (Args.hasArg(options::OPT_mno_scatter))
3108a4dda33SDimitry Andric     Features.push_back("+prefer-no-scatter");
311*0fca6ea1SDimitry Andric   if (Args.hasArg(options::OPT_mapx_inline_asm_use_gpr32))
312*0fca6ea1SDimitry Andric     Features.push_back("+inline-asm-use-gpr32");
313*0fca6ea1SDimitry Andric 
314*0fca6ea1SDimitry Andric   // Warn for removed 3dnow support
315*0fca6ea1SDimitry Andric   if (const Arg *A =
316*0fca6ea1SDimitry Andric           Args.getLastArg(options::OPT_m3dnowa, options::OPT_mno_3dnowa,
317*0fca6ea1SDimitry Andric                           options::OPT_mno_3dnow)) {
318*0fca6ea1SDimitry Andric     if (A->getOption().matches(options::OPT_m3dnowa))
319*0fca6ea1SDimitry Andric       D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args);
320*0fca6ea1SDimitry Andric   }
321*0fca6ea1SDimitry Andric   if (const Arg *A =
322*0fca6ea1SDimitry Andric           Args.getLastArg(options::OPT_m3dnow, options::OPT_mno_3dnow)) {
323*0fca6ea1SDimitry Andric     if (A->getOption().matches(options::OPT_m3dnow))
324*0fca6ea1SDimitry Andric       D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args);
325*0fca6ea1SDimitry Andric   }
3260b57cec5SDimitry Andric }
327