brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.0 KiB · 1e3ac2e Raw
479 lines · cpp
1//===- ABIInfoImpl.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 11using namespace clang;12using namespace clang::CodeGen;13 14// Pin the vtable to this file.15DefaultABIInfo::~DefaultABIInfo() = default;16 17ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty) const {18  Ty = useFirstFieldIfTransparentUnion(Ty);19 20  if (isAggregateTypeForABI(Ty)) {21    // Records with non-trivial destructors/copy-constructors should not be22    // passed by value.23    if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))24      return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(),25                                     RAA == CGCXXABI::RAA_DirectInMemory);26 27    return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace());28  }29 30  // Treat an enum type as its underlying type.31  if (const auto *ED = Ty->getAsEnumDecl())32    Ty = ED->getIntegerType();33 34  ASTContext &Context = getContext();35  if (const auto *EIT = Ty->getAs<BitIntType>())36    if (EIT->getNumBits() >37        Context.getTypeSize(Context.getTargetInfo().hasInt128Type()38                                ? Context.Int128Ty39                                : Context.LongLongTy))40      return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace());41 42  return (isPromotableIntegerTypeForABI(Ty)43              ? ABIArgInfo::getExtend(Ty, CGT.ConvertType(Ty))44              : ABIArgInfo::getDirect());45}46 47ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const {48  if (RetTy->isVoidType())49    return ABIArgInfo::getIgnore();50 51  if (isAggregateTypeForABI(RetTy))52    return getNaturalAlignIndirect(RetTy, getDataLayout().getAllocaAddrSpace());53 54  // Treat an enum type as its underlying type.55  if (const auto *ED = RetTy->getAsEnumDecl())56    RetTy = ED->getIntegerType();57 58  if (const auto *EIT = RetTy->getAs<BitIntType>())59    if (EIT->getNumBits() >60        getContext().getTypeSize(getContext().getTargetInfo().hasInt128Type()61                                     ? getContext().Int128Ty62                                     : getContext().LongLongTy))63      return getNaturalAlignIndirect(RetTy,64                                     getDataLayout().getAllocaAddrSpace());65 66  return (isPromotableIntegerTypeForABI(RetTy) ? ABIArgInfo::getExtend(RetTy)67                                               : ABIArgInfo::getDirect());68}69 70void DefaultABIInfo::computeInfo(CGFunctionInfo &FI) const {71  if (!getCXXABI().classifyReturnType(FI))72    FI.getReturnInfo() = classifyReturnType(FI.getReturnType());73  for (auto &I : FI.arguments())74    I.info = classifyArgumentType(I.type);75}76 77RValue DefaultABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,78                                 QualType Ty, AggValueSlot Slot) const {79  return CGF.EmitLoadOfAnyValue(80      CGF.MakeAddrLValue(81          EmitVAArgInstr(CGF, VAListAddr, Ty, classifyArgumentType(Ty)), Ty),82      Slot);83}84 85void CodeGen::AssignToArrayRange(CodeGen::CGBuilderTy &Builder,86                                 llvm::Value *Array, llvm::Value *Value,87                                 unsigned FirstIndex, unsigned LastIndex) {88  // Alternatively, we could emit this as a loop in the source.89  for (unsigned I = FirstIndex; I <= LastIndex; ++I) {90    llvm::Value *Cell =91        Builder.CreateConstInBoundsGEP1_32(Builder.getInt8Ty(), Array, I);92    Builder.CreateAlignedStore(Value, Cell, CharUnits::One());93  }94}95 96bool CodeGen::isAggregateTypeForABI(QualType T) {97  return !CodeGenFunction::hasScalarEvaluationKind(T) ||98         T->isMemberFunctionPointerType();99}100 101llvm::Type *CodeGen::getVAListElementType(CodeGenFunction &CGF) {102  return CGF.ConvertTypeForMem(103      CGF.getContext().getBuiltinVaListType()->getPointeeType());104}105 106CGCXXABI::RecordArgABI CodeGen::getRecordArgABI(const RecordType *RT,107                                                CGCXXABI &CXXABI) {108  const RecordDecl *RD = RT->getDecl()->getDefinitionOrSelf();109  if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD))110    return CXXABI.getRecordArgABI(CXXRD);111  if (!RD->canPassInRegisters())112    return CGCXXABI::RAA_Indirect;113  return CGCXXABI::RAA_Default;114}115 116CGCXXABI::RecordArgABI CodeGen::getRecordArgABI(QualType T, CGCXXABI &CXXABI) {117  const RecordType *RT = T->getAsCanonical<RecordType>();118  if (!RT)119    return CGCXXABI::RAA_Default;120  return getRecordArgABI(RT, CXXABI);121}122 123bool CodeGen::classifyReturnType(const CGCXXABI &CXXABI, CGFunctionInfo &FI,124                                 const ABIInfo &Info) {125  QualType Ty = FI.getReturnType();126 127  if (const auto *RD = Ty->getAsRecordDecl();128      RD && !isa<CXXRecordDecl>(RD) && !RD->canPassInRegisters()) {129    FI.getReturnInfo() = Info.getNaturalAlignIndirect(130        Ty, Info.getDataLayout().getAllocaAddrSpace());131    return true;132  }133 134  return CXXABI.classifyReturnType(FI);135}136 137QualType CodeGen::useFirstFieldIfTransparentUnion(QualType Ty) {138  if (const RecordType *UT = Ty->getAsUnionType()) {139    const RecordDecl *UD = UT->getDecl()->getDefinitionOrSelf();140    if (UD->hasAttr<TransparentUnionAttr>()) {141      assert(!UD->field_empty() && "sema created an empty transparent union");142      return UD->field_begin()->getType();143    }144  }145  return Ty;146}147 148llvm::Value *CodeGen::emitRoundPointerUpToAlignment(CodeGenFunction &CGF,149                                                    llvm::Value *Ptr,150                                                    CharUnits Align) {151  // OverflowArgArea = (OverflowArgArea + Align - 1) & -Align;152  llvm::Value *RoundUp = CGF.Builder.CreateConstInBoundsGEP1_32(153      CGF.Builder.getInt8Ty(), Ptr, Align.getQuantity() - 1);154  return CGF.Builder.CreateIntrinsic(155      llvm::Intrinsic::ptrmask, {Ptr->getType(), CGF.IntPtrTy},156      {RoundUp, llvm::ConstantInt::get(CGF.IntPtrTy, -Align.getQuantity())},157      nullptr, Ptr->getName() + ".aligned");158}159 160Address161CodeGen::emitVoidPtrDirectVAArg(CodeGenFunction &CGF, Address VAListAddr,162                                llvm::Type *DirectTy, CharUnits DirectSize,163                                CharUnits DirectAlign, CharUnits SlotSize,164                                bool AllowHigherAlign, bool ForceRightAdjust) {165  // Cast the element type to i8* if necessary.  Some platforms define166  // va_list as a struct containing an i8* instead of just an i8*.167  if (VAListAddr.getElementType() != CGF.Int8PtrTy)168    VAListAddr = VAListAddr.withElementType(CGF.Int8PtrTy);169 170  llvm::Value *Ptr = CGF.Builder.CreateLoad(VAListAddr, "argp.cur");171 172  // If the CC aligns values higher than the slot size, do so if needed.173  Address Addr = Address::invalid();174  if (AllowHigherAlign && DirectAlign > SlotSize) {175    Addr = Address(emitRoundPointerUpToAlignment(CGF, Ptr, DirectAlign),176                   CGF.Int8Ty, DirectAlign);177  } else {178    Addr = Address(Ptr, CGF.Int8Ty, SlotSize);179  }180 181  // Advance the pointer past the argument, then store that back.182  CharUnits FullDirectSize = DirectSize.alignTo(SlotSize);183  Address NextPtr =184      CGF.Builder.CreateConstInBoundsByteGEP(Addr, FullDirectSize, "argp.next");185  CGF.Builder.CreateStore(NextPtr.emitRawPointer(CGF), VAListAddr);186 187  // If the argument is smaller than a slot, and this is a big-endian188  // target, the argument will be right-adjusted in its slot.189  if (DirectSize < SlotSize && CGF.CGM.getDataLayout().isBigEndian() &&190      (!DirectTy->isStructTy() || ForceRightAdjust)) {191    Addr = CGF.Builder.CreateConstInBoundsByteGEP(Addr, SlotSize - DirectSize);192  }193 194  return Addr.withElementType(DirectTy);195}196 197RValue CodeGen::emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr,198                                 QualType ValueTy, bool IsIndirect,199                                 TypeInfoChars ValueInfo,200                                 CharUnits SlotSizeAndAlign,201                                 bool AllowHigherAlign, AggValueSlot Slot,202                                 bool ForceRightAdjust) {203  // The size and alignment of the value that was passed directly.204  CharUnits DirectSize, DirectAlign;205  if (IsIndirect) {206    DirectSize = CGF.getPointerSize();207    DirectAlign = CGF.getPointerAlign();208  } else {209    DirectSize = ValueInfo.Width;210    DirectAlign = ValueInfo.Align;211  }212 213  // Cast the address we've calculated to the right type.214  llvm::Type *DirectTy = CGF.ConvertTypeForMem(ValueTy), *ElementTy = DirectTy;215  if (IsIndirect) {216    unsigned AllocaAS = CGF.CGM.getDataLayout().getAllocaAddrSpace();217    DirectTy = llvm::PointerType::get(CGF.getLLVMContext(), AllocaAS);218  }219 220  Address Addr = emitVoidPtrDirectVAArg(CGF, VAListAddr, DirectTy, DirectSize,221                                        DirectAlign, SlotSizeAndAlign,222                                        AllowHigherAlign, ForceRightAdjust);223 224  if (IsIndirect) {225    Addr = Address(CGF.Builder.CreateLoad(Addr), ElementTy, ValueInfo.Align);226  }227 228  return CGF.EmitLoadOfAnyValue(CGF.MakeAddrLValue(Addr, ValueTy), Slot);229}230 231Address CodeGen::emitMergePHI(CodeGenFunction &CGF, Address Addr1,232                              llvm::BasicBlock *Block1, Address Addr2,233                              llvm::BasicBlock *Block2,234                              const llvm::Twine &Name) {235  assert(Addr1.getType() == Addr2.getType());236  llvm::PHINode *PHI = CGF.Builder.CreatePHI(Addr1.getType(), 2, Name);237  PHI->addIncoming(Addr1.emitRawPointer(CGF), Block1);238  PHI->addIncoming(Addr2.emitRawPointer(CGF), Block2);239  CharUnits Align = std::min(Addr1.getAlignment(), Addr2.getAlignment());240  return Address(PHI, Addr1.getElementType(), Align);241}242 243bool CodeGen::isEmptyField(ASTContext &Context, const FieldDecl *FD,244                           bool AllowArrays, bool AsIfNoUniqueAddr) {245  if (FD->isUnnamedBitField())246    return true;247 248  QualType FT = FD->getType();249 250  // Constant arrays of empty records count as empty, strip them off.251  // Constant arrays of zero length always count as empty.252  bool WasArray = false;253  if (AllowArrays)254    while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) {255      if (AT->isZeroSize())256        return true;257      FT = AT->getElementType();258      // The [[no_unique_address]] special case below does not apply to259      // arrays of C++ empty records, so we need to remember this fact.260      WasArray = true;261    }262 263  const RecordType *RT = FT->getAsCanonical<RecordType>();264  if (!RT)265    return false;266 267  // C++ record fields are never empty, at least in the Itanium ABI.268  //269  // FIXME: We should use a predicate for whether this behavior is true in the270  // current ABI.271  //272  // The exception to the above rule are fields marked with the273  // [[no_unique_address]] attribute (since C++20).  Those do count as empty274  // according to the Itanium ABI.  The exception applies only to records,275  // not arrays of records, so we must also check whether we stripped off an276  // array type above.277  if (isa<CXXRecordDecl>(RT->getDecl()) &&278      (WasArray || (!AsIfNoUniqueAddr && !FD->hasAttr<NoUniqueAddressAttr>())))279    return false;280 281  return isEmptyRecord(Context, FT, AllowArrays, AsIfNoUniqueAddr);282}283 284bool CodeGen::isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays,285                            bool AsIfNoUniqueAddr) {286  const auto *RD = T->getAsRecordDecl();287  if (!RD)288    return false;289  if (RD->hasFlexibleArrayMember())290    return false;291 292  // If this is a C++ record, check the bases first.293  if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))294    for (const auto &I : CXXRD->bases())295      if (!isEmptyRecord(Context, I.getType(), true, AsIfNoUniqueAddr))296        return false;297 298  for (const auto *I : RD->fields())299    if (!isEmptyField(Context, I, AllowArrays, AsIfNoUniqueAddr))300      return false;301  return true;302}303 304bool CodeGen::isEmptyFieldForLayout(const ASTContext &Context,305                                    const FieldDecl *FD) {306  if (FD->isZeroLengthBitField())307    return true;308 309  if (FD->isUnnamedBitField())310    return false;311 312  return isEmptyRecordForLayout(Context, FD->getType());313}314 315bool CodeGen::isEmptyRecordForLayout(const ASTContext &Context, QualType T) {316  const auto *RD = T->getAsRecordDecl();317  if (!RD)318    return false;319 320  // If this is a C++ record, check the bases first.321  if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {322    if (CXXRD->isDynamicClass())323      return false;324 325    for (const auto &I : CXXRD->bases())326      if (!isEmptyRecordForLayout(Context, I.getType()))327        return false;328  }329 330  for (const auto *I : RD->fields())331    if (!isEmptyFieldForLayout(Context, I))332      return false;333 334  return true;335}336 337const Type *CodeGen::isSingleElementStruct(QualType T, ASTContext &Context) {338  const auto *RD = T->getAsRecordDecl();339  if (!RD)340    return nullptr;341 342  if (RD->hasFlexibleArrayMember())343    return nullptr;344 345  const Type *Found = nullptr;346 347  // If this is a C++ record, check the bases first.348  if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {349    for (const auto &I : CXXRD->bases()) {350      // Ignore empty records.351      if (isEmptyRecord(Context, I.getType(), true))352        continue;353 354      // If we already found an element then this isn't a single-element struct.355      if (Found)356        return nullptr;357 358      // If this is non-empty and not a single element struct, the composite359      // cannot be a single element struct.360      Found = isSingleElementStruct(I.getType(), Context);361      if (!Found)362        return nullptr;363    }364  }365 366  // Check for single element.367  for (const auto *FD : RD->fields()) {368    QualType FT = FD->getType();369 370    // Ignore empty fields.371    if (isEmptyField(Context, FD, true))372      continue;373 374    // If we already found an element then this isn't a single-element375    // struct.376    if (Found)377      return nullptr;378 379    // Treat single element arrays as the element.380    while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) {381      if (AT->getZExtSize() != 1)382        break;383      FT = AT->getElementType();384    }385 386    if (!isAggregateTypeForABI(FT)) {387      Found = FT.getTypePtr();388    } else {389      Found = isSingleElementStruct(FT, Context);390      if (!Found)391        return nullptr;392    }393  }394 395  // We don't consider a struct a single-element struct if it has396  // padding beyond the element type.397  if (Found && Context.getTypeSize(Found) != Context.getTypeSize(T))398    return nullptr;399 400  return Found;401}402 403Address CodeGen::EmitVAArgInstr(CodeGenFunction &CGF, Address VAListAddr,404                                QualType Ty, const ABIArgInfo &AI) {405  // This default implementation defers to the llvm backend's va_arg406  // instruction. It can handle only passing arguments directly407  // (typically only handled in the backend for primitive types), or408  // aggregates passed indirectly by pointer (NOTE: if the "byval"409  // flag has ABI impact in the callee, this implementation cannot410  // work.)411 412  // Only a few cases are covered here at the moment -- those needed413  // by the default abi.414  llvm::Value *Val;415 416  if (AI.isIndirect()) {417    assert(!AI.getPaddingType() &&418           "Unexpected PaddingType seen in arginfo in generic VAArg emitter!");419    assert(420        !AI.getIndirectRealign() &&421        "Unexpected IndirectRealign seen in arginfo in generic VAArg emitter!");422 423    auto TyInfo = CGF.getContext().getTypeInfoInChars(Ty);424    CharUnits TyAlignForABI = TyInfo.Align;425 426    llvm::Type *ElementTy = CGF.ConvertTypeForMem(Ty);427    llvm::Type *BaseTy = llvm::PointerType::getUnqual(CGF.getLLVMContext());428    llvm::Value *Addr =429        CGF.Builder.CreateVAArg(VAListAddr.emitRawPointer(CGF), BaseTy);430    return Address(Addr, ElementTy, TyAlignForABI);431  } else {432    assert((AI.isDirect() || AI.isExtend()) &&433           "Unexpected ArgInfo Kind in generic VAArg emitter!");434 435    assert(!AI.getInReg() &&436           "Unexpected InReg seen in arginfo in generic VAArg emitter!");437    assert(!AI.getPaddingType() &&438           "Unexpected PaddingType seen in arginfo in generic VAArg emitter!");439    assert(!AI.getDirectOffset() &&440           "Unexpected DirectOffset seen in arginfo in generic VAArg emitter!");441    assert(!AI.getCoerceToType() &&442           "Unexpected CoerceToType seen in arginfo in generic VAArg emitter!");443 444    Address Temp = CGF.CreateMemTemp(Ty, "varet");445    Val = CGF.Builder.CreateVAArg(VAListAddr.emitRawPointer(CGF),446                                  CGF.ConvertTypeForMem(Ty));447    CGF.Builder.CreateStore(Val, Temp);448    return Temp;449  }450}451 452bool CodeGen::isSIMDVectorType(ASTContext &Context, QualType Ty) {453  return Ty->getAs<VectorType>() && Context.getTypeSize(Ty) == 128;454}455 456bool CodeGen::isRecordWithSIMDVectorType(ASTContext &Context, QualType Ty) {457  const auto *RD = Ty->getAsRecordDecl();458  if (!RD)459    return false;460 461  // If this is a C++ record, check the bases first.462  if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))463    for (const auto &I : CXXRD->bases())464      if (!isRecordWithSIMDVectorType(Context, I.getType()))465        return false;466 467  for (const auto *i : RD->fields()) {468    QualType FT = i->getType();469 470    if (isSIMDVectorType(Context, FT))471      return true;472 473    if (isRecordWithSIMDVectorType(Context, FT))474      return true;475  }476 477  return false;478}479