xref: /llvm-project/clang/lib/CodeGen/Targets/LoongArch.cpp (revision cfe26358e3051755961fb1f3b46328dc2c326895)
1992cb984SSergei Barannikov //===- LoongArch.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 #include "TargetInfo.h"
11992cb984SSergei Barannikov 
12992cb984SSergei Barannikov using namespace clang;
13992cb984SSergei Barannikov using namespace clang::CodeGen;
14992cb984SSergei Barannikov 
15992cb984SSergei Barannikov // LoongArch ABI Implementation. Documented at
16992cb984SSergei Barannikov // https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html
17992cb984SSergei Barannikov //
18992cb984SSergei Barannikov //===----------------------------------------------------------------------===//
19992cb984SSergei Barannikov 
20992cb984SSergei Barannikov namespace {
21992cb984SSergei Barannikov class LoongArchABIInfo : public DefaultABIInfo {
22992cb984SSergei Barannikov private:
23992cb984SSergei Barannikov   // Size of the integer ('r') registers in bits.
24992cb984SSergei Barannikov   unsigned GRLen;
25992cb984SSergei Barannikov   // Size of the floating point ('f') registers in bits.
26992cb984SSergei Barannikov   unsigned FRLen;
27992cb984SSergei Barannikov   // Number of general-purpose argument registers.
28992cb984SSergei Barannikov   static const int NumGARs = 8;
29992cb984SSergei Barannikov   // Number of floating-point argument registers.
30992cb984SSergei Barannikov   static const int NumFARs = 8;
31992cb984SSergei Barannikov   bool detectFARsEligibleStructHelper(QualType Ty, CharUnits CurOff,
32992cb984SSergei Barannikov                                       llvm::Type *&Field1Ty,
33992cb984SSergei Barannikov                                       CharUnits &Field1Off,
34992cb984SSergei Barannikov                                       llvm::Type *&Field2Ty,
35992cb984SSergei Barannikov                                       CharUnits &Field2Off) const;
36992cb984SSergei Barannikov 
37992cb984SSergei Barannikov public:
38992cb984SSergei Barannikov   LoongArchABIInfo(CodeGen::CodeGenTypes &CGT, unsigned GRLen, unsigned FRLen)
39992cb984SSergei Barannikov       : DefaultABIInfo(CGT), GRLen(GRLen), FRLen(FRLen) {}
40992cb984SSergei Barannikov 
41992cb984SSergei Barannikov   void computeInfo(CGFunctionInfo &FI) const override;
42992cb984SSergei Barannikov 
43992cb984SSergei Barannikov   ABIArgInfo classifyArgumentType(QualType Ty, bool IsFixed, int &GARsLeft,
44992cb984SSergei Barannikov                                   int &FARsLeft) const;
45992cb984SSergei Barannikov   ABIArgInfo classifyReturnType(QualType RetTy) const;
46992cb984SSergei Barannikov 
476d973b45SMariya Podchishchaeva   RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
486d973b45SMariya Podchishchaeva                    AggValueSlot Slot) const override;
49992cb984SSergei Barannikov 
50992cb984SSergei Barannikov   ABIArgInfo extendType(QualType Ty) const;
51992cb984SSergei Barannikov 
52992cb984SSergei Barannikov   bool detectFARsEligibleStruct(QualType Ty, llvm::Type *&Field1Ty,
53992cb984SSergei Barannikov                                 CharUnits &Field1Off, llvm::Type *&Field2Ty,
54992cb984SSergei Barannikov                                 CharUnits &Field2Off, int &NeededArgGPRs,
55992cb984SSergei Barannikov                                 int &NeededArgFPRs) const;
56992cb984SSergei Barannikov   ABIArgInfo coerceAndExpandFARsEligibleStruct(llvm::Type *Field1Ty,
57992cb984SSergei Barannikov                                                CharUnits Field1Off,
58992cb984SSergei Barannikov                                                llvm::Type *Field2Ty,
59992cb984SSergei Barannikov                                                CharUnits Field2Off) const;
60992cb984SSergei Barannikov };
61992cb984SSergei Barannikov } // end anonymous namespace
62992cb984SSergei Barannikov 
63992cb984SSergei Barannikov void LoongArchABIInfo::computeInfo(CGFunctionInfo &FI) const {
64992cb984SSergei Barannikov   QualType RetTy = FI.getReturnType();
65992cb984SSergei Barannikov   if (!getCXXABI().classifyReturnType(FI))
66992cb984SSergei Barannikov     FI.getReturnInfo() = classifyReturnType(RetTy);
67992cb984SSergei Barannikov 
68992cb984SSergei Barannikov   // IsRetIndirect is true if classifyArgumentType indicated the value should
69992cb984SSergei Barannikov   // be passed indirect, or if the type size is a scalar greater than 2*GRLen
70992cb984SSergei Barannikov   // and not a complex type with elements <= FRLen. e.g. fp128 is passed direct
71992cb984SSergei Barannikov   // in LLVM IR, relying on the backend lowering code to rewrite the argument
72992cb984SSergei Barannikov   // list and pass indirectly on LA32.
73992cb984SSergei Barannikov   bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect;
74992cb984SSergei Barannikov   if (!IsRetIndirect && RetTy->isScalarType() &&
75992cb984SSergei Barannikov       getContext().getTypeSize(RetTy) > (2 * GRLen)) {
76992cb984SSergei Barannikov     if (RetTy->isComplexType() && FRLen) {
77992cb984SSergei Barannikov       QualType EltTy = RetTy->castAs<ComplexType>()->getElementType();
78992cb984SSergei Barannikov       IsRetIndirect = getContext().getTypeSize(EltTy) > FRLen;
79992cb984SSergei Barannikov     } else {
80992cb984SSergei Barannikov       // This is a normal scalar > 2*GRLen, such as fp128 on LA32.
81992cb984SSergei Barannikov       IsRetIndirect = true;
82992cb984SSergei Barannikov     }
83992cb984SSergei Barannikov   }
84992cb984SSergei Barannikov 
85992cb984SSergei Barannikov   // We must track the number of GARs and FARs used in order to conform to the
86992cb984SSergei Barannikov   // LoongArch ABI. As GAR usage is different for variadic arguments, we must
87992cb984SSergei Barannikov   // also track whether we are examining a vararg or not.
88992cb984SSergei Barannikov   int GARsLeft = IsRetIndirect ? NumGARs - 1 : NumGARs;
89992cb984SSergei Barannikov   int FARsLeft = FRLen ? NumFARs : 0;
90992cb984SSergei Barannikov   int NumFixedArgs = FI.getNumRequiredArgs();
91992cb984SSergei Barannikov 
92992cb984SSergei Barannikov   int ArgNum = 0;
93992cb984SSergei Barannikov   for (auto &ArgInfo : FI.arguments()) {
94992cb984SSergei Barannikov     ArgInfo.info = classifyArgumentType(
95992cb984SSergei Barannikov         ArgInfo.type, /*IsFixed=*/ArgNum < NumFixedArgs, GARsLeft, FARsLeft);
96992cb984SSergei Barannikov     ArgNum++;
97992cb984SSergei Barannikov   }
98992cb984SSergei Barannikov }
99992cb984SSergei Barannikov 
100992cb984SSergei Barannikov // Returns true if the struct is a potential candidate to be passed in FARs (and
101992cb984SSergei Barannikov // GARs). If this function returns true, the caller is responsible for checking
102992cb984SSergei Barannikov // that if there is only a single field then that field is a float.
103992cb984SSergei Barannikov bool LoongArchABIInfo::detectFARsEligibleStructHelper(
104992cb984SSergei Barannikov     QualType Ty, CharUnits CurOff, llvm::Type *&Field1Ty, CharUnits &Field1Off,
105992cb984SSergei Barannikov     llvm::Type *&Field2Ty, CharUnits &Field2Off) const {
106992cb984SSergei Barannikov   bool IsInt = Ty->isIntegralOrEnumerationType();
107992cb984SSergei Barannikov   bool IsFloat = Ty->isRealFloatingType();
108992cb984SSergei Barannikov 
109992cb984SSergei Barannikov   if (IsInt || IsFloat) {
110992cb984SSergei Barannikov     uint64_t Size = getContext().getTypeSize(Ty);
111992cb984SSergei Barannikov     if (IsInt && Size > GRLen)
112992cb984SSergei Barannikov       return false;
113992cb984SSergei Barannikov     // Can't be eligible if larger than the FP registers. Half precision isn't
114992cb984SSergei Barannikov     // currently supported on LoongArch and the ABI hasn't been confirmed, so
115992cb984SSergei Barannikov     // default to the integer ABI in that case.
116992cb984SSergei Barannikov     if (IsFloat && (Size > FRLen || Size < 32))
117992cb984SSergei Barannikov       return false;
118992cb984SSergei Barannikov     // Can't be eligible if an integer type was already found (int+int pairs
119992cb984SSergei Barannikov     // are not eligible).
120992cb984SSergei Barannikov     if (IsInt && Field1Ty && Field1Ty->isIntegerTy())
121992cb984SSergei Barannikov       return false;
122992cb984SSergei Barannikov     if (!Field1Ty) {
123992cb984SSergei Barannikov       Field1Ty = CGT.ConvertType(Ty);
124992cb984SSergei Barannikov       Field1Off = CurOff;
125992cb984SSergei Barannikov       return true;
126992cb984SSergei Barannikov     }
127992cb984SSergei Barannikov     if (!Field2Ty) {
128992cb984SSergei Barannikov       Field2Ty = CGT.ConvertType(Ty);
129992cb984SSergei Barannikov       Field2Off = CurOff;
130992cb984SSergei Barannikov       return true;
131992cb984SSergei Barannikov     }
132992cb984SSergei Barannikov     return false;
133992cb984SSergei Barannikov   }
134992cb984SSergei Barannikov 
135992cb984SSergei Barannikov   if (auto CTy = Ty->getAs<ComplexType>()) {
136992cb984SSergei Barannikov     if (Field1Ty)
137992cb984SSergei Barannikov       return false;
138992cb984SSergei Barannikov     QualType EltTy = CTy->getElementType();
139992cb984SSergei Barannikov     if (getContext().getTypeSize(EltTy) > FRLen)
140992cb984SSergei Barannikov       return false;
141992cb984SSergei Barannikov     Field1Ty = CGT.ConvertType(EltTy);
142992cb984SSergei Barannikov     Field1Off = CurOff;
143992cb984SSergei Barannikov     Field2Ty = Field1Ty;
144992cb984SSergei Barannikov     Field2Off = Field1Off + getContext().getTypeSizeInChars(EltTy);
145992cb984SSergei Barannikov     return true;
146992cb984SSergei Barannikov   }
147992cb984SSergei Barannikov 
148992cb984SSergei Barannikov   if (const ConstantArrayType *ATy = getContext().getAsConstantArrayType(Ty)) {
14928ddbd4aSChris B     uint64_t ArraySize = ATy->getZExtSize();
150992cb984SSergei Barannikov     QualType EltTy = ATy->getElementType();
151e7a8a7d4SWeining Lu     // Non-zero-length arrays of empty records make the struct ineligible to be
152e7a8a7d4SWeining Lu     // passed via FARs in C++.
153e7a8a7d4SWeining Lu     if (const auto *RTy = EltTy->getAs<RecordType>()) {
154e7a8a7d4SWeining Lu       if (ArraySize != 0 && isa<CXXRecordDecl>(RTy->getDecl()) &&
155e7a8a7d4SWeining Lu           isEmptyRecord(getContext(), EltTy, true, true))
156e7a8a7d4SWeining Lu         return false;
157e7a8a7d4SWeining Lu     }
158992cb984SSergei Barannikov     CharUnits EltSize = getContext().getTypeSizeInChars(EltTy);
159992cb984SSergei Barannikov     for (uint64_t i = 0; i < ArraySize; ++i) {
160992cb984SSergei Barannikov       if (!detectFARsEligibleStructHelper(EltTy, CurOff, Field1Ty, Field1Off,
161992cb984SSergei Barannikov                                           Field2Ty, Field2Off))
162992cb984SSergei Barannikov         return false;
163992cb984SSergei Barannikov       CurOff += EltSize;
164992cb984SSergei Barannikov     }
165992cb984SSergei Barannikov     return true;
166992cb984SSergei Barannikov   }
167992cb984SSergei Barannikov 
168992cb984SSergei Barannikov   if (const auto *RTy = Ty->getAs<RecordType>()) {
169992cb984SSergei Barannikov     // Structures with either a non-trivial destructor or a non-trivial
170992cb984SSergei Barannikov     // copy constructor are not eligible for the FP calling convention.
171992cb984SSergei Barannikov     if (getRecordArgABI(Ty, CGT.getCXXABI()))
172992cb984SSergei Barannikov       return false;
173992cb984SSergei Barannikov     const RecordDecl *RD = RTy->getDecl();
1744253fdc2SLu Weining     if (isEmptyRecord(getContext(), Ty, true, true) &&
1754253fdc2SLu Weining         (!RD->isUnion() || !isa<CXXRecordDecl>(RD)))
1764253fdc2SLu Weining       return true;
1774253fdc2SLu Weining     // Unions aren't eligible unless they're empty in C (which is caught above).
178992cb984SSergei Barannikov     if (RD->isUnion())
179992cb984SSergei Barannikov       return false;
180992cb984SSergei Barannikov     const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
181992cb984SSergei Barannikov     // If this is a C++ record, check the bases first.
182992cb984SSergei Barannikov     if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
183992cb984SSergei Barannikov       for (const CXXBaseSpecifier &B : CXXRD->bases()) {
184992cb984SSergei Barannikov         const auto *BDecl =
185992cb984SSergei Barannikov             cast<CXXRecordDecl>(B.getType()->castAs<RecordType>()->getDecl());
186992cb984SSergei Barannikov         if (!detectFARsEligibleStructHelper(
187992cb984SSergei Barannikov                 B.getType(), CurOff + Layout.getBaseClassOffset(BDecl),
188992cb984SSergei Barannikov                 Field1Ty, Field1Off, Field2Ty, Field2Off))
189992cb984SSergei Barannikov           return false;
190992cb984SSergei Barannikov       }
191992cb984SSergei Barannikov     }
192992cb984SSergei Barannikov     for (const FieldDecl *FD : RD->fields()) {
193992cb984SSergei Barannikov       QualType QTy = FD->getType();
194992cb984SSergei Barannikov       if (FD->isBitField()) {
195*cfe26358STimm Baeder         unsigned BitWidth = FD->getBitWidthValue();
196992cb984SSergei Barannikov         // Zero-width bitfields are ignored.
197992cb984SSergei Barannikov         if (BitWidth == 0)
198992cb984SSergei Barannikov           continue;
199992cb984SSergei Barannikov         // Allow a bitfield with a type greater than GRLen as long as the
200992cb984SSergei Barannikov         // bitwidth is GRLen or less.
201992cb984SSergei Barannikov         if (getContext().getTypeSize(QTy) > GRLen && BitWidth <= GRLen) {
202992cb984SSergei Barannikov           QTy = getContext().getIntTypeForBitwidth(GRLen, false);
203992cb984SSergei Barannikov         }
204992cb984SSergei Barannikov       }
205992cb984SSergei Barannikov 
206992cb984SSergei Barannikov       if (!detectFARsEligibleStructHelper(
207992cb984SSergei Barannikov               QTy,
208992cb984SSergei Barannikov               CurOff + getContext().toCharUnitsFromBits(
209992cb984SSergei Barannikov                            Layout.getFieldOffset(FD->getFieldIndex())),
210992cb984SSergei Barannikov               Field1Ty, Field1Off, Field2Ty, Field2Off))
211992cb984SSergei Barannikov         return false;
212992cb984SSergei Barannikov     }
213992cb984SSergei Barannikov     return Field1Ty != nullptr;
214992cb984SSergei Barannikov   }
215992cb984SSergei Barannikov 
216992cb984SSergei Barannikov   return false;
217992cb984SSergei Barannikov }
218992cb984SSergei Barannikov 
219992cb984SSergei Barannikov // Determine if a struct is eligible to be passed in FARs (and GARs) (i.e., when
220992cb984SSergei Barannikov // flattened it contains a single fp value, fp+fp, or int+fp of appropriate
221992cb984SSergei Barannikov // size). If so, NeededFARs and NeededGARs are incremented appropriately.
222992cb984SSergei Barannikov bool LoongArchABIInfo::detectFARsEligibleStruct(
223992cb984SSergei Barannikov     QualType Ty, llvm::Type *&Field1Ty, CharUnits &Field1Off,
224992cb984SSergei Barannikov     llvm::Type *&Field2Ty, CharUnits &Field2Off, int &NeededGARs,
225992cb984SSergei Barannikov     int &NeededFARs) const {
226992cb984SSergei Barannikov   Field1Ty = nullptr;
227992cb984SSergei Barannikov   Field2Ty = nullptr;
228992cb984SSergei Barannikov   NeededGARs = 0;
229992cb984SSergei Barannikov   NeededFARs = 0;
230992cb984SSergei Barannikov   if (!detectFARsEligibleStructHelper(Ty, CharUnits::Zero(), Field1Ty,
231992cb984SSergei Barannikov                                       Field1Off, Field2Ty, Field2Off))
232992cb984SSergei Barannikov     return false;
233e7a8a7d4SWeining Lu   if (!Field1Ty)
234e7a8a7d4SWeining Lu     return false;
235992cb984SSergei Barannikov   // Not really a candidate if we have a single int but no float.
236992cb984SSergei Barannikov   if (Field1Ty && !Field2Ty && !Field1Ty->isFloatingPointTy())
237992cb984SSergei Barannikov     return false;
238992cb984SSergei Barannikov   if (Field1Ty && Field1Ty->isFloatingPointTy())
239992cb984SSergei Barannikov     NeededFARs++;
240992cb984SSergei Barannikov   else if (Field1Ty)
241992cb984SSergei Barannikov     NeededGARs++;
242992cb984SSergei Barannikov   if (Field2Ty && Field2Ty->isFloatingPointTy())
243992cb984SSergei Barannikov     NeededFARs++;
244992cb984SSergei Barannikov   else if (Field2Ty)
245992cb984SSergei Barannikov     NeededGARs++;
246992cb984SSergei Barannikov   return true;
247992cb984SSergei Barannikov }
248992cb984SSergei Barannikov 
249992cb984SSergei Barannikov // Call getCoerceAndExpand for the two-element flattened struct described by
250992cb984SSergei Barannikov // Field1Ty, Field1Off, Field2Ty, Field2Off. This method will create an
251992cb984SSergei Barannikov // appropriate coerceToType and unpaddedCoerceToType.
252992cb984SSergei Barannikov ABIArgInfo LoongArchABIInfo::coerceAndExpandFARsEligibleStruct(
253992cb984SSergei Barannikov     llvm::Type *Field1Ty, CharUnits Field1Off, llvm::Type *Field2Ty,
254992cb984SSergei Barannikov     CharUnits Field2Off) const {
255992cb984SSergei Barannikov   SmallVector<llvm::Type *, 3> CoerceElts;
256992cb984SSergei Barannikov   SmallVector<llvm::Type *, 2> UnpaddedCoerceElts;
257992cb984SSergei Barannikov   if (!Field1Off.isZero())
258992cb984SSergei Barannikov     CoerceElts.push_back(llvm::ArrayType::get(
259992cb984SSergei Barannikov         llvm::Type::getInt8Ty(getVMContext()), Field1Off.getQuantity()));
260992cb984SSergei Barannikov 
261992cb984SSergei Barannikov   CoerceElts.push_back(Field1Ty);
262992cb984SSergei Barannikov   UnpaddedCoerceElts.push_back(Field1Ty);
263992cb984SSergei Barannikov 
264992cb984SSergei Barannikov   if (!Field2Ty) {
265992cb984SSergei Barannikov     return ABIArgInfo::getCoerceAndExpand(
266992cb984SSergei Barannikov         llvm::StructType::get(getVMContext(), CoerceElts, !Field1Off.isZero()),
267992cb984SSergei Barannikov         UnpaddedCoerceElts[0]);
268992cb984SSergei Barannikov   }
269992cb984SSergei Barannikov 
270992cb984SSergei Barannikov   CharUnits Field2Align =
271992cb984SSergei Barannikov       CharUnits::fromQuantity(getDataLayout().getABITypeAlign(Field2Ty));
272992cb984SSergei Barannikov   CharUnits Field1End =
273992cb984SSergei Barannikov       Field1Off +
274992cb984SSergei Barannikov       CharUnits::fromQuantity(getDataLayout().getTypeStoreSize(Field1Ty));
275992cb984SSergei Barannikov   CharUnits Field2OffNoPadNoPack = Field1End.alignTo(Field2Align);
276992cb984SSergei Barannikov 
277992cb984SSergei Barannikov   CharUnits Padding = CharUnits::Zero();
278992cb984SSergei Barannikov   if (Field2Off > Field2OffNoPadNoPack)
279992cb984SSergei Barannikov     Padding = Field2Off - Field2OffNoPadNoPack;
280992cb984SSergei Barannikov   else if (Field2Off != Field2Align && Field2Off > Field1End)
281992cb984SSergei Barannikov     Padding = Field2Off - Field1End;
282992cb984SSergei Barannikov 
283992cb984SSergei Barannikov   bool IsPacked = !Field2Off.isMultipleOf(Field2Align);
284992cb984SSergei Barannikov 
285992cb984SSergei Barannikov   if (!Padding.isZero())
286992cb984SSergei Barannikov     CoerceElts.push_back(llvm::ArrayType::get(
287992cb984SSergei Barannikov         llvm::Type::getInt8Ty(getVMContext()), Padding.getQuantity()));
288992cb984SSergei Barannikov 
289992cb984SSergei Barannikov   CoerceElts.push_back(Field2Ty);
290992cb984SSergei Barannikov   UnpaddedCoerceElts.push_back(Field2Ty);
291992cb984SSergei Barannikov 
292992cb984SSergei Barannikov   return ABIArgInfo::getCoerceAndExpand(
293992cb984SSergei Barannikov       llvm::StructType::get(getVMContext(), CoerceElts, IsPacked),
294992cb984SSergei Barannikov       llvm::StructType::get(getVMContext(), UnpaddedCoerceElts, IsPacked));
295992cb984SSergei Barannikov }
296992cb984SSergei Barannikov 
297992cb984SSergei Barannikov ABIArgInfo LoongArchABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
298992cb984SSergei Barannikov                                                   int &GARsLeft,
299992cb984SSergei Barannikov                                                   int &FARsLeft) const {
300992cb984SSergei Barannikov   assert(GARsLeft <= NumGARs && "GAR tracking underflow");
301992cb984SSergei Barannikov   Ty = useFirstFieldIfTransparentUnion(Ty);
302992cb984SSergei Barannikov 
303992cb984SSergei Barannikov   // Structures with either a non-trivial destructor or a non-trivial
304992cb984SSergei Barannikov   // copy constructor are always passed indirectly.
305992cb984SSergei Barannikov   if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
306992cb984SSergei Barannikov     if (GARsLeft)
307992cb984SSergei Barannikov       GARsLeft -= 1;
308992cb984SSergei Barannikov     return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA ==
309992cb984SSergei Barannikov                                            CGCXXABI::RAA_DirectInMemory);
310992cb984SSergei Barannikov   }
311992cb984SSergei Barannikov 
312992cb984SSergei Barannikov   uint64_t Size = getContext().getTypeSize(Ty);
313992cb984SSergei Barannikov 
3149ca6bf3fSLu Weining   // Ignore empty struct or union whose size is zero, e.g. `struct { }` in C or
3159ca6bf3fSLu Weining   // `struct { int a[0]; }` in C++. In C++, `struct { }` is empty but it's size
3169ca6bf3fSLu Weining   // is 1 byte and g++ doesn't ignore it; clang++ matches this behaviour.
3179ca6bf3fSLu Weining   if (isEmptyRecord(getContext(), Ty, true) && Size == 0)
3189ca6bf3fSLu Weining     return ABIArgInfo::getIgnore();
3199ca6bf3fSLu Weining 
320992cb984SSergei Barannikov   // Pass floating point values via FARs if possible.
321992cb984SSergei Barannikov   if (IsFixed && Ty->isFloatingType() && !Ty->isComplexType() &&
322992cb984SSergei Barannikov       FRLen >= Size && FARsLeft) {
323992cb984SSergei Barannikov     FARsLeft--;
324992cb984SSergei Barannikov     return ABIArgInfo::getDirect();
325992cb984SSergei Barannikov   }
326992cb984SSergei Barannikov 
327992cb984SSergei Barannikov   // Complex types for the *f or *d ABI must be passed directly rather than
328992cb984SSergei Barannikov   // using CoerceAndExpand.
329992cb984SSergei Barannikov   if (IsFixed && Ty->isComplexType() && FRLen && FARsLeft >= 2) {
330992cb984SSergei Barannikov     QualType EltTy = Ty->castAs<ComplexType>()->getElementType();
331992cb984SSergei Barannikov     if (getContext().getTypeSize(EltTy) <= FRLen) {
332992cb984SSergei Barannikov       FARsLeft -= 2;
333992cb984SSergei Barannikov       return ABIArgInfo::getDirect();
334992cb984SSergei Barannikov     }
335992cb984SSergei Barannikov   }
336992cb984SSergei Barannikov 
337992cb984SSergei Barannikov   if (IsFixed && FRLen && Ty->isStructureOrClassType()) {
338992cb984SSergei Barannikov     llvm::Type *Field1Ty = nullptr;
339992cb984SSergei Barannikov     llvm::Type *Field2Ty = nullptr;
340992cb984SSergei Barannikov     CharUnits Field1Off = CharUnits::Zero();
341992cb984SSergei Barannikov     CharUnits Field2Off = CharUnits::Zero();
342992cb984SSergei Barannikov     int NeededGARs = 0;
343992cb984SSergei Barannikov     int NeededFARs = 0;
344992cb984SSergei Barannikov     bool IsCandidate = detectFARsEligibleStruct(
345992cb984SSergei Barannikov         Ty, Field1Ty, Field1Off, Field2Ty, Field2Off, NeededGARs, NeededFARs);
346992cb984SSergei Barannikov     if (IsCandidate && NeededGARs <= GARsLeft && NeededFARs <= FARsLeft) {
347992cb984SSergei Barannikov       GARsLeft -= NeededGARs;
348992cb984SSergei Barannikov       FARsLeft -= NeededFARs;
349992cb984SSergei Barannikov       return coerceAndExpandFARsEligibleStruct(Field1Ty, Field1Off, Field2Ty,
350992cb984SSergei Barannikov                                                Field2Off);
351992cb984SSergei Barannikov     }
352992cb984SSergei Barannikov   }
353992cb984SSergei Barannikov 
354992cb984SSergei Barannikov   uint64_t NeededAlign = getContext().getTypeAlign(Ty);
355992cb984SSergei Barannikov   // Determine the number of GARs needed to pass the current argument
356992cb984SSergei Barannikov   // according to the ABI. 2*GRLen-aligned varargs are passed in "aligned"
357992cb984SSergei Barannikov   // register pairs, so may consume 3 registers.
358992cb984SSergei Barannikov   int NeededGARs = 1;
359992cb984SSergei Barannikov   if (!IsFixed && NeededAlign == 2 * GRLen)
360992cb984SSergei Barannikov     NeededGARs = 2 + (GARsLeft % 2);
361992cb984SSergei Barannikov   else if (Size > GRLen && Size <= 2 * GRLen)
362992cb984SSergei Barannikov     NeededGARs = 2;
363992cb984SSergei Barannikov 
364992cb984SSergei Barannikov   if (NeededGARs > GARsLeft)
365992cb984SSergei Barannikov     NeededGARs = GARsLeft;
366992cb984SSergei Barannikov 
367992cb984SSergei Barannikov   GARsLeft -= NeededGARs;
368992cb984SSergei Barannikov 
369992cb984SSergei Barannikov   if (!isAggregateTypeForABI(Ty) && !Ty->isVectorType()) {
370992cb984SSergei Barannikov     // Treat an enum type as its underlying type.
371992cb984SSergei Barannikov     if (const EnumType *EnumTy = Ty->getAs<EnumType>())
372992cb984SSergei Barannikov       Ty = EnumTy->getDecl()->getIntegerType();
373992cb984SSergei Barannikov 
374992cb984SSergei Barannikov     // All integral types are promoted to GRLen width.
375992cb984SSergei Barannikov     if (Size < GRLen && Ty->isIntegralOrEnumerationType())
376992cb984SSergei Barannikov       return extendType(Ty);
377992cb984SSergei Barannikov 
378992cb984SSergei Barannikov     if (const auto *EIT = Ty->getAs<BitIntType>()) {
379992cb984SSergei Barannikov       if (EIT->getNumBits() < GRLen)
380992cb984SSergei Barannikov         return extendType(Ty);
381992cb984SSergei Barannikov       if (EIT->getNumBits() > 128 ||
382992cb984SSergei Barannikov           (!getContext().getTargetInfo().hasInt128Type() &&
383992cb984SSergei Barannikov            EIT->getNumBits() > 64))
384992cb984SSergei Barannikov         return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
385992cb984SSergei Barannikov     }
386992cb984SSergei Barannikov 
387992cb984SSergei Barannikov     return ABIArgInfo::getDirect();
388992cb984SSergei Barannikov   }
389992cb984SSergei Barannikov 
390992cb984SSergei Barannikov   // Aggregates which are <= 2*GRLen will be passed in registers if possible,
391992cb984SSergei Barannikov   // so coerce to integers.
392992cb984SSergei Barannikov   if (Size <= 2 * GRLen) {
393992cb984SSergei Barannikov     // Use a single GRLen int if possible, 2*GRLen if 2*GRLen alignment is
394992cb984SSergei Barannikov     // required, and a 2-element GRLen array if only GRLen alignment is
395992cb984SSergei Barannikov     // required.
396992cb984SSergei Barannikov     if (Size <= GRLen) {
397992cb984SSergei Barannikov       return ABIArgInfo::getDirect(
398992cb984SSergei Barannikov           llvm::IntegerType::get(getVMContext(), GRLen));
399992cb984SSergei Barannikov     }
400992cb984SSergei Barannikov     if (getContext().getTypeAlign(Ty) == 2 * GRLen) {
401992cb984SSergei Barannikov       return ABIArgInfo::getDirect(
402992cb984SSergei Barannikov           llvm::IntegerType::get(getVMContext(), 2 * GRLen));
403992cb984SSergei Barannikov     }
404992cb984SSergei Barannikov     return ABIArgInfo::getDirect(
405992cb984SSergei Barannikov         llvm::ArrayType::get(llvm::IntegerType::get(getVMContext(), GRLen), 2));
406992cb984SSergei Barannikov   }
407992cb984SSergei Barannikov   return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
408992cb984SSergei Barannikov }
409992cb984SSergei Barannikov 
410992cb984SSergei Barannikov ABIArgInfo LoongArchABIInfo::classifyReturnType(QualType RetTy) const {
411992cb984SSergei Barannikov   if (RetTy->isVoidType())
412992cb984SSergei Barannikov     return ABIArgInfo::getIgnore();
413992cb984SSergei Barannikov   // The rules for return and argument types are the same, so defer to
414992cb984SSergei Barannikov   // classifyArgumentType.
415992cb984SSergei Barannikov   int GARsLeft = 2;
416992cb984SSergei Barannikov   int FARsLeft = FRLen ? 2 : 0;
417992cb984SSergei Barannikov   return classifyArgumentType(RetTy, /*IsFixed=*/true, GARsLeft, FARsLeft);
418992cb984SSergei Barannikov }
419992cb984SSergei Barannikov 
4206d973b45SMariya Podchishchaeva RValue LoongArchABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
4216d973b45SMariya Podchishchaeva                                    QualType Ty, AggValueSlot Slot) const {
422992cb984SSergei Barannikov   CharUnits SlotSize = CharUnits::fromQuantity(GRLen / 8);
423992cb984SSergei Barannikov 
424992cb984SSergei Barannikov   // Empty records are ignored for parameter passing purposes.
425474ec694SYoungsuk Kim   if (isEmptyRecord(getContext(), Ty, true))
4266d973b45SMariya Podchishchaeva     return Slot.asRValue();
427992cb984SSergei Barannikov 
428992cb984SSergei Barannikov   auto TInfo = getContext().getTypeInfoInChars(Ty);
429992cb984SSergei Barannikov 
430992cb984SSergei Barannikov   // Arguments bigger than 2*GRLen bytes are passed indirectly.
431992cb984SSergei Barannikov   return emitVoidPtrVAArg(CGF, VAListAddr, Ty,
432992cb984SSergei Barannikov                           /*IsIndirect=*/TInfo.Width > 2 * SlotSize, TInfo,
433992cb984SSergei Barannikov                           SlotSize,
4346d973b45SMariya Podchishchaeva                           /*AllowHigherAlign=*/true, Slot);
435992cb984SSergei Barannikov }
436992cb984SSergei Barannikov 
437992cb984SSergei Barannikov ABIArgInfo LoongArchABIInfo::extendType(QualType Ty) const {
438992cb984SSergei Barannikov   int TySize = getContext().getTypeSize(Ty);
439992cb984SSergei Barannikov   // LA64 ABI requires unsigned 32 bit integers to be sign extended.
440992cb984SSergei Barannikov   if (GRLen == 64 && Ty->isUnsignedIntegerOrEnumerationType() && TySize == 32)
441992cb984SSergei Barannikov     return ABIArgInfo::getSignExtend(Ty);
442992cb984SSergei Barannikov   return ABIArgInfo::getExtend(Ty);
443992cb984SSergei Barannikov }
444992cb984SSergei Barannikov 
445992cb984SSergei Barannikov namespace {
446992cb984SSergei Barannikov class LoongArchTargetCodeGenInfo : public TargetCodeGenInfo {
447992cb984SSergei Barannikov public:
448992cb984SSergei Barannikov   LoongArchTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned GRLen,
449992cb984SSergei Barannikov                              unsigned FRLen)
450992cb984SSergei Barannikov       : TargetCodeGenInfo(
451992cb984SSergei Barannikov             std::make_unique<LoongArchABIInfo>(CGT, GRLen, FRLen)) {}
452992cb984SSergei Barannikov };
453992cb984SSergei Barannikov } // namespace
454992cb984SSergei Barannikov 
455992cb984SSergei Barannikov std::unique_ptr<TargetCodeGenInfo>
456992cb984SSergei Barannikov CodeGen::createLoongArchTargetCodeGenInfo(CodeGenModule &CGM, unsigned GRLen,
457992cb984SSergei Barannikov                                           unsigned FLen) {
458992cb984SSergei Barannikov   return std::make_unique<LoongArchTargetCodeGenInfo>(CGM.getTypes(), GRLen,
459992cb984SSergei Barannikov                                                       FLen);
460992cb984SSergei Barannikov }
461