404 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			404 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
//===--- Mips.cpp - Tools Implementations -----------------------*- C++ -*-===//
 | 
						|
//
 | 
						|
//                     The LLVM Compiler Infrastructure
 | 
						|
//
 | 
						|
// This file is distributed under the University of Illinois Open Source
 | 
						|
// License. See LICENSE.TXT for details.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "Mips.h"
 | 
						|
#include "ToolChains/CommonArgs.h"
 | 
						|
#include "clang/Driver/Driver.h"
 | 
						|
#include "clang/Driver/DriverDiagnostic.h"
 | 
						|
#include "clang/Driver/Options.h"
 | 
						|
#include "llvm/ADT/StringSwitch.h"
 | 
						|
#include "llvm/Option/ArgList.h"
 | 
						|
 | 
						|
using namespace clang::driver;
 | 
						|
using namespace clang::driver::tools;
 | 
						|
using namespace clang;
 | 
						|
using namespace llvm::opt;
 | 
						|
 | 
						|
bool tools::isMipsArch(llvm::Triple::ArchType Arch) {
 | 
						|
  return Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel ||
 | 
						|
         Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el;
 | 
						|
}
 | 
						|
 | 
						|
// Get CPU and ABI names. They are not independent
 | 
						|
// so we have to calculate them together.
 | 
						|
void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple,
 | 
						|
                            StringRef &CPUName, StringRef &ABIName) {
 | 
						|
  const char *DefMips32CPU = "mips32r2";
 | 
						|
  const char *DefMips64CPU = "mips64r2";
 | 
						|
 | 
						|
  // MIPS32r6 is the default for mips(el)?-img-linux-gnu and MIPS64r6 is the
 | 
						|
  // default for mips64(el)?-img-linux-gnu.
 | 
						|
  if (Triple.getVendor() == llvm::Triple::ImaginationTechnologies &&
 | 
						|
      Triple.getEnvironment() == llvm::Triple::GNU) {
 | 
						|
    DefMips32CPU = "mips32r6";
 | 
						|
    DefMips64CPU = "mips64r6";
 | 
						|
  }
 | 
						|
 | 
						|
  // MIPS64r6 is the default for Android MIPS64 (mips64el-linux-android).
 | 
						|
  if (Triple.isAndroid()) {
 | 
						|
    DefMips32CPU = "mips32";
 | 
						|
    DefMips64CPU = "mips64r6";
 | 
						|
  }
 | 
						|
 | 
						|
  // MIPS3 is the default for mips64*-unknown-openbsd.
 | 
						|
  if (Triple.getOS() == llvm::Triple::OpenBSD)
 | 
						|
    DefMips64CPU = "mips3";
 | 
						|
 | 
						|
  if (Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ,
 | 
						|
                               options::OPT_mcpu_EQ))
 | 
						|
    CPUName = A->getValue();
 | 
						|
 | 
						|
  if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
 | 
						|
    ABIName = A->getValue();
 | 
						|
    // Convert a GNU style Mips ABI name to the name
 | 
						|
    // accepted by LLVM Mips backend.
 | 
						|
    ABIName = llvm::StringSwitch<llvm::StringRef>(ABIName)
 | 
						|
                  .Case("32", "o32")
 | 
						|
                  .Case("64", "n64")
 | 
						|
                  .Default(ABIName);
 | 
						|
  }
 | 
						|
 | 
						|
  // Setup default CPU and ABI names.
 | 
						|
  if (CPUName.empty() && ABIName.empty()) {
 | 
						|
    switch (Triple.getArch()) {
 | 
						|
    default:
 | 
						|
      llvm_unreachable("Unexpected triple arch name");
 | 
						|
    case llvm::Triple::mips:
 | 
						|
    case llvm::Triple::mipsel:
 | 
						|
      CPUName = DefMips32CPU;
 | 
						|
      break;
 | 
						|
    case llvm::Triple::mips64:
 | 
						|
    case llvm::Triple::mips64el:
 | 
						|
      CPUName = DefMips64CPU;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (ABIName.empty() &&
 | 
						|
      (Triple.getVendor() == llvm::Triple::MipsTechnologies ||
 | 
						|
       Triple.getVendor() == llvm::Triple::ImaginationTechnologies)) {
 | 
						|
    ABIName = llvm::StringSwitch<const char *>(CPUName)
 | 
						|
                  .Case("mips1", "o32")
 | 
						|
                  .Case("mips2", "o32")
 | 
						|
                  .Case("mips3", "n64")
 | 
						|
                  .Case("mips4", "n64")
 | 
						|
                  .Case("mips5", "n64")
 | 
						|
                  .Case("mips32", "o32")
 | 
						|
                  .Case("mips32r2", "o32")
 | 
						|
                  .Case("mips32r3", "o32")
 | 
						|
                  .Case("mips32r5", "o32")
 | 
						|
                  .Case("mips32r6", "o32")
 | 
						|
                  .Case("mips64", "n64")
 | 
						|
                  .Case("mips64r2", "n64")
 | 
						|
                  .Case("mips64r3", "n64")
 | 
						|
                  .Case("mips64r5", "n64")
 | 
						|
                  .Case("mips64r6", "n64")
 | 
						|
                  .Case("octeon", "n64")
 | 
						|
                  .Case("p5600", "o32")
 | 
						|
                  .Default("");
 | 
						|
  }
 | 
						|
 | 
						|
  if (ABIName.empty()) {
 | 
						|
    // Deduce ABI name from the target triple.
 | 
						|
    if (Triple.getArch() == llvm::Triple::mips ||
 | 
						|
        Triple.getArch() == llvm::Triple::mipsel)
 | 
						|
      ABIName = "o32";
 | 
						|
    else
 | 
						|
      ABIName = "n64";
 | 
						|
  }
 | 
						|
 | 
						|
  if (CPUName.empty()) {
 | 
						|
    // Deduce CPU name from ABI name.
 | 
						|
    CPUName = llvm::StringSwitch<const char *>(ABIName)
 | 
						|
                  .Case("o32", DefMips32CPU)
 | 
						|
                  .Cases("n32", "n64", DefMips64CPU)
 | 
						|
                  .Default("");
 | 
						|
  }
 | 
						|
 | 
						|
  // FIXME: Warn on inconsistent use of -march and -mabi.
 | 
						|
}
 | 
						|
 | 
						|
std::string mips::getMipsABILibSuffix(const ArgList &Args,
 | 
						|
                                      const llvm::Triple &Triple) {
 | 
						|
  StringRef CPUName, ABIName;
 | 
						|
  tools::mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
 | 
						|
  return llvm::StringSwitch<std::string>(ABIName)
 | 
						|
      .Case("o32", "")
 | 
						|
      .Case("n32", "32")
 | 
						|
      .Case("n64", "64");
 | 
						|
}
 | 
						|
 | 
						|
// Convert ABI name to the GNU tools acceptable variant.
 | 
						|
StringRef mips::getGnuCompatibleMipsABIName(StringRef ABI) {
 | 
						|
  return llvm::StringSwitch<llvm::StringRef>(ABI)
 | 
						|
      .Case("o32", "32")
 | 
						|
      .Case("n64", "64")
 | 
						|
      .Default(ABI);
 | 
						|
}
 | 
						|
 | 
						|
// Select the MIPS float ABI as determined by -msoft-float, -mhard-float,
 | 
						|
// and -mfloat-abi=.
 | 
						|
mips::FloatABI mips::getMipsFloatABI(const Driver &D, const ArgList &Args) {
 | 
						|
  mips::FloatABI ABI = mips::FloatABI::Invalid;
 | 
						|
  if (Arg *A =
 | 
						|
          Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
 | 
						|
                          options::OPT_mfloat_abi_EQ)) {
 | 
						|
    if (A->getOption().matches(options::OPT_msoft_float))
 | 
						|
      ABI = mips::FloatABI::Soft;
 | 
						|
    else if (A->getOption().matches(options::OPT_mhard_float))
 | 
						|
      ABI = mips::FloatABI::Hard;
 | 
						|
    else {
 | 
						|
      ABI = llvm::StringSwitch<mips::FloatABI>(A->getValue())
 | 
						|
                .Case("soft", mips::FloatABI::Soft)
 | 
						|
                .Case("hard", mips::FloatABI::Hard)
 | 
						|
                .Default(mips::FloatABI::Invalid);
 | 
						|
      if (ABI == mips::FloatABI::Invalid && !StringRef(A->getValue()).empty()) {
 | 
						|
        D.Diag(clang::diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
 | 
						|
        ABI = mips::FloatABI::Hard;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // If unspecified, choose the default based on the platform.
 | 
						|
  if (ABI == mips::FloatABI::Invalid) {
 | 
						|
    // Assume "hard", because it's a default value used by gcc.
 | 
						|
    // When we start to recognize specific target MIPS processors,
 | 
						|
    // we will be able to select the default more correctly.
 | 
						|
    ABI = mips::FloatABI::Hard;
 | 
						|
  }
 | 
						|
 | 
						|
  assert(ABI != mips::FloatABI::Invalid && "must select an ABI");
 | 
						|
  return ABI;
 | 
						|
}
 | 
						|
 | 
						|
void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple,
 | 
						|
                                 const ArgList &Args,
 | 
						|
                                 std::vector<StringRef> &Features) {
 | 
						|
  StringRef CPUName;
 | 
						|
  StringRef ABIName;
 | 
						|
  getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
 | 
						|
  ABIName = getGnuCompatibleMipsABIName(ABIName);
 | 
						|
 | 
						|
  // Historically, PIC code for MIPS was associated with -mabicalls, a.k.a
 | 
						|
  // SVR4 abicalls. Static code does not use SVR4 calling sequences. An ABI
 | 
						|
  // extension was developed by Richard Sandiford & Code Sourcery to support
 | 
						|
  // static code calling PIC code (CPIC). For O32 and N32 this means we have
 | 
						|
  // several combinations of PIC/static and abicalls. Pure static, static
 | 
						|
  // with the CPIC extension, and pure PIC code.
 | 
						|
 | 
						|
  // At final link time, O32 and N32 with CPIC will have another section
 | 
						|
  // added to the binary which contains the stub functions to perform
 | 
						|
  // any fixups required for PIC code.
 | 
						|
 | 
						|
  // For N64, the situation is more regular: code can either be static
 | 
						|
  // (non-abicalls) or PIC (abicalls). GCC has traditionally picked PIC code
 | 
						|
  // code for N64. Since Clang has already built the relocation model portion
 | 
						|
  // of the commandline, we pick add +noabicalls feature in the N64 static
 | 
						|
  // case.
 | 
						|
 | 
						|
  // The is another case to be accounted for: -msym32, which enforces that all
 | 
						|
  // symbols have 32 bits in size. In this case, N64 can in theory use CPIC
 | 
						|
  // but it is unsupported.
 | 
						|
 | 
						|
  // The combinations for N64 are:
 | 
						|
  // a) Static without abicalls and 64bit symbols.
 | 
						|
  // b) Static with abicalls and 32bit symbols.
 | 
						|
  // c) PIC with abicalls and 64bit symbols.
 | 
						|
 | 
						|
  // For case (a) we need to add +noabicalls for N64.
 | 
						|
 | 
						|
  bool IsN64 = ABIName == "64";
 | 
						|
  bool NonPIC = false;
 | 
						|
 | 
						|
  Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
 | 
						|
                                    options::OPT_fpic, options::OPT_fno_pic,
 | 
						|
                                    options::OPT_fPIE, options::OPT_fno_PIE,
 | 
						|
                                    options::OPT_fpie, options::OPT_fno_pie);
 | 
						|
  if (LastPICArg) {
 | 
						|
    Option O = LastPICArg->getOption();
 | 
						|
    NonPIC =
 | 
						|
        (O.matches(options::OPT_fno_PIC) || O.matches(options::OPT_fno_pic) ||
 | 
						|
         O.matches(options::OPT_fno_PIE) || O.matches(options::OPT_fno_pie));
 | 
						|
  }
 | 
						|
 | 
						|
  if (IsN64 && NonPIC) {
 | 
						|
    Features.push_back("+noabicalls");
 | 
						|
  } else {
 | 
						|
    AddTargetFeature(Args, Features, options::OPT_mno_abicalls,
 | 
						|
                     options::OPT_mabicalls, "noabicalls");
 | 
						|
  }
 | 
						|
 | 
						|
  mips::FloatABI FloatABI = mips::getMipsFloatABI(D, Args);
 | 
						|
  if (FloatABI == mips::FloatABI::Soft) {
 | 
						|
    // FIXME: Note, this is a hack. We need to pass the selected float
 | 
						|
    // mode to the MipsTargetInfoBase to define appropriate macros there.
 | 
						|
    // Now it is the only method.
 | 
						|
    Features.push_back("+soft-float");
 | 
						|
  }
 | 
						|
 | 
						|
  if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) {
 | 
						|
    StringRef Val = StringRef(A->getValue());
 | 
						|
    if (Val == "2008") {
 | 
						|
      if (mips::getSupportedNanEncoding(CPUName) & mips::Nan2008)
 | 
						|
        Features.push_back("+nan2008");
 | 
						|
      else {
 | 
						|
        Features.push_back("-nan2008");
 | 
						|
        D.Diag(diag::warn_target_unsupported_nan2008) << CPUName;
 | 
						|
      }
 | 
						|
    } else if (Val == "legacy") {
 | 
						|
      if (mips::getSupportedNanEncoding(CPUName) & mips::NanLegacy)
 | 
						|
        Features.push_back("-nan2008");
 | 
						|
      else {
 | 
						|
        Features.push_back("+nan2008");
 | 
						|
        D.Diag(diag::warn_target_unsupported_nanlegacy) << CPUName;
 | 
						|
      }
 | 
						|
    } else
 | 
						|
      D.Diag(diag::err_drv_unsupported_option_argument)
 | 
						|
          << A->getOption().getName() << Val;
 | 
						|
  }
 | 
						|
 | 
						|
  AddTargetFeature(Args, Features, options::OPT_msingle_float,
 | 
						|
                   options::OPT_mdouble_float, "single-float");
 | 
						|
  AddTargetFeature(Args, Features, options::OPT_mips16, options::OPT_mno_mips16,
 | 
						|
                   "mips16");
 | 
						|
  AddTargetFeature(Args, Features, options::OPT_mmicromips,
 | 
						|
                   options::OPT_mno_micromips, "micromips");
 | 
						|
  AddTargetFeature(Args, Features, options::OPT_mdsp, options::OPT_mno_dsp,
 | 
						|
                   "dsp");
 | 
						|
  AddTargetFeature(Args, Features, options::OPT_mdspr2, options::OPT_mno_dspr2,
 | 
						|
                   "dspr2");
 | 
						|
  AddTargetFeature(Args, Features, options::OPT_mmsa, options::OPT_mno_msa,
 | 
						|
                   "msa");
 | 
						|
 | 
						|
  // Add the last -mfp32/-mfpxx/-mfp64, if none are given and the ABI is O32
 | 
						|
  // pass -mfpxx, or if none are given and fp64a is default, pass fp64 and
 | 
						|
  // nooddspreg.
 | 
						|
  if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx,
 | 
						|
                               options::OPT_mfp64)) {
 | 
						|
    if (A->getOption().matches(options::OPT_mfp32))
 | 
						|
      Features.push_back(Args.MakeArgString("-fp64"));
 | 
						|
    else if (A->getOption().matches(options::OPT_mfpxx)) {
 | 
						|
      Features.push_back(Args.MakeArgString("+fpxx"));
 | 
						|
      Features.push_back(Args.MakeArgString("+nooddspreg"));
 | 
						|
    } else
 | 
						|
      Features.push_back(Args.MakeArgString("+fp64"));
 | 
						|
  } else if (mips::shouldUseFPXX(Args, Triple, CPUName, ABIName, FloatABI)) {
 | 
						|
    Features.push_back(Args.MakeArgString("+fpxx"));
 | 
						|
    Features.push_back(Args.MakeArgString("+nooddspreg"));
 | 
						|
  } else if (mips::isFP64ADefault(Triple, CPUName)) {
 | 
						|
    Features.push_back(Args.MakeArgString("+fp64"));
 | 
						|
    Features.push_back(Args.MakeArgString("+nooddspreg"));
 | 
						|
  }
 | 
						|
 | 
						|
  AddTargetFeature(Args, Features, options::OPT_mno_odd_spreg,
 | 
						|
                   options::OPT_modd_spreg, "nooddspreg");
 | 
						|
}
 | 
						|
 | 
						|
mips::NanEncoding mips::getSupportedNanEncoding(StringRef &CPU) {
 | 
						|
  // Strictly speaking, mips32r2 and mips64r2 are NanLegacy-only since Nan2008
 | 
						|
  // was first introduced in Release 3. However, other compilers have
 | 
						|
  // traditionally allowed it for Release 2 so we should do the same.
 | 
						|
  return (NanEncoding)llvm::StringSwitch<int>(CPU)
 | 
						|
      .Case("mips1", NanLegacy)
 | 
						|
      .Case("mips2", NanLegacy)
 | 
						|
      .Case("mips3", NanLegacy)
 | 
						|
      .Case("mips4", NanLegacy)
 | 
						|
      .Case("mips5", NanLegacy)
 | 
						|
      .Case("mips32", NanLegacy)
 | 
						|
      .Case("mips32r2", NanLegacy | Nan2008)
 | 
						|
      .Case("mips32r3", NanLegacy | Nan2008)
 | 
						|
      .Case("mips32r5", NanLegacy | Nan2008)
 | 
						|
      .Case("mips32r6", Nan2008)
 | 
						|
      .Case("mips64", NanLegacy)
 | 
						|
      .Case("mips64r2", NanLegacy | Nan2008)
 | 
						|
      .Case("mips64r3", NanLegacy | Nan2008)
 | 
						|
      .Case("mips64r5", NanLegacy | Nan2008)
 | 
						|
      .Case("mips64r6", Nan2008)
 | 
						|
      .Default(NanLegacy);
 | 
						|
}
 | 
						|
 | 
						|
bool mips::hasCompactBranches(StringRef &CPU) {
 | 
						|
  // mips32r6 and mips64r6 have compact branches.
 | 
						|
  return llvm::StringSwitch<bool>(CPU)
 | 
						|
      .Case("mips32r6", true)
 | 
						|
      .Case("mips64r6", true)
 | 
						|
      .Default(false);
 | 
						|
}
 | 
						|
 | 
						|
bool mips::hasMipsAbiArg(const ArgList &Args, const char *Value) {
 | 
						|
  Arg *A = Args.getLastArg(options::OPT_mabi_EQ);
 | 
						|
  return A && (A->getValue() == StringRef(Value));
 | 
						|
}
 | 
						|
 | 
						|
bool mips::isUCLibc(const ArgList &Args) {
 | 
						|
  Arg *A = Args.getLastArg(options::OPT_m_libc_Group);
 | 
						|
  return A && A->getOption().matches(options::OPT_muclibc);
 | 
						|
}
 | 
						|
 | 
						|
bool mips::isNaN2008(const ArgList &Args, const llvm::Triple &Triple) {
 | 
						|
  if (Arg *NaNArg = Args.getLastArg(options::OPT_mnan_EQ))
 | 
						|
    return llvm::StringSwitch<bool>(NaNArg->getValue())
 | 
						|
        .Case("2008", true)
 | 
						|
        .Case("legacy", false)
 | 
						|
        .Default(false);
 | 
						|
 | 
						|
  // NaN2008 is the default for MIPS32r6/MIPS64r6.
 | 
						|
  return llvm::StringSwitch<bool>(getCPUName(Args, Triple))
 | 
						|
      .Cases("mips32r6", "mips64r6", true)
 | 
						|
      .Default(false);
 | 
						|
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
bool mips::isFP64ADefault(const llvm::Triple &Triple, StringRef CPUName) {
 | 
						|
  if (!Triple.isAndroid())
 | 
						|
    return false;
 | 
						|
 | 
						|
  // Android MIPS32R6 defaults to FP64A.
 | 
						|
  return llvm::StringSwitch<bool>(CPUName)
 | 
						|
      .Case("mips32r6", true)
 | 
						|
      .Default(false);
 | 
						|
}
 | 
						|
 | 
						|
bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName,
 | 
						|
                         StringRef ABIName, mips::FloatABI FloatABI) {
 | 
						|
  if (Triple.getVendor() != llvm::Triple::ImaginationTechnologies &&
 | 
						|
      Triple.getVendor() != llvm::Triple::MipsTechnologies &&
 | 
						|
      !Triple.isAndroid())
 | 
						|
    return false;
 | 
						|
 | 
						|
  if (ABIName != "32")
 | 
						|
    return false;
 | 
						|
 | 
						|
  // FPXX shouldn't be used if either -msoft-float or -mfloat-abi=soft is
 | 
						|
  // present.
 | 
						|
  if (FloatABI == mips::FloatABI::Soft)
 | 
						|
    return false;
 | 
						|
 | 
						|
  return llvm::StringSwitch<bool>(CPUName)
 | 
						|
      .Cases("mips2", "mips3", "mips4", "mips5", true)
 | 
						|
      .Cases("mips32", "mips32r2", "mips32r3", "mips32r5", true)
 | 
						|
      .Cases("mips64", "mips64r2", "mips64r3", "mips64r5", true)
 | 
						|
      .Default(false);
 | 
						|
}
 | 
						|
 | 
						|
bool mips::shouldUseFPXX(const ArgList &Args, const llvm::Triple &Triple,
 | 
						|
                         StringRef CPUName, StringRef ABIName,
 | 
						|
                         mips::FloatABI 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;
 | 
						|
}
 |