xref: /freebsd-src/contrib/llvm-project/clang/lib/CodeGen/ABIInfoImpl.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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