diff options
Diffstat (limited to 'lib/Driver')
-rw-r--r-- | lib/Driver/Driver.cpp | 34 | ||||
-rw-r--r-- | lib/Driver/MSVCToolChain.cpp | 9 | ||||
-rw-r--r-- | lib/Driver/SanitizerArgs.cpp | 138 | ||||
-rw-r--r-- | lib/Driver/ToolChain.cpp | 9 | ||||
-rw-r--r-- | lib/Driver/ToolChains.cpp | 186 | ||||
-rw-r--r-- | lib/Driver/ToolChains.h | 39 | ||||
-rw-r--r-- | lib/Driver/Tools.cpp | 359 | ||||
-rw-r--r-- | lib/Driver/Tools.h | 35 | ||||
-rw-r--r-- | lib/Driver/Types.cpp | 2 |
9 files changed, 606 insertions, 205 deletions
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 8cca1de..0f3ebef 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -277,7 +277,8 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { // Add a default value of -mlinker-version=, if one was given and the user // didn't specify one. #if defined(HOST_LINK_VERSION) - if (!Args.hasArg(options::OPT_mlinker_version_EQ)) { + if (!Args.hasArg(options::OPT_mlinker_version_EQ) && + strlen(HOST_LINK_VERSION) > 0) { DAL->AddJoinedArg(0, Opts->getOption(options::OPT_mlinker_version_EQ), HOST_LINK_VERSION); DAL->getLastArg(options::OPT_mlinker_version_EQ)->claim(); @@ -814,9 +815,12 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { return true; } +// Display an action graph human-readably. Action A is the "sink" node +// and latest-occuring action. Traversal is in pre-order, visiting the +// inputs to each action before printing the action itself. static unsigned PrintActions1(const Compilation &C, Action *A, std::map<Action*, unsigned> &Ids) { - if (Ids.count(A)) + if (Ids.count(A)) // A was already visited. return Ids[A]; std::string str; @@ -847,6 +851,8 @@ static unsigned PrintActions1(const Compilation &C, Action *A, return Id; } +// Print the action graphs in a compilation C. +// For example "clang -c file1.c file2.c" is composed of two subgraphs. void Driver::PrintActions(const Compilation &C) const { std::map<Action*, unsigned> Ids; for (ActionList::const_iterator it = C.getActions().begin(), @@ -1356,7 +1362,7 @@ Driver::ConstructPhaseAction(const ToolChain &TC, const ArgList &Args, types::TY_LLVM_BC); } case phases::Backend: { - if (IsUsingLTO(TC, Args)) { + if (IsUsingLTO(Args)) { types::ID Output = Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC; return llvm::make_unique<BackendJobAction>(std::move(Input), Output); @@ -1377,14 +1383,8 @@ Driver::ConstructPhaseAction(const ToolChain &TC, const ArgList &Args, llvm_unreachable("invalid phase in ConstructPhaseAction"); } -bool Driver::IsUsingLTO(const ToolChain &TC, const ArgList &Args) const { - if (TC.getSanitizerArgs().needsLTO()) - return true; - - if (Args.hasFlag(options::OPT_flto, options::OPT_fno_lto, false)) - return true; - - return false; +bool Driver::IsUsingLTO(const ArgList &Args) const { + return Args.hasFlag(options::OPT_flto, options::OPT_fno_lto, false); } void Driver::BuildJobs(Compilation &C) const { @@ -1563,8 +1563,9 @@ void Driver::BuildJobsForAction(Compilation &C, if (Input.getOption().matches(options::OPT_INPUT)) { const char *Name = Input.getValue(); Result = InputInfo(Name, A->getType(), Name); - } else + } else { Result = InputInfo(&Input, A->getType(), ""); + } return; } @@ -1738,7 +1739,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C, // Determine what the derived output name should be. const char *NamedOutput; - if ((JA.getType() == types::TY_Object || JA.getType() == types::TY_LTO_BC) && + if (JA.getType() == types::TY_Object && C.getArgs().hasArg(options::OPT__SLASH_Fo, options::OPT__SLASH_o)) { // The /Fo or /o flag decides the object filename. StringRef Val = C.getArgs().getLastArg(options::OPT__SLASH_Fo, @@ -2099,6 +2100,8 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, TC = new toolchains::Hexagon_TC(*this, Target, Args); else if (Target.getArch() == llvm::Triple::xcore) TC = new toolchains::XCore(*this, Target, Args); + else if (Target.getArch() == llvm::Triple::shave) + TC = new toolchains::SHAVEToolChain(*this, Target, Args); else if (Target.isOSBinFormatELF()) TC = new toolchains::Generic_ELF(*this, Target, Args); else if (Target.isOSBinFormatMachO()) @@ -2112,13 +2115,12 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, } bool Driver::ShouldUseClangCompiler(const JobAction &JA) const { - // Check if user requested no clang, or clang doesn't understand this type (we - // only handle single inputs for now). + // Say "no" if there is not exactly one input of a type clang understands. if (JA.size() != 1 || !types::isAcceptedByClang((*JA.begin())->getType())) return false; - // Otherwise make sure this is an action clang understands. + // And say "no" if this is not a kind of action clang understands. if (!isa<PreprocessJobAction>(JA) && !isa<PrecompileJobAction>(JA) && !isa<CompileJobAction>(JA) && !isa<BackendJobAction>(JA)) return false; diff --git a/lib/Driver/MSVCToolChain.cpp b/lib/Driver/MSVCToolChain.cpp index d824fe4..7216121 100644 --- a/lib/Driver/MSVCToolChain.cpp +++ b/lib/Driver/MSVCToolChain.cpp @@ -522,3 +522,12 @@ MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args, } return Triple.getTriple(); } + +SanitizerMask MSVCToolChain::getSupportedSanitizers() const { + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + Res |= SanitizerKind::Address; + // CFI checks are not implemented for MSVC ABI for now. + Res &= ~SanitizerKind::CFI; + Res &= ~SanitizerKind::CFICastStrict; + return Res; +} diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp index 72530b4..14c3702 100644 --- a/lib/Driver/SanitizerArgs.cpp +++ b/lib/Driver/SanitizerArgs.cpp @@ -25,7 +25,7 @@ using namespace clang::driver; using namespace llvm::opt; enum : SanitizerMask { - NeedsUbsanRt = Undefined | Integer, + NeedsUbsanRt = Undefined | Integer | CFI, NotAllowedWithTrap = Vptr, RequiresPIE = Memory | DataFlow, NeedsUnwindTables = Address | Thread | Memory | DataFlow, @@ -34,6 +34,9 @@ enum : SanitizerMask { Unrecoverable = Address | Unreachable | Return, LegacyFsanitizeRecoverMask = Undefined | Integer, NeedsLTO = CFI, + TrappingSupported = + (Undefined & ~Vptr) | UnsignedIntegerOverflow | LocalBounds | CFI, + TrappingDefault = CFI, }; enum CoverageFeature { @@ -74,27 +77,6 @@ static std::string describeSanitizeArg(const llvm::opt::Arg *A, /// Sanitizers set. static std::string toString(const clang::SanitizerSet &Sanitizers); -static SanitizerMask getToolchainUnsupportedKinds(const ToolChain &TC) { - bool IsFreeBSD = TC.getTriple().getOS() == llvm::Triple::FreeBSD; - bool IsLinux = TC.getTriple().getOS() == llvm::Triple::Linux; - bool IsX86 = TC.getTriple().getArch() == llvm::Triple::x86; - bool IsX86_64 = TC.getTriple().getArch() == llvm::Triple::x86_64; - bool IsMIPS64 = TC.getTriple().getArch() == llvm::Triple::mips64 || - TC.getTriple().getArch() == llvm::Triple::mips64el; - - SanitizerMask Unsupported = 0; - if (!(IsLinux && (IsX86_64 || IsMIPS64))) { - Unsupported |= Memory | DataFlow; - } - if (!((IsLinux || IsFreeBSD) && (IsX86_64 || IsMIPS64))) { - Unsupported |= Thread; - } - if (!(IsLinux && (IsX86 || IsX86_64))) { - Unsupported |= Function; - } - return Unsupported; -} - static bool getDefaultBlacklist(const Driver &D, SanitizerMask Kinds, std::string &BLPath) { const char *BlacklistFile = nullptr; @@ -116,8 +98,62 @@ static bool getDefaultBlacklist(const Driver &D, SanitizerMask Kinds, return false; } +/// Sets group bits for every group that has at least one representative already +/// enabled in \p Kinds. +static SanitizerMask setGroupBits(SanitizerMask Kinds) { +#define SANITIZER(NAME, ID) +#define SANITIZER_GROUP(NAME, ID, ALIAS) \ + if (Kinds & SanitizerKind::ID) \ + Kinds |= SanitizerKind::ID##Group; +#include "clang/Basic/Sanitizers.def" + return Kinds; +} + +static SanitizerMask parseSanitizeTrapArgs(const Driver &D, + const llvm::opt::ArgList &Args) { + SanitizerMask TrapRemove = 0; // During the loop below, the accumulated set of + // sanitizers disabled by the current sanitizer + // argument or any argument after it. + SanitizerMask TrappingKinds = 0; + SanitizerMask TrappingSupportedWithGroups = setGroupBits(TrappingSupported); + + for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend(); + I != E; ++I) { + const auto *Arg = *I; + if (Arg->getOption().matches(options::OPT_fsanitize_trap_EQ)) { + Arg->claim(); + SanitizerMask Add = parseArgValues(D, Arg, true); + Add &= ~TrapRemove; + if (SanitizerMask InvalidValues = Add & ~TrappingSupportedWithGroups) { + SanitizerSet S; + S.Mask = InvalidValues; + D.Diag(diag::err_drv_unsupported_option_argument) << "-fsanitize-trap" + << toString(S); + } + TrappingKinds |= expandSanitizerGroups(Add) & ~TrapRemove; + } else if (Arg->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) { + Arg->claim(); + TrapRemove |= expandSanitizerGroups(parseArgValues(D, Arg, true)); + } else if (Arg->getOption().matches( + options::OPT_fsanitize_undefined_trap_on_error)) { + Arg->claim(); + TrappingKinds |= + expandSanitizerGroups(UndefinedGroup & ~TrapRemove) & ~TrapRemove; + } else if (Arg->getOption().matches( + options::OPT_fno_sanitize_undefined_trap_on_error)) { + Arg->claim(); + TrapRemove |= expandSanitizerGroups(UndefinedGroup); + } + } + + // Apply default trapping behavior. + TrappingKinds |= TrappingDefault & ~TrapRemove; + + return TrappingKinds; +} + bool SanitizerArgs::needsUbsanRt() const { - return !UbsanTrapOnError && (Sanitizers.Mask & NeedsUbsanRt) && + return (Sanitizers.Mask & NeedsUbsanRt & ~TrapSanitizers.Mask) && !Sanitizers.has(Address) && !Sanitizers.has(Memory) && !Sanitizers.has(Thread); @@ -131,19 +167,15 @@ bool SanitizerArgs::needsUnwindTables() const { return Sanitizers.Mask & NeedsUnwindTables; } -bool SanitizerArgs::needsLTO() const { - return Sanitizers.Mask & NeedsLTO; -} - void SanitizerArgs::clear() { Sanitizers.clear(); RecoverableSanitizers.clear(); + TrapSanitizers.clear(); BlacklistFiles.clear(); CoverageFeatures = 0; MsanTrackOrigins = 0; AsanFieldPadding = 0; AsanZeroBaseShadow = false; - UbsanTrapOnError = false; AsanSharedRuntime = false; LinkCXXRuntimes = false; } @@ -162,10 +194,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, SanitizerMask DiagnosedKinds = 0; // All Kinds we have diagnosed up to now. // Used to deduplicate diagnostics. SanitizerMask Kinds = 0; - SanitizerMask NotSupported = getToolchainUnsupportedKinds(TC); + SanitizerMask Supported = setGroupBits(TC.getSupportedSanitizers()); ToolChain::RTTIMode RTTIMode = TC.getRTTIMode(); const Driver &D = TC.getDriver(); + SanitizerMask TrappingKinds = parseSanitizeTrapArgs(D, Args); + SanitizerMask InvalidTrappingKinds = TrappingKinds & NotAllowedWithTrap; + for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend(); I != E; ++I) { const auto *Arg = *I; @@ -180,14 +215,20 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // sanitizers in Add are those which have been explicitly enabled. // Diagnose them. if (SanitizerMask KindsToDiagnose = - Add & NotSupported & ~DiagnosedKinds) { - // Only diagnose the new kinds. + Add & InvalidTrappingKinds & ~DiagnosedKinds) { + std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); + D.Diag(diag::err_drv_argument_not_allowed_with) + << Desc << "-fsanitize-trap=undefined"; + DiagnosedKinds |= KindsToDiagnose; + } + Add &= ~InvalidTrappingKinds; + if (SanitizerMask KindsToDiagnose = Add & ~Supported & ~DiagnosedKinds) { std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); D.Diag(diag::err_drv_unsupported_opt_for_target) << Desc << TC.getTriple().str(); DiagnosedKinds |= KindsToDiagnose; } - Add &= ~NotSupported; + Add &= Supported; // Test for -fno-rtti + explicit -fsanitizer=vptr before expanding groups // so we don't error out if -fno-rtti and -fsanitize=undefined were @@ -216,7 +257,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, Add &= ~AllRemove; // Silently discard any unsupported sanitizers implicitly enabled through // group expansion. - Add &= ~NotSupported; + Add &= ~InvalidTrappingKinds; + Add &= Supported; Kinds |= Add; } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) { @@ -234,22 +276,20 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, Kinds &= ~Vptr; } - // Warn about undefined sanitizer options that require runtime support. - UbsanTrapOnError = - Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error, - options::OPT_fno_sanitize_undefined_trap_on_error, false); - if (UbsanTrapOnError && (Kinds & NotAllowedWithTrap)) { - D.Diag(clang::diag::err_drv_argument_not_allowed_with) - << lastArgumentForMask(D, Args, NotAllowedWithTrap) - << "-fsanitize-undefined-trap-on-error"; - Kinds &= ~NotAllowedWithTrap; + // Check that LTO is enabled if we need it. + if ((Kinds & NeedsLTO) && !D.IsUsingLTO(Args)) { + D.Diag(diag::err_drv_argument_only_allowed_with) + << lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto"; } // Warn about incompatible groups of sanitizers. std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = { std::make_pair(Address, Thread), std::make_pair(Address, Memory), std::make_pair(Thread, Memory), std::make_pair(Leak, Thread), - std::make_pair(Leak, Memory)}; + std::make_pair(Leak, Memory), std::make_pair(KernelAddress, Address), + std::make_pair(KernelAddress, Leak), + std::make_pair(KernelAddress, Thread), + std::make_pair(KernelAddress, Memory)}; for (auto G : IncompatibleGroups) { SanitizerMask Group = G.first; if (Kinds & Group) { @@ -305,6 +345,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, RecoverableKinds &= Kinds; RecoverableKinds &= ~Unrecoverable; + TrappingKinds &= Kinds; + // Setup blacklist files. // Add default blacklist from resource directory. { @@ -460,6 +502,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // Finally, initialize the set of available and recoverable sanitizers. Sanitizers.Mask |= Kinds; RecoverableSanitizers.Mask |= RecoverableKinds; + TrapSanitizers.Mask |= TrappingKinds; } static std::string toString(const clang::SanitizerSet &Sanitizers) { @@ -484,8 +527,9 @@ void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args, CmdArgs.push_back(Args.MakeArgString("-fsanitize-recover=" + toString(RecoverableSanitizers))); - if (UbsanTrapOnError) - CmdArgs.push_back("-fsanitize-undefined-trap-on-error"); + if (!TrapSanitizers.empty()) + CmdArgs.push_back( + Args.MakeArgString("-fsanitize-trap=" + toString(TrapSanitizers))); for (const auto &BLPath : BlacklistFiles) { SmallString<64> BlacklistOpt("-fsanitize-blacklist="); @@ -528,7 +572,9 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, assert((A->getOption().matches(options::OPT_fsanitize_EQ) || A->getOption().matches(options::OPT_fno_sanitize_EQ) || A->getOption().matches(options::OPT_fsanitize_recover_EQ) || - A->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) && + A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) || + A->getOption().matches(options::OPT_fsanitize_trap_EQ) || + A->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) && "Invalid argument in parseArgValues!"); SanitizerMask Kinds = 0; for (int i = 0, n = A->getNumValues(); i != n; ++i) { diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index 82eb854..da020a2 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -481,3 +481,12 @@ bool ToolChain::AddFastMathRuntimeIfAvailable(const ArgList &Args, CmdArgs.push_back(Args.MakeArgString(Path)); return true; } + +SanitizerMask ToolChain::getSupportedSanitizers() const { + // Return sanitizers which don't require runtime support and are not + // platform or architecture-dependent. + using namespace SanitizerKind; + return (Undefined & ~Vptr & ~Function) | CFI | CFICastStrict | + UnsignedIntegerOverflow | LocalBounds; +} + diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 115a16f..987e063 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -42,10 +42,6 @@ using namespace llvm::opt; MachO::MachO(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args) { - getProgramPaths().push_back(getDriver().getInstalledDir()); - if (getDriver().getInstalledDir() != getDriver().Dir) - getProgramPaths().push_back(getDriver().Dir); - // We expect 'as', 'ld', etc. to be adjacent to our install dir. getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) @@ -53,28 +49,8 @@ MachO::MachO(const Driver &D, const llvm::Triple &Triple, } /// Darwin - Darwin tool chain for i386 and x86_64. -Darwin::Darwin(const Driver & D, const llvm::Triple & Triple, - const ArgList & Args) - : MachO(D, Triple, Args), TargetInitialized(false) { - // Compute the initial Darwin version from the triple - unsigned Major, Minor, Micro; - if (!Triple.getMacOSXVersion(Major, Minor, Micro)) - getDriver().Diag(diag::err_drv_invalid_darwin_version) << - Triple.getOSName(); - llvm::raw_string_ostream(MacosxVersionMin) - << Major << '.' << Minor << '.' << Micro; - - // FIXME: DarwinVersion is only used to find GCC's libexec directory. - // It should be removed when we stop supporting that. - DarwinVersion[0] = Minor + 4; - DarwinVersion[1] = Micro; - DarwinVersion[2] = 0; - - // Compute the initial iOS version from the triple - Triple.getiOSVersion(Major, Minor, Micro); - llvm::raw_string_ostream(iOSVersionMin) - << Major << '.' << Minor << '.' << Micro; -} +Darwin::Darwin(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) + : MachO(D, Triple, Args), TargetInitialized(false) {} types::ID MachO::LookupTypeForExtension(const char *Ext) const { types::ID Ty = types::lookupTypeForExtension(Ext); @@ -403,26 +379,10 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, const SanitizerArgs &Sanitize = getSanitizerArgs(); - - if (Sanitize.needsAsanRt()) { - if (!isTargetMacOS() && !isTargetIOSSimulator()) { - // FIXME: Move this check to SanitizerArgs::filterUnsupportedKinds. - getDriver().Diag(diag::err_drv_clang_unsupported_per_platform) - << "-fsanitize=address"; - } else { - AddLinkSanitizerLibArgs(Args, CmdArgs, "asan"); - } - } - - if (Sanitize.needsUbsanRt()) { - if (!isTargetMacOS() && !isTargetIOSSimulator()) { - // FIXME: Move this check to SanitizerArgs::filterUnsupportedKinds. - getDriver().Diag(diag::err_drv_clang_unsupported_per_platform) - << "-fsanitize=undefined"; - } else { - AddLinkSanitizerLibArgs(Args, CmdArgs, "ubsan"); - } - } + if (Sanitize.needsAsanRt()) + AddLinkSanitizerLibArgs(Args, CmdArgs, "asan"); + if (Sanitize.needsUbsanRt()) + AddLinkSanitizerLibArgs(Args, CmdArgs, "ubsan"); // Otherwise link libSystem, then the dynamic runtime library, and finally any // target specific static runtime library. @@ -499,8 +459,8 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { } else if (!OSXVersion && !iOSVersion) { // If no deployment target was specified on the command line, check for // environment defines. - StringRef OSXTarget; - StringRef iOSTarget; + std::string OSXTarget; + std::string iOSTarget; if (char *env = ::getenv("MACOSX_DEPLOYMENT_TARGET")) OSXTarget = env; if (char *env = ::getenv("IPHONEOS_DEPLOYMENT_TARGET")) @@ -519,13 +479,26 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { } } - // If no OSX or iOS target has been specified and we're compiling for armv7, - // go ahead as assume we're targeting iOS. - StringRef MachOArchName = getMachOArchName(Args); - if (OSXTarget.empty() && iOSTarget.empty() && - (MachOArchName == "armv7" || MachOArchName == "armv7s" || - MachOArchName == "arm64")) - iOSTarget = iOSVersionMin; + // If no OSX or iOS target has been specified, try to guess platform + // from arch name and compute the version from the triple. + if (OSXTarget.empty() && iOSTarget.empty()) { + StringRef MachOArchName = getMachOArchName(Args); + unsigned Major, Minor, Micro; + if (MachOArchName == "armv7" || MachOArchName == "armv7s" || + MachOArchName == "arm64") { + getTriple().getiOSVersion(Major, Minor, Micro); + llvm::raw_string_ostream(iOSTarget) << Major << '.' << Minor << '.' + << Micro; + } else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" && + MachOArchName != "armv7em") { + if (!getTriple().getMacOSXVersion(Major, Minor, Micro)) { + getDriver().Diag(diag::err_drv_invalid_darwin_version) + << getTriple().getOSName(); + } + llvm::raw_string_ostream(OSXTarget) << Major << '.' << Minor << '.' + << Micro; + } + } // Allow conflicts among OSX and iOS for historical reasons, but choose the // default platform. @@ -546,12 +519,6 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { const Option O = Opts.getOption(options::OPT_miphoneos_version_min_EQ); iOSVersion = Args.MakeJoinedArg(nullptr, O, iOSTarget); Args.append(iOSVersion); - } else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" && - MachOArchName != "armv7em") { - // Otherwise, assume we are targeting OS X. - const Option O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); - OSXVersion = Args.MakeJoinedArg(nullptr, O, MacosxVersionMin); - Args.append(OSXVersion); } } @@ -1101,6 +1068,18 @@ void Darwin::CheckObjCARC() const { getDriver().Diag(diag::err_arc_unsupported_on_toolchain); } +SanitizerMask Darwin::getSupportedSanitizers() const { + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + if (isTargetMacOS() || isTargetIOSSimulator()) { + // ASan and UBSan are available on Mac OS and on iOS simulator. + Res |= SanitizerKind::Address; + Res |= SanitizerKind::Vptr; + } + if (isTargetMacOS()) + Res |= SanitizerKind::SafeStack; + return Res; +} + /// Generic_GCC - A tool chain using the 'gcc' command to perform /// all subcommands; this relies on gcc translating the majority of /// command line options. @@ -2084,6 +2063,8 @@ bool Generic_GCC::IsIntegratedAssemblerDefault() const { case llvm::Triple::aarch64_be: case llvm::Triple::arm: case llvm::Triple::armeb: + case llvm::Triple::bpfel: + case llvm::Triple::bpfeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: case llvm::Triple::ppc: @@ -2739,6 +2720,24 @@ bool FreeBSD::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); } +SanitizerMask FreeBSD::getSupportedSanitizers() const { + const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; + const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; + const bool IsMIPS64 = getTriple().getArch() == llvm::Triple::mips64 || + getTriple().getArch() == llvm::Triple::mips64el; + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + Res |= SanitizerKind::Address; + Res |= SanitizerKind::Vptr; + if (IsX86_64 || IsMIPS64) { + Res |= SanitizerKind::Leak; + Res |= SanitizerKind::Thread; + } + if (IsX86 || IsX86_64) { + Res |= SanitizerKind::SafeStack; + } + return Res; +} + /// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly. NetBSD::NetBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) @@ -3643,6 +3642,28 @@ bool Linux::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); } +SanitizerMask Linux::getSupportedSanitizers() const { + const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; + const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; + const bool IsMIPS64 = getTriple().getArch() == llvm::Triple::mips64 || + getTriple().getArch() == llvm::Triple::mips64el; + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + Res |= SanitizerKind::Address; + Res |= SanitizerKind::KernelAddress; + Res |= SanitizerKind::Vptr; + if (IsX86_64 || IsMIPS64) { + Res |= SanitizerKind::DataFlow; + Res |= SanitizerKind::Leak; + Res |= SanitizerKind::Memory; + Res |= SanitizerKind::Thread; + } + if (IsX86 || IsX86_64) { + Res |= SanitizerKind::Function; + Res |= SanitizerKind::SafeStack; + } + return Res; +} + /// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly. DragonFly::DragonFly(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) @@ -3742,3 +3763,46 @@ void XCore::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // We don't output any lib args. This is handled by xcc. } + +// SHAVEToolChain does not call Clang's C compiler. +// We override SelectTool to avoid testing ShouldUseClangCompiler(). +Tool *SHAVEToolChain::SelectTool(const JobAction &JA) const { + switch (JA.getKind()) { + case Action::CompileJobClass: + if (!Compiler) + Compiler.reset(new tools::SHAVE::Compile(*this)); + return Compiler.get(); + case Action::AssembleJobClass: + if (!Assembler) + Assembler.reset(new tools::SHAVE::Assemble(*this)); + return Assembler.get(); + default: + return ToolChain::getTool(JA.getKind()); + } +} + +SHAVEToolChain::SHAVEToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_GCC(D, Triple, Args) {} + +SHAVEToolChain::~SHAVEToolChain() {} + +/// Following are methods necessary to avoid having moviClang be an abstract +/// class. + +Tool *SHAVEToolChain::getTool(Action::ActionClass AC) const { + // SelectTool() must find a tool using the method in the superclass. + // There's nothing we can do if that fails. + llvm_unreachable("SHAVEToolChain can't getTool"); +} + +Tool *SHAVEToolChain::buildLinker() const { + // SHAVEToolChain executables can not be linked except by the vendor tools. + llvm_unreachable("SHAVEToolChain can't buildLinker"); +} + +Tool *SHAVEToolChain::buildAssembler() const { + // This one you'd think should be reachable since we expose an + // assembler to the driver, except not the way it expects. + llvm_unreachable("SHAVEToolChain can't buildAssembler"); +} diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 0b7073f..a48bb5f 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -316,9 +316,6 @@ public: /// Darwin - The base Darwin tool chain. class LLVM_LIBRARY_VISIBILITY Darwin : public MachO { public: - /// The host version. - unsigned DarwinVersion[3]; - /// Whether the information on the target has been initialized. // // FIXME: This should be eliminated. What we want to do is make this part of @@ -338,15 +335,6 @@ public: mutable VersionTuple TargetVersion; private: - /// The default macosx-version-min of this tool chain; empty until - /// initialized. - std::string MacosxVersionMin; - - /// The default ios-version-min of this tool chain; empty until - /// initialized. - std::string iOSVersionMin; - -private: void AddDeploymentTarget(llvm::opt::DerivedArgList &Args) const; public: @@ -412,6 +400,7 @@ protected: } bool isTargetMacOS() const { + assert(TargetInitialized && "Target not initialized!"); return TargetPlatform == MacOS; } @@ -474,6 +463,8 @@ public: void CheckObjCARC() const override; bool UseSjLjExceptions() const override; + + SanitizerMask getSupportedSanitizers() const override; }; /// DarwinClang - The Darwin toolchain used by Clang. @@ -616,6 +607,7 @@ public: bool UseSjLjExceptions() const override; bool isPIEDefault() const override; + SanitizerMask getSupportedSanitizers() const override; protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; @@ -679,6 +671,7 @@ public: AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; bool isPIEDefault() const override; + SanitizerMask getSupportedSanitizers() const override; std::string Linker; std::vector<std::string> ExtraOpts; @@ -809,6 +802,7 @@ public: std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, types::ID InputType) const override; + SanitizerMask getSupportedSanitizers() const override; protected: void AddSystemIncludeWithSubfolder(const llvm::opt::ArgList &DriverArgs, @@ -872,6 +866,27 @@ public: llvm::opt::ArgStringList &CmdArgs) const override; }; +/// SHAVEToolChain - A tool chain using the compiler installed by the the +// Movidius SDK into MV_TOOLS_DIR (which we assume will be copied to llvm's +// installation dir) to perform all subcommands. +class LLVM_LIBRARY_VISIBILITY SHAVEToolChain : public Generic_GCC { +public: + SHAVEToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + ~SHAVEToolChain() override; + + virtual Tool *SelectTool(const JobAction &JA) const override; + +protected: + Tool *getTool(Action::ActionClass AC) const override; + Tool *buildAssembler() const override; + Tool *buildLinker() const override; + +private: + mutable std::unique_ptr<Tool> Compiler; + mutable std::unique_ptr<Tool> Assembler; +}; + } // end namespace toolchains } // end namespace driver } // end namespace clang diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 711dee2..2367914 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -679,7 +679,7 @@ static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, // getARMArch is used here instead of just checking the -march value in order // to handle -march=native correctly. if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { - StringRef Arch = arm::getARMArch(Args, Triple); + std::string Arch = arm::getARMArch(Args, Triple); if (llvm::ARMTargetParser::parseArch(Arch) == llvm::ARM::AK_INVALID) D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); } @@ -689,7 +689,7 @@ static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, // getLLVMArchSuffixForARM which also needs an architecture. if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { std::string CPU = arm::getARMTargetCPU(Args, Triple); - StringRef Arch = arm::getARMArch(Args, Triple); + std::string Arch = arm::getARMArch(Args, Triple); if (strcmp(arm::getLLVMArchSuffixForARM(CPU, Arch), "") == 0) D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); } @@ -850,7 +850,7 @@ static std::string getAArch64TargetCPU(const ArgList &Args) { CPU = A->getValue(); } else if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) { StringRef Mcpu = A->getValue(); - CPU = Mcpu.split("+").first; + CPU = Mcpu.split("+").first.lower(); } // Handle CPU name is 'native'. @@ -1116,7 +1116,7 @@ static void getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, Features.push_back(Args.MakeArgString("+nooddspreg")); } else Features.push_back(Args.MakeArgString("+fp64")); - } else if (mips::isFPXXDefault(Triple, CPUName, ABIName)) { + } else if (mips::shouldUseFPXX(Args, Triple, CPUName, ABIName, FloatABI)) { Features.push_back(Args.MakeArgString("+fpxx")); Features.push_back(Args.MakeArgString("+nooddspreg")); } @@ -1334,47 +1334,26 @@ static std::string getR600TargetGPU(const ArgList &Args) { return ""; } -static void getSparcTargetFeatures(const ArgList &Args, - std::vector<const char *> &Features) { - bool SoftFloatABI = true; - if (Arg *A = - Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float)) { - if (A->getOption().matches(options::OPT_mhard_float)) - SoftFloatABI = false; - } - if (SoftFloatABI) - Features.push_back("+soft-float"); -} - void Clang::AddSparcTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); + std::string Triple = getToolChain().ComputeEffectiveClangTriple(Args); - // Select the float ABI as determined by -msoft-float and -mhard-float. - StringRef FloatABI; - if (Arg *A = Args.getLastArg(options::OPT_msoft_float, - options::OPT_mhard_float)) { + bool SoftFloatABI = false; + if (Arg *A = + Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float)) { if (A->getOption().matches(options::OPT_msoft_float)) - FloatABI = "soft"; - else if (A->getOption().matches(options::OPT_mhard_float)) - FloatABI = "hard"; + SoftFloatABI = true; } - // If unspecified, choose the default based on the platform. - if (FloatABI.empty()) { - // Assume "soft", but warn the user we are guessing. - FloatABI = "soft"; - D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft"; - } - - if (FloatABI == "soft") { - // Floating point operations and argument passing are soft. - // - // FIXME: This changes CPP defines, we need -target-soft-float. - CmdArgs.push_back("-msoft-float"); - } else { - assert(FloatABI == "hard" && "Invalid float abi!"); - CmdArgs.push_back("-mhard-float"); + // Only the hard-float ABI on Sparc is standardized, and it is the + // default. GCC also supports a nonstandard soft-float ABI mode, and + // perhaps LLVM should implement that, too. However, since llvm + // currently does not support Sparc soft-float, at all, display an + // error if it's requested. + if (SoftFloatABI) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << "-msoft-float" << Triple; } } @@ -1550,6 +1529,137 @@ static void AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mcpu=") + CPU)); } +/// This is a helper function for validating the optional refinement step +/// parameter in reciprocal argument strings. Return false if there is an error +/// parsing the refinement step. Otherwise, return true and set the Position +/// of the refinement step in the input string. +static bool getRefinementStep(const StringRef &In, const Driver &D, + const Arg &A, size_t &Position) { + const char RefinementStepToken = ':'; + Position = In.find(RefinementStepToken); + if (Position != StringRef::npos) { + StringRef Option = A.getOption().getName(); + StringRef RefStep = In.substr(Position + 1); + // Allow exactly one numeric character for the additional refinement + // step parameter. This is reasonable for all currently-supported + // operations and architectures because we would expect that a larger value + // of refinement steps would cause the estimate "optimization" to + // under-perform the native operation. Also, if the estimate does not + // converge quickly, it probably will not ever converge, so further + // refinement steps will not produce a better answer. + if (RefStep.size() != 1) { + D.Diag(diag::err_drv_invalid_value) << Option << RefStep; + return false; + } + char RefStepChar = RefStep[0]; + if (RefStepChar < '0' || RefStepChar > '9') { + D.Diag(diag::err_drv_invalid_value) << Option << RefStep; + return false; + } + } + return true; +} + +/// The -mrecip flag requires processing of many optional parameters. +static void ParseMRecip(const Driver &D, const ArgList &Args, + ArgStringList &OutStrings) { + StringRef DisabledPrefixIn = "!"; + StringRef DisabledPrefixOut = "!"; + StringRef EnabledPrefixOut = ""; + StringRef Out = "-mrecip="; + + Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ); + if (!A) + return; + + unsigned NumOptions = A->getNumValues(); + if (NumOptions == 0) { + // No option is the same as "all". + OutStrings.push_back(Args.MakeArgString(Out + "all")); + return; + } + + // Pass through "all", "none", or "default" with an optional refinement step. + if (NumOptions == 1) { + StringRef Val = A->getValue(0); + size_t RefStepLoc; + if (!getRefinementStep(Val, D, *A, RefStepLoc)) + return; + StringRef ValBase = Val.slice(0, RefStepLoc); + if (ValBase == "all" || ValBase == "none" || ValBase == "default") { + OutStrings.push_back(Args.MakeArgString(Out + Val)); + return; + } + } + + // Each reciprocal type may be enabled or disabled individually. + // Check each input value for validity, concatenate them all back together, + // and pass through. + + llvm::StringMap<bool> OptionStrings; + OptionStrings.insert(std::make_pair("divd", false)); + OptionStrings.insert(std::make_pair("divf", false)); + OptionStrings.insert(std::make_pair("vec-divd", false)); + OptionStrings.insert(std::make_pair("vec-divf", false)); + OptionStrings.insert(std::make_pair("sqrtd", false)); + OptionStrings.insert(std::make_pair("sqrtf", false)); + OptionStrings.insert(std::make_pair("vec-sqrtd", false)); + OptionStrings.insert(std::make_pair("vec-sqrtf", false)); + + for (unsigned i = 0; i != NumOptions; ++i) { + StringRef Val = A->getValue(i); + + bool IsDisabled = Val.startswith(DisabledPrefixIn); + // Ignore the disablement token for string matching. + if (IsDisabled) + Val = Val.substr(1); + + size_t RefStep; + if (!getRefinementStep(Val, D, *A, RefStep)) + return; + + StringRef ValBase = Val.slice(0, RefStep); + llvm::StringMap<bool>::iterator OptionIter = OptionStrings.find(ValBase); + if (OptionIter == OptionStrings.end()) { + // Try again specifying float suffix. + OptionIter = OptionStrings.find(ValBase.str() + 'f'); + if (OptionIter == OptionStrings.end()) { + // The input name did not match any known option string. + D.Diag(diag::err_drv_unknown_argument) << Val; + return; + } + // The option was specified without a float or double suffix. + // Make sure that the double entry was not already specified. + // The float entry will be checked below. + if (OptionStrings[ValBase.str() + 'd']) { + D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Val; + return; + } + } + + if (OptionIter->second == true) { + // Duplicate option specified. + D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Val; + return; + } + + // Mark the matched option as found. Do not allow duplicate specifiers. + OptionIter->second = true; + + // If the precision was not specified, also mark the double entry as found. + if (ValBase.back() != 'f' && ValBase.back() != 'd') + OptionStrings[ValBase.str() + 'd'] = true; + + // Build the output string. + StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut; + Out = Args.MakeArgString(Out + Prefix + Val); + if (i != NumOptions - 1) + Out = Args.MakeArgString(Out + ","); + } + + OutStrings.push_back(Args.MakeArgString(Out)); +} + static void getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, std::vector<const char *> &Features) { @@ -1738,7 +1848,8 @@ static bool getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March, const ArgList &Args, std::vector<const char *> &Features) { - std::pair<StringRef, StringRef> Split = March.split("+"); + std::string MarchLowerCase = March.lower(); + std::pair<StringRef, StringRef> Split = StringRef(MarchLowerCase).split("+"); if (Split.first == "armv8-a" || Split.first == "armv8a") { @@ -1762,7 +1873,8 @@ getAArch64ArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, const ArgList &Args, std::vector<const char *> &Features) { StringRef CPU; - if (!DecodeAArch64Mcpu(D, Mcpu, CPU, Features)) + std::string McpuLowerCase = Mcpu.lower(); + if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, Features)) return false; return true; @@ -1788,7 +1900,8 @@ getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, std::vector<const char *> &Features) { StringRef CPU; std::vector<const char *> DecodedFeature; - if (!DecodeAArch64Mcpu(D, Mcpu, CPU, DecodedFeature)) + std::string McpuLowerCase = Mcpu.lower(); + if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, DecodedFeature)) return false; return getAArch64MicroArchFeaturesFromMtune(D, CPU, Args, Features); @@ -1863,11 +1976,6 @@ static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple, case llvm::Triple::ppc64le: getPPCTargetFeatures(Args, Features); break; - case llvm::Triple::sparc: - case llvm::Triple::sparcel: - case llvm::Triple::sparcv9: - getSparcTargetFeatures(Args, Features); - break; case llvm::Triple::systemz: getSystemZTargetFeatures(Args, Features); break; @@ -2326,6 +2434,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("ubsan_standalone_cxx"); } + if (SanArgs.needsSafeStackRt()) + StaticRuntimes.push_back("safestack"); } // Should be called before we add system libraries (C++ ABI, libstdc++/libc++, @@ -3151,6 +3261,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString("-ffp-contract=fast")); } } + + ParseMRecip(getToolChain().getDriver(), Args, CmdArgs); // We separately look for the '-ffast-math' and '-ffinite-math-only' flags, // and if we find them, tell the frontend to provide the appropriate @@ -3892,7 +4004,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -stack-protector=0 is default. unsigned StackProtectorLevel = 0; - if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector, + if (getToolChain().getSanitizerArgs().needsSafeStackRt()) { + Args.ClaimAllArgs(options::OPT_fno_stack_protector); + Args.ClaimAllArgs(options::OPT_fstack_protector_all); + Args.ClaimAllArgs(options::OPT_fstack_protector_strong); + Args.ClaimAllArgs(options::OPT_fstack_protector); + } else if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector, options::OPT_fstack_protector_all, options::OPT_fstack_protector_strong, options::OPT_fstack_protector)) { @@ -4019,9 +4136,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fblocks-runtime-optional"); } - // -fmodules enables modules (off by default). + // -fmodules enables the use of precompiled modules (off by default). // Users can pass -fno-cxx-modules to turn off modules support for - // C++/Objective-C++ programs, which is a little less mature. + // C++/Objective-C++ programs. bool HaveModules = false; if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) { bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules, @@ -4033,11 +4150,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } - // -fmodule-maps enables module map processing (off by default) for header - // checking. It is implied by -fmodules. - if (Args.hasFlag(options::OPT_fmodule_maps, options::OPT_fno_module_maps, - false)) { - CmdArgs.push_back("-fmodule-maps"); + // -fmodule-maps enables implicit reading of module map files. By default, + // this is enabled if we are using precompiled modules. + if (Args.hasFlag(options::OPT_fimplicit_module_maps, + options::OPT_fno_implicit_module_maps, HaveModules)) { + CmdArgs.push_back("-fimplicit-module-maps"); } // -fmodules-decluse checks that modules used are declared so (off by @@ -5627,9 +5744,9 @@ void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA, } // Hexagon tools end. -const StringRef arm::getARMArch(const ArgList &Args, - const llvm::Triple &Triple) { - StringRef MArch; +const std::string arm::getARMArch(const ArgList &Args, + const llvm::Triple &Triple) { + std::string MArch; if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) { // Otherwise, if we have -march= choose the base CPU for that arch. MArch = A->getValue(); @@ -5637,6 +5754,7 @@ const StringRef arm::getARMArch(const ArgList &Args, // Otherwise, use the Arch from the triple. MArch = Triple.getArchName(); } + MArch = StringRef(MArch).lower(); // Handle -march=native. if (MArch == "native") { @@ -5658,7 +5776,7 @@ const StringRef arm::getARMArch(const ArgList &Args, /// Get the (LLVM) name of the minimum ARM CPU for the arch we are targeting. const char *arm::getARMCPUForMArch(const ArgList &Args, const llvm::Triple &Triple) { - StringRef MArch = getARMArch(Args, Triple); + std::string MArch = getARMArch(Args, Triple); // getARMCPUForArch defaults to the triple if MArch is empty, but empty MArch // here means an -march=native that we can't handle, so instead return no CPU. if (MArch.empty()) @@ -5761,7 +5879,7 @@ bool mips::isNaN2008(const ArgList &Args, const llvm::Triple &Triple) { } bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, - StringRef ABIName) { + StringRef ABIName, StringRef FloatABI) { if (Triple.getVendor() != llvm::Triple::ImaginationTechnologies && Triple.getVendor() != llvm::Triple::MipsTechnologies) return false; @@ -5769,6 +5887,11 @@ bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, if (ABIName != "32") return false; + // FPXX shouldn't be used if either -msoft-float or -mfloat-abi=soft is + // present. + if (FloatABI == "soft") + return false; + return llvm::StringSwitch<bool>(CPUName) .Cases("mips2", "mips3", "mips4", "mips5", true) .Cases("mips32", "mips32r2", "mips32r3", "mips32r5", true) @@ -5776,6 +5899,20 @@ bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, .Default(false); } +bool mips::shouldUseFPXX(const ArgList &Args, const llvm::Triple &Triple, + StringRef CPUName, StringRef ABIName, + StringRef FloatABI) { + bool UseFPXX = isFPXXDefault(Triple, CPUName, ABIName, FloatABI); + + // FPXX shouldn't be used if -msingle-float is present. + if (Arg *A = Args.getLastArg(options::OPT_msingle_float, + options::OPT_mdouble_float)) + if (A->getOption().matches(options::OPT_msingle_float)) + UseFPXX = false; + + return UseFPXX; +} + llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) { // See arch(3) and llvm-gcc's driver-driver.c. We don't implement support for // archs which Darwin doesn't use. @@ -5901,7 +6038,7 @@ void cloudabi::Link::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_r); - if (D.IsUsingLTO(ToolChain, Args)) + if (D.IsUsingLTO(Args)) AddGoldPlugin(ToolChain, Args, CmdArgs); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); @@ -6052,8 +6189,7 @@ void darwin::Link::AddLinkArgs(Compilation &C, // If we are using LTO, then automatically create a temporary file path for // the linker to use, so that it's lifetime will extend past a possible // dsymutil step. - if (Version[0] >= 116 && D.IsUsingLTO(getToolChain(), Args) && - NeedsTempPath(Inputs)) { + if (Version[0] >= 116 && D.IsUsingLTO(Args) && NeedsTempPath(Inputs)) { const char *TmpPath = C.getArgs().MakeArgString( D.GetTemporaryPath("cc", types::getTypeTempSuffix(types::TY_Object))); C.addTempFile(TmpPath); @@ -6254,6 +6390,15 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, !Args.hasArg(options::OPT_nostartfiles)) getMachOToolChain().addStartObjectFileArgs(Args, CmdArgs); + // SafeStack requires its own runtime libraries + // These libraries should be linked first, to make sure the + // __safestack_init constructor executes before everything else + if (getToolChain().getSanitizerArgs().needsSafeStackRt()) { + getMachOToolChain().AddLinkRuntimeLib(Args, CmdArgs, + "libclang_rt.safestack_osx.a", + /*AlwaysLink=*/true); + } + Args.AddAllArgs(CmdArgs, options::OPT_L); if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, @@ -7080,7 +7225,7 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_r); - if (D.IsUsingLTO(getToolChain(), Args)) + if (D.IsUsingLTO(Args)) AddGoldPlugin(ToolChain, Args, CmdArgs); bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); @@ -7577,12 +7722,13 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, } // Add the last -mfp32/-mfpxx/-mfp64 or -mfpxx if it is enabled by default. + StringRef MIPSFloatABI = getMipsFloatABI(getToolChain().getDriver(), Args); if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx, options::OPT_mfp64)) { A->claim(); A->render(Args, CmdArgs); - } else if (mips::isFPXXDefault(getToolChain().getTriple(), CPUName, - ABIName)) + } else if (mips::shouldUseFPXX(Args, getToolChain().getTriple(), CPUName, + ABIName, MIPSFloatABI)) CmdArgs.push_back("-mfpxx"); // Pass on -mmips16 or -mno-mips16. However, the assembler equivalent of @@ -7613,6 +7759,9 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_mhard_float, options::OPT_msoft_float); + Args.AddLastArg(CmdArgs, options::OPT_mdouble_float, + options::OPT_msingle_float); + Args.AddLastArg(CmdArgs, options::OPT_modd_spreg, options::OPT_mno_odd_spreg); @@ -7936,7 +8085,7 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, for (const auto &Path : Paths) CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path)); - if (D.IsUsingLTO(getToolChain(), Args)) + if (D.IsUsingLTO(Args)) AddGoldPlugin(ToolChain, Args, CmdArgs); if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) @@ -8948,3 +9097,81 @@ void CrossWindows::Link::ConstructJob(Compilation &C, const JobAction &JA, C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs)); } + +void tools::SHAVE::Compile::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + + ArgStringList CmdArgs; + + assert(Inputs.size() == 1); + const InputInfo &II = Inputs[0]; + assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX); + assert(Output.getType() == types::TY_PP_Asm); // Require preprocessed asm. + + // Append all -I, -iquote, -isystem paths. + Args.AddAllArgs(CmdArgs, options::OPT_clang_i_Group); + // These are spelled the same way in clang and moviCompile. + Args.AddAllArgs(CmdArgs, options::OPT_D, options::OPT_U); + + CmdArgs.push_back("-DMYRIAD2"); + CmdArgs.push_back("-mcpu=myriad2"); + CmdArgs.push_back("-S"); + + // Any -O option passes through without translation. What about -Ofast ? + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) + A->render(Args, CmdArgs); + + if (Args.hasFlag(options::OPT_ffunction_sections, + options::OPT_fno_function_sections)) { + CmdArgs.push_back("-ffunction-sections"); + } + if (Args.hasArg(options::OPT_fno_inline_functions)) + CmdArgs.push_back("-fno-inline-functions"); + + CmdArgs.push_back("-fno-exceptions"); // Always do this even if unspecified. + + CmdArgs.push_back(II.getFilename()); + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + std::string Exec = + Args.MakeArgString(getToolChain().GetProgramPath("moviCompile")); + C.addCommand( + llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), CmdArgs)); +} + +void tools::SHAVE::Assemble::ConstructJob(Compilation &C, + const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + assert(Inputs.size() == 1); + const InputInfo &II = Inputs[0]; + assert(II.getType() == types::TY_PP_Asm); // Require preprocessed asm input. + assert(Output.getType() == types::TY_Object); + + CmdArgs.push_back("-no6thSlotCompression"); + CmdArgs.push_back("-cv:myriad2"); // Chip Version ? + CmdArgs.push_back("-noSPrefixing"); + CmdArgs.push_back("-a"); // Mystery option. + for (auto Arg : Args.filtered(options::OPT_I)) { + Arg->claim(); + CmdArgs.push_back( + Args.MakeArgString(std::string("-i:") + Arg->getValue(0))); + } + CmdArgs.push_back("-elf"); // Output format. + CmdArgs.push_back(II.getFilename()); + CmdArgs.push_back( + Args.MakeArgString(std::string("-o:") + Output.getFilename())); + + std::string Exec = + Args.MakeArgString(getToolChain().GetProgramPath("moviAsm")); + C.addCommand( + llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), CmdArgs)); +} diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h index 133a389..753f542 100644 --- a/lib/Driver/Tools.h +++ b/lib/Driver/Tools.h @@ -227,8 +227,8 @@ namespace hexagon { namespace arm { std::string getARMTargetCPU(const llvm::opt::ArgList &Args, const llvm::Triple &Triple); - const StringRef getARMArch(const llvm::opt::ArgList &Args, - const llvm::Triple &Triple); + const std::string getARMArch(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple); const char* getARMCPUForMArch(const llvm::opt::ArgList &Args, const llvm::Triple &Triple); const char* getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch); @@ -249,7 +249,9 @@ namespace mips { bool isUCLibc(const llvm::opt::ArgList &Args); bool isNaN2008(const llvm::opt::ArgList &Args, const llvm::Triple &Triple); bool isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, - StringRef ABIName); + StringRef ABIName, StringRef FloatABI); + bool shouldUseFPXX(const llvm::opt::ArgList &Args, const llvm::Triple &Triple, + StringRef CPUName, StringRef ABIName, StringRef FloatABI); } namespace ppc { @@ -731,6 +733,33 @@ public: }; } +/// SHAVE tools -- Directly call moviCompile and moviAsm +namespace SHAVE { +class LLVM_LIBRARY_VISIBILITY Compile : public Tool { +public: + Compile(const ToolChain &TC) : Tool("moviCompile", "movicompile", TC) {} + + bool hasIntegratedCPP() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Assemble : public Tool { +public: + Assemble(const ToolChain &TC) : Tool("moviAsm", "moviAsm", TC) {} + + bool hasIntegratedCPP() const override { return false; } // not sure. + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; +} // end namespace SHAVE + } // end namespace tools } // end namespace driver } // end namespace clang diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp index 0b0878f..7b28145 100644 --- a/lib/Driver/Types.cpp +++ b/lib/Driver/Types.cpp @@ -45,7 +45,7 @@ types::ID types::getPreprocessedType(ID Id) { } const char *types::getTypeTempSuffix(ID Id, bool CLMode) { - if ((Id == TY_Object || Id == TY_LTO_BC) && CLMode) + if (Id == TY_Object && CLMode) return "obj"; if (Id == TY_Image && CLMode) return "exe"; |