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