brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.4 KiB · 22fdcd9 Raw
463 lines · cpp
1//===- Mips.cpp -----------------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "ABIInfoImpl.h"10#include "TargetInfo.h"11 12using namespace clang;13using namespace clang::CodeGen;14 15//===----------------------------------------------------------------------===//16// MIPS ABI Implementation.  This works for both little-endian and17// big-endian variants.18//===----------------------------------------------------------------------===//19 20namespace {21class MipsABIInfo : public ABIInfo {22  bool IsO32;23  const unsigned MinABIStackAlignInBytes, StackAlignInBytes;24  void CoerceToIntArgs(uint64_t TySize,25                       SmallVectorImpl<llvm::Type *> &ArgList) const;26  llvm::Type* HandleAggregates(QualType Ty, uint64_t TySize) const;27  llvm::Type* returnAggregateInRegs(QualType RetTy, uint64_t Size) const;28  llvm::Type* getPaddingType(uint64_t Align, uint64_t Offset) const;29public:30  MipsABIInfo(CodeGenTypes &CGT, bool _IsO32) :31    ABIInfo(CGT), IsO32(_IsO32), MinABIStackAlignInBytes(IsO32 ? 4 : 8),32    StackAlignInBytes(IsO32 ? 8 : 16) {}33 34  ABIArgInfo classifyReturnType(QualType RetTy) const;35  ABIArgInfo classifyArgumentType(QualType RetTy, uint64_t &Offset) const;36  void computeInfo(CGFunctionInfo &FI) const override;37  RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,38                   AggValueSlot Slot) const override;39  ABIArgInfo extendType(QualType Ty) const;40};41 42class MIPSTargetCodeGenInfo : public TargetCodeGenInfo {43  unsigned SizeOfUnwindException;44public:45  MIPSTargetCodeGenInfo(CodeGenTypes &CGT, bool IsO32)46      : TargetCodeGenInfo(std::make_unique<MipsABIInfo>(CGT, IsO32)),47        SizeOfUnwindException(IsO32 ? 24 : 32) {}48 49  int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override {50    return 29;51  }52 53  void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,54                           CodeGen::CodeGenModule &CGM) const override {55    const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);56    if (!FD) return;57    llvm::Function *Fn = cast<llvm::Function>(GV);58 59    if (FD->hasAttr<MipsLongCallAttr>())60      Fn->addFnAttr("long-call");61    else if (FD->hasAttr<MipsShortCallAttr>())62      Fn->addFnAttr("short-call");63 64    // Other attributes do not have a meaning for declarations.65    if (GV->isDeclaration())66      return;67 68    if (FD->hasAttr<Mips16Attr>()) {69      Fn->addFnAttr("mips16");70    }71    else if (FD->hasAttr<NoMips16Attr>()) {72      Fn->addFnAttr("nomips16");73    }74 75    if (FD->hasAttr<MicroMipsAttr>())76      Fn->addFnAttr("micromips");77    else if (FD->hasAttr<NoMicroMipsAttr>())78      Fn->addFnAttr("nomicromips");79 80    const MipsInterruptAttr *Attr = FD->getAttr<MipsInterruptAttr>();81    if (!Attr)82      return;83 84    const char *Kind;85    switch (Attr->getInterrupt()) {86    case MipsInterruptAttr::eic:     Kind = "eic"; break;87    case MipsInterruptAttr::sw0:     Kind = "sw0"; break;88    case MipsInterruptAttr::sw1:     Kind = "sw1"; break;89    case MipsInterruptAttr::hw0:     Kind = "hw0"; break;90    case MipsInterruptAttr::hw1:     Kind = "hw1"; break;91    case MipsInterruptAttr::hw2:     Kind = "hw2"; break;92    case MipsInterruptAttr::hw3:     Kind = "hw3"; break;93    case MipsInterruptAttr::hw4:     Kind = "hw4"; break;94    case MipsInterruptAttr::hw5:     Kind = "hw5"; break;95    }96 97    Fn->addFnAttr("interrupt", Kind);98 99  }100 101  bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,102                               llvm::Value *Address) const override;103 104  unsigned getSizeOfUnwindException() const override {105    return SizeOfUnwindException;106  }107};108 109class WindowsMIPSTargetCodeGenInfo : public MIPSTargetCodeGenInfo {110public:111  WindowsMIPSTargetCodeGenInfo(CodeGenTypes &CGT, bool IsO32)112      : MIPSTargetCodeGenInfo(CGT, IsO32) {}113 114  void getDependentLibraryOption(llvm::StringRef Lib,115                                 llvm::SmallString<24> &Opt) const override {116    Opt = "/DEFAULTLIB:";117    Opt += qualifyWindowsLibrary(Lib);118  }119 120  void getDetectMismatchOption(llvm::StringRef Name, llvm::StringRef Value,121                               llvm::SmallString<32> &Opt) const override {122    Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\"";123  }124};125}126 127void MipsABIInfo::CoerceToIntArgs(128    uint64_t TySize, SmallVectorImpl<llvm::Type *> &ArgList) const {129  llvm::IntegerType *IntTy =130    llvm::IntegerType::get(getVMContext(), MinABIStackAlignInBytes * 8);131 132  // Add (TySize / MinABIStackAlignInBytes) args of IntTy.133  for (unsigned N = TySize / (MinABIStackAlignInBytes * 8); N; --N)134    ArgList.push_back(IntTy);135 136  // If necessary, add one more integer type to ArgList.137  unsigned R = TySize % (MinABIStackAlignInBytes * 8);138 139  if (R)140    ArgList.push_back(llvm::IntegerType::get(getVMContext(), R));141}142 143// In N32/64, an aligned double precision floating point field is passed in144// a register.145llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty, uint64_t TySize) const {146  SmallVector<llvm::Type*, 8> ArgList, IntArgList;147 148  if (IsO32) {149    CoerceToIntArgs(TySize, ArgList);150    return llvm::StructType::get(getVMContext(), ArgList);151  }152 153  if (Ty->isComplexType())154    return CGT.ConvertType(Ty);155 156  const RecordType *RT = Ty->getAsCanonical<RecordType>();157 158  // Unions/vectors are passed in integer registers.159  if (!RT || !RT->isStructureOrClassType()) {160    CoerceToIntArgs(TySize, ArgList);161    return llvm::StructType::get(getVMContext(), ArgList);162  }163 164  const RecordDecl *RD = RT->getDecl()->getDefinitionOrSelf();165  const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);166  assert(!(TySize % 8) && "Size of structure must be multiple of 8.");167 168  uint64_t LastOffset = 0;169  unsigned idx = 0;170  llvm::IntegerType *I64 = llvm::IntegerType::get(getVMContext(), 64);171 172  // Iterate over fields in the struct/class and check if there are any aligned173  // double fields.174  for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();175       i != e; ++i, ++idx) {176    const QualType Ty = i->getType();177    const BuiltinType *BT = Ty->getAs<BuiltinType>();178 179    if (!BT || BT->getKind() != BuiltinType::Double)180      continue;181 182    uint64_t Offset = Layout.getFieldOffset(idx);183    if (Offset % 64) // Ignore doubles that are not aligned.184      continue;185 186    // Add ((Offset - LastOffset) / 64) args of type i64.187    for (unsigned j = (Offset - LastOffset) / 64; j > 0; --j)188      ArgList.push_back(I64);189 190    // Add double type.191    ArgList.push_back(llvm::Type::getDoubleTy(getVMContext()));192    LastOffset = Offset + 64;193  }194 195  CoerceToIntArgs(TySize - LastOffset, IntArgList);196  ArgList.append(IntArgList.begin(), IntArgList.end());197 198  return llvm::StructType::get(getVMContext(), ArgList);199}200 201llvm::Type *MipsABIInfo::getPaddingType(uint64_t OrigOffset,202                                        uint64_t Offset) const {203  if (OrigOffset + MinABIStackAlignInBytes > Offset)204    return nullptr;205 206  return llvm::IntegerType::get(getVMContext(), (Offset - OrigOffset) * 8);207}208 209ABIArgInfo210MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const {211  Ty = useFirstFieldIfTransparentUnion(Ty);212 213  uint64_t OrigOffset = Offset;214  uint64_t TySize = getContext().getTypeSize(Ty);215  uint64_t Align = getContext().getTypeAlign(Ty) / 8;216 217  Align = std::clamp(Align, (uint64_t)MinABIStackAlignInBytes,218                     (uint64_t)StackAlignInBytes);219  unsigned CurrOffset = llvm::alignTo(Offset, Align);220  Offset = CurrOffset + llvm::alignTo(TySize, Align * 8) / 8;221 222  if (isAggregateTypeForABI(Ty) || Ty->isVectorType()) {223    // Ignore empty aggregates.224    if (TySize == 0)225      return ABIArgInfo::getIgnore();226 227    if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {228      Offset = OrigOffset + MinABIStackAlignInBytes;229      return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(),230                                     RAA == CGCXXABI::RAA_DirectInMemory);231    }232 233    // If we have reached here, aggregates are passed directly by coercing to234    // another structure type. Padding is inserted if the offset of the235    // aggregate is unaligned.236    ABIArgInfo ArgInfo =237        ABIArgInfo::getDirect(HandleAggregates(Ty, TySize), 0,238                              getPaddingType(OrigOffset, CurrOffset));239    ArgInfo.setInReg(true);240    return ArgInfo;241  }242 243  // Treat an enum type as its underlying type.244  if (const auto *ED = Ty->getAsEnumDecl())245    Ty = ED->getIntegerType();246 247  // Make sure we pass indirectly things that are too large.248  if (const auto *EIT = Ty->getAs<BitIntType>())249    if (EIT->getNumBits() > 128 ||250        (EIT->getNumBits() > 64 &&251         !getContext().getTargetInfo().hasInt128Type()))252      return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace());253 254  // All integral types are promoted to the GPR width.255  if (Ty->isIntegralOrEnumerationType())256    return extendType(Ty);257 258  return ABIArgInfo::getDirect(259      nullptr, 0, IsO32 ? nullptr : getPaddingType(OrigOffset, CurrOffset));260}261 262llvm::Type*263MipsABIInfo::returnAggregateInRegs(QualType RetTy, uint64_t Size) const {264  const RecordType *RT = RetTy->getAsCanonical<RecordType>();265  SmallVector<llvm::Type*, 8> RTList;266 267  if (RT && RT->isStructureOrClassType()) {268    const RecordDecl *RD = RT->getDecl()->getDefinitionOrSelf();269    const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);270    unsigned FieldCnt = Layout.getFieldCount();271 272    // N32/64 returns struct/classes in floating point registers if the273    // following conditions are met:274    // 1. The size of the struct/class is no larger than 128-bit.275    // 2. The struct/class has one or two fields all of which are floating276    //    point types.277    // 3. The offset of the first field is zero (this follows what gcc does).278    //279    // Any other composite results are returned in integer registers.280    //281    if (FieldCnt && (FieldCnt <= 2) && !Layout.getFieldOffset(0)) {282      RecordDecl::field_iterator b = RD->field_begin(), e = RD->field_end();283      for (; b != e; ++b) {284        const BuiltinType *BT = b->getType()->getAs<BuiltinType>();285 286        if (!BT || !BT->isFloatingPoint())287          break;288 289        RTList.push_back(CGT.ConvertType(b->getType()));290      }291 292      if (b == e)293        return llvm::StructType::get(getVMContext(), RTList,294                                     RD->hasAttr<PackedAttr>());295 296      RTList.clear();297    }298  }299 300  CoerceToIntArgs(Size, RTList);301  return llvm::StructType::get(getVMContext(), RTList);302}303 304ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const {305  uint64_t Size = getContext().getTypeSize(RetTy);306 307  if (RetTy->isVoidType())308    return ABIArgInfo::getIgnore();309 310  // O32 doesn't treat zero-sized structs differently from other structs.311  // However, N32/N64 ignores zero sized return values.312  if (!IsO32 && Size == 0)313    return ABIArgInfo::getIgnore();314 315  if (isAggregateTypeForABI(RetTy) || RetTy->isVectorType()) {316    if (Size <= 128) {317      if (RetTy->isAnyComplexType())318        return ABIArgInfo::getDirect();319 320      // O32 returns integer vectors in registers and N32/N64 returns all small321      // aggregates in registers.322      if (!IsO32 ||323          (RetTy->isVectorType() && !RetTy->hasFloatingRepresentation())) {324        ABIArgInfo ArgInfo =325            ABIArgInfo::getDirect(returnAggregateInRegs(RetTy, Size));326        ArgInfo.setInReg(true);327        return ArgInfo;328      }329    }330 331    return getNaturalAlignIndirect(RetTy, getDataLayout().getAllocaAddrSpace());332  }333 334  // Treat an enum type as its underlying type.335  if (const auto *ED = RetTy->getAsEnumDecl())336    RetTy = ED->getIntegerType();337 338  // Make sure we pass indirectly things that are too large.339  if (const auto *EIT = RetTy->getAs<BitIntType>())340    if (EIT->getNumBits() > 128 ||341        (EIT->getNumBits() > 64 &&342         !getContext().getTargetInfo().hasInt128Type()))343      return getNaturalAlignIndirect(RetTy,344                                     getDataLayout().getAllocaAddrSpace());345 346  if (isPromotableIntegerTypeForABI(RetTy))347    return ABIArgInfo::getExtend(RetTy);348 349  if ((RetTy->isUnsignedIntegerOrEnumerationType() ||350      RetTy->isSignedIntegerOrEnumerationType()) && Size == 32 && !IsO32)351    return ABIArgInfo::getSignExtend(RetTy);352 353  return ABIArgInfo::getDirect();354}355 356void MipsABIInfo::computeInfo(CGFunctionInfo &FI) const {357  ABIArgInfo &RetInfo = FI.getReturnInfo();358  if (!getCXXABI().classifyReturnType(FI))359    RetInfo = classifyReturnType(FI.getReturnType());360 361  // Check if a pointer to an aggregate is passed as a hidden argument.362  uint64_t Offset = RetInfo.isIndirect() ? MinABIStackAlignInBytes : 0;363 364  for (auto &I : FI.arguments())365    I.info = classifyArgumentType(I.type, Offset);366}367 368RValue MipsABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,369                              QualType OrigTy, AggValueSlot Slot) const {370  QualType Ty = OrigTy;371 372  // Integer arguments are promoted to 32-bit on O32 and 64-bit on N32/N64.373  // Pointers are also promoted in the same way but this only matters for N32.374  unsigned SlotSizeInBits = IsO32 ? 32 : 64;375  unsigned PtrWidth = getTarget().getPointerWidth(LangAS::Default);376  bool DidPromote = false;377  if ((Ty->isIntegerType() &&378          getContext().getIntWidth(Ty) < SlotSizeInBits) ||379      (Ty->isPointerType() && PtrWidth < SlotSizeInBits)) {380    DidPromote = true;381    Ty = getContext().getIntTypeForBitwidth(SlotSizeInBits,382                                            Ty->isSignedIntegerType());383  }384 385  auto TyInfo = getContext().getTypeInfoInChars(Ty);386 387  // The alignment of things in the argument area is never larger than388  // StackAlignInBytes.389  TyInfo.Align =390    std::min(TyInfo.Align, CharUnits::fromQuantity(StackAlignInBytes));391 392  // MinABIStackAlignInBytes is the size of argument slots on the stack.393  CharUnits ArgSlotSize = CharUnits::fromQuantity(MinABIStackAlignInBytes);394 395  RValue Res = emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false, TyInfo,396                                ArgSlotSize, /*AllowHigherAlign*/ true, Slot);397 398  // If there was a promotion, "unpromote".399  // TODO: can we just use a pointer into a subset of the original slot?400  if (DidPromote) {401    llvm::Type *ValTy = CGF.ConvertType(OrigTy);402    llvm::Value *Promoted = Res.getScalarVal();403 404    // Truncate down to the right width.405    llvm::Type *IntTy = (OrigTy->isIntegerType() ? ValTy : CGF.IntPtrTy);406    llvm::Value *V = CGF.Builder.CreateTrunc(Promoted, IntTy);407    if (OrigTy->isPointerType())408      V = CGF.Builder.CreateIntToPtr(V, ValTy);409 410    return RValue::get(V);411  }412 413  return Res;414}415 416ABIArgInfo MipsABIInfo::extendType(QualType Ty) const {417  int TySize = getContext().getTypeSize(Ty);418 419  // MIPS64 ABI requires unsigned 32 bit integers to be sign extended.420  if (Ty->isUnsignedIntegerOrEnumerationType() && TySize == 32)421    return ABIArgInfo::getSignExtend(Ty);422 423  return ABIArgInfo::getExtend(Ty);424}425 426bool427MIPSTargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,428                                               llvm::Value *Address) const {429  // This information comes from gcc's implementation, which seems to430  // as canonical as it gets.431 432  // Everything on MIPS is 4 bytes.  Double-precision FP registers433  // are aliased to pairs of single-precision FP registers.434  llvm::Value *Four8 = llvm::ConstantInt::get(CGF.Int8Ty, 4);435 436  // 0-31 are the general purpose registers, $0 - $31.437  // 32-63 are the floating-point registers, $f0 - $f31.438  // 64 and 65 are the multiply/divide registers, $hi and $lo.439  // 66 is the (notional, I think) register for signal-handler return.440  AssignToArrayRange(CGF.Builder, Address, Four8, 0, 65);441 442  // 67-74 are the floating-point status registers, $fcc0 - $fcc7.443  // They are one bit wide and ignored here.444 445  // 80-111 are the coprocessor 0 registers, $c0r0 - $c0r31.446  // (coprocessor 1 is the FP unit)447  // 112-143 are the coprocessor 2 registers, $c2r0 - $c2r31.448  // 144-175 are the coprocessor 3 registers, $c3r0 - $c3r31.449  // 176-181 are the DSP accumulator registers.450  AssignToArrayRange(CGF.Builder, Address, Four8, 80, 181);451  return false;452}453 454std::unique_ptr<TargetCodeGenInfo>455CodeGen::createMIPSTargetCodeGenInfo(CodeGenModule &CGM, bool IsOS32) {456  return std::make_unique<MIPSTargetCodeGenInfo>(CGM.getTypes(), IsOS32);457}458 459std::unique_ptr<TargetCodeGenInfo>460CodeGen::createWindowsMIPSTargetCodeGenInfo(CodeGenModule &CGM, bool IsOS32) {461  return std::make_unique<WindowsMIPSTargetCodeGenInfo>(CGM.getTypes(), IsOS32);462}463