xref: /llvm-project/clang/lib/CodeGen/ABIInfoImpl.cpp (revision cfe26358e3051755961fb1f3b46328dc2c326895)
1992cb984SSergei Barannikov //===- ABIInfoImpl.cpp ----------------------------------------------------===//
2992cb984SSergei Barannikov //
3992cb984SSergei Barannikov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4992cb984SSergei Barannikov // See https://llvm.org/LICENSE.txt for license information.
5992cb984SSergei Barannikov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6992cb984SSergei Barannikov //
7992cb984SSergei Barannikov //===----------------------------------------------------------------------===//
8992cb984SSergei Barannikov 
9992cb984SSergei Barannikov #include "ABIInfoImpl.h"
10992cb984SSergei Barannikov 
11992cb984SSergei Barannikov using namespace clang;
12992cb984SSergei Barannikov using namespace clang::CodeGen;
13992cb984SSergei Barannikov 
14992cb984SSergei Barannikov // Pin the vtable to this file.
15992cb984SSergei Barannikov DefaultABIInfo::~DefaultABIInfo() = default;
16992cb984SSergei Barannikov 
17992cb984SSergei Barannikov ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty) const {
18992cb984SSergei Barannikov   Ty = useFirstFieldIfTransparentUnion(Ty);
19992cb984SSergei Barannikov 
20992cb984SSergei Barannikov   if (isAggregateTypeForABI(Ty)) {
21992cb984SSergei Barannikov     // Records with non-trivial destructors/copy-constructors should not be
22992cb984SSergei Barannikov     // passed by value.
23992cb984SSergei Barannikov     if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
24992cb984SSergei Barannikov       return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
25992cb984SSergei Barannikov 
26992cb984SSergei Barannikov     return getNaturalAlignIndirect(Ty);
27992cb984SSergei Barannikov   }
28992cb984SSergei Barannikov 
29992cb984SSergei Barannikov   // Treat an enum type as its underlying type.
30992cb984SSergei Barannikov   if (const EnumType *EnumTy = Ty->getAs<EnumType>())
31992cb984SSergei Barannikov     Ty = EnumTy->getDecl()->getIntegerType();
32992cb984SSergei Barannikov 
33992cb984SSergei Barannikov   ASTContext &Context = getContext();
34992cb984SSergei Barannikov   if (const auto *EIT = Ty->getAs<BitIntType>())
35992cb984SSergei Barannikov     if (EIT->getNumBits() >
36992cb984SSergei Barannikov         Context.getTypeSize(Context.getTargetInfo().hasInt128Type()
37992cb984SSergei Barannikov                                 ? Context.Int128Ty
38992cb984SSergei Barannikov                                 : Context.LongLongTy))
39992cb984SSergei Barannikov       return getNaturalAlignIndirect(Ty);
40992cb984SSergei Barannikov 
41f95026dbSLei Huang   return (isPromotableIntegerTypeForABI(Ty)
42f95026dbSLei Huang               ? ABIArgInfo::getExtend(Ty, CGT.ConvertType(Ty))
43992cb984SSergei Barannikov               : ABIArgInfo::getDirect());
44992cb984SSergei Barannikov }
45992cb984SSergei Barannikov 
46992cb984SSergei Barannikov ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const {
47992cb984SSergei Barannikov   if (RetTy->isVoidType())
48992cb984SSergei Barannikov     return ABIArgInfo::getIgnore();
49992cb984SSergei Barannikov 
50992cb984SSergei Barannikov   if (isAggregateTypeForABI(RetTy))
51992cb984SSergei Barannikov     return getNaturalAlignIndirect(RetTy);
52992cb984SSergei Barannikov 
53992cb984SSergei Barannikov   // Treat an enum type as its underlying type.
54992cb984SSergei Barannikov   if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
55992cb984SSergei Barannikov     RetTy = EnumTy->getDecl()->getIntegerType();
56992cb984SSergei Barannikov 
57992cb984SSergei Barannikov   if (const auto *EIT = RetTy->getAs<BitIntType>())
58992cb984SSergei Barannikov     if (EIT->getNumBits() >
59992cb984SSergei Barannikov         getContext().getTypeSize(getContext().getTargetInfo().hasInt128Type()
60992cb984SSergei Barannikov                                      ? getContext().Int128Ty
61992cb984SSergei Barannikov                                      : getContext().LongLongTy))
62992cb984SSergei Barannikov       return getNaturalAlignIndirect(RetTy);
63992cb984SSergei Barannikov 
64992cb984SSergei Barannikov   return (isPromotableIntegerTypeForABI(RetTy) ? ABIArgInfo::getExtend(RetTy)
65992cb984SSergei Barannikov                                                : ABIArgInfo::getDirect());
66992cb984SSergei Barannikov }
67992cb984SSergei Barannikov 
68992cb984SSergei Barannikov void DefaultABIInfo::computeInfo(CGFunctionInfo &FI) const {
69992cb984SSergei Barannikov   if (!getCXXABI().classifyReturnType(FI))
70992cb984SSergei Barannikov     FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
71992cb984SSergei Barannikov   for (auto &I : FI.arguments())
72992cb984SSergei Barannikov     I.info = classifyArgumentType(I.type);
73992cb984SSergei Barannikov }
74992cb984SSergei Barannikov 
756d973b45SMariya Podchishchaeva RValue DefaultABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
766d973b45SMariya Podchishchaeva                                  QualType Ty, AggValueSlot Slot) const {
776d973b45SMariya Podchishchaeva   return CGF.EmitLoadOfAnyValue(
786d973b45SMariya Podchishchaeva       CGF.MakeAddrLValue(
796d973b45SMariya Podchishchaeva           EmitVAArgInstr(CGF, VAListAddr, Ty, classifyArgumentType(Ty)), Ty),
806d973b45SMariya Podchishchaeva       Slot);
81992cb984SSergei Barannikov }
82992cb984SSergei Barannikov 
83992cb984SSergei Barannikov void CodeGen::AssignToArrayRange(CodeGen::CGBuilderTy &Builder,
84992cb984SSergei Barannikov                                  llvm::Value *Array, llvm::Value *Value,
85992cb984SSergei Barannikov                                  unsigned FirstIndex, unsigned LastIndex) {
86992cb984SSergei Barannikov   // Alternatively, we could emit this as a loop in the source.
87992cb984SSergei Barannikov   for (unsigned I = FirstIndex; I <= LastIndex; ++I) {
88992cb984SSergei Barannikov     llvm::Value *Cell =
89992cb984SSergei Barannikov         Builder.CreateConstInBoundsGEP1_32(Builder.getInt8Ty(), Array, I);
90992cb984SSergei Barannikov     Builder.CreateAlignedStore(Value, Cell, CharUnits::One());
91992cb984SSergei Barannikov   }
92992cb984SSergei Barannikov }
93992cb984SSergei Barannikov 
94992cb984SSergei Barannikov bool CodeGen::isAggregateTypeForABI(QualType T) {
95992cb984SSergei Barannikov   return !CodeGenFunction::hasScalarEvaluationKind(T) ||
96992cb984SSergei Barannikov          T->isMemberFunctionPointerType();
97992cb984SSergei Barannikov }
98992cb984SSergei Barannikov 
99992cb984SSergei Barannikov llvm::Type *CodeGen::getVAListElementType(CodeGenFunction &CGF) {
100992cb984SSergei Barannikov   return CGF.ConvertTypeForMem(
101992cb984SSergei Barannikov       CGF.getContext().getBuiltinVaListType()->getPointeeType());
102992cb984SSergei Barannikov }
103992cb984SSergei Barannikov 
104992cb984SSergei Barannikov CGCXXABI::RecordArgABI CodeGen::getRecordArgABI(const RecordType *RT,
105992cb984SSergei Barannikov                                                 CGCXXABI &CXXABI) {
106992cb984SSergei Barannikov   const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
107992cb984SSergei Barannikov   if (!RD) {
108992cb984SSergei Barannikov     if (!RT->getDecl()->canPassInRegisters())
109992cb984SSergei Barannikov       return CGCXXABI::RAA_Indirect;
110992cb984SSergei Barannikov     return CGCXXABI::RAA_Default;
111992cb984SSergei Barannikov   }
112992cb984SSergei Barannikov   return CXXABI.getRecordArgABI(RD);
113992cb984SSergei Barannikov }
114992cb984SSergei Barannikov 
115992cb984SSergei Barannikov CGCXXABI::RecordArgABI CodeGen::getRecordArgABI(QualType T, CGCXXABI &CXXABI) {
116992cb984SSergei Barannikov   const RecordType *RT = T->getAs<RecordType>();
117992cb984SSergei Barannikov   if (!RT)
118992cb984SSergei Barannikov     return CGCXXABI::RAA_Default;
119992cb984SSergei Barannikov   return getRecordArgABI(RT, CXXABI);
120992cb984SSergei Barannikov }
121992cb984SSergei Barannikov 
122992cb984SSergei Barannikov bool CodeGen::classifyReturnType(const CGCXXABI &CXXABI, CGFunctionInfo &FI,
123992cb984SSergei Barannikov                                  const ABIInfo &Info) {
124992cb984SSergei Barannikov   QualType Ty = FI.getReturnType();
125992cb984SSergei Barannikov 
126992cb984SSergei Barannikov   if (const auto *RT = Ty->getAs<RecordType>())
127992cb984SSergei Barannikov     if (!isa<CXXRecordDecl>(RT->getDecl()) &&
128992cb984SSergei Barannikov         !RT->getDecl()->canPassInRegisters()) {
129992cb984SSergei Barannikov       FI.getReturnInfo() = Info.getNaturalAlignIndirect(Ty);
130992cb984SSergei Barannikov       return true;
131992cb984SSergei Barannikov     }
132992cb984SSergei Barannikov 
133992cb984SSergei Barannikov   return CXXABI.classifyReturnType(FI);
134992cb984SSergei Barannikov }
135992cb984SSergei Barannikov 
136992cb984SSergei Barannikov QualType CodeGen::useFirstFieldIfTransparentUnion(QualType Ty) {
137992cb984SSergei Barannikov   if (const RecordType *UT = Ty->getAsUnionType()) {
138992cb984SSergei Barannikov     const RecordDecl *UD = UT->getDecl();
139992cb984SSergei Barannikov     if (UD->hasAttr<TransparentUnionAttr>()) {
140992cb984SSergei Barannikov       assert(!UD->field_empty() && "sema created an empty transparent union");
141992cb984SSergei Barannikov       return UD->field_begin()->getType();
142992cb984SSergei Barannikov     }
143992cb984SSergei Barannikov   }
144992cb984SSergei Barannikov   return Ty;
145992cb984SSergei Barannikov }
146992cb984SSergei Barannikov 
147992cb984SSergei Barannikov llvm::Value *CodeGen::emitRoundPointerUpToAlignment(CodeGenFunction &CGF,
148992cb984SSergei Barannikov                                                     llvm::Value *Ptr,
149992cb984SSergei Barannikov                                                     CharUnits Align) {
150992cb984SSergei Barannikov   // OverflowArgArea = (OverflowArgArea + Align - 1) & -Align;
151992cb984SSergei Barannikov   llvm::Value *RoundUp = CGF.Builder.CreateConstInBoundsGEP1_32(
152992cb984SSergei Barannikov       CGF.Builder.getInt8Ty(), Ptr, Align.getQuantity() - 1);
153992cb984SSergei Barannikov   return CGF.Builder.CreateIntrinsic(
15478eb2c2cSJon Chesterfield       llvm::Intrinsic::ptrmask, {Ptr->getType(), CGF.IntPtrTy},
155992cb984SSergei Barannikov       {RoundUp, llvm::ConstantInt::get(CGF.IntPtrTy, -Align.getQuantity())},
156992cb984SSergei Barannikov       nullptr, Ptr->getName() + ".aligned");
157992cb984SSergei Barannikov }
158992cb984SSergei Barannikov 
159992cb984SSergei Barannikov Address
160992cb984SSergei Barannikov CodeGen::emitVoidPtrDirectVAArg(CodeGenFunction &CGF, Address VAListAddr,
161992cb984SSergei Barannikov                                 llvm::Type *DirectTy, CharUnits DirectSize,
162992cb984SSergei Barannikov                                 CharUnits DirectAlign, CharUnits SlotSize,
163992cb984SSergei Barannikov                                 bool AllowHigherAlign, bool ForceRightAdjust) {
164992cb984SSergei Barannikov   // Cast the element type to i8* if necessary.  Some platforms define
165992cb984SSergei Barannikov   // va_list as a struct containing an i8* instead of just an i8*.
166992cb984SSergei Barannikov   if (VAListAddr.getElementType() != CGF.Int8PtrTy)
1675f32baf1SYoungsuk Kim     VAListAddr = VAListAddr.withElementType(CGF.Int8PtrTy);
168992cb984SSergei Barannikov 
169992cb984SSergei Barannikov   llvm::Value *Ptr = CGF.Builder.CreateLoad(VAListAddr, "argp.cur");
170992cb984SSergei Barannikov 
171992cb984SSergei Barannikov   // If the CC aligns values higher than the slot size, do so if needed.
172992cb984SSergei Barannikov   Address Addr = Address::invalid();
173992cb984SSergei Barannikov   if (AllowHigherAlign && DirectAlign > SlotSize) {
174992cb984SSergei Barannikov     Addr = Address(emitRoundPointerUpToAlignment(CGF, Ptr, DirectAlign),
175992cb984SSergei Barannikov                    CGF.Int8Ty, DirectAlign);
176992cb984SSergei Barannikov   } else {
177992cb984SSergei Barannikov     Addr = Address(Ptr, CGF.Int8Ty, SlotSize);
178992cb984SSergei Barannikov   }
179992cb984SSergei Barannikov 
180992cb984SSergei Barannikov   // Advance the pointer past the argument, then store that back.
181992cb984SSergei Barannikov   CharUnits FullDirectSize = DirectSize.alignTo(SlotSize);
182992cb984SSergei Barannikov   Address NextPtr =
183992cb984SSergei Barannikov       CGF.Builder.CreateConstInBoundsByteGEP(Addr, FullDirectSize, "argp.next");
18484780af4SAkira Hatanaka   CGF.Builder.CreateStore(NextPtr.emitRawPointer(CGF), VAListAddr);
185992cb984SSergei Barannikov 
186992cb984SSergei Barannikov   // If the argument is smaller than a slot, and this is a big-endian
187992cb984SSergei Barannikov   // target, the argument will be right-adjusted in its slot.
188992cb984SSergei Barannikov   if (DirectSize < SlotSize && CGF.CGM.getDataLayout().isBigEndian() &&
189992cb984SSergei Barannikov       (!DirectTy->isStructTy() || ForceRightAdjust)) {
190992cb984SSergei Barannikov     Addr = CGF.Builder.CreateConstInBoundsByteGEP(Addr, SlotSize - DirectSize);
191992cb984SSergei Barannikov   }
192992cb984SSergei Barannikov 
1935f32baf1SYoungsuk Kim   return Addr.withElementType(DirectTy);
194992cb984SSergei Barannikov }
195992cb984SSergei Barannikov 
1966d973b45SMariya Podchishchaeva RValue CodeGen::emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr,
197992cb984SSergei Barannikov                                  QualType ValueTy, bool IsIndirect,
198992cb984SSergei Barannikov                                  TypeInfoChars ValueInfo,
199992cb984SSergei Barannikov                                  CharUnits SlotSizeAndAlign,
2006d973b45SMariya Podchishchaeva                                  bool AllowHigherAlign, AggValueSlot Slot,
201992cb984SSergei Barannikov                                  bool ForceRightAdjust) {
202992cb984SSergei Barannikov   // The size and alignment of the value that was passed directly.
203992cb984SSergei Barannikov   CharUnits DirectSize, DirectAlign;
204992cb984SSergei Barannikov   if (IsIndirect) {
205992cb984SSergei Barannikov     DirectSize = CGF.getPointerSize();
206992cb984SSergei Barannikov     DirectAlign = CGF.getPointerAlign();
207992cb984SSergei Barannikov   } else {
208992cb984SSergei Barannikov     DirectSize = ValueInfo.Width;
209992cb984SSergei Barannikov     DirectAlign = ValueInfo.Align;
210992cb984SSergei Barannikov   }
211992cb984SSergei Barannikov 
212992cb984SSergei Barannikov   // Cast the address we've calculated to the right type.
213992cb984SSergei Barannikov   llvm::Type *DirectTy = CGF.ConvertTypeForMem(ValueTy), *ElementTy = DirectTy;
214992cb984SSergei Barannikov   if (IsIndirect) {
215992cb984SSergei Barannikov     unsigned AllocaAS = CGF.CGM.getDataLayout().getAllocaAddrSpace();
216992cb984SSergei Barannikov     DirectTy = llvm::PointerType::get(CGF.getLLVMContext(), AllocaAS);
217992cb984SSergei Barannikov   }
218992cb984SSergei Barannikov 
219992cb984SSergei Barannikov   Address Addr = emitVoidPtrDirectVAArg(CGF, VAListAddr, DirectTy, DirectSize,
220992cb984SSergei Barannikov                                         DirectAlign, SlotSizeAndAlign,
221992cb984SSergei Barannikov                                         AllowHigherAlign, ForceRightAdjust);
222992cb984SSergei Barannikov 
223992cb984SSergei Barannikov   if (IsIndirect) {
224992cb984SSergei Barannikov     Addr = Address(CGF.Builder.CreateLoad(Addr), ElementTy, ValueInfo.Align);
225992cb984SSergei Barannikov   }
226992cb984SSergei Barannikov 
2276d973b45SMariya Podchishchaeva   return CGF.EmitLoadOfAnyValue(CGF.MakeAddrLValue(Addr, ValueTy), Slot);
228992cb984SSergei Barannikov }
229992cb984SSergei Barannikov 
230992cb984SSergei Barannikov Address CodeGen::emitMergePHI(CodeGenFunction &CGF, Address Addr1,
231992cb984SSergei Barannikov                               llvm::BasicBlock *Block1, Address Addr2,
232992cb984SSergei Barannikov                               llvm::BasicBlock *Block2,
233992cb984SSergei Barannikov                               const llvm::Twine &Name) {
234992cb984SSergei Barannikov   assert(Addr1.getType() == Addr2.getType());
235992cb984SSergei Barannikov   llvm::PHINode *PHI = CGF.Builder.CreatePHI(Addr1.getType(), 2, Name);
23684780af4SAkira Hatanaka   PHI->addIncoming(Addr1.emitRawPointer(CGF), Block1);
23784780af4SAkira Hatanaka   PHI->addIncoming(Addr2.emitRawPointer(CGF), Block2);
238992cb984SSergei Barannikov   CharUnits Align = std::min(Addr1.getAlignment(), Addr2.getAlignment());
239992cb984SSergei Barannikov   return Address(PHI, Addr1.getElementType(), Align);
240992cb984SSergei Barannikov }
241992cb984SSergei Barannikov 
242992cb984SSergei Barannikov bool CodeGen::isEmptyField(ASTContext &Context, const FieldDecl *FD,
243e3c57fddSAlex Bradbury                            bool AllowArrays, bool AsIfNoUniqueAddr) {
2443d56ea05STimm Baeder   if (FD->isUnnamedBitField())
245992cb984SSergei Barannikov     return true;
246992cb984SSergei Barannikov 
247992cb984SSergei Barannikov   QualType FT = FD->getType();
248992cb984SSergei Barannikov 
249992cb984SSergei Barannikov   // Constant arrays of empty records count as empty, strip them off.
250992cb984SSergei Barannikov   // Constant arrays of zero length always count as empty.
251992cb984SSergei Barannikov   bool WasArray = false;
252992cb984SSergei Barannikov   if (AllowArrays)
253992cb984SSergei Barannikov     while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) {
25428ddbd4aSChris B       if (AT->isZeroSize())
255992cb984SSergei Barannikov         return true;
256992cb984SSergei Barannikov       FT = AT->getElementType();
257992cb984SSergei Barannikov       // The [[no_unique_address]] special case below does not apply to
258992cb984SSergei Barannikov       // arrays of C++ empty records, so we need to remember this fact.
259992cb984SSergei Barannikov       WasArray = true;
260992cb984SSergei Barannikov     }
261992cb984SSergei Barannikov 
262992cb984SSergei Barannikov   const RecordType *RT = FT->getAs<RecordType>();
263992cb984SSergei Barannikov   if (!RT)
264992cb984SSergei Barannikov     return false;
265992cb984SSergei Barannikov 
266992cb984SSergei Barannikov   // C++ record fields are never empty, at least in the Itanium ABI.
267992cb984SSergei Barannikov   //
268992cb984SSergei Barannikov   // FIXME: We should use a predicate for whether this behavior is true in the
269992cb984SSergei Barannikov   // current ABI.
270992cb984SSergei Barannikov   //
271992cb984SSergei Barannikov   // The exception to the above rule are fields marked with the
272992cb984SSergei Barannikov   // [[no_unique_address]] attribute (since C++20).  Those do count as empty
273992cb984SSergei Barannikov   // according to the Itanium ABI.  The exception applies only to records,
274992cb984SSergei Barannikov   // not arrays of records, so we must also check whether we stripped off an
275992cb984SSergei Barannikov   // array type above.
276992cb984SSergei Barannikov   if (isa<CXXRecordDecl>(RT->getDecl()) &&
277e3c57fddSAlex Bradbury       (WasArray || (!AsIfNoUniqueAddr && !FD->hasAttr<NoUniqueAddressAttr>())))
278992cb984SSergei Barannikov     return false;
279992cb984SSergei Barannikov 
280e3c57fddSAlex Bradbury   return isEmptyRecord(Context, FT, AllowArrays, AsIfNoUniqueAddr);
281992cb984SSergei Barannikov }
282992cb984SSergei Barannikov 
283e3c57fddSAlex Bradbury bool CodeGen::isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays,
284e3c57fddSAlex Bradbury                             bool AsIfNoUniqueAddr) {
285992cb984SSergei Barannikov   const RecordType *RT = T->getAs<RecordType>();
286992cb984SSergei Barannikov   if (!RT)
287992cb984SSergei Barannikov     return false;
288992cb984SSergei Barannikov   const RecordDecl *RD = RT->getDecl();
289992cb984SSergei Barannikov   if (RD->hasFlexibleArrayMember())
290992cb984SSergei Barannikov     return false;
291992cb984SSergei Barannikov 
292992cb984SSergei Barannikov   // If this is a C++ record, check the bases first.
293992cb984SSergei Barannikov   if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
294992cb984SSergei Barannikov     for (const auto &I : CXXRD->bases())
295e3c57fddSAlex Bradbury       if (!isEmptyRecord(Context, I.getType(), true, AsIfNoUniqueAddr))
296992cb984SSergei Barannikov         return false;
297992cb984SSergei Barannikov 
298992cb984SSergei Barannikov   for (const auto *I : RD->fields())
299e3c57fddSAlex Bradbury     if (!isEmptyField(Context, I, AllowArrays, AsIfNoUniqueAddr))
300992cb984SSergei Barannikov       return false;
301992cb984SSergei Barannikov   return true;
302992cb984SSergei Barannikov }
303992cb984SSergei Barannikov 
3044497ec29SMichael Buch bool CodeGen::isEmptyFieldForLayout(const ASTContext &Context,
3054497ec29SMichael Buch                                     const FieldDecl *FD) {
306*cfe26358STimm Baeder   if (FD->isZeroLengthBitField())
3074497ec29SMichael Buch     return true;
3084497ec29SMichael Buch 
3094497ec29SMichael Buch   if (FD->isUnnamedBitField())
3104497ec29SMichael Buch     return false;
3114497ec29SMichael Buch 
3124497ec29SMichael Buch   return isEmptyRecordForLayout(Context, FD->getType());
3134497ec29SMichael Buch }
3144497ec29SMichael Buch 
3154497ec29SMichael Buch bool CodeGen::isEmptyRecordForLayout(const ASTContext &Context, QualType T) {
3164497ec29SMichael Buch   const RecordType *RT = T->getAs<RecordType>();
3174497ec29SMichael Buch   if (!RT)
3184497ec29SMichael Buch     return false;
3194497ec29SMichael Buch 
3204497ec29SMichael Buch   const RecordDecl *RD = RT->getDecl();
3214497ec29SMichael Buch 
3224497ec29SMichael Buch   // If this is a C++ record, check the bases first.
3234497ec29SMichael Buch   if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
3244497ec29SMichael Buch     if (CXXRD->isDynamicClass())
3254497ec29SMichael Buch       return false;
3264497ec29SMichael Buch 
3274497ec29SMichael Buch     for (const auto &I : CXXRD->bases())
3284497ec29SMichael Buch       if (!isEmptyRecordForLayout(Context, I.getType()))
3294497ec29SMichael Buch         return false;
3304497ec29SMichael Buch   }
3314497ec29SMichael Buch 
3324497ec29SMichael Buch   for (const auto *I : RD->fields())
3334497ec29SMichael Buch     if (!isEmptyFieldForLayout(Context, I))
3344497ec29SMichael Buch       return false;
3354497ec29SMichael Buch 
3364497ec29SMichael Buch   return true;
3374497ec29SMichael Buch }
3384497ec29SMichael Buch 
339992cb984SSergei Barannikov const Type *CodeGen::isSingleElementStruct(QualType T, ASTContext &Context) {
340992cb984SSergei Barannikov   const RecordType *RT = T->getAs<RecordType>();
341992cb984SSergei Barannikov   if (!RT)
342992cb984SSergei Barannikov     return nullptr;
343992cb984SSergei Barannikov 
344992cb984SSergei Barannikov   const RecordDecl *RD = RT->getDecl();
345992cb984SSergei Barannikov   if (RD->hasFlexibleArrayMember())
346992cb984SSergei Barannikov     return nullptr;
347992cb984SSergei Barannikov 
348992cb984SSergei Barannikov   const Type *Found = nullptr;
349992cb984SSergei Barannikov 
350992cb984SSergei Barannikov   // If this is a C++ record, check the bases first.
351992cb984SSergei Barannikov   if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
352992cb984SSergei Barannikov     for (const auto &I : CXXRD->bases()) {
353992cb984SSergei Barannikov       // Ignore empty records.
354992cb984SSergei Barannikov       if (isEmptyRecord(Context, I.getType(), true))
355992cb984SSergei Barannikov         continue;
356992cb984SSergei Barannikov 
357992cb984SSergei Barannikov       // If we already found an element then this isn't a single-element struct.
358992cb984SSergei Barannikov       if (Found)
359992cb984SSergei Barannikov         return nullptr;
360992cb984SSergei Barannikov 
361992cb984SSergei Barannikov       // If this is non-empty and not a single element struct, the composite
362992cb984SSergei Barannikov       // cannot be a single element struct.
363992cb984SSergei Barannikov       Found = isSingleElementStruct(I.getType(), Context);
364992cb984SSergei Barannikov       if (!Found)
365992cb984SSergei Barannikov         return nullptr;
366992cb984SSergei Barannikov     }
367992cb984SSergei Barannikov   }
368992cb984SSergei Barannikov 
369992cb984SSergei Barannikov   // Check for single element.
370992cb984SSergei Barannikov   for (const auto *FD : RD->fields()) {
371992cb984SSergei Barannikov     QualType FT = FD->getType();
372992cb984SSergei Barannikov 
373992cb984SSergei Barannikov     // Ignore empty fields.
374992cb984SSergei Barannikov     if (isEmptyField(Context, FD, true))
375992cb984SSergei Barannikov       continue;
376992cb984SSergei Barannikov 
377992cb984SSergei Barannikov     // If we already found an element then this isn't a single-element
378992cb984SSergei Barannikov     // struct.
379992cb984SSergei Barannikov     if (Found)
380992cb984SSergei Barannikov       return nullptr;
381992cb984SSergei Barannikov 
382992cb984SSergei Barannikov     // Treat single element arrays as the element.
383992cb984SSergei Barannikov     while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) {
38428ddbd4aSChris B       if (AT->getZExtSize() != 1)
385992cb984SSergei Barannikov         break;
386992cb984SSergei Barannikov       FT = AT->getElementType();
387992cb984SSergei Barannikov     }
388992cb984SSergei Barannikov 
389992cb984SSergei Barannikov     if (!isAggregateTypeForABI(FT)) {
390992cb984SSergei Barannikov       Found = FT.getTypePtr();
391992cb984SSergei Barannikov     } else {
392992cb984SSergei Barannikov       Found = isSingleElementStruct(FT, Context);
393992cb984SSergei Barannikov       if (!Found)
394992cb984SSergei Barannikov         return nullptr;
395992cb984SSergei Barannikov     }
396992cb984SSergei Barannikov   }
397992cb984SSergei Barannikov 
398992cb984SSergei Barannikov   // We don't consider a struct a single-element struct if it has
399992cb984SSergei Barannikov   // padding beyond the element type.
400992cb984SSergei Barannikov   if (Found && Context.getTypeSize(Found) != Context.getTypeSize(T))
401992cb984SSergei Barannikov     return nullptr;
402992cb984SSergei Barannikov 
403992cb984SSergei Barannikov   return Found;
404992cb984SSergei Barannikov }
405992cb984SSergei Barannikov 
406992cb984SSergei Barannikov Address CodeGen::EmitVAArgInstr(CodeGenFunction &CGF, Address VAListAddr,
407992cb984SSergei Barannikov                                 QualType Ty, const ABIArgInfo &AI) {
408992cb984SSergei Barannikov   // This default implementation defers to the llvm backend's va_arg
409992cb984SSergei Barannikov   // instruction. It can handle only passing arguments directly
410992cb984SSergei Barannikov   // (typically only handled in the backend for primitive types), or
411992cb984SSergei Barannikov   // aggregates passed indirectly by pointer (NOTE: if the "byval"
412992cb984SSergei Barannikov   // flag has ABI impact in the callee, this implementation cannot
413992cb984SSergei Barannikov   // work.)
414992cb984SSergei Barannikov 
415992cb984SSergei Barannikov   // Only a few cases are covered here at the moment -- those needed
416992cb984SSergei Barannikov   // by the default abi.
417992cb984SSergei Barannikov   llvm::Value *Val;
418992cb984SSergei Barannikov 
419992cb984SSergei Barannikov   if (AI.isIndirect()) {
420992cb984SSergei Barannikov     assert(!AI.getPaddingType() &&
421992cb984SSergei Barannikov            "Unexpected PaddingType seen in arginfo in generic VAArg emitter!");
422992cb984SSergei Barannikov     assert(
423992cb984SSergei Barannikov         !AI.getIndirectRealign() &&
424992cb984SSergei Barannikov         "Unexpected IndirectRealign seen in arginfo in generic VAArg emitter!");
425992cb984SSergei Barannikov 
426992cb984SSergei Barannikov     auto TyInfo = CGF.getContext().getTypeInfoInChars(Ty);
427992cb984SSergei Barannikov     CharUnits TyAlignForABI = TyInfo.Align;
428992cb984SSergei Barannikov 
429992cb984SSergei Barannikov     llvm::Type *ElementTy = CGF.ConvertTypeForMem(Ty);
430992cb984SSergei Barannikov     llvm::Type *BaseTy = llvm::PointerType::getUnqual(ElementTy);
431992cb984SSergei Barannikov     llvm::Value *Addr =
43284780af4SAkira Hatanaka         CGF.Builder.CreateVAArg(VAListAddr.emitRawPointer(CGF), BaseTy);
433992cb984SSergei Barannikov     return Address(Addr, ElementTy, TyAlignForABI);
434992cb984SSergei Barannikov   } else {
435992cb984SSergei Barannikov     assert((AI.isDirect() || AI.isExtend()) &&
436992cb984SSergei Barannikov            "Unexpected ArgInfo Kind in generic VAArg emitter!");
437992cb984SSergei Barannikov 
438992cb984SSergei Barannikov     assert(!AI.getInReg() &&
439992cb984SSergei Barannikov            "Unexpected InReg seen in arginfo in generic VAArg emitter!");
440992cb984SSergei Barannikov     assert(!AI.getPaddingType() &&
441992cb984SSergei Barannikov            "Unexpected PaddingType seen in arginfo in generic VAArg emitter!");
442992cb984SSergei Barannikov     assert(!AI.getDirectOffset() &&
443992cb984SSergei Barannikov            "Unexpected DirectOffset seen in arginfo in generic VAArg emitter!");
444992cb984SSergei Barannikov     assert(!AI.getCoerceToType() &&
445992cb984SSergei Barannikov            "Unexpected CoerceToType seen in arginfo in generic VAArg emitter!");
446992cb984SSergei Barannikov 
447992cb984SSergei Barannikov     Address Temp = CGF.CreateMemTemp(Ty, "varet");
44884780af4SAkira Hatanaka     Val = CGF.Builder.CreateVAArg(VAListAddr.emitRawPointer(CGF),
449992cb984SSergei Barannikov                                   CGF.ConvertTypeForMem(Ty));
450992cb984SSergei Barannikov     CGF.Builder.CreateStore(Val, Temp);
451992cb984SSergei Barannikov     return Temp;
452992cb984SSergei Barannikov   }
453992cb984SSergei Barannikov }
454992cb984SSergei Barannikov 
455992cb984SSergei Barannikov bool CodeGen::isSIMDVectorType(ASTContext &Context, QualType Ty) {
456992cb984SSergei Barannikov   return Ty->getAs<VectorType>() && Context.getTypeSize(Ty) == 128;
457992cb984SSergei Barannikov }
458992cb984SSergei Barannikov 
459992cb984SSergei Barannikov bool CodeGen::isRecordWithSIMDVectorType(ASTContext &Context, QualType Ty) {
460992cb984SSergei Barannikov   const RecordType *RT = Ty->getAs<RecordType>();
461992cb984SSergei Barannikov   if (!RT)
462992cb984SSergei Barannikov     return false;
463992cb984SSergei Barannikov   const RecordDecl *RD = RT->getDecl();
464992cb984SSergei Barannikov 
465992cb984SSergei Barannikov   // If this is a C++ record, check the bases first.
466992cb984SSergei Barannikov   if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
467992cb984SSergei Barannikov     for (const auto &I : CXXRD->bases())
468992cb984SSergei Barannikov       if (!isRecordWithSIMDVectorType(Context, I.getType()))
469992cb984SSergei Barannikov         return false;
470992cb984SSergei Barannikov 
471992cb984SSergei Barannikov   for (const auto *i : RD->fields()) {
472992cb984SSergei Barannikov     QualType FT = i->getType();
473992cb984SSergei Barannikov 
474992cb984SSergei Barannikov     if (isSIMDVectorType(Context, FT))
475992cb984SSergei Barannikov       return true;
476992cb984SSergei Barannikov 
477992cb984SSergei Barannikov     if (isRecordWithSIMDVectorType(Context, FT))
478992cb984SSergei Barannikov       return true;
479992cb984SSergei Barannikov   }
480992cb984SSergei Barannikov 
481992cb984SSergei Barannikov   return false;
482992cb984SSergei Barannikov }
483