Path: blob/main/contrib/llvm-project/clang/lib/CodeGen/ABIInfoImpl.cpp
35233 views
//===- ABIInfoImpl.cpp ----------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "ABIInfoImpl.h"910using namespace clang;11using namespace clang::CodeGen;1213// Pin the vtable to this file.14DefaultABIInfo::~DefaultABIInfo() = default;1516ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty) const {17Ty = useFirstFieldIfTransparentUnion(Ty);1819if (isAggregateTypeForABI(Ty)) {20// Records with non-trivial destructors/copy-constructors should not be21// passed by value.22if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))23return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);2425return getNaturalAlignIndirect(Ty);26}2728// Treat an enum type as its underlying type.29if (const EnumType *EnumTy = Ty->getAs<EnumType>())30Ty = EnumTy->getDecl()->getIntegerType();3132ASTContext &Context = getContext();33if (const auto *EIT = Ty->getAs<BitIntType>())34if (EIT->getNumBits() >35Context.getTypeSize(Context.getTargetInfo().hasInt128Type()36? Context.Int128Ty37: Context.LongLongTy))38return getNaturalAlignIndirect(Ty);3940return (isPromotableIntegerTypeForABI(Ty) ? ABIArgInfo::getExtend(Ty)41: ABIArgInfo::getDirect());42}4344ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const {45if (RetTy->isVoidType())46return ABIArgInfo::getIgnore();4748if (isAggregateTypeForABI(RetTy))49return getNaturalAlignIndirect(RetTy);5051// Treat an enum type as its underlying type.52if (const EnumType *EnumTy = RetTy->getAs<EnumType>())53RetTy = EnumTy->getDecl()->getIntegerType();5455if (const auto *EIT = RetTy->getAs<BitIntType>())56if (EIT->getNumBits() >57getContext().getTypeSize(getContext().getTargetInfo().hasInt128Type()58? getContext().Int128Ty59: getContext().LongLongTy))60return getNaturalAlignIndirect(RetTy);6162return (isPromotableIntegerTypeForABI(RetTy) ? ABIArgInfo::getExtend(RetTy)63: ABIArgInfo::getDirect());64}6566void DefaultABIInfo::computeInfo(CGFunctionInfo &FI) const {67if (!getCXXABI().classifyReturnType(FI))68FI.getReturnInfo() = classifyReturnType(FI.getReturnType());69for (auto &I : FI.arguments())70I.info = classifyArgumentType(I.type);71}7273RValue DefaultABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,74QualType Ty, AggValueSlot Slot) const {75return CGF.EmitLoadOfAnyValue(76CGF.MakeAddrLValue(77EmitVAArgInstr(CGF, VAListAddr, Ty, classifyArgumentType(Ty)), Ty),78Slot);79}8081ABIArgInfo CodeGen::coerceToIntArray(QualType Ty, ASTContext &Context,82llvm::LLVMContext &LLVMContext) {83// Alignment and Size are measured in bits.84const uint64_t Size = Context.getTypeSize(Ty);85const uint64_t Alignment = Context.getTypeAlign(Ty);86llvm::Type *IntType = llvm::Type::getIntNTy(LLVMContext, Alignment);87const uint64_t NumElements = (Size + Alignment - 1) / Alignment;88return ABIArgInfo::getDirect(llvm::ArrayType::get(IntType, NumElements));89}9091void CodeGen::AssignToArrayRange(CodeGen::CGBuilderTy &Builder,92llvm::Value *Array, llvm::Value *Value,93unsigned FirstIndex, unsigned LastIndex) {94// Alternatively, we could emit this as a loop in the source.95for (unsigned I = FirstIndex; I <= LastIndex; ++I) {96llvm::Value *Cell =97Builder.CreateConstInBoundsGEP1_32(Builder.getInt8Ty(), Array, I);98Builder.CreateAlignedStore(Value, Cell, CharUnits::One());99}100}101102bool CodeGen::isAggregateTypeForABI(QualType T) {103return !CodeGenFunction::hasScalarEvaluationKind(T) ||104T->isMemberFunctionPointerType();105}106107llvm::Type *CodeGen::getVAListElementType(CodeGenFunction &CGF) {108return CGF.ConvertTypeForMem(109CGF.getContext().getBuiltinVaListType()->getPointeeType());110}111112CGCXXABI::RecordArgABI CodeGen::getRecordArgABI(const RecordType *RT,113CGCXXABI &CXXABI) {114const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());115if (!RD) {116if (!RT->getDecl()->canPassInRegisters())117return CGCXXABI::RAA_Indirect;118return CGCXXABI::RAA_Default;119}120return CXXABI.getRecordArgABI(RD);121}122123CGCXXABI::RecordArgABI CodeGen::getRecordArgABI(QualType T, CGCXXABI &CXXABI) {124const RecordType *RT = T->getAs<RecordType>();125if (!RT)126return CGCXXABI::RAA_Default;127return getRecordArgABI(RT, CXXABI);128}129130bool CodeGen::classifyReturnType(const CGCXXABI &CXXABI, CGFunctionInfo &FI,131const ABIInfo &Info) {132QualType Ty = FI.getReturnType();133134if (const auto *RT = Ty->getAs<RecordType>())135if (!isa<CXXRecordDecl>(RT->getDecl()) &&136!RT->getDecl()->canPassInRegisters()) {137FI.getReturnInfo() = Info.getNaturalAlignIndirect(Ty);138return true;139}140141return CXXABI.classifyReturnType(FI);142}143144QualType CodeGen::useFirstFieldIfTransparentUnion(QualType Ty) {145if (const RecordType *UT = Ty->getAsUnionType()) {146const RecordDecl *UD = UT->getDecl();147if (UD->hasAttr<TransparentUnionAttr>()) {148assert(!UD->field_empty() && "sema created an empty transparent union");149return UD->field_begin()->getType();150}151}152return Ty;153}154155llvm::Value *CodeGen::emitRoundPointerUpToAlignment(CodeGenFunction &CGF,156llvm::Value *Ptr,157CharUnits Align) {158// OverflowArgArea = (OverflowArgArea + Align - 1) & -Align;159llvm::Value *RoundUp = CGF.Builder.CreateConstInBoundsGEP1_32(160CGF.Builder.getInt8Ty(), Ptr, Align.getQuantity() - 1);161return CGF.Builder.CreateIntrinsic(162llvm::Intrinsic::ptrmask, {Ptr->getType(), CGF.IntPtrTy},163{RoundUp, llvm::ConstantInt::get(CGF.IntPtrTy, -Align.getQuantity())},164nullptr, Ptr->getName() + ".aligned");165}166167Address168CodeGen::emitVoidPtrDirectVAArg(CodeGenFunction &CGF, Address VAListAddr,169llvm::Type *DirectTy, CharUnits DirectSize,170CharUnits DirectAlign, CharUnits SlotSize,171bool AllowHigherAlign, bool ForceRightAdjust) {172// Cast the element type to i8* if necessary. Some platforms define173// va_list as a struct containing an i8* instead of just an i8*.174if (VAListAddr.getElementType() != CGF.Int8PtrTy)175VAListAddr = VAListAddr.withElementType(CGF.Int8PtrTy);176177llvm::Value *Ptr = CGF.Builder.CreateLoad(VAListAddr, "argp.cur");178179// If the CC aligns values higher than the slot size, do so if needed.180Address Addr = Address::invalid();181if (AllowHigherAlign && DirectAlign > SlotSize) {182Addr = Address(emitRoundPointerUpToAlignment(CGF, Ptr, DirectAlign),183CGF.Int8Ty, DirectAlign);184} else {185Addr = Address(Ptr, CGF.Int8Ty, SlotSize);186}187188// Advance the pointer past the argument, then store that back.189CharUnits FullDirectSize = DirectSize.alignTo(SlotSize);190Address NextPtr =191CGF.Builder.CreateConstInBoundsByteGEP(Addr, FullDirectSize, "argp.next");192CGF.Builder.CreateStore(NextPtr.emitRawPointer(CGF), VAListAddr);193194// If the argument is smaller than a slot, and this is a big-endian195// target, the argument will be right-adjusted in its slot.196if (DirectSize < SlotSize && CGF.CGM.getDataLayout().isBigEndian() &&197(!DirectTy->isStructTy() || ForceRightAdjust)) {198Addr = CGF.Builder.CreateConstInBoundsByteGEP(Addr, SlotSize - DirectSize);199}200201return Addr.withElementType(DirectTy);202}203204RValue CodeGen::emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr,205QualType ValueTy, bool IsIndirect,206TypeInfoChars ValueInfo,207CharUnits SlotSizeAndAlign,208bool AllowHigherAlign, AggValueSlot Slot,209bool ForceRightAdjust) {210// The size and alignment of the value that was passed directly.211CharUnits DirectSize, DirectAlign;212if (IsIndirect) {213DirectSize = CGF.getPointerSize();214DirectAlign = CGF.getPointerAlign();215} else {216DirectSize = ValueInfo.Width;217DirectAlign = ValueInfo.Align;218}219220// Cast the address we've calculated to the right type.221llvm::Type *DirectTy = CGF.ConvertTypeForMem(ValueTy), *ElementTy = DirectTy;222if (IsIndirect) {223unsigned AllocaAS = CGF.CGM.getDataLayout().getAllocaAddrSpace();224DirectTy = llvm::PointerType::get(CGF.getLLVMContext(), AllocaAS);225}226227Address Addr = emitVoidPtrDirectVAArg(CGF, VAListAddr, DirectTy, DirectSize,228DirectAlign, SlotSizeAndAlign,229AllowHigherAlign, ForceRightAdjust);230231if (IsIndirect) {232Addr = Address(CGF.Builder.CreateLoad(Addr), ElementTy, ValueInfo.Align);233}234235return CGF.EmitLoadOfAnyValue(CGF.MakeAddrLValue(Addr, ValueTy), Slot);236}237238Address CodeGen::emitMergePHI(CodeGenFunction &CGF, Address Addr1,239llvm::BasicBlock *Block1, Address Addr2,240llvm::BasicBlock *Block2,241const llvm::Twine &Name) {242assert(Addr1.getType() == Addr2.getType());243llvm::PHINode *PHI = CGF.Builder.CreatePHI(Addr1.getType(), 2, Name);244PHI->addIncoming(Addr1.emitRawPointer(CGF), Block1);245PHI->addIncoming(Addr2.emitRawPointer(CGF), Block2);246CharUnits Align = std::min(Addr1.getAlignment(), Addr2.getAlignment());247return Address(PHI, Addr1.getElementType(), Align);248}249250bool CodeGen::isEmptyField(ASTContext &Context, const FieldDecl *FD,251bool AllowArrays, bool AsIfNoUniqueAddr) {252if (FD->isUnnamedBitField())253return true;254255QualType FT = FD->getType();256257// Constant arrays of empty records count as empty, strip them off.258// Constant arrays of zero length always count as empty.259bool WasArray = false;260if (AllowArrays)261while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) {262if (AT->isZeroSize())263return true;264FT = AT->getElementType();265// The [[no_unique_address]] special case below does not apply to266// arrays of C++ empty records, so we need to remember this fact.267WasArray = true;268}269270const RecordType *RT = FT->getAs<RecordType>();271if (!RT)272return false;273274// C++ record fields are never empty, at least in the Itanium ABI.275//276// FIXME: We should use a predicate for whether this behavior is true in the277// current ABI.278//279// The exception to the above rule are fields marked with the280// [[no_unique_address]] attribute (since C++20). Those do count as empty281// according to the Itanium ABI. The exception applies only to records,282// not arrays of records, so we must also check whether we stripped off an283// array type above.284if (isa<CXXRecordDecl>(RT->getDecl()) &&285(WasArray || (!AsIfNoUniqueAddr && !FD->hasAttr<NoUniqueAddressAttr>())))286return false;287288return isEmptyRecord(Context, FT, AllowArrays, AsIfNoUniqueAddr);289}290291bool CodeGen::isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays,292bool AsIfNoUniqueAddr) {293const RecordType *RT = T->getAs<RecordType>();294if (!RT)295return false;296const RecordDecl *RD = RT->getDecl();297if (RD->hasFlexibleArrayMember())298return false;299300// If this is a C++ record, check the bases first.301if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))302for (const auto &I : CXXRD->bases())303if (!isEmptyRecord(Context, I.getType(), true, AsIfNoUniqueAddr))304return false;305306for (const auto *I : RD->fields())307if (!isEmptyField(Context, I, AllowArrays, AsIfNoUniqueAddr))308return false;309return true;310}311312bool CodeGen::isEmptyFieldForLayout(const ASTContext &Context,313const FieldDecl *FD) {314if (FD->isZeroLengthBitField(Context))315return true;316317if (FD->isUnnamedBitField())318return false;319320return isEmptyRecordForLayout(Context, FD->getType());321}322323bool CodeGen::isEmptyRecordForLayout(const ASTContext &Context, QualType T) {324const RecordType *RT = T->getAs<RecordType>();325if (!RT)326return false;327328const RecordDecl *RD = RT->getDecl();329330// If this is a C++ record, check the bases first.331if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {332if (CXXRD->isDynamicClass())333return false;334335for (const auto &I : CXXRD->bases())336if (!isEmptyRecordForLayout(Context, I.getType()))337return false;338}339340for (const auto *I : RD->fields())341if (!isEmptyFieldForLayout(Context, I))342return false;343344return true;345}346347const Type *CodeGen::isSingleElementStruct(QualType T, ASTContext &Context) {348const RecordType *RT = T->getAs<RecordType>();349if (!RT)350return nullptr;351352const RecordDecl *RD = RT->getDecl();353if (RD->hasFlexibleArrayMember())354return nullptr;355356const Type *Found = nullptr;357358// If this is a C++ record, check the bases first.359if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {360for (const auto &I : CXXRD->bases()) {361// Ignore empty records.362if (isEmptyRecord(Context, I.getType(), true))363continue;364365// If we already found an element then this isn't a single-element struct.366if (Found)367return nullptr;368369// If this is non-empty and not a single element struct, the composite370// cannot be a single element struct.371Found = isSingleElementStruct(I.getType(), Context);372if (!Found)373return nullptr;374}375}376377// Check for single element.378for (const auto *FD : RD->fields()) {379QualType FT = FD->getType();380381// Ignore empty fields.382if (isEmptyField(Context, FD, true))383continue;384385// If we already found an element then this isn't a single-element386// struct.387if (Found)388return nullptr;389390// Treat single element arrays as the element.391while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) {392if (AT->getZExtSize() != 1)393break;394FT = AT->getElementType();395}396397if (!isAggregateTypeForABI(FT)) {398Found = FT.getTypePtr();399} else {400Found = isSingleElementStruct(FT, Context);401if (!Found)402return nullptr;403}404}405406// We don't consider a struct a single-element struct if it has407// padding beyond the element type.408if (Found && Context.getTypeSize(Found) != Context.getTypeSize(T))409return nullptr;410411return Found;412}413414Address CodeGen::EmitVAArgInstr(CodeGenFunction &CGF, Address VAListAddr,415QualType Ty, const ABIArgInfo &AI) {416// This default implementation defers to the llvm backend's va_arg417// instruction. It can handle only passing arguments directly418// (typically only handled in the backend for primitive types), or419// aggregates passed indirectly by pointer (NOTE: if the "byval"420// flag has ABI impact in the callee, this implementation cannot421// work.)422423// Only a few cases are covered here at the moment -- those needed424// by the default abi.425llvm::Value *Val;426427if (AI.isIndirect()) {428assert(!AI.getPaddingType() &&429"Unexpected PaddingType seen in arginfo in generic VAArg emitter!");430assert(431!AI.getIndirectRealign() &&432"Unexpected IndirectRealign seen in arginfo in generic VAArg emitter!");433434auto TyInfo = CGF.getContext().getTypeInfoInChars(Ty);435CharUnits TyAlignForABI = TyInfo.Align;436437llvm::Type *ElementTy = CGF.ConvertTypeForMem(Ty);438llvm::Type *BaseTy = llvm::PointerType::getUnqual(ElementTy);439llvm::Value *Addr =440CGF.Builder.CreateVAArg(VAListAddr.emitRawPointer(CGF), BaseTy);441return Address(Addr, ElementTy, TyAlignForABI);442} else {443assert((AI.isDirect() || AI.isExtend()) &&444"Unexpected ArgInfo Kind in generic VAArg emitter!");445446assert(!AI.getInReg() &&447"Unexpected InReg seen in arginfo in generic VAArg emitter!");448assert(!AI.getPaddingType() &&449"Unexpected PaddingType seen in arginfo in generic VAArg emitter!");450assert(!AI.getDirectOffset() &&451"Unexpected DirectOffset seen in arginfo in generic VAArg emitter!");452assert(!AI.getCoerceToType() &&453"Unexpected CoerceToType seen in arginfo in generic VAArg emitter!");454455Address Temp = CGF.CreateMemTemp(Ty, "varet");456Val = CGF.Builder.CreateVAArg(VAListAddr.emitRawPointer(CGF),457CGF.ConvertTypeForMem(Ty));458CGF.Builder.CreateStore(Val, Temp);459return Temp;460}461}462463bool CodeGen::isSIMDVectorType(ASTContext &Context, QualType Ty) {464return Ty->getAs<VectorType>() && Context.getTypeSize(Ty) == 128;465}466467bool CodeGen::isRecordWithSIMDVectorType(ASTContext &Context, QualType Ty) {468const RecordType *RT = Ty->getAs<RecordType>();469if (!RT)470return false;471const RecordDecl *RD = RT->getDecl();472473// If this is a C++ record, check the bases first.474if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))475for (const auto &I : CXXRD->bases())476if (!isRecordWithSIMDVectorType(Context, I.getType()))477return false;478479for (const auto *i : RD->fields()) {480QualType FT = i->getType();481482if (isSIMDVectorType(Context, FT))483return true;484485if (isRecordWithSIMDVectorType(Context, FT))486return true;487}488489return false;490}491492493