xref: /freebsd-src/contrib/llvm-project/clang/lib/CodeGen/ABIInfoImpl.cpp (revision 8a4dda33d67586ca2624f2a38417baa03a533a7f)
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 
7406c3fb27SDimitry Andric Address DefaultABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
7506c3fb27SDimitry Andric                                   QualType Ty) const {
7606c3fb27SDimitry Andric   return EmitVAArgInstr(CGF, VAListAddr, Ty, classifyArgumentType(Ty));
7706c3fb27SDimitry Andric }
7806c3fb27SDimitry Andric 
7906c3fb27SDimitry Andric ABIArgInfo CodeGen::coerceToIntArray(QualType Ty, ASTContext &Context,
8006c3fb27SDimitry Andric                                      llvm::LLVMContext &LLVMContext) {
8106c3fb27SDimitry Andric   // Alignment and Size are measured in bits.
8206c3fb27SDimitry Andric   const uint64_t Size = Context.getTypeSize(Ty);
8306c3fb27SDimitry Andric   const uint64_t Alignment = Context.getTypeAlign(Ty);
8406c3fb27SDimitry Andric   llvm::Type *IntType = llvm::Type::getIntNTy(LLVMContext, Alignment);
8506c3fb27SDimitry Andric   const uint64_t NumElements = (Size + Alignment - 1) / Alignment;
8606c3fb27SDimitry Andric   return ABIArgInfo::getDirect(llvm::ArrayType::get(IntType, NumElements));
8706c3fb27SDimitry Andric }
8806c3fb27SDimitry Andric 
8906c3fb27SDimitry Andric void CodeGen::AssignToArrayRange(CodeGen::CGBuilderTy &Builder,
9006c3fb27SDimitry Andric                                  llvm::Value *Array, llvm::Value *Value,
9106c3fb27SDimitry Andric                                  unsigned FirstIndex, unsigned LastIndex) {
9206c3fb27SDimitry Andric   // Alternatively, we could emit this as a loop in the source.
9306c3fb27SDimitry Andric   for (unsigned I = FirstIndex; I <= LastIndex; ++I) {
9406c3fb27SDimitry Andric     llvm::Value *Cell =
9506c3fb27SDimitry Andric         Builder.CreateConstInBoundsGEP1_32(Builder.getInt8Ty(), Array, I);
9606c3fb27SDimitry Andric     Builder.CreateAlignedStore(Value, Cell, CharUnits::One());
9706c3fb27SDimitry Andric   }
9806c3fb27SDimitry Andric }
9906c3fb27SDimitry Andric 
10006c3fb27SDimitry Andric bool CodeGen::isAggregateTypeForABI(QualType T) {
10106c3fb27SDimitry Andric   return !CodeGenFunction::hasScalarEvaluationKind(T) ||
10206c3fb27SDimitry Andric          T->isMemberFunctionPointerType();
10306c3fb27SDimitry Andric }
10406c3fb27SDimitry Andric 
10506c3fb27SDimitry Andric llvm::Type *CodeGen::getVAListElementType(CodeGenFunction &CGF) {
10606c3fb27SDimitry Andric   return CGF.ConvertTypeForMem(
10706c3fb27SDimitry Andric       CGF.getContext().getBuiltinVaListType()->getPointeeType());
10806c3fb27SDimitry Andric }
10906c3fb27SDimitry Andric 
11006c3fb27SDimitry Andric CGCXXABI::RecordArgABI CodeGen::getRecordArgABI(const RecordType *RT,
11106c3fb27SDimitry Andric                                                 CGCXXABI &CXXABI) {
11206c3fb27SDimitry Andric   const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
11306c3fb27SDimitry Andric   if (!RD) {
11406c3fb27SDimitry Andric     if (!RT->getDecl()->canPassInRegisters())
11506c3fb27SDimitry Andric       return CGCXXABI::RAA_Indirect;
11606c3fb27SDimitry Andric     return CGCXXABI::RAA_Default;
11706c3fb27SDimitry Andric   }
11806c3fb27SDimitry Andric   return CXXABI.getRecordArgABI(RD);
11906c3fb27SDimitry Andric }
12006c3fb27SDimitry Andric 
12106c3fb27SDimitry Andric CGCXXABI::RecordArgABI CodeGen::getRecordArgABI(QualType T, CGCXXABI &CXXABI) {
12206c3fb27SDimitry Andric   const RecordType *RT = T->getAs<RecordType>();
12306c3fb27SDimitry Andric   if (!RT)
12406c3fb27SDimitry Andric     return CGCXXABI::RAA_Default;
12506c3fb27SDimitry Andric   return getRecordArgABI(RT, CXXABI);
12606c3fb27SDimitry Andric }
12706c3fb27SDimitry Andric 
12806c3fb27SDimitry Andric bool CodeGen::classifyReturnType(const CGCXXABI &CXXABI, CGFunctionInfo &FI,
12906c3fb27SDimitry Andric                                  const ABIInfo &Info) {
13006c3fb27SDimitry Andric   QualType Ty = FI.getReturnType();
13106c3fb27SDimitry Andric 
13206c3fb27SDimitry Andric   if (const auto *RT = Ty->getAs<RecordType>())
13306c3fb27SDimitry Andric     if (!isa<CXXRecordDecl>(RT->getDecl()) &&
13406c3fb27SDimitry Andric         !RT->getDecl()->canPassInRegisters()) {
13506c3fb27SDimitry Andric       FI.getReturnInfo() = Info.getNaturalAlignIndirect(Ty);
13606c3fb27SDimitry Andric       return true;
13706c3fb27SDimitry Andric     }
13806c3fb27SDimitry Andric 
13906c3fb27SDimitry Andric   return CXXABI.classifyReturnType(FI);
14006c3fb27SDimitry Andric }
14106c3fb27SDimitry Andric 
14206c3fb27SDimitry Andric QualType CodeGen::useFirstFieldIfTransparentUnion(QualType Ty) {
14306c3fb27SDimitry Andric   if (const RecordType *UT = Ty->getAsUnionType()) {
14406c3fb27SDimitry Andric     const RecordDecl *UD = UT->getDecl();
14506c3fb27SDimitry Andric     if (UD->hasAttr<TransparentUnionAttr>()) {
14606c3fb27SDimitry Andric       assert(!UD->field_empty() && "sema created an empty transparent union");
14706c3fb27SDimitry Andric       return UD->field_begin()->getType();
14806c3fb27SDimitry Andric     }
14906c3fb27SDimitry Andric   }
15006c3fb27SDimitry Andric   return Ty;
15106c3fb27SDimitry Andric }
15206c3fb27SDimitry Andric 
15306c3fb27SDimitry Andric llvm::Value *CodeGen::emitRoundPointerUpToAlignment(CodeGenFunction &CGF,
15406c3fb27SDimitry Andric                                                     llvm::Value *Ptr,
15506c3fb27SDimitry Andric                                                     CharUnits Align) {
15606c3fb27SDimitry Andric   // OverflowArgArea = (OverflowArgArea + Align - 1) & -Align;
15706c3fb27SDimitry Andric   llvm::Value *RoundUp = CGF.Builder.CreateConstInBoundsGEP1_32(
15806c3fb27SDimitry Andric       CGF.Builder.getInt8Ty(), Ptr, Align.getQuantity() - 1);
15906c3fb27SDimitry Andric   return CGF.Builder.CreateIntrinsic(
16006c3fb27SDimitry Andric       llvm::Intrinsic::ptrmask, {CGF.AllocaInt8PtrTy, CGF.IntPtrTy},
16106c3fb27SDimitry Andric       {RoundUp, llvm::ConstantInt::get(CGF.IntPtrTy, -Align.getQuantity())},
16206c3fb27SDimitry Andric       nullptr, Ptr->getName() + ".aligned");
16306c3fb27SDimitry Andric }
16406c3fb27SDimitry Andric 
16506c3fb27SDimitry Andric Address
16606c3fb27SDimitry Andric CodeGen::emitVoidPtrDirectVAArg(CodeGenFunction &CGF, Address VAListAddr,
16706c3fb27SDimitry Andric                                 llvm::Type *DirectTy, CharUnits DirectSize,
16806c3fb27SDimitry Andric                                 CharUnits DirectAlign, CharUnits SlotSize,
16906c3fb27SDimitry Andric                                 bool AllowHigherAlign, bool ForceRightAdjust) {
17006c3fb27SDimitry Andric   // Cast the element type to i8* if necessary.  Some platforms define
17106c3fb27SDimitry Andric   // va_list as a struct containing an i8* instead of just an i8*.
17206c3fb27SDimitry Andric   if (VAListAddr.getElementType() != CGF.Int8PtrTy)
17306c3fb27SDimitry Andric     VAListAddr = VAListAddr.withElementType(CGF.Int8PtrTy);
17406c3fb27SDimitry Andric 
17506c3fb27SDimitry Andric   llvm::Value *Ptr = CGF.Builder.CreateLoad(VAListAddr, "argp.cur");
17606c3fb27SDimitry Andric 
17706c3fb27SDimitry Andric   // If the CC aligns values higher than the slot size, do so if needed.
17806c3fb27SDimitry Andric   Address Addr = Address::invalid();
17906c3fb27SDimitry Andric   if (AllowHigherAlign && DirectAlign > SlotSize) {
18006c3fb27SDimitry Andric     Addr = Address(emitRoundPointerUpToAlignment(CGF, Ptr, DirectAlign),
18106c3fb27SDimitry Andric                    CGF.Int8Ty, DirectAlign);
18206c3fb27SDimitry Andric   } else {
18306c3fb27SDimitry Andric     Addr = Address(Ptr, CGF.Int8Ty, SlotSize);
18406c3fb27SDimitry Andric   }
18506c3fb27SDimitry Andric 
18606c3fb27SDimitry Andric   // Advance the pointer past the argument, then store that back.
18706c3fb27SDimitry Andric   CharUnits FullDirectSize = DirectSize.alignTo(SlotSize);
18806c3fb27SDimitry Andric   Address NextPtr =
18906c3fb27SDimitry Andric       CGF.Builder.CreateConstInBoundsByteGEP(Addr, FullDirectSize, "argp.next");
19006c3fb27SDimitry Andric   CGF.Builder.CreateStore(NextPtr.getPointer(), VAListAddr);
19106c3fb27SDimitry Andric 
19206c3fb27SDimitry Andric   // If the argument is smaller than a slot, and this is a big-endian
19306c3fb27SDimitry Andric   // target, the argument will be right-adjusted in its slot.
19406c3fb27SDimitry Andric   if (DirectSize < SlotSize && CGF.CGM.getDataLayout().isBigEndian() &&
19506c3fb27SDimitry Andric       (!DirectTy->isStructTy() || ForceRightAdjust)) {
19606c3fb27SDimitry Andric     Addr = CGF.Builder.CreateConstInBoundsByteGEP(Addr, SlotSize - DirectSize);
19706c3fb27SDimitry Andric   }
19806c3fb27SDimitry Andric 
19906c3fb27SDimitry Andric   return Addr.withElementType(DirectTy);
20006c3fb27SDimitry Andric }
20106c3fb27SDimitry Andric 
20206c3fb27SDimitry Andric Address CodeGen::emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr,
20306c3fb27SDimitry Andric                                   QualType ValueTy, bool IsIndirect,
20406c3fb27SDimitry Andric                                   TypeInfoChars ValueInfo,
20506c3fb27SDimitry Andric                                   CharUnits SlotSizeAndAlign,
20606c3fb27SDimitry Andric                                   bool AllowHigherAlign,
20706c3fb27SDimitry Andric                                   bool ForceRightAdjust) {
20806c3fb27SDimitry Andric   // The size and alignment of the value that was passed directly.
20906c3fb27SDimitry Andric   CharUnits DirectSize, DirectAlign;
21006c3fb27SDimitry Andric   if (IsIndirect) {
21106c3fb27SDimitry Andric     DirectSize = CGF.getPointerSize();
21206c3fb27SDimitry Andric     DirectAlign = CGF.getPointerAlign();
21306c3fb27SDimitry Andric   } else {
21406c3fb27SDimitry Andric     DirectSize = ValueInfo.Width;
21506c3fb27SDimitry Andric     DirectAlign = ValueInfo.Align;
21606c3fb27SDimitry Andric   }
21706c3fb27SDimitry Andric 
21806c3fb27SDimitry Andric   // Cast the address we've calculated to the right type.
21906c3fb27SDimitry Andric   llvm::Type *DirectTy = CGF.ConvertTypeForMem(ValueTy), *ElementTy = DirectTy;
22006c3fb27SDimitry Andric   if (IsIndirect) {
22106c3fb27SDimitry Andric     unsigned AllocaAS = CGF.CGM.getDataLayout().getAllocaAddrSpace();
22206c3fb27SDimitry Andric     DirectTy = llvm::PointerType::get(CGF.getLLVMContext(), AllocaAS);
22306c3fb27SDimitry Andric   }
22406c3fb27SDimitry Andric 
22506c3fb27SDimitry Andric   Address Addr = emitVoidPtrDirectVAArg(CGF, VAListAddr, DirectTy, DirectSize,
22606c3fb27SDimitry Andric                                         DirectAlign, SlotSizeAndAlign,
22706c3fb27SDimitry Andric                                         AllowHigherAlign, ForceRightAdjust);
22806c3fb27SDimitry Andric 
22906c3fb27SDimitry Andric   if (IsIndirect) {
23006c3fb27SDimitry Andric     Addr = Address(CGF.Builder.CreateLoad(Addr), ElementTy, ValueInfo.Align);
23106c3fb27SDimitry Andric   }
23206c3fb27SDimitry Andric 
23306c3fb27SDimitry Andric   return Addr;
23406c3fb27SDimitry Andric }
23506c3fb27SDimitry Andric 
23606c3fb27SDimitry Andric Address CodeGen::emitMergePHI(CodeGenFunction &CGF, Address Addr1,
23706c3fb27SDimitry Andric                               llvm::BasicBlock *Block1, Address Addr2,
23806c3fb27SDimitry Andric                               llvm::BasicBlock *Block2,
23906c3fb27SDimitry Andric                               const llvm::Twine &Name) {
24006c3fb27SDimitry Andric   assert(Addr1.getType() == Addr2.getType());
24106c3fb27SDimitry Andric   llvm::PHINode *PHI = CGF.Builder.CreatePHI(Addr1.getType(), 2, Name);
24206c3fb27SDimitry Andric   PHI->addIncoming(Addr1.getPointer(), Block1);
24306c3fb27SDimitry Andric   PHI->addIncoming(Addr2.getPointer(), Block2);
24406c3fb27SDimitry Andric   CharUnits Align = std::min(Addr1.getAlignment(), Addr2.getAlignment());
24506c3fb27SDimitry Andric   return Address(PHI, Addr1.getElementType(), Align);
24606c3fb27SDimitry Andric }
24706c3fb27SDimitry Andric 
24806c3fb27SDimitry Andric bool CodeGen::isEmptyField(ASTContext &Context, const FieldDecl *FD,
249*8a4dda33SDimitry Andric                            bool AllowArrays, bool AsIfNoUniqueAddr) {
25006c3fb27SDimitry Andric   if (FD->isUnnamedBitfield())
25106c3fb27SDimitry Andric     return true;
25206c3fb27SDimitry Andric 
25306c3fb27SDimitry Andric   QualType FT = FD->getType();
25406c3fb27SDimitry Andric 
25506c3fb27SDimitry Andric   // Constant arrays of empty records count as empty, strip them off.
25606c3fb27SDimitry Andric   // Constant arrays of zero length always count as empty.
25706c3fb27SDimitry Andric   bool WasArray = false;
25806c3fb27SDimitry Andric   if (AllowArrays)
25906c3fb27SDimitry Andric     while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) {
26006c3fb27SDimitry Andric       if (AT->getSize() == 0)
26106c3fb27SDimitry Andric         return true;
26206c3fb27SDimitry Andric       FT = AT->getElementType();
26306c3fb27SDimitry Andric       // The [[no_unique_address]] special case below does not apply to
26406c3fb27SDimitry Andric       // arrays of C++ empty records, so we need to remember this fact.
26506c3fb27SDimitry Andric       WasArray = true;
26606c3fb27SDimitry Andric     }
26706c3fb27SDimitry Andric 
26806c3fb27SDimitry Andric   const RecordType *RT = FT->getAs<RecordType>();
26906c3fb27SDimitry Andric   if (!RT)
27006c3fb27SDimitry Andric     return false;
27106c3fb27SDimitry Andric 
27206c3fb27SDimitry Andric   // C++ record fields are never empty, at least in the Itanium ABI.
27306c3fb27SDimitry Andric   //
27406c3fb27SDimitry Andric   // FIXME: We should use a predicate for whether this behavior is true in the
27506c3fb27SDimitry Andric   // current ABI.
27606c3fb27SDimitry Andric   //
27706c3fb27SDimitry Andric   // The exception to the above rule are fields marked with the
27806c3fb27SDimitry Andric   // [[no_unique_address]] attribute (since C++20).  Those do count as empty
27906c3fb27SDimitry Andric   // according to the Itanium ABI.  The exception applies only to records,
28006c3fb27SDimitry Andric   // not arrays of records, so we must also check whether we stripped off an
28106c3fb27SDimitry Andric   // array type above.
28206c3fb27SDimitry Andric   if (isa<CXXRecordDecl>(RT->getDecl()) &&
283*8a4dda33SDimitry Andric       (WasArray || (!AsIfNoUniqueAddr && !FD->hasAttr<NoUniqueAddressAttr>())))
28406c3fb27SDimitry Andric     return false;
28506c3fb27SDimitry Andric 
286*8a4dda33SDimitry Andric   return isEmptyRecord(Context, FT, AllowArrays, AsIfNoUniqueAddr);
28706c3fb27SDimitry Andric }
28806c3fb27SDimitry Andric 
289*8a4dda33SDimitry Andric bool CodeGen::isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays,
290*8a4dda33SDimitry Andric                             bool AsIfNoUniqueAddr) {
29106c3fb27SDimitry Andric   const RecordType *RT = T->getAs<RecordType>();
29206c3fb27SDimitry Andric   if (!RT)
29306c3fb27SDimitry Andric     return false;
29406c3fb27SDimitry Andric   const RecordDecl *RD = RT->getDecl();
29506c3fb27SDimitry Andric   if (RD->hasFlexibleArrayMember())
29606c3fb27SDimitry Andric     return false;
29706c3fb27SDimitry Andric 
29806c3fb27SDimitry Andric   // If this is a C++ record, check the bases first.
29906c3fb27SDimitry Andric   if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
30006c3fb27SDimitry Andric     for (const auto &I : CXXRD->bases())
301*8a4dda33SDimitry Andric       if (!isEmptyRecord(Context, I.getType(), true, AsIfNoUniqueAddr))
30206c3fb27SDimitry Andric         return false;
30306c3fb27SDimitry Andric 
30406c3fb27SDimitry Andric   for (const auto *I : RD->fields())
305*8a4dda33SDimitry Andric     if (!isEmptyField(Context, I, AllowArrays, AsIfNoUniqueAddr))
30606c3fb27SDimitry Andric       return false;
30706c3fb27SDimitry Andric   return true;
30806c3fb27SDimitry Andric }
30906c3fb27SDimitry Andric 
31006c3fb27SDimitry Andric const Type *CodeGen::isSingleElementStruct(QualType T, ASTContext &Context) {
31106c3fb27SDimitry Andric   const RecordType *RT = T->getAs<RecordType>();
31206c3fb27SDimitry Andric   if (!RT)
31306c3fb27SDimitry Andric     return nullptr;
31406c3fb27SDimitry Andric 
31506c3fb27SDimitry Andric   const RecordDecl *RD = RT->getDecl();
31606c3fb27SDimitry Andric   if (RD->hasFlexibleArrayMember())
31706c3fb27SDimitry Andric     return nullptr;
31806c3fb27SDimitry Andric 
31906c3fb27SDimitry Andric   const Type *Found = nullptr;
32006c3fb27SDimitry Andric 
32106c3fb27SDimitry Andric   // If this is a C++ record, check the bases first.
32206c3fb27SDimitry Andric   if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
32306c3fb27SDimitry Andric     for (const auto &I : CXXRD->bases()) {
32406c3fb27SDimitry Andric       // Ignore empty records.
32506c3fb27SDimitry Andric       if (isEmptyRecord(Context, I.getType(), true))
32606c3fb27SDimitry Andric         continue;
32706c3fb27SDimitry Andric 
32806c3fb27SDimitry Andric       // If we already found an element then this isn't a single-element struct.
32906c3fb27SDimitry Andric       if (Found)
33006c3fb27SDimitry Andric         return nullptr;
33106c3fb27SDimitry Andric 
33206c3fb27SDimitry Andric       // If this is non-empty and not a single element struct, the composite
33306c3fb27SDimitry Andric       // cannot be a single element struct.
33406c3fb27SDimitry Andric       Found = isSingleElementStruct(I.getType(), Context);
33506c3fb27SDimitry Andric       if (!Found)
33606c3fb27SDimitry Andric         return nullptr;
33706c3fb27SDimitry Andric     }
33806c3fb27SDimitry Andric   }
33906c3fb27SDimitry Andric 
34006c3fb27SDimitry Andric   // Check for single element.
34106c3fb27SDimitry Andric   for (const auto *FD : RD->fields()) {
34206c3fb27SDimitry Andric     QualType FT = FD->getType();
34306c3fb27SDimitry Andric 
34406c3fb27SDimitry Andric     // Ignore empty fields.
34506c3fb27SDimitry Andric     if (isEmptyField(Context, FD, true))
34606c3fb27SDimitry Andric       continue;
34706c3fb27SDimitry Andric 
34806c3fb27SDimitry Andric     // If we already found an element then this isn't a single-element
34906c3fb27SDimitry Andric     // struct.
35006c3fb27SDimitry Andric     if (Found)
35106c3fb27SDimitry Andric       return nullptr;
35206c3fb27SDimitry Andric 
35306c3fb27SDimitry Andric     // Treat single element arrays as the element.
35406c3fb27SDimitry Andric     while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) {
35506c3fb27SDimitry Andric       if (AT->getSize().getZExtValue() != 1)
35606c3fb27SDimitry Andric         break;
35706c3fb27SDimitry Andric       FT = AT->getElementType();
35806c3fb27SDimitry Andric     }
35906c3fb27SDimitry Andric 
36006c3fb27SDimitry Andric     if (!isAggregateTypeForABI(FT)) {
36106c3fb27SDimitry Andric       Found = FT.getTypePtr();
36206c3fb27SDimitry Andric     } else {
36306c3fb27SDimitry Andric       Found = isSingleElementStruct(FT, Context);
36406c3fb27SDimitry Andric       if (!Found)
36506c3fb27SDimitry Andric         return nullptr;
36606c3fb27SDimitry Andric     }
36706c3fb27SDimitry Andric   }
36806c3fb27SDimitry Andric 
36906c3fb27SDimitry Andric   // We don't consider a struct a single-element struct if it has
37006c3fb27SDimitry Andric   // padding beyond the element type.
37106c3fb27SDimitry Andric   if (Found && Context.getTypeSize(Found) != Context.getTypeSize(T))
37206c3fb27SDimitry Andric     return nullptr;
37306c3fb27SDimitry Andric 
37406c3fb27SDimitry Andric   return Found;
37506c3fb27SDimitry Andric }
37606c3fb27SDimitry Andric 
37706c3fb27SDimitry Andric Address CodeGen::EmitVAArgInstr(CodeGenFunction &CGF, Address VAListAddr,
37806c3fb27SDimitry Andric                                 QualType Ty, const ABIArgInfo &AI) {
37906c3fb27SDimitry Andric   // This default implementation defers to the llvm backend's va_arg
38006c3fb27SDimitry Andric   // instruction. It can handle only passing arguments directly
38106c3fb27SDimitry Andric   // (typically only handled in the backend for primitive types), or
38206c3fb27SDimitry Andric   // aggregates passed indirectly by pointer (NOTE: if the "byval"
38306c3fb27SDimitry Andric   // flag has ABI impact in the callee, this implementation cannot
38406c3fb27SDimitry Andric   // work.)
38506c3fb27SDimitry Andric 
38606c3fb27SDimitry Andric   // Only a few cases are covered here at the moment -- those needed
38706c3fb27SDimitry Andric   // by the default abi.
38806c3fb27SDimitry Andric   llvm::Value *Val;
38906c3fb27SDimitry Andric 
39006c3fb27SDimitry Andric   if (AI.isIndirect()) {
39106c3fb27SDimitry Andric     assert(!AI.getPaddingType() &&
39206c3fb27SDimitry Andric            "Unexpected PaddingType seen in arginfo in generic VAArg emitter!");
39306c3fb27SDimitry Andric     assert(
39406c3fb27SDimitry Andric         !AI.getIndirectRealign() &&
39506c3fb27SDimitry Andric         "Unexpected IndirectRealign seen in arginfo in generic VAArg emitter!");
39606c3fb27SDimitry Andric 
39706c3fb27SDimitry Andric     auto TyInfo = CGF.getContext().getTypeInfoInChars(Ty);
39806c3fb27SDimitry Andric     CharUnits TyAlignForABI = TyInfo.Align;
39906c3fb27SDimitry Andric 
40006c3fb27SDimitry Andric     llvm::Type *ElementTy = CGF.ConvertTypeForMem(Ty);
40106c3fb27SDimitry Andric     llvm::Type *BaseTy = llvm::PointerType::getUnqual(ElementTy);
40206c3fb27SDimitry Andric     llvm::Value *Addr =
40306c3fb27SDimitry Andric         CGF.Builder.CreateVAArg(VAListAddr.getPointer(), BaseTy);
40406c3fb27SDimitry Andric     return Address(Addr, ElementTy, TyAlignForABI);
40506c3fb27SDimitry Andric   } else {
40606c3fb27SDimitry Andric     assert((AI.isDirect() || AI.isExtend()) &&
40706c3fb27SDimitry Andric            "Unexpected ArgInfo Kind in generic VAArg emitter!");
40806c3fb27SDimitry Andric 
40906c3fb27SDimitry Andric     assert(!AI.getInReg() &&
41006c3fb27SDimitry Andric            "Unexpected InReg seen in arginfo in generic VAArg emitter!");
41106c3fb27SDimitry Andric     assert(!AI.getPaddingType() &&
41206c3fb27SDimitry Andric            "Unexpected PaddingType seen in arginfo in generic VAArg emitter!");
41306c3fb27SDimitry Andric     assert(!AI.getDirectOffset() &&
41406c3fb27SDimitry Andric            "Unexpected DirectOffset seen in arginfo in generic VAArg emitter!");
41506c3fb27SDimitry Andric     assert(!AI.getCoerceToType() &&
41606c3fb27SDimitry Andric            "Unexpected CoerceToType seen in arginfo in generic VAArg emitter!");
41706c3fb27SDimitry Andric 
41806c3fb27SDimitry Andric     Address Temp = CGF.CreateMemTemp(Ty, "varet");
41906c3fb27SDimitry Andric     Val = CGF.Builder.CreateVAArg(VAListAddr.getPointer(),
42006c3fb27SDimitry Andric                                   CGF.ConvertTypeForMem(Ty));
42106c3fb27SDimitry Andric     CGF.Builder.CreateStore(Val, Temp);
42206c3fb27SDimitry Andric     return Temp;
42306c3fb27SDimitry Andric   }
42406c3fb27SDimitry Andric }
42506c3fb27SDimitry Andric 
42606c3fb27SDimitry Andric bool CodeGen::isSIMDVectorType(ASTContext &Context, QualType Ty) {
42706c3fb27SDimitry Andric   return Ty->getAs<VectorType>() && Context.getTypeSize(Ty) == 128;
42806c3fb27SDimitry Andric }
42906c3fb27SDimitry Andric 
43006c3fb27SDimitry Andric bool CodeGen::isRecordWithSIMDVectorType(ASTContext &Context, QualType Ty) {
43106c3fb27SDimitry Andric   const RecordType *RT = Ty->getAs<RecordType>();
43206c3fb27SDimitry Andric   if (!RT)
43306c3fb27SDimitry Andric     return false;
43406c3fb27SDimitry Andric   const RecordDecl *RD = RT->getDecl();
43506c3fb27SDimitry Andric 
43606c3fb27SDimitry Andric   // If this is a C++ record, check the bases first.
43706c3fb27SDimitry Andric   if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
43806c3fb27SDimitry Andric     for (const auto &I : CXXRD->bases())
43906c3fb27SDimitry Andric       if (!isRecordWithSIMDVectorType(Context, I.getType()))
44006c3fb27SDimitry Andric         return false;
44106c3fb27SDimitry Andric 
44206c3fb27SDimitry Andric   for (const auto *i : RD->fields()) {
44306c3fb27SDimitry Andric     QualType FT = i->getType();
44406c3fb27SDimitry Andric 
44506c3fb27SDimitry Andric     if (isSIMDVectorType(Context, FT))
44606c3fb27SDimitry Andric       return true;
44706c3fb27SDimitry Andric 
44806c3fb27SDimitry Andric     if (isRecordWithSIMDVectorType(Context, FT))
44906c3fb27SDimitry Andric       return true;
45006c3fb27SDimitry Andric   }
45106c3fb27SDimitry Andric 
45206c3fb27SDimitry Andric   return false;
45306c3fb27SDimitry Andric }
454