diff options
Diffstat (limited to 'clang/lib/Basic/Targets/PPC.h')
| -rw-r--r-- | clang/lib/Basic/Targets/PPC.h | 466 | 
1 files changed, 466 insertions, 0 deletions
| diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h new file mode 100644 index 000000000000..6c6421c28e23 --- /dev/null +++ b/clang/lib/Basic/Targets/PPC.h @@ -0,0 +1,466 @@ +//===--- PPC.h - Declare PPC target feature support -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares PPC TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_PPC_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_PPC_H + +#include "OSTargets.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +// PPC abstract base class +class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo { + +  /// Flags for architecture specific defines. +  typedef enum { +    ArchDefineNone = 0, +    ArchDefineName = 1 << 0, // <name> is substituted for arch name. +    ArchDefinePpcgr = 1 << 1, +    ArchDefinePpcsq = 1 << 2, +    ArchDefine440 = 1 << 3, +    ArchDefine603 = 1 << 4, +    ArchDefine604 = 1 << 5, +    ArchDefinePwr4 = 1 << 6, +    ArchDefinePwr5 = 1 << 7, +    ArchDefinePwr5x = 1 << 8, +    ArchDefinePwr6 = 1 << 9, +    ArchDefinePwr6x = 1 << 10, +    ArchDefinePwr7 = 1 << 11, +    ArchDefinePwr8 = 1 << 12, +    ArchDefinePwr9 = 1 << 13, +    ArchDefineA2 = 1 << 14, +    ArchDefineA2q = 1 << 15 +  } ArchDefineTypes; + + +  ArchDefineTypes ArchDefs = ArchDefineNone; +  static const Builtin::Info BuiltinInfo[]; +  static const char *const GCCRegNames[]; +  static const TargetInfo::GCCRegAlias GCCRegAliases[]; +  std::string CPU; +  enum PPCFloatABI { HardFloat, SoftFloat } FloatABI; + +  // Target cpu features. +  bool HasAltivec = false; +  bool HasVSX = false; +  bool HasP8Vector = false; +  bool HasP8Crypto = false; +  bool HasDirectMove = false; +  bool HasQPX = false; +  bool HasHTM = false; +  bool HasBPERMD = false; +  bool HasExtDiv = false; +  bool HasP9Vector = false; +  bool HasSPE = false; + +protected: +  std::string ABI; + +public: +  PPCTargetInfo(const llvm::Triple &Triple, const TargetOptions &) +      : TargetInfo(Triple) { +    SuitableAlign = 128; +    SimdDefaultAlign = 128; +    LongDoubleWidth = LongDoubleAlign = 128; +    LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble(); +  } + +  // Set the language option for altivec based on our value. +  void adjust(LangOptions &Opts) override; + +  // Note: GCC recognizes the following additional cpus: +  //  401, 403, 405, 405fp, 440fp, 464, 464fp, 476, 476fp, 505, 740, 801, +  //  821, 823, 8540, 8548, e300c2, e300c3, e500mc64, e6500, 860, cell, +  //  titan, rs64. +  bool isValidCPUName(StringRef Name) const override; +  void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; + +  bool setCPU(const std::string &Name) override { +    bool CPUKnown = isValidCPUName(Name); +    if (CPUKnown) { +      CPU = Name; + +      // CPU identification. +      ArchDefs = +          (ArchDefineTypes)llvm::StringSwitch<int>(CPU) +              .Case("440", ArchDefineName) +              .Case("450", ArchDefineName | ArchDefine440) +              .Case("601", ArchDefineName) +              .Case("602", ArchDefineName | ArchDefinePpcgr) +              .Case("603", ArchDefineName | ArchDefinePpcgr) +              .Case("603e", ArchDefineName | ArchDefine603 | ArchDefinePpcgr) +              .Case("603ev", ArchDefineName | ArchDefine603 | ArchDefinePpcgr) +              .Case("604", ArchDefineName | ArchDefinePpcgr) +              .Case("604e", ArchDefineName | ArchDefine604 | ArchDefinePpcgr) +              .Case("620", ArchDefineName | ArchDefinePpcgr) +              .Case("630", ArchDefineName | ArchDefinePpcgr) +              .Case("7400", ArchDefineName | ArchDefinePpcgr) +              .Case("7450", ArchDefineName | ArchDefinePpcgr) +              .Case("750", ArchDefineName | ArchDefinePpcgr) +              .Case("970", ArchDefineName | ArchDefinePwr4 | ArchDefinePpcgr | +                               ArchDefinePpcsq) +              .Case("a2", ArchDefineA2) +              .Case("a2q", ArchDefineName | ArchDefineA2 | ArchDefineA2q) +              .Cases("power3", "pwr3", ArchDefinePpcgr) +              .Cases("power4", "pwr4", +                    ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) +              .Cases("power5", "pwr5", +                    ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | +                        ArchDefinePpcsq) +              .Cases("power5x", "pwr5x", +                    ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | +                        ArchDefinePpcgr | ArchDefinePpcsq) +              .Cases("power6", "pwr6", +                    ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | +                        ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) +              .Cases("power6x", "pwr6x", +                    ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x | +                        ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | +                        ArchDefinePpcsq) +              .Cases("power7", "pwr7", +                     ArchDefinePwr7 | ArchDefinePwr6 | ArchDefinePwr5x | +                         ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | +                         ArchDefinePpcsq) +              // powerpc64le automatically defaults to at least power8. +              .Cases("power8", "pwr8", "ppc64le", +                     ArchDefinePwr8 | ArchDefinePwr7 | ArchDefinePwr6 | +                         ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | +                         ArchDefinePpcgr | ArchDefinePpcsq) +              .Cases("power9", "pwr9", +                     ArchDefinePwr9 | ArchDefinePwr8 | ArchDefinePwr7 | +                         ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | +                         ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) +              .Default(ArchDefineNone); +    } +    return CPUKnown; +  } + +  StringRef getABI() const override { return ABI; } + +  ArrayRef<Builtin::Info> getTargetBuiltins() const override; + +  bool isCLZForZeroUndef() const override { return false; } + +  void getTargetDefines(const LangOptions &Opts, +                        MacroBuilder &Builder) const override; + +  bool +  initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, +                 StringRef CPU, +                 const std::vector<std::string> &FeaturesVec) const override; + +  bool handleTargetFeatures(std::vector<std::string> &Features, +                            DiagnosticsEngine &Diags) override; + +  bool hasFeature(StringRef Feature) const override; + +  void setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name, +                         bool Enabled) const override; + +  ArrayRef<const char *> getGCCRegNames() const override; + +  ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; + +  ArrayRef<TargetInfo::AddlRegName> getGCCAddlRegNames() const override; + +  bool validateAsmConstraint(const char *&Name, +                             TargetInfo::ConstraintInfo &Info) const override { +    switch (*Name) { +    default: +      return false; +    case 'O': // Zero +      break; +    case 'f': // Floating point register +      // Don't use floating point registers on soft float ABI. +      if (FloatABI == SoftFloat) +        return false; +      LLVM_FALLTHROUGH; +    case 'b': // Base register +      Info.setAllowsRegister(); +      break; +    // FIXME: The following are added to allow parsing. +    // I just took a guess at what the actions should be. +    // Also, is more specific checking needed?  I.e. specific registers? +    case 'd': // Floating point register (containing 64-bit value) +    case 'v': // Altivec vector register +      // Don't use floating point and altivec vector registers +      // on soft float ABI +      if (FloatABI == SoftFloat) +        return false; +      Info.setAllowsRegister(); +      break; +    case 'w': +      switch (Name[1]) { +      case 'd': // VSX vector register to hold vector double data +      case 'f': // VSX vector register to hold vector float data +      case 's': // VSX vector register to hold scalar double data +      case 'w': // VSX vector register to hold scalar double data +      case 'a': // Any VSX register +      case 'c': // An individual CR bit +      case 'i': // FP or VSX register to hold 64-bit integers data +        break; +      default: +        return false; +      } +      Info.setAllowsRegister(); +      Name++; // Skip over 'w'. +      break; +    case 'h': // `MQ', `CTR', or `LINK' register +    case 'q': // `MQ' register +    case 'c': // `CTR' register +    case 'l': // `LINK' register +    case 'x': // `CR' register (condition register) number 0 +    case 'y': // `CR' register (condition register) +    case 'z': // `XER[CA]' carry bit (part of the XER register) +      Info.setAllowsRegister(); +      break; +    case 'I': // Signed 16-bit constant +    case 'J': // Unsigned 16-bit constant shifted left 16 bits +              //  (use `L' instead for SImode constants) +    case 'K': // Unsigned 16-bit constant +    case 'L': // Signed 16-bit constant shifted left 16 bits +    case 'M': // Constant larger than 31 +    case 'N': // Exact power of 2 +    case 'P': // Constant whose negation is a signed 16-bit constant +    case 'G': // Floating point constant that can be loaded into a +              // register with one instruction per word +    case 'H': // Integer/Floating point constant that can be loaded +              // into a register using three instructions +      break; +    case 'm': // Memory operand. Note that on PowerPC targets, m can +              // include addresses that update the base register. It +              // is therefore only safe to use `m' in an asm statement +              // if that asm statement accesses the operand exactly once. +              // The asm statement must also use `%U<opno>' as a +              // placeholder for the "update" flag in the corresponding +              // load or store instruction. For example: +              // asm ("st%U0 %1,%0" : "=m" (mem) : "r" (val)); +              // is correct but: +              // asm ("st %1,%0" : "=m" (mem) : "r" (val)); +              // is not. Use es rather than m if you don't want the base +              // register to be updated. +    case 'e': +      if (Name[1] != 's') +        return false; +      // es: A "stable" memory operand; that is, one which does not +      // include any automodification of the base register. Unlike +      // `m', this constraint can be used in asm statements that +      // might access the operand several times, or that might not +      // access it at all. +      Info.setAllowsMemory(); +      Name++; // Skip over 'e'. +      break; +    case 'Q': // Memory operand that is an offset from a register (it is +              // usually better to use `m' or `es' in asm statements) +    case 'Z': // Memory operand that is an indexed or indirect from a +              // register (it is usually better to use `m' or `es' in +              // asm statements) +      Info.setAllowsMemory(); +      Info.setAllowsRegister(); +      break; +    case 'R': // AIX TOC entry +    case 'a': // Address operand that is an indexed or indirect from a +              // register (`p' is preferable for asm statements) +    case 'S': // Constant suitable as a 64-bit mask operand +    case 'T': // Constant suitable as a 32-bit mask operand +    case 'U': // System V Release 4 small data area reference +    case 't': // AND masks that can be performed by two rldic{l, r} +              // instructions +    case 'W': // Vector constant that does not require memory +    case 'j': // Vector constant that is all zeros. +      break; +      // End FIXME. +    } +    return true; +  } + +  std::string convertConstraint(const char *&Constraint) const override { +    std::string R; +    switch (*Constraint) { +    case 'e': +    case 'w': +      // Two-character constraint; add "^" hint for later parsing. +      R = std::string("^") + std::string(Constraint, 2); +      Constraint++; +      break; +    default: +      return TargetInfo::convertConstraint(Constraint); +    } +    return R; +  } + +  const char *getClobbers() const override { return ""; } +  int getEHDataRegisterNumber(unsigned RegNo) const override { +    if (RegNo == 0) +      return 3; +    if (RegNo == 1) +      return 4; +    return -1; +  } + +  bool hasSjLjLowering() const override { return true; } + +  const char *getLongDoubleMangling() const override { +    if (LongDoubleWidth == 64) +      return "e"; +    return LongDoubleFormat == &llvm::APFloat::PPCDoubleDouble() +               ? "g" +               : "u9__ieee128"; +  } +  const char *getFloat128Mangling() const override { return "u9__ieee128"; } +}; + +class LLVM_LIBRARY_VISIBILITY PPC32TargetInfo : public PPCTargetInfo { +public: +  PPC32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) +      : PPCTargetInfo(Triple, Opts) { +    resetDataLayout("E-m:e-p:32:32-i64:64-n32"); + +    switch (getTriple().getOS()) { +    case llvm::Triple::Linux: +    case llvm::Triple::FreeBSD: +    case llvm::Triple::NetBSD: +      SizeType = UnsignedInt; +      PtrDiffType = SignedInt; +      IntPtrType = SignedInt; +      break; +    case llvm::Triple::AIX: +      SizeType = UnsignedLong; +      PtrDiffType = SignedLong; +      IntPtrType = SignedLong; +      SuitableAlign = 64; +      break; +    default: +      break; +    } + +    if (Triple.isOSFreeBSD() || Triple.isOSNetBSD() || Triple.isOSOpenBSD() || +        Triple.getOS() == llvm::Triple::AIX || Triple.isMusl()) { +      LongDoubleWidth = LongDoubleAlign = 64; +      LongDoubleFormat = &llvm::APFloat::IEEEdouble(); +    } + +    // PPC32 supports atomics up to 4 bytes. +    MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; +  } + +  BuiltinVaListKind getBuiltinVaListKind() const override { +    // This is the ELF definition, and is overridden by the Darwin sub-target +    return TargetInfo::PowerABIBuiltinVaList; +  } +}; + +// Note: ABI differences may eventually require us to have a separate +// TargetInfo for little endian. +class LLVM_LIBRARY_VISIBILITY PPC64TargetInfo : public PPCTargetInfo { +public: +  PPC64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) +      : PPCTargetInfo(Triple, Opts) { +    LongWidth = LongAlign = PointerWidth = PointerAlign = 64; +    IntMaxType = SignedLong; +    Int64Type = SignedLong; + +    if ((Triple.getArch() == llvm::Triple::ppc64le)) { +      resetDataLayout("e-m:e-i64:64-n32:64"); +      ABI = "elfv2"; +    } else { +      resetDataLayout("E-m:e-i64:64-n32:64"); +      ABI = Triple.getEnvironment() == llvm::Triple::ELFv2 ? "elfv2" : "elfv1"; +    } + +    if (Triple.getOS() == llvm::Triple::AIX) +      SuitableAlign = 64; + +    if (Triple.isOSFreeBSD() || Triple.getOS() == llvm::Triple::AIX || +        Triple.isMusl()) { +      LongDoubleWidth = LongDoubleAlign = 64; +      LongDoubleFormat = &llvm::APFloat::IEEEdouble(); +    } + +    // PPC64 supports atomics up to 8 bytes. +    MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; +  } + +  BuiltinVaListKind getBuiltinVaListKind() const override { +    return TargetInfo::CharPtrBuiltinVaList; +  } + +  // PPC64 Linux-specific ABI options. +  bool setABI(const std::string &Name) override { +    if (Name == "elfv1" || Name == "elfv1-qpx" || Name == "elfv2") { +      ABI = Name; +      return true; +    } +    return false; +  } + +  CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { +    switch (CC) { +    case CC_Swift: +      return CCCR_OK; +    default: +      return CCCR_Warning; +    } +  } +}; + +class LLVM_LIBRARY_VISIBILITY DarwinPPC32TargetInfo +    : public DarwinTargetInfo<PPC32TargetInfo> { +public: +  DarwinPPC32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) +      : DarwinTargetInfo<PPC32TargetInfo>(Triple, Opts) { +    HasAlignMac68kSupport = true; +    BoolWidth = BoolAlign = 32; // XXX support -mone-byte-bool? +    PtrDiffType = SignedInt; // for http://llvm.org/bugs/show_bug.cgi?id=15726 +    LongLongAlign = 32; +    resetDataLayout("E-m:o-p:32:32-f64:32:64-n32"); +  } + +  BuiltinVaListKind getBuiltinVaListKind() const override { +    return TargetInfo::CharPtrBuiltinVaList; +  } +}; + +class LLVM_LIBRARY_VISIBILITY DarwinPPC64TargetInfo +    : public DarwinTargetInfo<PPC64TargetInfo> { +public: +  DarwinPPC64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) +      : DarwinTargetInfo<PPC64TargetInfo>(Triple, Opts) { +    HasAlignMac68kSupport = true; +    resetDataLayout("E-m:o-i64:64-n32:64"); +  } +}; + +class LLVM_LIBRARY_VISIBILITY AIXPPC32TargetInfo : +  public AIXTargetInfo<PPC32TargetInfo> { +public: +  using AIXTargetInfo::AIXTargetInfo; +  BuiltinVaListKind getBuiltinVaListKind() const override { +    return TargetInfo::CharPtrBuiltinVaList; +  } +}; + +class LLVM_LIBRARY_VISIBILITY AIXPPC64TargetInfo : +  public AIXTargetInfo<PPC64TargetInfo> { +public: +  using AIXTargetInfo::AIXTargetInfo; +}; + +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_PPC_H | 
