106c3fb27SDimitry Andric //===- ABIInfoImpl.cpp ----------------------------------------------------===// 206c3fb27SDimitry Andric // 306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 606c3fb27SDimitry Andric // 706c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 806c3fb27SDimitry Andric 906c3fb27SDimitry Andric #include "ABIInfoImpl.h" 1006c3fb27SDimitry Andric 1106c3fb27SDimitry Andric using namespace clang; 1206c3fb27SDimitry Andric using namespace clang::CodeGen; 1306c3fb27SDimitry Andric 1406c3fb27SDimitry Andric // Pin the vtable to this file. 1506c3fb27SDimitry Andric DefaultABIInfo::~DefaultABIInfo() = default; 1606c3fb27SDimitry Andric 1706c3fb27SDimitry Andric ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty) const { 1806c3fb27SDimitry Andric Ty = useFirstFieldIfTransparentUnion(Ty); 1906c3fb27SDimitry Andric 2006c3fb27SDimitry Andric if (isAggregateTypeForABI(Ty)) { 2106c3fb27SDimitry Andric // Records with non-trivial destructors/copy-constructors should not be 2206c3fb27SDimitry Andric // passed by value. 2306c3fb27SDimitry Andric if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) 2406c3fb27SDimitry Andric return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); 2506c3fb27SDimitry Andric 2606c3fb27SDimitry Andric return getNaturalAlignIndirect(Ty); 2706c3fb27SDimitry Andric } 2806c3fb27SDimitry Andric 2906c3fb27SDimitry Andric // Treat an enum type as its underlying type. 3006c3fb27SDimitry Andric if (const EnumType *EnumTy = Ty->getAs<EnumType>()) 3106c3fb27SDimitry Andric Ty = EnumTy->getDecl()->getIntegerType(); 3206c3fb27SDimitry Andric 3306c3fb27SDimitry Andric ASTContext &Context = getContext(); 3406c3fb27SDimitry Andric if (const auto *EIT = Ty->getAs<BitIntType>()) 3506c3fb27SDimitry Andric if (EIT->getNumBits() > 3606c3fb27SDimitry Andric Context.getTypeSize(Context.getTargetInfo().hasInt128Type() 3706c3fb27SDimitry Andric ? Context.Int128Ty 3806c3fb27SDimitry Andric : Context.LongLongTy)) 3906c3fb27SDimitry Andric return getNaturalAlignIndirect(Ty); 4006c3fb27SDimitry Andric 4106c3fb27SDimitry Andric return (isPromotableIntegerTypeForABI(Ty) ? ABIArgInfo::getExtend(Ty) 4206c3fb27SDimitry Andric : ABIArgInfo::getDirect()); 4306c3fb27SDimitry Andric } 4406c3fb27SDimitry Andric 4506c3fb27SDimitry Andric ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const { 4606c3fb27SDimitry Andric if (RetTy->isVoidType()) 4706c3fb27SDimitry Andric return ABIArgInfo::getIgnore(); 4806c3fb27SDimitry Andric 4906c3fb27SDimitry Andric if (isAggregateTypeForABI(RetTy)) 5006c3fb27SDimitry Andric return getNaturalAlignIndirect(RetTy); 5106c3fb27SDimitry Andric 5206c3fb27SDimitry Andric // Treat an enum type as its underlying type. 5306c3fb27SDimitry Andric if (const EnumType *EnumTy = RetTy->getAs<EnumType>()) 5406c3fb27SDimitry Andric RetTy = EnumTy->getDecl()->getIntegerType(); 5506c3fb27SDimitry Andric 5606c3fb27SDimitry Andric if (const auto *EIT = RetTy->getAs<BitIntType>()) 5706c3fb27SDimitry Andric if (EIT->getNumBits() > 5806c3fb27SDimitry Andric getContext().getTypeSize(getContext().getTargetInfo().hasInt128Type() 5906c3fb27SDimitry Andric ? getContext().Int128Ty 6006c3fb27SDimitry Andric : getContext().LongLongTy)) 6106c3fb27SDimitry Andric return getNaturalAlignIndirect(RetTy); 6206c3fb27SDimitry Andric 6306c3fb27SDimitry Andric return (isPromotableIntegerTypeForABI(RetTy) ? ABIArgInfo::getExtend(RetTy) 6406c3fb27SDimitry Andric : ABIArgInfo::getDirect()); 6506c3fb27SDimitry Andric } 6606c3fb27SDimitry Andric 6706c3fb27SDimitry Andric void DefaultABIInfo::computeInfo(CGFunctionInfo &FI) const { 6806c3fb27SDimitry Andric if (!getCXXABI().classifyReturnType(FI)) 6906c3fb27SDimitry Andric FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); 7006c3fb27SDimitry Andric for (auto &I : FI.arguments()) 7106c3fb27SDimitry Andric I.info = classifyArgumentType(I.type); 7206c3fb27SDimitry Andric } 7306c3fb27SDimitry Andric 74*0fca6ea1SDimitry Andric RValue DefaultABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, 75*0fca6ea1SDimitry Andric QualType Ty, AggValueSlot Slot) const { 76*0fca6ea1SDimitry Andric return CGF.EmitLoadOfAnyValue( 77*0fca6ea1SDimitry Andric CGF.MakeAddrLValue( 78*0fca6ea1SDimitry Andric EmitVAArgInstr(CGF, VAListAddr, Ty, classifyArgumentType(Ty)), Ty), 79*0fca6ea1SDimitry Andric Slot); 8006c3fb27SDimitry Andric } 8106c3fb27SDimitry Andric 8206c3fb27SDimitry Andric ABIArgInfo CodeGen::coerceToIntArray(QualType Ty, ASTContext &Context, 8306c3fb27SDimitry Andric llvm::LLVMContext &LLVMContext) { 8406c3fb27SDimitry Andric // Alignment and Size are measured in bits. 8506c3fb27SDimitry Andric const uint64_t Size = Context.getTypeSize(Ty); 8606c3fb27SDimitry Andric const uint64_t Alignment = Context.getTypeAlign(Ty); 8706c3fb27SDimitry Andric llvm::Type *IntType = llvm::Type::getIntNTy(LLVMContext, Alignment); 8806c3fb27SDimitry Andric const uint64_t NumElements = (Size + Alignment - 1) / Alignment; 8906c3fb27SDimitry Andric return ABIArgInfo::getDirect(llvm::ArrayType::get(IntType, NumElements)); 9006c3fb27SDimitry Andric } 9106c3fb27SDimitry Andric 9206c3fb27SDimitry Andric void CodeGen::AssignToArrayRange(CodeGen::CGBuilderTy &Builder, 9306c3fb27SDimitry Andric llvm::Value *Array, llvm::Value *Value, 9406c3fb27SDimitry Andric unsigned FirstIndex, unsigned LastIndex) { 9506c3fb27SDimitry Andric // Alternatively, we could emit this as a loop in the source. 9606c3fb27SDimitry Andric for (unsigned I = FirstIndex; I <= LastIndex; ++I) { 9706c3fb27SDimitry Andric llvm::Value *Cell = 9806c3fb27SDimitry Andric Builder.CreateConstInBoundsGEP1_32(Builder.getInt8Ty(), Array, I); 9906c3fb27SDimitry Andric Builder.CreateAlignedStore(Value, Cell, CharUnits::One()); 10006c3fb27SDimitry Andric } 10106c3fb27SDimitry Andric } 10206c3fb27SDimitry Andric 10306c3fb27SDimitry Andric bool CodeGen::isAggregateTypeForABI(QualType T) { 10406c3fb27SDimitry Andric return !CodeGenFunction::hasScalarEvaluationKind(T) || 10506c3fb27SDimitry Andric T->isMemberFunctionPointerType(); 10606c3fb27SDimitry Andric } 10706c3fb27SDimitry Andric 10806c3fb27SDimitry Andric llvm::Type *CodeGen::getVAListElementType(CodeGenFunction &CGF) { 10906c3fb27SDimitry Andric return CGF.ConvertTypeForMem( 11006c3fb27SDimitry Andric CGF.getContext().getBuiltinVaListType()->getPointeeType()); 11106c3fb27SDimitry Andric } 11206c3fb27SDimitry Andric 11306c3fb27SDimitry Andric CGCXXABI::RecordArgABI CodeGen::getRecordArgABI(const RecordType *RT, 11406c3fb27SDimitry Andric CGCXXABI &CXXABI) { 11506c3fb27SDimitry Andric const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); 11606c3fb27SDimitry Andric if (!RD) { 11706c3fb27SDimitry Andric if (!RT->getDecl()->canPassInRegisters()) 11806c3fb27SDimitry Andric return CGCXXABI::RAA_Indirect; 11906c3fb27SDimitry Andric return CGCXXABI::RAA_Default; 12006c3fb27SDimitry Andric } 12106c3fb27SDimitry Andric return CXXABI.getRecordArgABI(RD); 12206c3fb27SDimitry Andric } 12306c3fb27SDimitry Andric 12406c3fb27SDimitry Andric CGCXXABI::RecordArgABI CodeGen::getRecordArgABI(QualType T, CGCXXABI &CXXABI) { 12506c3fb27SDimitry Andric const RecordType *RT = T->getAs<RecordType>(); 12606c3fb27SDimitry Andric if (!RT) 12706c3fb27SDimitry Andric return CGCXXABI::RAA_Default; 12806c3fb27SDimitry Andric return getRecordArgABI(RT, CXXABI); 12906c3fb27SDimitry Andric } 13006c3fb27SDimitry Andric 13106c3fb27SDimitry Andric bool CodeGen::classifyReturnType(const CGCXXABI &CXXABI, CGFunctionInfo &FI, 13206c3fb27SDimitry Andric const ABIInfo &Info) { 13306c3fb27SDimitry Andric QualType Ty = FI.getReturnType(); 13406c3fb27SDimitry Andric 13506c3fb27SDimitry Andric if (const auto *RT = Ty->getAs<RecordType>()) 13606c3fb27SDimitry Andric if (!isa<CXXRecordDecl>(RT->getDecl()) && 13706c3fb27SDimitry Andric !RT->getDecl()->canPassInRegisters()) { 13806c3fb27SDimitry Andric FI.getReturnInfo() = Info.getNaturalAlignIndirect(Ty); 13906c3fb27SDimitry Andric return true; 14006c3fb27SDimitry Andric } 14106c3fb27SDimitry Andric 14206c3fb27SDimitry Andric return CXXABI.classifyReturnType(FI); 14306c3fb27SDimitry Andric } 14406c3fb27SDimitry Andric 14506c3fb27SDimitry Andric QualType CodeGen::useFirstFieldIfTransparentUnion(QualType Ty) { 14606c3fb27SDimitry Andric if (const RecordType *UT = Ty->getAsUnionType()) { 14706c3fb27SDimitry Andric const RecordDecl *UD = UT->getDecl(); 14806c3fb27SDimitry Andric if (UD->hasAttr<TransparentUnionAttr>()) { 14906c3fb27SDimitry Andric assert(!UD->field_empty() && "sema created an empty transparent union"); 15006c3fb27SDimitry Andric return UD->field_begin()->getType(); 15106c3fb27SDimitry Andric } 15206c3fb27SDimitry Andric } 15306c3fb27SDimitry Andric return Ty; 15406c3fb27SDimitry Andric } 15506c3fb27SDimitry Andric 15606c3fb27SDimitry Andric llvm::Value *CodeGen::emitRoundPointerUpToAlignment(CodeGenFunction &CGF, 15706c3fb27SDimitry Andric llvm::Value *Ptr, 15806c3fb27SDimitry Andric CharUnits Align) { 15906c3fb27SDimitry Andric // OverflowArgArea = (OverflowArgArea + Align - 1) & -Align; 16006c3fb27SDimitry Andric llvm::Value *RoundUp = CGF.Builder.CreateConstInBoundsGEP1_32( 16106c3fb27SDimitry Andric CGF.Builder.getInt8Ty(), Ptr, Align.getQuantity() - 1); 16206c3fb27SDimitry Andric return CGF.Builder.CreateIntrinsic( 163*0fca6ea1SDimitry Andric llvm::Intrinsic::ptrmask, {Ptr->getType(), CGF.IntPtrTy}, 16406c3fb27SDimitry Andric {RoundUp, llvm::ConstantInt::get(CGF.IntPtrTy, -Align.getQuantity())}, 16506c3fb27SDimitry Andric nullptr, Ptr->getName() + ".aligned"); 16606c3fb27SDimitry Andric } 16706c3fb27SDimitry Andric 16806c3fb27SDimitry Andric Address 16906c3fb27SDimitry Andric CodeGen::emitVoidPtrDirectVAArg(CodeGenFunction &CGF, Address VAListAddr, 17006c3fb27SDimitry Andric llvm::Type *DirectTy, CharUnits DirectSize, 17106c3fb27SDimitry Andric CharUnits DirectAlign, CharUnits SlotSize, 17206c3fb27SDimitry Andric bool AllowHigherAlign, bool ForceRightAdjust) { 17306c3fb27SDimitry Andric // Cast the element type to i8* if necessary. Some platforms define 17406c3fb27SDimitry Andric // va_list as a struct containing an i8* instead of just an i8*. 17506c3fb27SDimitry Andric if (VAListAddr.getElementType() != CGF.Int8PtrTy) 17606c3fb27SDimitry Andric VAListAddr = VAListAddr.withElementType(CGF.Int8PtrTy); 17706c3fb27SDimitry Andric 17806c3fb27SDimitry Andric llvm::Value *Ptr = CGF.Builder.CreateLoad(VAListAddr, "argp.cur"); 17906c3fb27SDimitry Andric 18006c3fb27SDimitry Andric // If the CC aligns values higher than the slot size, do so if needed. 18106c3fb27SDimitry Andric Address Addr = Address::invalid(); 18206c3fb27SDimitry Andric if (AllowHigherAlign && DirectAlign > SlotSize) { 18306c3fb27SDimitry Andric Addr = Address(emitRoundPointerUpToAlignment(CGF, Ptr, DirectAlign), 18406c3fb27SDimitry Andric CGF.Int8Ty, DirectAlign); 18506c3fb27SDimitry Andric } else { 18606c3fb27SDimitry Andric Addr = Address(Ptr, CGF.Int8Ty, SlotSize); 18706c3fb27SDimitry Andric } 18806c3fb27SDimitry Andric 18906c3fb27SDimitry Andric // Advance the pointer past the argument, then store that back. 19006c3fb27SDimitry Andric CharUnits FullDirectSize = DirectSize.alignTo(SlotSize); 19106c3fb27SDimitry Andric Address NextPtr = 19206c3fb27SDimitry Andric CGF.Builder.CreateConstInBoundsByteGEP(Addr, FullDirectSize, "argp.next"); 193*0fca6ea1SDimitry Andric CGF.Builder.CreateStore(NextPtr.emitRawPointer(CGF), VAListAddr); 19406c3fb27SDimitry Andric 19506c3fb27SDimitry Andric // If the argument is smaller than a slot, and this is a big-endian 19606c3fb27SDimitry Andric // target, the argument will be right-adjusted in its slot. 19706c3fb27SDimitry Andric if (DirectSize < SlotSize && CGF.CGM.getDataLayout().isBigEndian() && 19806c3fb27SDimitry Andric (!DirectTy->isStructTy() || ForceRightAdjust)) { 19906c3fb27SDimitry Andric Addr = CGF.Builder.CreateConstInBoundsByteGEP(Addr, SlotSize - DirectSize); 20006c3fb27SDimitry Andric } 20106c3fb27SDimitry Andric 20206c3fb27SDimitry Andric return Addr.withElementType(DirectTy); 20306c3fb27SDimitry Andric } 20406c3fb27SDimitry Andric 205*0fca6ea1SDimitry Andric RValue CodeGen::emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr, 20606c3fb27SDimitry Andric QualType ValueTy, bool IsIndirect, 20706c3fb27SDimitry Andric TypeInfoChars ValueInfo, 20806c3fb27SDimitry Andric CharUnits SlotSizeAndAlign, 209*0fca6ea1SDimitry Andric bool AllowHigherAlign, AggValueSlot Slot, 21006c3fb27SDimitry Andric bool ForceRightAdjust) { 21106c3fb27SDimitry Andric // The size and alignment of the value that was passed directly. 21206c3fb27SDimitry Andric CharUnits DirectSize, DirectAlign; 21306c3fb27SDimitry Andric if (IsIndirect) { 21406c3fb27SDimitry Andric DirectSize = CGF.getPointerSize(); 21506c3fb27SDimitry Andric DirectAlign = CGF.getPointerAlign(); 21606c3fb27SDimitry Andric } else { 21706c3fb27SDimitry Andric DirectSize = ValueInfo.Width; 21806c3fb27SDimitry Andric DirectAlign = ValueInfo.Align; 21906c3fb27SDimitry Andric } 22006c3fb27SDimitry Andric 22106c3fb27SDimitry Andric // Cast the address we've calculated to the right type. 22206c3fb27SDimitry Andric llvm::Type *DirectTy = CGF.ConvertTypeForMem(ValueTy), *ElementTy = DirectTy; 22306c3fb27SDimitry Andric if (IsIndirect) { 22406c3fb27SDimitry Andric unsigned AllocaAS = CGF.CGM.getDataLayout().getAllocaAddrSpace(); 22506c3fb27SDimitry Andric DirectTy = llvm::PointerType::get(CGF.getLLVMContext(), AllocaAS); 22606c3fb27SDimitry Andric } 22706c3fb27SDimitry Andric 22806c3fb27SDimitry Andric Address Addr = emitVoidPtrDirectVAArg(CGF, VAListAddr, DirectTy, DirectSize, 22906c3fb27SDimitry Andric DirectAlign, SlotSizeAndAlign, 23006c3fb27SDimitry Andric AllowHigherAlign, ForceRightAdjust); 23106c3fb27SDimitry Andric 23206c3fb27SDimitry Andric if (IsIndirect) { 23306c3fb27SDimitry Andric Addr = Address(CGF.Builder.CreateLoad(Addr), ElementTy, ValueInfo.Align); 23406c3fb27SDimitry Andric } 23506c3fb27SDimitry Andric 236*0fca6ea1SDimitry Andric return CGF.EmitLoadOfAnyValue(CGF.MakeAddrLValue(Addr, ValueTy), Slot); 23706c3fb27SDimitry Andric } 23806c3fb27SDimitry Andric 23906c3fb27SDimitry Andric Address CodeGen::emitMergePHI(CodeGenFunction &CGF, Address Addr1, 24006c3fb27SDimitry Andric llvm::BasicBlock *Block1, Address Addr2, 24106c3fb27SDimitry Andric llvm::BasicBlock *Block2, 24206c3fb27SDimitry Andric const llvm::Twine &Name) { 24306c3fb27SDimitry Andric assert(Addr1.getType() == Addr2.getType()); 24406c3fb27SDimitry Andric llvm::PHINode *PHI = CGF.Builder.CreatePHI(Addr1.getType(), 2, Name); 245*0fca6ea1SDimitry Andric PHI->addIncoming(Addr1.emitRawPointer(CGF), Block1); 246*0fca6ea1SDimitry Andric PHI->addIncoming(Addr2.emitRawPointer(CGF), Block2); 24706c3fb27SDimitry Andric CharUnits Align = std::min(Addr1.getAlignment(), Addr2.getAlignment()); 24806c3fb27SDimitry Andric return Address(PHI, Addr1.getElementType(), Align); 24906c3fb27SDimitry Andric } 25006c3fb27SDimitry Andric 25106c3fb27SDimitry Andric bool CodeGen::isEmptyField(ASTContext &Context, const FieldDecl *FD, 2528a4dda33SDimitry Andric bool AllowArrays, bool AsIfNoUniqueAddr) { 253*0fca6ea1SDimitry Andric if (FD->isUnnamedBitField()) 25406c3fb27SDimitry Andric return true; 25506c3fb27SDimitry Andric 25606c3fb27SDimitry Andric QualType FT = FD->getType(); 25706c3fb27SDimitry Andric 25806c3fb27SDimitry Andric // Constant arrays of empty records count as empty, strip them off. 25906c3fb27SDimitry Andric // Constant arrays of zero length always count as empty. 26006c3fb27SDimitry Andric bool WasArray = false; 26106c3fb27SDimitry Andric if (AllowArrays) 26206c3fb27SDimitry Andric while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) { 263*0fca6ea1SDimitry Andric if (AT->isZeroSize()) 26406c3fb27SDimitry Andric return true; 26506c3fb27SDimitry Andric FT = AT->getElementType(); 26606c3fb27SDimitry Andric // The [[no_unique_address]] special case below does not apply to 26706c3fb27SDimitry Andric // arrays of C++ empty records, so we need to remember this fact. 26806c3fb27SDimitry Andric WasArray = true; 26906c3fb27SDimitry Andric } 27006c3fb27SDimitry Andric 27106c3fb27SDimitry Andric const RecordType *RT = FT->getAs<RecordType>(); 27206c3fb27SDimitry Andric if (!RT) 27306c3fb27SDimitry Andric return false; 27406c3fb27SDimitry Andric 27506c3fb27SDimitry Andric // C++ record fields are never empty, at least in the Itanium ABI. 27606c3fb27SDimitry Andric // 27706c3fb27SDimitry Andric // FIXME: We should use a predicate for whether this behavior is true in the 27806c3fb27SDimitry Andric // current ABI. 27906c3fb27SDimitry Andric // 28006c3fb27SDimitry Andric // The exception to the above rule are fields marked with the 28106c3fb27SDimitry Andric // [[no_unique_address]] attribute (since C++20). Those do count as empty 28206c3fb27SDimitry Andric // according to the Itanium ABI. The exception applies only to records, 28306c3fb27SDimitry Andric // not arrays of records, so we must also check whether we stripped off an 28406c3fb27SDimitry Andric // array type above. 28506c3fb27SDimitry Andric if (isa<CXXRecordDecl>(RT->getDecl()) && 2868a4dda33SDimitry Andric (WasArray || (!AsIfNoUniqueAddr && !FD->hasAttr<NoUniqueAddressAttr>()))) 28706c3fb27SDimitry Andric return false; 28806c3fb27SDimitry Andric 2898a4dda33SDimitry Andric return isEmptyRecord(Context, FT, AllowArrays, AsIfNoUniqueAddr); 29006c3fb27SDimitry Andric } 29106c3fb27SDimitry Andric 2928a4dda33SDimitry Andric bool CodeGen::isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays, 2938a4dda33SDimitry Andric bool AsIfNoUniqueAddr) { 29406c3fb27SDimitry Andric const RecordType *RT = T->getAs<RecordType>(); 29506c3fb27SDimitry Andric if (!RT) 29606c3fb27SDimitry Andric return false; 29706c3fb27SDimitry Andric const RecordDecl *RD = RT->getDecl(); 29806c3fb27SDimitry Andric if (RD->hasFlexibleArrayMember()) 29906c3fb27SDimitry Andric return false; 30006c3fb27SDimitry Andric 30106c3fb27SDimitry Andric // If this is a C++ record, check the bases first. 30206c3fb27SDimitry Andric if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) 30306c3fb27SDimitry Andric for (const auto &I : CXXRD->bases()) 3048a4dda33SDimitry Andric if (!isEmptyRecord(Context, I.getType(), true, AsIfNoUniqueAddr)) 30506c3fb27SDimitry Andric return false; 30606c3fb27SDimitry Andric 30706c3fb27SDimitry Andric for (const auto *I : RD->fields()) 3088a4dda33SDimitry Andric if (!isEmptyField(Context, I, AllowArrays, AsIfNoUniqueAddr)) 30906c3fb27SDimitry Andric return false; 31006c3fb27SDimitry Andric return true; 31106c3fb27SDimitry Andric } 31206c3fb27SDimitry Andric 313*0fca6ea1SDimitry Andric bool CodeGen::isEmptyFieldForLayout(const ASTContext &Context, 314*0fca6ea1SDimitry Andric const FieldDecl *FD) { 315*0fca6ea1SDimitry Andric if (FD->isZeroLengthBitField(Context)) 316*0fca6ea1SDimitry Andric return true; 317*0fca6ea1SDimitry Andric 318*0fca6ea1SDimitry Andric if (FD->isUnnamedBitField()) 319*0fca6ea1SDimitry Andric return false; 320*0fca6ea1SDimitry Andric 321*0fca6ea1SDimitry Andric return isEmptyRecordForLayout(Context, FD->getType()); 322*0fca6ea1SDimitry Andric } 323*0fca6ea1SDimitry Andric 324*0fca6ea1SDimitry Andric bool CodeGen::isEmptyRecordForLayout(const ASTContext &Context, QualType T) { 325*0fca6ea1SDimitry Andric const RecordType *RT = T->getAs<RecordType>(); 326*0fca6ea1SDimitry Andric if (!RT) 327*0fca6ea1SDimitry Andric return false; 328*0fca6ea1SDimitry Andric 329*0fca6ea1SDimitry Andric const RecordDecl *RD = RT->getDecl(); 330*0fca6ea1SDimitry Andric 331*0fca6ea1SDimitry Andric // If this is a C++ record, check the bases first. 332*0fca6ea1SDimitry Andric if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { 333*0fca6ea1SDimitry Andric if (CXXRD->isDynamicClass()) 334*0fca6ea1SDimitry Andric return false; 335*0fca6ea1SDimitry Andric 336*0fca6ea1SDimitry Andric for (const auto &I : CXXRD->bases()) 337*0fca6ea1SDimitry Andric if (!isEmptyRecordForLayout(Context, I.getType())) 338*0fca6ea1SDimitry Andric return false; 339*0fca6ea1SDimitry Andric } 340*0fca6ea1SDimitry Andric 341*0fca6ea1SDimitry Andric for (const auto *I : RD->fields()) 342*0fca6ea1SDimitry Andric if (!isEmptyFieldForLayout(Context, I)) 343*0fca6ea1SDimitry Andric return false; 344*0fca6ea1SDimitry Andric 345*0fca6ea1SDimitry Andric return true; 346*0fca6ea1SDimitry Andric } 347*0fca6ea1SDimitry Andric 34806c3fb27SDimitry Andric const Type *CodeGen::isSingleElementStruct(QualType T, ASTContext &Context) { 34906c3fb27SDimitry Andric const RecordType *RT = T->getAs<RecordType>(); 35006c3fb27SDimitry Andric if (!RT) 35106c3fb27SDimitry Andric return nullptr; 35206c3fb27SDimitry Andric 35306c3fb27SDimitry Andric const RecordDecl *RD = RT->getDecl(); 35406c3fb27SDimitry Andric if (RD->hasFlexibleArrayMember()) 35506c3fb27SDimitry Andric return nullptr; 35606c3fb27SDimitry Andric 35706c3fb27SDimitry Andric const Type *Found = nullptr; 35806c3fb27SDimitry Andric 35906c3fb27SDimitry Andric // If this is a C++ record, check the bases first. 36006c3fb27SDimitry Andric if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { 36106c3fb27SDimitry Andric for (const auto &I : CXXRD->bases()) { 36206c3fb27SDimitry Andric // Ignore empty records. 36306c3fb27SDimitry Andric if (isEmptyRecord(Context, I.getType(), true)) 36406c3fb27SDimitry Andric continue; 36506c3fb27SDimitry Andric 36606c3fb27SDimitry Andric // If we already found an element then this isn't a single-element struct. 36706c3fb27SDimitry Andric if (Found) 36806c3fb27SDimitry Andric return nullptr; 36906c3fb27SDimitry Andric 37006c3fb27SDimitry Andric // If this is non-empty and not a single element struct, the composite 37106c3fb27SDimitry Andric // cannot be a single element struct. 37206c3fb27SDimitry Andric Found = isSingleElementStruct(I.getType(), Context); 37306c3fb27SDimitry Andric if (!Found) 37406c3fb27SDimitry Andric return nullptr; 37506c3fb27SDimitry Andric } 37606c3fb27SDimitry Andric } 37706c3fb27SDimitry Andric 37806c3fb27SDimitry Andric // Check for single element. 37906c3fb27SDimitry Andric for (const auto *FD : RD->fields()) { 38006c3fb27SDimitry Andric QualType FT = FD->getType(); 38106c3fb27SDimitry Andric 38206c3fb27SDimitry Andric // Ignore empty fields. 38306c3fb27SDimitry Andric if (isEmptyField(Context, FD, true)) 38406c3fb27SDimitry Andric continue; 38506c3fb27SDimitry Andric 38606c3fb27SDimitry Andric // If we already found an element then this isn't a single-element 38706c3fb27SDimitry Andric // struct. 38806c3fb27SDimitry Andric if (Found) 38906c3fb27SDimitry Andric return nullptr; 39006c3fb27SDimitry Andric 39106c3fb27SDimitry Andric // Treat single element arrays as the element. 39206c3fb27SDimitry Andric while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) { 393*0fca6ea1SDimitry Andric if (AT->getZExtSize() != 1) 39406c3fb27SDimitry Andric break; 39506c3fb27SDimitry Andric FT = AT->getElementType(); 39606c3fb27SDimitry Andric } 39706c3fb27SDimitry Andric 39806c3fb27SDimitry Andric if (!isAggregateTypeForABI(FT)) { 39906c3fb27SDimitry Andric Found = FT.getTypePtr(); 40006c3fb27SDimitry Andric } else { 40106c3fb27SDimitry Andric Found = isSingleElementStruct(FT, Context); 40206c3fb27SDimitry Andric if (!Found) 40306c3fb27SDimitry Andric return nullptr; 40406c3fb27SDimitry Andric } 40506c3fb27SDimitry Andric } 40606c3fb27SDimitry Andric 40706c3fb27SDimitry Andric // We don't consider a struct a single-element struct if it has 40806c3fb27SDimitry Andric // padding beyond the element type. 40906c3fb27SDimitry Andric if (Found && Context.getTypeSize(Found) != Context.getTypeSize(T)) 41006c3fb27SDimitry Andric return nullptr; 41106c3fb27SDimitry Andric 41206c3fb27SDimitry Andric return Found; 41306c3fb27SDimitry Andric } 41406c3fb27SDimitry Andric 41506c3fb27SDimitry Andric Address CodeGen::EmitVAArgInstr(CodeGenFunction &CGF, Address VAListAddr, 41606c3fb27SDimitry Andric QualType Ty, const ABIArgInfo &AI) { 41706c3fb27SDimitry Andric // This default implementation defers to the llvm backend's va_arg 41806c3fb27SDimitry Andric // instruction. It can handle only passing arguments directly 41906c3fb27SDimitry Andric // (typically only handled in the backend for primitive types), or 42006c3fb27SDimitry Andric // aggregates passed indirectly by pointer (NOTE: if the "byval" 42106c3fb27SDimitry Andric // flag has ABI impact in the callee, this implementation cannot 42206c3fb27SDimitry Andric // work.) 42306c3fb27SDimitry Andric 42406c3fb27SDimitry Andric // Only a few cases are covered here at the moment -- those needed 42506c3fb27SDimitry Andric // by the default abi. 42606c3fb27SDimitry Andric llvm::Value *Val; 42706c3fb27SDimitry Andric 42806c3fb27SDimitry Andric if (AI.isIndirect()) { 42906c3fb27SDimitry Andric assert(!AI.getPaddingType() && 43006c3fb27SDimitry Andric "Unexpected PaddingType seen in arginfo in generic VAArg emitter!"); 43106c3fb27SDimitry Andric assert( 43206c3fb27SDimitry Andric !AI.getIndirectRealign() && 43306c3fb27SDimitry Andric "Unexpected IndirectRealign seen in arginfo in generic VAArg emitter!"); 43406c3fb27SDimitry Andric 43506c3fb27SDimitry Andric auto TyInfo = CGF.getContext().getTypeInfoInChars(Ty); 43606c3fb27SDimitry Andric CharUnits TyAlignForABI = TyInfo.Align; 43706c3fb27SDimitry Andric 43806c3fb27SDimitry Andric llvm::Type *ElementTy = CGF.ConvertTypeForMem(Ty); 43906c3fb27SDimitry Andric llvm::Type *BaseTy = llvm::PointerType::getUnqual(ElementTy); 44006c3fb27SDimitry Andric llvm::Value *Addr = 441*0fca6ea1SDimitry Andric CGF.Builder.CreateVAArg(VAListAddr.emitRawPointer(CGF), BaseTy); 44206c3fb27SDimitry Andric return Address(Addr, ElementTy, TyAlignForABI); 44306c3fb27SDimitry Andric } else { 44406c3fb27SDimitry Andric assert((AI.isDirect() || AI.isExtend()) && 44506c3fb27SDimitry Andric "Unexpected ArgInfo Kind in generic VAArg emitter!"); 44606c3fb27SDimitry Andric 44706c3fb27SDimitry Andric assert(!AI.getInReg() && 44806c3fb27SDimitry Andric "Unexpected InReg seen in arginfo in generic VAArg emitter!"); 44906c3fb27SDimitry Andric assert(!AI.getPaddingType() && 45006c3fb27SDimitry Andric "Unexpected PaddingType seen in arginfo in generic VAArg emitter!"); 45106c3fb27SDimitry Andric assert(!AI.getDirectOffset() && 45206c3fb27SDimitry Andric "Unexpected DirectOffset seen in arginfo in generic VAArg emitter!"); 45306c3fb27SDimitry Andric assert(!AI.getCoerceToType() && 45406c3fb27SDimitry Andric "Unexpected CoerceToType seen in arginfo in generic VAArg emitter!"); 45506c3fb27SDimitry Andric 45606c3fb27SDimitry Andric Address Temp = CGF.CreateMemTemp(Ty, "varet"); 457*0fca6ea1SDimitry Andric Val = CGF.Builder.CreateVAArg(VAListAddr.emitRawPointer(CGF), 45806c3fb27SDimitry Andric CGF.ConvertTypeForMem(Ty)); 45906c3fb27SDimitry Andric CGF.Builder.CreateStore(Val, Temp); 46006c3fb27SDimitry Andric return Temp; 46106c3fb27SDimitry Andric } 46206c3fb27SDimitry Andric } 46306c3fb27SDimitry Andric 46406c3fb27SDimitry Andric bool CodeGen::isSIMDVectorType(ASTContext &Context, QualType Ty) { 46506c3fb27SDimitry Andric return Ty->getAs<VectorType>() && Context.getTypeSize(Ty) == 128; 46606c3fb27SDimitry Andric } 46706c3fb27SDimitry Andric 46806c3fb27SDimitry Andric bool CodeGen::isRecordWithSIMDVectorType(ASTContext &Context, QualType Ty) { 46906c3fb27SDimitry Andric const RecordType *RT = Ty->getAs<RecordType>(); 47006c3fb27SDimitry Andric if (!RT) 47106c3fb27SDimitry Andric return false; 47206c3fb27SDimitry Andric const RecordDecl *RD = RT->getDecl(); 47306c3fb27SDimitry Andric 47406c3fb27SDimitry Andric // If this is a C++ record, check the bases first. 47506c3fb27SDimitry Andric if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) 47606c3fb27SDimitry Andric for (const auto &I : CXXRD->bases()) 47706c3fb27SDimitry Andric if (!isRecordWithSIMDVectorType(Context, I.getType())) 47806c3fb27SDimitry Andric return false; 47906c3fb27SDimitry Andric 48006c3fb27SDimitry Andric for (const auto *i : RD->fields()) { 48106c3fb27SDimitry Andric QualType FT = i->getType(); 48206c3fb27SDimitry Andric 48306c3fb27SDimitry Andric if (isSIMDVectorType(Context, FT)) 48406c3fb27SDimitry Andric return true; 48506c3fb27SDimitry Andric 48606c3fb27SDimitry Andric if (isRecordWithSIMDVectorType(Context, FT)) 48706c3fb27SDimitry Andric return true; 48806c3fb27SDimitry Andric } 48906c3fb27SDimitry Andric 49006c3fb27SDimitry Andric return false; 49106c3fb27SDimitry Andric } 492