Home | History | Annotate | Line # | Download | only in Targets
      1 //===--- Mips.h - Declare Mips target feature support -----------*- C++ -*-===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // This file declares Mips TargetInfo objects.
     10 //
     11 //===----------------------------------------------------------------------===//
     12 
     13 #ifndef LLVM_CLANG_LIB_BASIC_TARGETS_MIPS_H
     14 #define LLVM_CLANG_LIB_BASIC_TARGETS_MIPS_H
     15 
     16 #include "clang/Basic/TargetInfo.h"
     17 #include "clang/Basic/TargetOptions.h"
     18 #include "llvm/ADT/Triple.h"
     19 #include "llvm/Support/Compiler.h"
     20 
     21 namespace clang {
     22 namespace targets {
     23 
     24 class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public TargetInfo {
     25   void setDataLayout() {
     26     StringRef Layout;
     27 
     28     if (ABI == "o32")
     29       Layout = "m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64";
     30     else if (ABI == "n32")
     31       Layout = "m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32:64-S128";
     32     else if (ABI == "n64")
     33       Layout = "m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128";
     34     else
     35       llvm_unreachable("Invalid ABI");
     36 
     37     if (BigEndian)
     38       resetDataLayout(("E-" + Layout).str());
     39     else
     40       resetDataLayout(("e-" + Layout).str());
     41   }
     42 
     43   static const Builtin::Info BuiltinInfo[];
     44   std::string CPU;
     45   bool IsMips16;
     46   bool IsMicromips;
     47   bool IsNan2008;
     48   bool IsAbs2008;
     49   bool IsSingleFloat;
     50   bool IsNoABICalls;
     51   bool CanUseBSDABICalls;
     52   enum MipsFloatABI { HardFloat, SoftFloat } FloatABI;
     53   enum DspRevEnum { NoDSP, DSP1, DSP2 } DspRev;
     54   bool HasMSA;
     55   bool DisableMadd4;
     56   bool UseIndirectJumpHazard;
     57 
     58 protected:
     59   enum FPModeEnum { FPXX, FP32, FP64 } FPMode;
     60   std::string ABI;
     61 
     62 public:
     63   MipsTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
     64       : TargetInfo(Triple), IsMips16(false), IsMicromips(false),
     65         IsNan2008(false), IsAbs2008(false), IsSingleFloat(false),
     66         IsNoABICalls(false), CanUseBSDABICalls(false), FloatABI(HardFloat),
     67         DspRev(NoDSP), HasMSA(false), DisableMadd4(false),
     68         UseIndirectJumpHazard(false), FPMode(FPXX) {
     69     TheCXXABI.set(TargetCXXABI::GenericMIPS);
     70 
     71     if (Triple.isMIPS32())
     72       setABI("o32");
     73     else if (Triple.getEnvironment() == llvm::Triple::GNUABIN32)
     74       setABI("n32");
     75     else
     76       setABI("n64");
     77 
     78     CPU = ABI == "o32" ? "mips32r2" : "mips64r2";
     79 
     80     CanUseBSDABICalls = Triple.isOSFreeBSD() ||
     81                         Triple.isOSOpenBSD();
     82   }
     83 
     84   bool isIEEE754_2008Default() const {
     85     return CPU == "mips32r6" || CPU == "mips64r6";
     86   }
     87 
     88   bool isFP64Default() const {
     89     return CPU == "mips32r6" || ABI == "n32" || ABI == "n64" || ABI == "64";
     90   }
     91 
     92   bool isNan2008() const override { return IsNan2008; }
     93 
     94   bool processorSupportsGPR64() const;
     95 
     96   StringRef getABI() const override { return ABI; }
     97 
     98   bool setABI(const std::string &Name) override {
     99     if (Name == "o32") {
    100       setO32ABITypes();
    101       ABI = Name;
    102       return true;
    103     }
    104 
    105     if (Name == "n32") {
    106       setN32ABITypes();
    107       ABI = Name;
    108       return true;
    109     }
    110     if (Name == "n64") {
    111       setN64ABITypes();
    112       ABI = Name;
    113       return true;
    114     }
    115     return false;
    116   }
    117 
    118   void setO32ABITypes() {
    119     Int64Type = SignedLongLong;
    120     IntMaxType = Int64Type;
    121     LongDoubleFormat = &llvm::APFloat::IEEEdouble();
    122     LongDoubleWidth = LongDoubleAlign = 64;
    123     LongWidth = LongAlign = 32;
    124     MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
    125     PointerWidth = PointerAlign = 32;
    126     PtrDiffType = SignedInt;
    127     SizeType = UnsignedInt;
    128     SuitableAlign = 64;
    129   }
    130 
    131   void setN32N64ABITypes() {
    132     LongDoubleWidth = LongDoubleAlign = 128;
    133     LongDoubleFormat = &llvm::APFloat::IEEEquad();
    134     if (getTriple().isOSFreeBSD()) {
    135       LongDoubleWidth = LongDoubleAlign = 64;
    136       LongDoubleFormat = &llvm::APFloat::IEEEdouble();
    137     }
    138     MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
    139     SuitableAlign = 128;
    140   }
    141 
    142   void setN64ABITypes() {
    143     setN32N64ABITypes();
    144     if (getTriple().isOSOpenBSD()) {
    145       Int64Type = SignedLongLong;
    146     } else {
    147       Int64Type = SignedLong;
    148     }
    149     IntMaxType = Int64Type;
    150     LongWidth = LongAlign = 64;
    151     PointerWidth = PointerAlign = 64;
    152     PtrDiffType = SignedLong;
    153     SizeType = UnsignedLong;
    154   }
    155 
    156   void setN32ABITypes() {
    157     setN32N64ABITypes();
    158     Int64Type = SignedLongLong;
    159     IntMaxType = Int64Type;
    160     LongWidth = LongAlign = 32;
    161     PointerWidth = PointerAlign = 32;
    162     PtrDiffType = SignedInt;
    163     SizeType = UnsignedInt;
    164   }
    165 
    166   bool isValidCPUName(StringRef Name) const override;
    167   void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
    168 
    169   bool setCPU(const std::string &Name) override {
    170     CPU = Name;
    171     return isValidCPUName(Name);
    172   }
    173 
    174   const std::string &getCPU() const { return CPU; }
    175   bool
    176   initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
    177                  StringRef CPU,
    178                  const std::vector<std::string> &FeaturesVec) const override {
    179     if (CPU.empty())
    180       CPU = getCPU();
    181     if (CPU == "octeon")
    182       Features["mips64r2"] = Features["cnmips"] = true;
    183     else if (CPU == "octeon+")
    184       Features["mips64r2"] = Features["cnmips"] = Features["cnmipsp"] = true;
    185     else
    186       Features[CPU] = true;
    187     return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
    188   }
    189 
    190   unsigned getISARev() const;
    191 
    192   void getTargetDefines(const LangOptions &Opts,
    193                         MacroBuilder &Builder) const override;
    194 
    195   ArrayRef<Builtin::Info> getTargetBuiltins() const override;
    196 
    197   bool hasFeature(StringRef Feature) const override;
    198 
    199   BuiltinVaListKind getBuiltinVaListKind() const override {
    200     return TargetInfo::VoidPtrBuiltinVaList;
    201   }
    202 
    203   ArrayRef<const char *> getGCCRegNames() const override {
    204     static const char *const GCCRegNames[] = {
    205         // CPU register names
    206         // Must match second column of GCCRegAliases
    207         "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10",
    208         "$11", "$12", "$13", "$14", "$15", "$16", "$17", "$18", "$19", "$20",
    209         "$21", "$22", "$23", "$24", "$25", "$26", "$27", "$28", "$29", "$30",
    210         "$31",
    211         // Floating point register names
    212         "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9",
    213         "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", "$f16", "$f17", "$f18",
    214         "$f19", "$f20", "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27",
    215         "$f28", "$f29", "$f30", "$f31",
    216         // Hi/lo and condition register names
    217         "hi", "lo", "", "$fcc0", "$fcc1", "$fcc2", "$fcc3", "$fcc4", "$fcc5",
    218         "$fcc6", "$fcc7", "$ac1hi", "$ac1lo", "$ac2hi", "$ac2lo", "$ac3hi",
    219         "$ac3lo",
    220         // MSA register names
    221         "$w0", "$w1", "$w2", "$w3", "$w4", "$w5", "$w6", "$w7", "$w8", "$w9",
    222         "$w10", "$w11", "$w12", "$w13", "$w14", "$w15", "$w16", "$w17", "$w18",
    223         "$w19", "$w20", "$w21", "$w22", "$w23", "$w24", "$w25", "$w26", "$w27",
    224         "$w28", "$w29", "$w30", "$w31",
    225         // MSA control register names
    226         "$msair", "$msacsr", "$msaaccess", "$msasave", "$msamodify",
    227         "$msarequest", "$msamap", "$msaunmap"
    228     };
    229     return llvm::makeArrayRef(GCCRegNames);
    230   }
    231 
    232   bool validateAsmConstraint(const char *&Name,
    233                              TargetInfo::ConstraintInfo &Info) const override {
    234     switch (*Name) {
    235     default:
    236       return false;
    237     case 'r': // CPU registers.
    238     case 'd': // Equivalent to "r" unless generating MIPS16 code.
    239     case 'y': // Equivalent to "r", backward compatibility only.
    240     case 'f': // floating-point registers.
    241     case 'c': // $25 for indirect jumps
    242     case 'l': // lo register
    243     case 'x': // hilo register pair
    244       Info.setAllowsRegister();
    245       return true;
    246     case 'I': // Signed 16-bit constant
    247     case 'J': // Integer 0
    248     case 'K': // Unsigned 16-bit constant
    249     case 'L': // Signed 32-bit constant, lower 16-bit zeros (for lui)
    250     case 'M': // Constants not loadable via lui, addiu, or ori
    251     case 'N': // Constant -1 to -65535
    252     case 'O': // A signed 15-bit constant
    253     case 'P': // A constant between 1 go 65535
    254       return true;
    255     case 'R': // An address that can be used in a non-macro load or store
    256       Info.setAllowsMemory();
    257       return true;
    258     case 'Z':
    259       if (Name[1] == 'C') { // An address usable by ll, and sc.
    260         Info.setAllowsMemory();
    261         Name++; // Skip over 'Z'.
    262         return true;
    263       }
    264       return false;
    265     }
    266   }
    267 
    268   std::string convertConstraint(const char *&Constraint) const override {
    269     std::string R;
    270     switch (*Constraint) {
    271     case 'Z': // Two-character constraint; add "^" hint for later parsing.
    272       if (Constraint[1] == 'C') {
    273         R = std::string("^") + std::string(Constraint, 2);
    274         Constraint++;
    275         return R;
    276       }
    277       break;
    278     }
    279     return TargetInfo::convertConstraint(Constraint);
    280   }
    281 
    282   const char *getClobbers() const override {
    283     // In GCC, $1 is not widely used in generated code (it's used only in a few
    284     // specific situations), so there is no real need for users to add it to
    285     // the clobbers list if they want to use it in their inline assembly code.
    286     //
    287     // In LLVM, $1 is treated as a normal GPR and is always allocatable during
    288     // code generation, so using it in inline assembly without adding it to the
    289     // clobbers list can cause conflicts between the inline assembly code and
    290     // the surrounding generated code.
    291     //
    292     // Another problem is that LLVM is allowed to choose $1 for inline assembly
    293     // operands, which will conflict with the ".set at" assembler option (which
    294     // we use only for inline assembly, in order to maintain compatibility with
    295     // GCC) and will also conflict with the user's usage of $1.
    296     //
    297     // The easiest way to avoid these conflicts and keep $1 as an allocatable
    298     // register for generated code is to automatically clobber $1 for all inline
    299     // assembly code.
    300     //
    301     // FIXME: We should automatically clobber $1 only for inline assembly code
    302     // which actually uses it. This would allow LLVM to use $1 for inline
    303     // assembly operands if the user's assembly code doesn't use it.
    304     return "~{$1}";
    305   }
    306 
    307   bool handleTargetFeatures(std::vector<std::string> &Features,
    308                             DiagnosticsEngine &Diags) override {
    309     IsMips16 = false;
    310     IsMicromips = false;
    311     IsNan2008 = isIEEE754_2008Default();
    312     IsAbs2008 = isIEEE754_2008Default();
    313     IsSingleFloat = false;
    314     FloatABI = HardFloat;
    315     DspRev = NoDSP;
    316     FPMode = isFP64Default() ? FP64 : FPXX;
    317 
    318     for (const auto &Feature : Features) {
    319       if (Feature == "+single-float")
    320         IsSingleFloat = true;
    321       else if (Feature == "+soft-float")
    322         FloatABI = SoftFloat;
    323       else if (Feature == "+mips16")
    324         IsMips16 = true;
    325       else if (Feature == "+micromips")
    326         IsMicromips = true;
    327       else if (Feature == "+dsp")
    328         DspRev = std::max(DspRev, DSP1);
    329       else if (Feature == "+dspr2")
    330         DspRev = std::max(DspRev, DSP2);
    331       else if (Feature == "+msa")
    332         HasMSA = true;
    333       else if (Feature == "+nomadd4")
    334         DisableMadd4 = true;
    335       else if (Feature == "+fp64")
    336         FPMode = FP64;
    337       else if (Feature == "-fp64")
    338         FPMode = FP32;
    339       else if (Feature == "+fpxx")
    340         FPMode = FPXX;
    341       else if (Feature == "+nan2008")
    342         IsNan2008 = true;
    343       else if (Feature == "-nan2008")
    344         IsNan2008 = false;
    345       else if (Feature == "+abs2008")
    346         IsAbs2008 = true;
    347       else if (Feature == "-abs2008")
    348         IsAbs2008 = false;
    349       else if (Feature == "+noabicalls")
    350         IsNoABICalls = true;
    351       else if (Feature == "+use-indirect-jump-hazard")
    352         UseIndirectJumpHazard = true;
    353     }
    354 
    355     setDataLayout();
    356 
    357     return true;
    358   }
    359 
    360   int getEHDataRegisterNumber(unsigned RegNo) const override {
    361     if (RegNo == 0)
    362       return 4;
    363     if (RegNo == 1)
    364       return 5;
    365     return -1;
    366   }
    367 
    368   bool isCLZForZeroUndef() const override { return false; }
    369 
    370   ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
    371     static const TargetInfo::GCCRegAlias O32RegAliases[] = {
    372         {{"at"}, "$1"},  {{"v0"}, "$2"},         {{"v1"}, "$3"},
    373         {{"a0"}, "$4"},  {{"a1"}, "$5"},         {{"a2"}, "$6"},
    374         {{"a3"}, "$7"},  {{"t0"}, "$8"},         {{"t1"}, "$9"},
    375         {{"t2"}, "$10"}, {{"t3"}, "$11"},        {{"t4"}, "$12"},
    376         {{"t5"}, "$13"}, {{"t6"}, "$14"},        {{"t7"}, "$15"},
    377         {{"s0"}, "$16"}, {{"s1"}, "$17"},        {{"s2"}, "$18"},
    378         {{"s3"}, "$19"}, {{"s4"}, "$20"},        {{"s5"}, "$21"},
    379         {{"s6"}, "$22"}, {{"s7"}, "$23"},        {{"t8"}, "$24"},
    380         {{"t9"}, "$25"}, {{"k0"}, "$26"},        {{"k1"}, "$27"},
    381         {{"gp"}, "$28"}, {{"sp", "$sp"}, "$29"}, {{"fp", "$fp"}, "$30"},
    382         {{"ra"}, "$31"}
    383     };
    384     static const TargetInfo::GCCRegAlias NewABIRegAliases[] = {
    385         {{"at"}, "$1"},  {{"v0"}, "$2"},         {{"v1"}, "$3"},
    386         {{"a0"}, "$4"},  {{"a1"}, "$5"},         {{"a2"}, "$6"},
    387         {{"a3"}, "$7"},  {{"a4"}, "$8"},         {{"a5"}, "$9"},
    388         {{"a6"}, "$10"}, {{"a7"}, "$11"},        {{"t0"}, "$12"},
    389         {{"t1"}, "$13"}, {{"t2"}, "$14"},        {{"t3"}, "$15"},
    390         {{"s0"}, "$16"}, {{"s1"}, "$17"},        {{"s2"}, "$18"},
    391         {{"s3"}, "$19"}, {{"s4"}, "$20"},        {{"s5"}, "$21"},
    392         {{"s6"}, "$22"}, {{"s7"}, "$23"},        {{"t8"}, "$24"},
    393         {{"t9"}, "$25"}, {{"k0"}, "$26"},        {{"k1"}, "$27"},
    394         {{"gp"}, "$28"}, {{"sp", "$sp"}, "$29"}, {{"fp", "$fp"}, "$30"},
    395         {{"ra"}, "$31"}
    396     };
    397     if (ABI == "o32")
    398       return llvm::makeArrayRef(O32RegAliases);
    399     return llvm::makeArrayRef(NewABIRegAliases);
    400   }
    401 
    402   bool hasInt128Type() const override {
    403     return (ABI == "n32" || ABI == "n64") || getTargetOpts().ForceEnableInt128;
    404   }
    405 
    406   unsigned getUnwindWordWidth() const override;
    407 
    408   bool validateTarget(DiagnosticsEngine &Diags) const override;
    409   bool hasExtIntType() const override { return true; }
    410 };
    411 } // namespace targets
    412 } // namespace clang
    413 
    414 #endif // LLVM_CLANG_LIB_BASIC_TARGETS_MIPS_H
    415