xref: /freebsd-src/contrib/llvm-project/clang/lib/CodeGen/Targets/LoongArch.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1*06c3fb27SDimitry Andric //===- LoongArch.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 #include "TargetInfo.h"
11*06c3fb27SDimitry Andric 
12*06c3fb27SDimitry Andric using namespace clang;
13*06c3fb27SDimitry Andric using namespace clang::CodeGen;
14*06c3fb27SDimitry Andric 
15*06c3fb27SDimitry Andric // LoongArch ABI Implementation. Documented at
16*06c3fb27SDimitry Andric // https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html
17*06c3fb27SDimitry Andric //
18*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
19*06c3fb27SDimitry Andric 
20*06c3fb27SDimitry Andric namespace {
21*06c3fb27SDimitry Andric class LoongArchABIInfo : public DefaultABIInfo {
22*06c3fb27SDimitry Andric private:
23*06c3fb27SDimitry Andric   // Size of the integer ('r') registers in bits.
24*06c3fb27SDimitry Andric   unsigned GRLen;
25*06c3fb27SDimitry Andric   // Size of the floating point ('f') registers in bits.
26*06c3fb27SDimitry Andric   unsigned FRLen;
27*06c3fb27SDimitry Andric   // Number of general-purpose argument registers.
28*06c3fb27SDimitry Andric   static const int NumGARs = 8;
29*06c3fb27SDimitry Andric   // Number of floating-point argument registers.
30*06c3fb27SDimitry Andric   static const int NumFARs = 8;
31*06c3fb27SDimitry Andric   bool detectFARsEligibleStructHelper(QualType Ty, CharUnits CurOff,
32*06c3fb27SDimitry Andric                                       llvm::Type *&Field1Ty,
33*06c3fb27SDimitry Andric                                       CharUnits &Field1Off,
34*06c3fb27SDimitry Andric                                       llvm::Type *&Field2Ty,
35*06c3fb27SDimitry Andric                                       CharUnits &Field2Off) const;
36*06c3fb27SDimitry Andric 
37*06c3fb27SDimitry Andric public:
38*06c3fb27SDimitry Andric   LoongArchABIInfo(CodeGen::CodeGenTypes &CGT, unsigned GRLen, unsigned FRLen)
39*06c3fb27SDimitry Andric       : DefaultABIInfo(CGT), GRLen(GRLen), FRLen(FRLen) {}
40*06c3fb27SDimitry Andric 
41*06c3fb27SDimitry Andric   void computeInfo(CGFunctionInfo &FI) const override;
42*06c3fb27SDimitry Andric 
43*06c3fb27SDimitry Andric   ABIArgInfo classifyArgumentType(QualType Ty, bool IsFixed, int &GARsLeft,
44*06c3fb27SDimitry Andric                                   int &FARsLeft) const;
45*06c3fb27SDimitry Andric   ABIArgInfo classifyReturnType(QualType RetTy) const;
46*06c3fb27SDimitry Andric 
47*06c3fb27SDimitry Andric   Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
48*06c3fb27SDimitry Andric                     QualType Ty) const override;
49*06c3fb27SDimitry Andric 
50*06c3fb27SDimitry Andric   ABIArgInfo extendType(QualType Ty) const;
51*06c3fb27SDimitry Andric 
52*06c3fb27SDimitry Andric   bool detectFARsEligibleStruct(QualType Ty, llvm::Type *&Field1Ty,
53*06c3fb27SDimitry Andric                                 CharUnits &Field1Off, llvm::Type *&Field2Ty,
54*06c3fb27SDimitry Andric                                 CharUnits &Field2Off, int &NeededArgGPRs,
55*06c3fb27SDimitry Andric                                 int &NeededArgFPRs) const;
56*06c3fb27SDimitry Andric   ABIArgInfo coerceAndExpandFARsEligibleStruct(llvm::Type *Field1Ty,
57*06c3fb27SDimitry Andric                                                CharUnits Field1Off,
58*06c3fb27SDimitry Andric                                                llvm::Type *Field2Ty,
59*06c3fb27SDimitry Andric                                                CharUnits Field2Off) const;
60*06c3fb27SDimitry Andric };
61*06c3fb27SDimitry Andric } // end anonymous namespace
62*06c3fb27SDimitry Andric 
63*06c3fb27SDimitry Andric void LoongArchABIInfo::computeInfo(CGFunctionInfo &FI) const {
64*06c3fb27SDimitry Andric   QualType RetTy = FI.getReturnType();
65*06c3fb27SDimitry Andric   if (!getCXXABI().classifyReturnType(FI))
66*06c3fb27SDimitry Andric     FI.getReturnInfo() = classifyReturnType(RetTy);
67*06c3fb27SDimitry Andric 
68*06c3fb27SDimitry Andric   // IsRetIndirect is true if classifyArgumentType indicated the value should
69*06c3fb27SDimitry Andric   // be passed indirect, or if the type size is a scalar greater than 2*GRLen
70*06c3fb27SDimitry Andric   // and not a complex type with elements <= FRLen. e.g. fp128 is passed direct
71*06c3fb27SDimitry Andric   // in LLVM IR, relying on the backend lowering code to rewrite the argument
72*06c3fb27SDimitry Andric   // list and pass indirectly on LA32.
73*06c3fb27SDimitry Andric   bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect;
74*06c3fb27SDimitry Andric   if (!IsRetIndirect && RetTy->isScalarType() &&
75*06c3fb27SDimitry Andric       getContext().getTypeSize(RetTy) > (2 * GRLen)) {
76*06c3fb27SDimitry Andric     if (RetTy->isComplexType() && FRLen) {
77*06c3fb27SDimitry Andric       QualType EltTy = RetTy->castAs<ComplexType>()->getElementType();
78*06c3fb27SDimitry Andric       IsRetIndirect = getContext().getTypeSize(EltTy) > FRLen;
79*06c3fb27SDimitry Andric     } else {
80*06c3fb27SDimitry Andric       // This is a normal scalar > 2*GRLen, such as fp128 on LA32.
81*06c3fb27SDimitry Andric       IsRetIndirect = true;
82*06c3fb27SDimitry Andric     }
83*06c3fb27SDimitry Andric   }
84*06c3fb27SDimitry Andric 
85*06c3fb27SDimitry Andric   // We must track the number of GARs and FARs used in order to conform to the
86*06c3fb27SDimitry Andric   // LoongArch ABI. As GAR usage is different for variadic arguments, we must
87*06c3fb27SDimitry Andric   // also track whether we are examining a vararg or not.
88*06c3fb27SDimitry Andric   int GARsLeft = IsRetIndirect ? NumGARs - 1 : NumGARs;
89*06c3fb27SDimitry Andric   int FARsLeft = FRLen ? NumFARs : 0;
90*06c3fb27SDimitry Andric   int NumFixedArgs = FI.getNumRequiredArgs();
91*06c3fb27SDimitry Andric 
92*06c3fb27SDimitry Andric   int ArgNum = 0;
93*06c3fb27SDimitry Andric   for (auto &ArgInfo : FI.arguments()) {
94*06c3fb27SDimitry Andric     ArgInfo.info = classifyArgumentType(
95*06c3fb27SDimitry Andric         ArgInfo.type, /*IsFixed=*/ArgNum < NumFixedArgs, GARsLeft, FARsLeft);
96*06c3fb27SDimitry Andric     ArgNum++;
97*06c3fb27SDimitry Andric   }
98*06c3fb27SDimitry Andric }
99*06c3fb27SDimitry Andric 
100*06c3fb27SDimitry Andric // Returns true if the struct is a potential candidate to be passed in FARs (and
101*06c3fb27SDimitry Andric // GARs). If this function returns true, the caller is responsible for checking
102*06c3fb27SDimitry Andric // that if there is only a single field then that field is a float.
103*06c3fb27SDimitry Andric bool LoongArchABIInfo::detectFARsEligibleStructHelper(
104*06c3fb27SDimitry Andric     QualType Ty, CharUnits CurOff, llvm::Type *&Field1Ty, CharUnits &Field1Off,
105*06c3fb27SDimitry Andric     llvm::Type *&Field2Ty, CharUnits &Field2Off) const {
106*06c3fb27SDimitry Andric   bool IsInt = Ty->isIntegralOrEnumerationType();
107*06c3fb27SDimitry Andric   bool IsFloat = Ty->isRealFloatingType();
108*06c3fb27SDimitry Andric 
109*06c3fb27SDimitry Andric   if (IsInt || IsFloat) {
110*06c3fb27SDimitry Andric     uint64_t Size = getContext().getTypeSize(Ty);
111*06c3fb27SDimitry Andric     if (IsInt && Size > GRLen)
112*06c3fb27SDimitry Andric       return false;
113*06c3fb27SDimitry Andric     // Can't be eligible if larger than the FP registers. Half precision isn't
114*06c3fb27SDimitry Andric     // currently supported on LoongArch and the ABI hasn't been confirmed, so
115*06c3fb27SDimitry Andric     // default to the integer ABI in that case.
116*06c3fb27SDimitry Andric     if (IsFloat && (Size > FRLen || Size < 32))
117*06c3fb27SDimitry Andric       return false;
118*06c3fb27SDimitry Andric     // Can't be eligible if an integer type was already found (int+int pairs
119*06c3fb27SDimitry Andric     // are not eligible).
120*06c3fb27SDimitry Andric     if (IsInt && Field1Ty && Field1Ty->isIntegerTy())
121*06c3fb27SDimitry Andric       return false;
122*06c3fb27SDimitry Andric     if (!Field1Ty) {
123*06c3fb27SDimitry Andric       Field1Ty = CGT.ConvertType(Ty);
124*06c3fb27SDimitry Andric       Field1Off = CurOff;
125*06c3fb27SDimitry Andric       return true;
126*06c3fb27SDimitry Andric     }
127*06c3fb27SDimitry Andric     if (!Field2Ty) {
128*06c3fb27SDimitry Andric       Field2Ty = CGT.ConvertType(Ty);
129*06c3fb27SDimitry Andric       Field2Off = CurOff;
130*06c3fb27SDimitry Andric       return true;
131*06c3fb27SDimitry Andric     }
132*06c3fb27SDimitry Andric     return false;
133*06c3fb27SDimitry Andric   }
134*06c3fb27SDimitry Andric 
135*06c3fb27SDimitry Andric   if (auto CTy = Ty->getAs<ComplexType>()) {
136*06c3fb27SDimitry Andric     if (Field1Ty)
137*06c3fb27SDimitry Andric       return false;
138*06c3fb27SDimitry Andric     QualType EltTy = CTy->getElementType();
139*06c3fb27SDimitry Andric     if (getContext().getTypeSize(EltTy) > FRLen)
140*06c3fb27SDimitry Andric       return false;
141*06c3fb27SDimitry Andric     Field1Ty = CGT.ConvertType(EltTy);
142*06c3fb27SDimitry Andric     Field1Off = CurOff;
143*06c3fb27SDimitry Andric     Field2Ty = Field1Ty;
144*06c3fb27SDimitry Andric     Field2Off = Field1Off + getContext().getTypeSizeInChars(EltTy);
145*06c3fb27SDimitry Andric     return true;
146*06c3fb27SDimitry Andric   }
147*06c3fb27SDimitry Andric 
148*06c3fb27SDimitry Andric   if (const ConstantArrayType *ATy = getContext().getAsConstantArrayType(Ty)) {
149*06c3fb27SDimitry Andric     uint64_t ArraySize = ATy->getSize().getZExtValue();
150*06c3fb27SDimitry Andric     QualType EltTy = ATy->getElementType();
151*06c3fb27SDimitry Andric     CharUnits EltSize = getContext().getTypeSizeInChars(EltTy);
152*06c3fb27SDimitry Andric     for (uint64_t i = 0; i < ArraySize; ++i) {
153*06c3fb27SDimitry Andric       if (!detectFARsEligibleStructHelper(EltTy, CurOff, Field1Ty, Field1Off,
154*06c3fb27SDimitry Andric                                           Field2Ty, Field2Off))
155*06c3fb27SDimitry Andric         return false;
156*06c3fb27SDimitry Andric       CurOff += EltSize;
157*06c3fb27SDimitry Andric     }
158*06c3fb27SDimitry Andric     return true;
159*06c3fb27SDimitry Andric   }
160*06c3fb27SDimitry Andric 
161*06c3fb27SDimitry Andric   if (const auto *RTy = Ty->getAs<RecordType>()) {
162*06c3fb27SDimitry Andric     // Structures with either a non-trivial destructor or a non-trivial
163*06c3fb27SDimitry Andric     // copy constructor are not eligible for the FP calling convention.
164*06c3fb27SDimitry Andric     if (getRecordArgABI(Ty, CGT.getCXXABI()))
165*06c3fb27SDimitry Andric       return false;
166*06c3fb27SDimitry Andric     if (isEmptyRecord(getContext(), Ty, true))
167*06c3fb27SDimitry Andric       return true;
168*06c3fb27SDimitry Andric     const RecordDecl *RD = RTy->getDecl();
169*06c3fb27SDimitry Andric     // Unions aren't eligible unless they're empty (which is caught above).
170*06c3fb27SDimitry Andric     if (RD->isUnion())
171*06c3fb27SDimitry Andric       return false;
172*06c3fb27SDimitry Andric     const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
173*06c3fb27SDimitry Andric     // If this is a C++ record, check the bases first.
174*06c3fb27SDimitry Andric     if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
175*06c3fb27SDimitry Andric       for (const CXXBaseSpecifier &B : CXXRD->bases()) {
176*06c3fb27SDimitry Andric         const auto *BDecl =
177*06c3fb27SDimitry Andric             cast<CXXRecordDecl>(B.getType()->castAs<RecordType>()->getDecl());
178*06c3fb27SDimitry Andric         if (!detectFARsEligibleStructHelper(
179*06c3fb27SDimitry Andric                 B.getType(), CurOff + Layout.getBaseClassOffset(BDecl),
180*06c3fb27SDimitry Andric                 Field1Ty, Field1Off, Field2Ty, Field2Off))
181*06c3fb27SDimitry Andric           return false;
182*06c3fb27SDimitry Andric       }
183*06c3fb27SDimitry Andric     }
184*06c3fb27SDimitry Andric     for (const FieldDecl *FD : RD->fields()) {
185*06c3fb27SDimitry Andric       QualType QTy = FD->getType();
186*06c3fb27SDimitry Andric       if (FD->isBitField()) {
187*06c3fb27SDimitry Andric         unsigned BitWidth = FD->getBitWidthValue(getContext());
188*06c3fb27SDimitry Andric         // Zero-width bitfields are ignored.
189*06c3fb27SDimitry Andric         if (BitWidth == 0)
190*06c3fb27SDimitry Andric           continue;
191*06c3fb27SDimitry Andric         // Allow a bitfield with a type greater than GRLen as long as the
192*06c3fb27SDimitry Andric         // bitwidth is GRLen or less.
193*06c3fb27SDimitry Andric         if (getContext().getTypeSize(QTy) > GRLen && BitWidth <= GRLen) {
194*06c3fb27SDimitry Andric           QTy = getContext().getIntTypeForBitwidth(GRLen, false);
195*06c3fb27SDimitry Andric         }
196*06c3fb27SDimitry Andric       }
197*06c3fb27SDimitry Andric 
198*06c3fb27SDimitry Andric       if (!detectFARsEligibleStructHelper(
199*06c3fb27SDimitry Andric               QTy,
200*06c3fb27SDimitry Andric               CurOff + getContext().toCharUnitsFromBits(
201*06c3fb27SDimitry Andric                            Layout.getFieldOffset(FD->getFieldIndex())),
202*06c3fb27SDimitry Andric               Field1Ty, Field1Off, Field2Ty, Field2Off))
203*06c3fb27SDimitry Andric         return false;
204*06c3fb27SDimitry Andric     }
205*06c3fb27SDimitry Andric     return Field1Ty != nullptr;
206*06c3fb27SDimitry Andric   }
207*06c3fb27SDimitry Andric 
208*06c3fb27SDimitry Andric   return false;
209*06c3fb27SDimitry Andric }
210*06c3fb27SDimitry Andric 
211*06c3fb27SDimitry Andric // Determine if a struct is eligible to be passed in FARs (and GARs) (i.e., when
212*06c3fb27SDimitry Andric // flattened it contains a single fp value, fp+fp, or int+fp of appropriate
213*06c3fb27SDimitry Andric // size). If so, NeededFARs and NeededGARs are incremented appropriately.
214*06c3fb27SDimitry Andric bool LoongArchABIInfo::detectFARsEligibleStruct(
215*06c3fb27SDimitry Andric     QualType Ty, llvm::Type *&Field1Ty, CharUnits &Field1Off,
216*06c3fb27SDimitry Andric     llvm::Type *&Field2Ty, CharUnits &Field2Off, int &NeededGARs,
217*06c3fb27SDimitry Andric     int &NeededFARs) const {
218*06c3fb27SDimitry Andric   Field1Ty = nullptr;
219*06c3fb27SDimitry Andric   Field2Ty = nullptr;
220*06c3fb27SDimitry Andric   NeededGARs = 0;
221*06c3fb27SDimitry Andric   NeededFARs = 0;
222*06c3fb27SDimitry Andric   if (!detectFARsEligibleStructHelper(Ty, CharUnits::Zero(), Field1Ty,
223*06c3fb27SDimitry Andric                                       Field1Off, Field2Ty, Field2Off))
224*06c3fb27SDimitry Andric     return false;
225*06c3fb27SDimitry Andric   // Not really a candidate if we have a single int but no float.
226*06c3fb27SDimitry Andric   if (Field1Ty && !Field2Ty && !Field1Ty->isFloatingPointTy())
227*06c3fb27SDimitry Andric     return false;
228*06c3fb27SDimitry Andric   if (Field1Ty && Field1Ty->isFloatingPointTy())
229*06c3fb27SDimitry Andric     NeededFARs++;
230*06c3fb27SDimitry Andric   else if (Field1Ty)
231*06c3fb27SDimitry Andric     NeededGARs++;
232*06c3fb27SDimitry Andric   if (Field2Ty && Field2Ty->isFloatingPointTy())
233*06c3fb27SDimitry Andric     NeededFARs++;
234*06c3fb27SDimitry Andric   else if (Field2Ty)
235*06c3fb27SDimitry Andric     NeededGARs++;
236*06c3fb27SDimitry Andric   return true;
237*06c3fb27SDimitry Andric }
238*06c3fb27SDimitry Andric 
239*06c3fb27SDimitry Andric // Call getCoerceAndExpand for the two-element flattened struct described by
240*06c3fb27SDimitry Andric // Field1Ty, Field1Off, Field2Ty, Field2Off. This method will create an
241*06c3fb27SDimitry Andric // appropriate coerceToType and unpaddedCoerceToType.
242*06c3fb27SDimitry Andric ABIArgInfo LoongArchABIInfo::coerceAndExpandFARsEligibleStruct(
243*06c3fb27SDimitry Andric     llvm::Type *Field1Ty, CharUnits Field1Off, llvm::Type *Field2Ty,
244*06c3fb27SDimitry Andric     CharUnits Field2Off) const {
245*06c3fb27SDimitry Andric   SmallVector<llvm::Type *, 3> CoerceElts;
246*06c3fb27SDimitry Andric   SmallVector<llvm::Type *, 2> UnpaddedCoerceElts;
247*06c3fb27SDimitry Andric   if (!Field1Off.isZero())
248*06c3fb27SDimitry Andric     CoerceElts.push_back(llvm::ArrayType::get(
249*06c3fb27SDimitry Andric         llvm::Type::getInt8Ty(getVMContext()), Field1Off.getQuantity()));
250*06c3fb27SDimitry Andric 
251*06c3fb27SDimitry Andric   CoerceElts.push_back(Field1Ty);
252*06c3fb27SDimitry Andric   UnpaddedCoerceElts.push_back(Field1Ty);
253*06c3fb27SDimitry Andric 
254*06c3fb27SDimitry Andric   if (!Field2Ty) {
255*06c3fb27SDimitry Andric     return ABIArgInfo::getCoerceAndExpand(
256*06c3fb27SDimitry Andric         llvm::StructType::get(getVMContext(), CoerceElts, !Field1Off.isZero()),
257*06c3fb27SDimitry Andric         UnpaddedCoerceElts[0]);
258*06c3fb27SDimitry Andric   }
259*06c3fb27SDimitry Andric 
260*06c3fb27SDimitry Andric   CharUnits Field2Align =
261*06c3fb27SDimitry Andric       CharUnits::fromQuantity(getDataLayout().getABITypeAlign(Field2Ty));
262*06c3fb27SDimitry Andric   CharUnits Field1End =
263*06c3fb27SDimitry Andric       Field1Off +
264*06c3fb27SDimitry Andric       CharUnits::fromQuantity(getDataLayout().getTypeStoreSize(Field1Ty));
265*06c3fb27SDimitry Andric   CharUnits Field2OffNoPadNoPack = Field1End.alignTo(Field2Align);
266*06c3fb27SDimitry Andric 
267*06c3fb27SDimitry Andric   CharUnits Padding = CharUnits::Zero();
268*06c3fb27SDimitry Andric   if (Field2Off > Field2OffNoPadNoPack)
269*06c3fb27SDimitry Andric     Padding = Field2Off - Field2OffNoPadNoPack;
270*06c3fb27SDimitry Andric   else if (Field2Off != Field2Align && Field2Off > Field1End)
271*06c3fb27SDimitry Andric     Padding = Field2Off - Field1End;
272*06c3fb27SDimitry Andric 
273*06c3fb27SDimitry Andric   bool IsPacked = !Field2Off.isMultipleOf(Field2Align);
274*06c3fb27SDimitry Andric 
275*06c3fb27SDimitry Andric   if (!Padding.isZero())
276*06c3fb27SDimitry Andric     CoerceElts.push_back(llvm::ArrayType::get(
277*06c3fb27SDimitry Andric         llvm::Type::getInt8Ty(getVMContext()), Padding.getQuantity()));
278*06c3fb27SDimitry Andric 
279*06c3fb27SDimitry Andric   CoerceElts.push_back(Field2Ty);
280*06c3fb27SDimitry Andric   UnpaddedCoerceElts.push_back(Field2Ty);
281*06c3fb27SDimitry Andric 
282*06c3fb27SDimitry Andric   return ABIArgInfo::getCoerceAndExpand(
283*06c3fb27SDimitry Andric       llvm::StructType::get(getVMContext(), CoerceElts, IsPacked),
284*06c3fb27SDimitry Andric       llvm::StructType::get(getVMContext(), UnpaddedCoerceElts, IsPacked));
285*06c3fb27SDimitry Andric }
286*06c3fb27SDimitry Andric 
287*06c3fb27SDimitry Andric ABIArgInfo LoongArchABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
288*06c3fb27SDimitry Andric                                                   int &GARsLeft,
289*06c3fb27SDimitry Andric                                                   int &FARsLeft) const {
290*06c3fb27SDimitry Andric   assert(GARsLeft <= NumGARs && "GAR tracking underflow");
291*06c3fb27SDimitry Andric   Ty = useFirstFieldIfTransparentUnion(Ty);
292*06c3fb27SDimitry Andric 
293*06c3fb27SDimitry Andric   // Structures with either a non-trivial destructor or a non-trivial
294*06c3fb27SDimitry Andric   // copy constructor are always passed indirectly.
295*06c3fb27SDimitry Andric   if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
296*06c3fb27SDimitry Andric     if (GARsLeft)
297*06c3fb27SDimitry Andric       GARsLeft -= 1;
298*06c3fb27SDimitry Andric     return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA ==
299*06c3fb27SDimitry Andric                                            CGCXXABI::RAA_DirectInMemory);
300*06c3fb27SDimitry Andric   }
301*06c3fb27SDimitry Andric 
302*06c3fb27SDimitry Andric   // Ignore empty structs/unions.
303*06c3fb27SDimitry Andric   if (isEmptyRecord(getContext(), Ty, true))
304*06c3fb27SDimitry Andric     return ABIArgInfo::getIgnore();
305*06c3fb27SDimitry Andric 
306*06c3fb27SDimitry Andric   uint64_t Size = getContext().getTypeSize(Ty);
307*06c3fb27SDimitry Andric 
308*06c3fb27SDimitry Andric   // Pass floating point values via FARs if possible.
309*06c3fb27SDimitry Andric   if (IsFixed && Ty->isFloatingType() && !Ty->isComplexType() &&
310*06c3fb27SDimitry Andric       FRLen >= Size && FARsLeft) {
311*06c3fb27SDimitry Andric     FARsLeft--;
312*06c3fb27SDimitry Andric     return ABIArgInfo::getDirect();
313*06c3fb27SDimitry Andric   }
314*06c3fb27SDimitry Andric 
315*06c3fb27SDimitry Andric   // Complex types for the *f or *d ABI must be passed directly rather than
316*06c3fb27SDimitry Andric   // using CoerceAndExpand.
317*06c3fb27SDimitry Andric   if (IsFixed && Ty->isComplexType() && FRLen && FARsLeft >= 2) {
318*06c3fb27SDimitry Andric     QualType EltTy = Ty->castAs<ComplexType>()->getElementType();
319*06c3fb27SDimitry Andric     if (getContext().getTypeSize(EltTy) <= FRLen) {
320*06c3fb27SDimitry Andric       FARsLeft -= 2;
321*06c3fb27SDimitry Andric       return ABIArgInfo::getDirect();
322*06c3fb27SDimitry Andric     }
323*06c3fb27SDimitry Andric   }
324*06c3fb27SDimitry Andric 
325*06c3fb27SDimitry Andric   if (IsFixed && FRLen && Ty->isStructureOrClassType()) {
326*06c3fb27SDimitry Andric     llvm::Type *Field1Ty = nullptr;
327*06c3fb27SDimitry Andric     llvm::Type *Field2Ty = nullptr;
328*06c3fb27SDimitry Andric     CharUnits Field1Off = CharUnits::Zero();
329*06c3fb27SDimitry Andric     CharUnits Field2Off = CharUnits::Zero();
330*06c3fb27SDimitry Andric     int NeededGARs = 0;
331*06c3fb27SDimitry Andric     int NeededFARs = 0;
332*06c3fb27SDimitry Andric     bool IsCandidate = detectFARsEligibleStruct(
333*06c3fb27SDimitry Andric         Ty, Field1Ty, Field1Off, Field2Ty, Field2Off, NeededGARs, NeededFARs);
334*06c3fb27SDimitry Andric     if (IsCandidate && NeededGARs <= GARsLeft && NeededFARs <= FARsLeft) {
335*06c3fb27SDimitry Andric       GARsLeft -= NeededGARs;
336*06c3fb27SDimitry Andric       FARsLeft -= NeededFARs;
337*06c3fb27SDimitry Andric       return coerceAndExpandFARsEligibleStruct(Field1Ty, Field1Off, Field2Ty,
338*06c3fb27SDimitry Andric                                                Field2Off);
339*06c3fb27SDimitry Andric     }
340*06c3fb27SDimitry Andric   }
341*06c3fb27SDimitry Andric 
342*06c3fb27SDimitry Andric   uint64_t NeededAlign = getContext().getTypeAlign(Ty);
343*06c3fb27SDimitry Andric   // Determine the number of GARs needed to pass the current argument
344*06c3fb27SDimitry Andric   // according to the ABI. 2*GRLen-aligned varargs are passed in "aligned"
345*06c3fb27SDimitry Andric   // register pairs, so may consume 3 registers.
346*06c3fb27SDimitry Andric   int NeededGARs = 1;
347*06c3fb27SDimitry Andric   if (!IsFixed && NeededAlign == 2 * GRLen)
348*06c3fb27SDimitry Andric     NeededGARs = 2 + (GARsLeft % 2);
349*06c3fb27SDimitry Andric   else if (Size > GRLen && Size <= 2 * GRLen)
350*06c3fb27SDimitry Andric     NeededGARs = 2;
351*06c3fb27SDimitry Andric 
352*06c3fb27SDimitry Andric   if (NeededGARs > GARsLeft)
353*06c3fb27SDimitry Andric     NeededGARs = GARsLeft;
354*06c3fb27SDimitry Andric 
355*06c3fb27SDimitry Andric   GARsLeft -= NeededGARs;
356*06c3fb27SDimitry Andric 
357*06c3fb27SDimitry Andric   if (!isAggregateTypeForABI(Ty) && !Ty->isVectorType()) {
358*06c3fb27SDimitry Andric     // Treat an enum type as its underlying type.
359*06c3fb27SDimitry Andric     if (const EnumType *EnumTy = Ty->getAs<EnumType>())
360*06c3fb27SDimitry Andric       Ty = EnumTy->getDecl()->getIntegerType();
361*06c3fb27SDimitry Andric 
362*06c3fb27SDimitry Andric     // All integral types are promoted to GRLen width.
363*06c3fb27SDimitry Andric     if (Size < GRLen && Ty->isIntegralOrEnumerationType())
364*06c3fb27SDimitry Andric       return extendType(Ty);
365*06c3fb27SDimitry Andric 
366*06c3fb27SDimitry Andric     if (const auto *EIT = Ty->getAs<BitIntType>()) {
367*06c3fb27SDimitry Andric       if (EIT->getNumBits() < GRLen)
368*06c3fb27SDimitry Andric         return extendType(Ty);
369*06c3fb27SDimitry Andric       if (EIT->getNumBits() > 128 ||
370*06c3fb27SDimitry Andric           (!getContext().getTargetInfo().hasInt128Type() &&
371*06c3fb27SDimitry Andric            EIT->getNumBits() > 64))
372*06c3fb27SDimitry Andric         return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
373*06c3fb27SDimitry Andric     }
374*06c3fb27SDimitry Andric 
375*06c3fb27SDimitry Andric     return ABIArgInfo::getDirect();
376*06c3fb27SDimitry Andric   }
377*06c3fb27SDimitry Andric 
378*06c3fb27SDimitry Andric   // Aggregates which are <= 2*GRLen will be passed in registers if possible,
379*06c3fb27SDimitry Andric   // so coerce to integers.
380*06c3fb27SDimitry Andric   if (Size <= 2 * GRLen) {
381*06c3fb27SDimitry Andric     // Use a single GRLen int if possible, 2*GRLen if 2*GRLen alignment is
382*06c3fb27SDimitry Andric     // required, and a 2-element GRLen array if only GRLen alignment is
383*06c3fb27SDimitry Andric     // required.
384*06c3fb27SDimitry Andric     if (Size <= GRLen) {
385*06c3fb27SDimitry Andric       return ABIArgInfo::getDirect(
386*06c3fb27SDimitry Andric           llvm::IntegerType::get(getVMContext(), GRLen));
387*06c3fb27SDimitry Andric     }
388*06c3fb27SDimitry Andric     if (getContext().getTypeAlign(Ty) == 2 * GRLen) {
389*06c3fb27SDimitry Andric       return ABIArgInfo::getDirect(
390*06c3fb27SDimitry Andric           llvm::IntegerType::get(getVMContext(), 2 * GRLen));
391*06c3fb27SDimitry Andric     }
392*06c3fb27SDimitry Andric     return ABIArgInfo::getDirect(
393*06c3fb27SDimitry Andric         llvm::ArrayType::get(llvm::IntegerType::get(getVMContext(), GRLen), 2));
394*06c3fb27SDimitry Andric   }
395*06c3fb27SDimitry Andric   return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
396*06c3fb27SDimitry Andric }
397*06c3fb27SDimitry Andric 
398*06c3fb27SDimitry Andric ABIArgInfo LoongArchABIInfo::classifyReturnType(QualType RetTy) const {
399*06c3fb27SDimitry Andric   if (RetTy->isVoidType())
400*06c3fb27SDimitry Andric     return ABIArgInfo::getIgnore();
401*06c3fb27SDimitry Andric   // The rules for return and argument types are the same, so defer to
402*06c3fb27SDimitry Andric   // classifyArgumentType.
403*06c3fb27SDimitry Andric   int GARsLeft = 2;
404*06c3fb27SDimitry Andric   int FARsLeft = FRLen ? 2 : 0;
405*06c3fb27SDimitry Andric   return classifyArgumentType(RetTy, /*IsFixed=*/true, GARsLeft, FARsLeft);
406*06c3fb27SDimitry Andric }
407*06c3fb27SDimitry Andric 
408*06c3fb27SDimitry Andric Address LoongArchABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
409*06c3fb27SDimitry Andric                                     QualType Ty) const {
410*06c3fb27SDimitry Andric   CharUnits SlotSize = CharUnits::fromQuantity(GRLen / 8);
411*06c3fb27SDimitry Andric 
412*06c3fb27SDimitry Andric   // Empty records are ignored for parameter passing purposes.
413*06c3fb27SDimitry Andric   if (isEmptyRecord(getContext(), Ty, true))
414*06c3fb27SDimitry Andric     return Address(CGF.Builder.CreateLoad(VAListAddr),
415*06c3fb27SDimitry Andric                    CGF.ConvertTypeForMem(Ty), SlotSize);
416*06c3fb27SDimitry Andric 
417*06c3fb27SDimitry Andric   auto TInfo = getContext().getTypeInfoInChars(Ty);
418*06c3fb27SDimitry Andric 
419*06c3fb27SDimitry Andric   // Arguments bigger than 2*GRLen bytes are passed indirectly.
420*06c3fb27SDimitry Andric   return emitVoidPtrVAArg(CGF, VAListAddr, Ty,
421*06c3fb27SDimitry Andric                           /*IsIndirect=*/TInfo.Width > 2 * SlotSize, TInfo,
422*06c3fb27SDimitry Andric                           SlotSize,
423*06c3fb27SDimitry Andric                           /*AllowHigherAlign=*/true);
424*06c3fb27SDimitry Andric }
425*06c3fb27SDimitry Andric 
426*06c3fb27SDimitry Andric ABIArgInfo LoongArchABIInfo::extendType(QualType Ty) const {
427*06c3fb27SDimitry Andric   int TySize = getContext().getTypeSize(Ty);
428*06c3fb27SDimitry Andric   // LA64 ABI requires unsigned 32 bit integers to be sign extended.
429*06c3fb27SDimitry Andric   if (GRLen == 64 && Ty->isUnsignedIntegerOrEnumerationType() && TySize == 32)
430*06c3fb27SDimitry Andric     return ABIArgInfo::getSignExtend(Ty);
431*06c3fb27SDimitry Andric   return ABIArgInfo::getExtend(Ty);
432*06c3fb27SDimitry Andric }
433*06c3fb27SDimitry Andric 
434*06c3fb27SDimitry Andric namespace {
435*06c3fb27SDimitry Andric class LoongArchTargetCodeGenInfo : public TargetCodeGenInfo {
436*06c3fb27SDimitry Andric public:
437*06c3fb27SDimitry Andric   LoongArchTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned GRLen,
438*06c3fb27SDimitry Andric                              unsigned FRLen)
439*06c3fb27SDimitry Andric       : TargetCodeGenInfo(
440*06c3fb27SDimitry Andric             std::make_unique<LoongArchABIInfo>(CGT, GRLen, FRLen)) {}
441*06c3fb27SDimitry Andric };
442*06c3fb27SDimitry Andric } // namespace
443*06c3fb27SDimitry Andric 
444*06c3fb27SDimitry Andric std::unique_ptr<TargetCodeGenInfo>
445*06c3fb27SDimitry Andric CodeGen::createLoongArchTargetCodeGenInfo(CodeGenModule &CGM, unsigned GRLen,
446*06c3fb27SDimitry Andric                                           unsigned FLen) {
447*06c3fb27SDimitry Andric   return std::make_unique<LoongArchTargetCodeGenInfo>(CGM.getTypes(), GRLen,
448*06c3fb27SDimitry Andric                                                       FLen);
449*06c3fb27SDimitry Andric }
450