brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.2 KiB · 3fa4e84 Raw
423 lines · cpp
1//===- Sparc.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#include <algorithm>12 13using namespace clang;14using namespace clang::CodeGen;15 16//===----------------------------------------------------------------------===//17// SPARC v8 ABI Implementation.18// Based on the SPARC Compliance Definition version 2.4.1.19//20// Ensures that complex values are passed in registers.21//22namespace {23class SparcV8ABIInfo : public DefaultABIInfo {24public:25  SparcV8ABIInfo(CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}26 27private:28  ABIArgInfo classifyReturnType(QualType RetTy) const;29  ABIArgInfo classifyArgumentType(QualType Ty) const;30  void computeInfo(CGFunctionInfo &FI) const override;31};32} // end anonymous namespace33 34ABIArgInfo SparcV8ABIInfo::classifyReturnType(QualType Ty) const {35  const auto *CT = Ty->getAs<ComplexType>();36  const auto *BT = Ty->getAs<BuiltinType>();37  if (CT)38    BT = CT->getElementType()->getAs<BuiltinType>();39  bool IsLongDouble = BT && BT->getKind() == BuiltinType::LongDouble;40 41  // long double _Complex is special in that it should be marked as inreg.42  if (CT)43    return IsLongDouble ? ABIArgInfo::getDirectInReg()44                        : ABIArgInfo::getDirect();45 46  if (IsLongDouble)47    return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(),48                                   /*ByVal=*/false);49 50  return DefaultABIInfo::classifyReturnType(Ty);51}52 53ABIArgInfo SparcV8ABIInfo::classifyArgumentType(QualType Ty) const {54  if (const auto *BT = Ty->getAs<BuiltinType>();55      BT && BT->getKind() == BuiltinType::LongDouble)56    return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace());57 58  return DefaultABIInfo::classifyArgumentType(Ty);59}60 61void SparcV8ABIInfo::computeInfo(CGFunctionInfo &FI) const {62  FI.getReturnInfo() = classifyReturnType(FI.getReturnType());63  for (auto &Arg : FI.arguments())64    Arg.info = classifyArgumentType(Arg.type);65}66 67namespace {68class SparcV8TargetCodeGenInfo : public TargetCodeGenInfo {69public:70  SparcV8TargetCodeGenInfo(CodeGenTypes &CGT)71      : TargetCodeGenInfo(std::make_unique<SparcV8ABIInfo>(CGT)) {}72 73  llvm::Value *decodeReturnAddress(CodeGen::CodeGenFunction &CGF,74                                   llvm::Value *Address) const override {75    int Offset;76    if (isAggregateTypeForABI(CGF.CurFnInfo->getReturnType()))77      Offset = 12;78    else79      Offset = 8;80    return CGF.Builder.CreateGEP(CGF.Int8Ty, Address,81                                 llvm::ConstantInt::get(CGF.Int32Ty, Offset));82  }83 84  llvm::Value *encodeReturnAddress(CodeGen::CodeGenFunction &CGF,85                                   llvm::Value *Address) const override {86    int Offset;87    if (isAggregateTypeForABI(CGF.CurFnInfo->getReturnType()))88      Offset = -12;89    else90      Offset = -8;91    return CGF.Builder.CreateGEP(CGF.Int8Ty, Address,92                                 llvm::ConstantInt::get(CGF.Int32Ty, Offset));93  }94};95} // end anonymous namespace96 97//===----------------------------------------------------------------------===//98// SPARC v9 ABI Implementation.99// Based on the SPARC Compliance Definition version 2.4.1.100//101// Function arguments a mapped to a nominal "parameter array" and promoted to102// registers depending on their type. Each argument occupies 8 or 16 bytes in103// the array, structs larger than 16 bytes are passed indirectly.104//105// One case requires special care:106//107//   struct mixed {108//     int i;109//     float f;110//   };111//112// When a struct mixed is passed by value, it only occupies 8 bytes in the113// parameter array, but the int is passed in an integer register, and the float114// is passed in a floating point register. This is represented as two arguments115// with the LLVM IR inreg attribute:116//117//   declare void f(i32 inreg %i, float inreg %f)118//119// The code generator will only allocate 4 bytes from the parameter array for120// the inreg arguments. All other arguments are allocated a multiple of 8121// bytes.122//123namespace {124class SparcV9ABIInfo : public ABIInfo {125public:126  SparcV9ABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}127 128private:129  ABIArgInfo classifyType(QualType RetTy, unsigned SizeLimit,130                          unsigned &RegOffset) const;131  void computeInfo(CGFunctionInfo &FI) const override;132  RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,133                   AggValueSlot Slot) const override;134 135  // Coercion type builder for structs passed in registers. The coercion type136  // serves two purposes:137  //138  // 1. Pad structs to a multiple of 64 bits, so they are passed 'left-aligned'139  //    in registers.140  // 2. Expose aligned floating point elements as first-level elements, so the141  //    code generator knows to pass them in floating point registers.142  //143  // We also compute the InReg flag which indicates that the struct contains144  // aligned 32-bit floats.145  //146  struct CoerceBuilder {147    llvm::LLVMContext &Context;148    const llvm::DataLayout &DL;149    SmallVector<llvm::Type*, 8> Elems;150    uint64_t Size;151    bool InReg;152 153    CoerceBuilder(llvm::LLVMContext &c, const llvm::DataLayout &dl)154      : Context(c), DL(dl), Size(0), InReg(false) {}155 156    // Pad Elems with integers until Size is ToSize.157    void pad(uint64_t ToSize) {158      assert(ToSize >= Size && "Cannot remove elements");159      if (ToSize == Size)160        return;161 162      // Finish the current 64-bit word.163      uint64_t Aligned = llvm::alignTo(Size, 64);164      if (Aligned > Size && Aligned <= ToSize) {165        Elems.push_back(llvm::IntegerType::get(Context, Aligned - Size));166        Size = Aligned;167      }168 169      // Add whole 64-bit words.170      while (Size + 64 <= ToSize) {171        Elems.push_back(llvm::Type::getInt64Ty(Context));172        Size += 64;173      }174 175      // Final in-word padding.176      if (Size < ToSize) {177        Elems.push_back(llvm::IntegerType::get(Context, ToSize - Size));178        Size = ToSize;179      }180    }181 182    // Add a floating point element at Offset.183    void addFloat(uint64_t Offset, llvm::Type *Ty, unsigned Bits) {184      // Unaligned floats are treated as integers.185      if (Offset % Bits)186        return;187      // The InReg flag is only required if there are any floats < 64 bits.188      if (Bits < 64)189        InReg = true;190      pad(Offset);191      Elems.push_back(Ty);192      Size = Offset + Bits;193    }194 195    // Add a struct type to the coercion type, starting at Offset (in bits).196    void addStruct(uint64_t Offset, llvm::StructType *StrTy) {197      const llvm::StructLayout *Layout = DL.getStructLayout(StrTy);198      for (unsigned i = 0, e = StrTy->getNumElements(); i != e; ++i) {199        llvm::Type *ElemTy = StrTy->getElementType(i);200        uint64_t ElemOffset = Offset + Layout->getElementOffsetInBits(i);201        switch (ElemTy->getTypeID()) {202        case llvm::Type::StructTyID:203          addStruct(ElemOffset, cast<llvm::StructType>(ElemTy));204          break;205        case llvm::Type::FloatTyID:206          addFloat(ElemOffset, ElemTy, 32);207          break;208        case llvm::Type::DoubleTyID:209          addFloat(ElemOffset, ElemTy, 64);210          break;211        case llvm::Type::FP128TyID:212          addFloat(ElemOffset, ElemTy, 128);213          break;214        case llvm::Type::PointerTyID:215          if (ElemOffset % 64 == 0) {216            pad(ElemOffset);217            Elems.push_back(ElemTy);218            Size += 64;219          }220          break;221        default:222          break;223        }224      }225    }226 227    // Check if Ty is a usable substitute for the coercion type.228    bool isUsableType(llvm::StructType *Ty) const {229      return llvm::ArrayRef(Elems) == Ty->elements();230    }231 232    // Get the coercion type as a literal struct type.233    llvm::Type *getType() const {234      if (Elems.size() == 1)235        return Elems.front();236      else237        return llvm::StructType::get(Context, Elems);238    }239  };240};241} // end anonymous namespace242 243ABIArgInfo SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit,244                                        unsigned &RegOffset) const {245  if (Ty->isVoidType())246    return ABIArgInfo::getIgnore();247 248  auto &Context = getContext();249  auto &VMContext = getVMContext();250 251  uint64_t Size = Context.getTypeSize(Ty);252  unsigned Alignment = Context.getTypeAlign(Ty);253  bool NeedPadding = (Alignment > 64) && (RegOffset % 2 != 0);254 255  // Anything too big to fit in registers is passed with an explicit indirect256  // pointer / sret pointer.257  if (Size > SizeLimit) {258    RegOffset += 1;259    return getNaturalAlignIndirect(260        Ty, /*AddrSpace=*/getDataLayout().getAllocaAddrSpace(),261        /*ByVal=*/false);262  }263 264  // Treat an enum type as its underlying type.265  if (const auto *ED = Ty->getAsEnumDecl())266    Ty = ED->getIntegerType();267 268  // Integer types smaller than a register are extended.269  if (Size < 64 && Ty->isIntegerType()) {270    RegOffset += 1;271    return ABIArgInfo::getExtend(Ty);272  }273 274  if (const auto *EIT = Ty->getAs<BitIntType>())275    if (EIT->getNumBits() < 64) {276      RegOffset += 1;277      return ABIArgInfo::getExtend(Ty);278    }279 280  // Other non-aggregates go in registers.281  if (!isAggregateTypeForABI(Ty)) {282    RegOffset += Size / 64;283    return ABIArgInfo::getDirect();284  }285 286  // If a C++ object has either a non-trivial copy constructor or a non-trivial287  // destructor, it is passed with an explicit indirect pointer / sret pointer.288  if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {289    RegOffset += 1;290    return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(),291                                   RAA == CGCXXABI::RAA_DirectInMemory);292  }293 294  // This is a small aggregate type that should be passed in registers.295  // Build a coercion type from the LLVM struct type.296  llvm::StructType *StrTy = dyn_cast<llvm::StructType>(CGT.ConvertType(Ty));297  if (!StrTy) {298    RegOffset += Size / 64;299    return ABIArgInfo::getDirect();300  }301 302  CoerceBuilder CB(VMContext, getDataLayout());303  CB.addStruct(0, StrTy);304  // All structs, even empty ones, should take up a register argument slot,305  // so pin the minimum struct size to one bit.306  CB.pad(llvm::alignTo(307      std::max(CB.DL.getTypeSizeInBits(StrTy).getKnownMinValue(), uint64_t(1)),308      64));309  RegOffset += CB.Size / 64;310 311  // If we're dealing with overaligned structs we may need to add a padding in312  // the front, to preserve the correct register-memory mapping.313  //314  // See SCD 2.4.1, pages 3P-11 and 3P-12.315  llvm::Type *Padding =316      NeedPadding ? llvm::Type::getInt64Ty(VMContext) : nullptr;317  RegOffset += NeedPadding ? 1 : 0;318 319  // Try to use the original type for coercion.320  llvm::Type *CoerceTy = CB.isUsableType(StrTy) ? StrTy : CB.getType();321 322  ABIArgInfo AAI = ABIArgInfo::getDirect(CoerceTy, 0, Padding);323  AAI.setInReg(CB.InReg);324  return AAI;325}326 327RValue SparcV9ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,328                                 QualType Ty, AggValueSlot Slot) const {329  CharUnits SlotSize = CharUnits::fromQuantity(8);330  auto TInfo = getContext().getTypeInfoInChars(Ty);331 332  // Zero-sized types have a width of one byte for parameter passing purposes.333  TInfo.Width = std::max(TInfo.Width, CharUnits::fromQuantity(1));334 335  // Arguments bigger than 2*SlotSize bytes are passed indirectly.336  return emitVoidPtrVAArg(CGF, VAListAddr, Ty,337                          /*IsIndirect=*/TInfo.Width > 2 * SlotSize, TInfo,338                          SlotSize,339                          /*AllowHigherAlign=*/true, Slot);340}341 342void SparcV9ABIInfo::computeInfo(CGFunctionInfo &FI) const {343  unsigned RetOffset = 0;344  ABIArgInfo RetType = classifyType(FI.getReturnType(), 32 * 8, RetOffset);345  FI.getReturnInfo() = RetType;346 347  // Indirect returns will have its pointer passed as an argument.348  unsigned ArgOffset = RetType.isIndirect() ? RetOffset : 0;349  for (auto &I : FI.arguments())350    I.info = classifyType(I.type, 16 * 8, ArgOffset);351}352 353namespace {354class SparcV9TargetCodeGenInfo : public TargetCodeGenInfo {355public:356  SparcV9TargetCodeGenInfo(CodeGenTypes &CGT)357      : TargetCodeGenInfo(std::make_unique<SparcV9ABIInfo>(CGT)) {}358 359  int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {360    return 14;361  }362 363  bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,364                               llvm::Value *Address) const override;365 366  llvm::Value *decodeReturnAddress(CodeGen::CodeGenFunction &CGF,367                                   llvm::Value *Address) const override {368    return CGF.Builder.CreateGEP(CGF.Int8Ty, Address,369                                 llvm::ConstantInt::get(CGF.Int32Ty, 8));370  }371 372  llvm::Value *encodeReturnAddress(CodeGen::CodeGenFunction &CGF,373                                   llvm::Value *Address) const override {374    return CGF.Builder.CreateGEP(CGF.Int8Ty, Address,375                                 llvm::ConstantInt::get(CGF.Int32Ty, -8));376  }377};378} // end anonymous namespace379 380bool381SparcV9TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,382                                                llvm::Value *Address) const {383  // This is calculated from the LLVM and GCC tables and verified384  // against gcc output.  AFAIK all ABIs use the same encoding.385 386  CodeGen::CGBuilderTy &Builder = CGF.Builder;387 388  llvm::IntegerType *i8 = CGF.Int8Ty;389  llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4);390  llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8);391 392  // 0-31: the 8-byte general-purpose registers393  AssignToArrayRange(Builder, Address, Eight8, 0, 31);394 395  // 32-63: f0-31, the 4-byte floating-point registers396  AssignToArrayRange(Builder, Address, Four8, 32, 63);397 398  //   Y   = 64399  //   PSR = 65400  //   WIM = 66401  //   TBR = 67402  //   PC  = 68403  //   NPC = 69404  //   FSR = 70405  //   CSR = 71406  AssignToArrayRange(Builder, Address, Eight8, 64, 71);407 408  // 72-87: d0-15, the 8-byte floating-point registers409  AssignToArrayRange(Builder, Address, Eight8, 72, 87);410 411  return false;412}413 414std::unique_ptr<TargetCodeGenInfo>415CodeGen::createSparcV8TargetCodeGenInfo(CodeGenModule &CGM) {416  return std::make_unique<SparcV8TargetCodeGenInfo>(CGM.getTypes());417}418 419std::unique_ptr<TargetCodeGenInfo>420CodeGen::createSparcV9TargetCodeGenInfo(CodeGenModule &CGM) {421  return std::make_unique<SparcV9TargetCodeGenInfo>(CGM.getTypes());422}423