xref: /freebsd/contrib/llvm-project/clang/lib/CodeGen/Targets/LoongArch.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
106c3fb27SDimitry Andric //===- LoongArch.cpp ------------------------------------------------------===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric 
906c3fb27SDimitry Andric #include "ABIInfoImpl.h"
1006c3fb27SDimitry Andric #include "TargetInfo.h"
1106c3fb27SDimitry Andric 
1206c3fb27SDimitry Andric using namespace clang;
1306c3fb27SDimitry Andric using namespace clang::CodeGen;
1406c3fb27SDimitry Andric 
1506c3fb27SDimitry Andric // LoongArch ABI Implementation. Documented at
1606c3fb27SDimitry Andric // https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html
1706c3fb27SDimitry Andric //
1806c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
1906c3fb27SDimitry Andric 
2006c3fb27SDimitry Andric namespace {
2106c3fb27SDimitry Andric class LoongArchABIInfo : public DefaultABIInfo {
2206c3fb27SDimitry Andric private:
2306c3fb27SDimitry Andric   // Size of the integer ('r') registers in bits.
2406c3fb27SDimitry Andric   unsigned GRLen;
2506c3fb27SDimitry Andric   // Size of the floating point ('f') registers in bits.
2606c3fb27SDimitry Andric   unsigned FRLen;
2706c3fb27SDimitry Andric   // Number of general-purpose argument registers.
2806c3fb27SDimitry Andric   static const int NumGARs = 8;
2906c3fb27SDimitry Andric   // Number of floating-point argument registers.
3006c3fb27SDimitry Andric   static const int NumFARs = 8;
3106c3fb27SDimitry Andric   bool detectFARsEligibleStructHelper(QualType Ty, CharUnits CurOff,
3206c3fb27SDimitry Andric                                       llvm::Type *&Field1Ty,
3306c3fb27SDimitry Andric                                       CharUnits &Field1Off,
3406c3fb27SDimitry Andric                                       llvm::Type *&Field2Ty,
3506c3fb27SDimitry Andric                                       CharUnits &Field2Off) const;
3606c3fb27SDimitry Andric 
3706c3fb27SDimitry Andric public:
LoongArchABIInfo(CodeGen::CodeGenTypes & CGT,unsigned GRLen,unsigned FRLen)3806c3fb27SDimitry Andric   LoongArchABIInfo(CodeGen::CodeGenTypes &CGT, unsigned GRLen, unsigned FRLen)
3906c3fb27SDimitry Andric       : DefaultABIInfo(CGT), GRLen(GRLen), FRLen(FRLen) {}
4006c3fb27SDimitry Andric 
4106c3fb27SDimitry Andric   void computeInfo(CGFunctionInfo &FI) const override;
4206c3fb27SDimitry Andric 
4306c3fb27SDimitry Andric   ABIArgInfo classifyArgumentType(QualType Ty, bool IsFixed, int &GARsLeft,
4406c3fb27SDimitry Andric                                   int &FARsLeft) const;
4506c3fb27SDimitry Andric   ABIArgInfo classifyReturnType(QualType RetTy) const;
4606c3fb27SDimitry Andric 
47*0fca6ea1SDimitry Andric   RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
48*0fca6ea1SDimitry Andric                    AggValueSlot Slot) const override;
4906c3fb27SDimitry Andric 
5006c3fb27SDimitry Andric   ABIArgInfo extendType(QualType Ty) const;
5106c3fb27SDimitry Andric 
5206c3fb27SDimitry Andric   bool detectFARsEligibleStruct(QualType Ty, llvm::Type *&Field1Ty,
5306c3fb27SDimitry Andric                                 CharUnits &Field1Off, llvm::Type *&Field2Ty,
5406c3fb27SDimitry Andric                                 CharUnits &Field2Off, int &NeededArgGPRs,
5506c3fb27SDimitry Andric                                 int &NeededArgFPRs) const;
5606c3fb27SDimitry Andric   ABIArgInfo coerceAndExpandFARsEligibleStruct(llvm::Type *Field1Ty,
5706c3fb27SDimitry Andric                                                CharUnits Field1Off,
5806c3fb27SDimitry Andric                                                llvm::Type *Field2Ty,
5906c3fb27SDimitry Andric                                                CharUnits Field2Off) const;
6006c3fb27SDimitry Andric };
6106c3fb27SDimitry Andric } // end anonymous namespace
6206c3fb27SDimitry Andric 
computeInfo(CGFunctionInfo & FI) const6306c3fb27SDimitry Andric void LoongArchABIInfo::computeInfo(CGFunctionInfo &FI) const {
6406c3fb27SDimitry Andric   QualType RetTy = FI.getReturnType();
6506c3fb27SDimitry Andric   if (!getCXXABI().classifyReturnType(FI))
6606c3fb27SDimitry Andric     FI.getReturnInfo() = classifyReturnType(RetTy);
6706c3fb27SDimitry Andric 
6806c3fb27SDimitry Andric   // IsRetIndirect is true if classifyArgumentType indicated the value should
6906c3fb27SDimitry Andric   // be passed indirect, or if the type size is a scalar greater than 2*GRLen
7006c3fb27SDimitry Andric   // and not a complex type with elements <= FRLen. e.g. fp128 is passed direct
7106c3fb27SDimitry Andric   // in LLVM IR, relying on the backend lowering code to rewrite the argument
7206c3fb27SDimitry Andric   // list and pass indirectly on LA32.
7306c3fb27SDimitry Andric   bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect;
7406c3fb27SDimitry Andric   if (!IsRetIndirect && RetTy->isScalarType() &&
7506c3fb27SDimitry Andric       getContext().getTypeSize(RetTy) > (2 * GRLen)) {
7606c3fb27SDimitry Andric     if (RetTy->isComplexType() && FRLen) {
7706c3fb27SDimitry Andric       QualType EltTy = RetTy->castAs<ComplexType>()->getElementType();
7806c3fb27SDimitry Andric       IsRetIndirect = getContext().getTypeSize(EltTy) > FRLen;
7906c3fb27SDimitry Andric     } else {
8006c3fb27SDimitry Andric       // This is a normal scalar > 2*GRLen, such as fp128 on LA32.
8106c3fb27SDimitry Andric       IsRetIndirect = true;
8206c3fb27SDimitry Andric     }
8306c3fb27SDimitry Andric   }
8406c3fb27SDimitry Andric 
8506c3fb27SDimitry Andric   // We must track the number of GARs and FARs used in order to conform to the
8606c3fb27SDimitry Andric   // LoongArch ABI. As GAR usage is different for variadic arguments, we must
8706c3fb27SDimitry Andric   // also track whether we are examining a vararg or not.
8806c3fb27SDimitry Andric   int GARsLeft = IsRetIndirect ? NumGARs - 1 : NumGARs;
8906c3fb27SDimitry Andric   int FARsLeft = FRLen ? NumFARs : 0;
9006c3fb27SDimitry Andric   int NumFixedArgs = FI.getNumRequiredArgs();
9106c3fb27SDimitry Andric 
9206c3fb27SDimitry Andric   int ArgNum = 0;
9306c3fb27SDimitry Andric   for (auto &ArgInfo : FI.arguments()) {
9406c3fb27SDimitry Andric     ArgInfo.info = classifyArgumentType(
9506c3fb27SDimitry Andric         ArgInfo.type, /*IsFixed=*/ArgNum < NumFixedArgs, GARsLeft, FARsLeft);
9606c3fb27SDimitry Andric     ArgNum++;
9706c3fb27SDimitry Andric   }
9806c3fb27SDimitry Andric }
9906c3fb27SDimitry Andric 
10006c3fb27SDimitry Andric // Returns true if the struct is a potential candidate to be passed in FARs (and
10106c3fb27SDimitry Andric // GARs). If this function returns true, the caller is responsible for checking
10206c3fb27SDimitry Andric // that if there is only a single field then that field is a float.
detectFARsEligibleStructHelper(QualType Ty,CharUnits CurOff,llvm::Type * & Field1Ty,CharUnits & Field1Off,llvm::Type * & Field2Ty,CharUnits & Field2Off) const10306c3fb27SDimitry Andric bool LoongArchABIInfo::detectFARsEligibleStructHelper(
10406c3fb27SDimitry Andric     QualType Ty, CharUnits CurOff, llvm::Type *&Field1Ty, CharUnits &Field1Off,
10506c3fb27SDimitry Andric     llvm::Type *&Field2Ty, CharUnits &Field2Off) const {
10606c3fb27SDimitry Andric   bool IsInt = Ty->isIntegralOrEnumerationType();
10706c3fb27SDimitry Andric   bool IsFloat = Ty->isRealFloatingType();
10806c3fb27SDimitry Andric 
10906c3fb27SDimitry Andric   if (IsInt || IsFloat) {
11006c3fb27SDimitry Andric     uint64_t Size = getContext().getTypeSize(Ty);
11106c3fb27SDimitry Andric     if (IsInt && Size > GRLen)
11206c3fb27SDimitry Andric       return false;
11306c3fb27SDimitry Andric     // Can't be eligible if larger than the FP registers. Half precision isn't
11406c3fb27SDimitry Andric     // currently supported on LoongArch and the ABI hasn't been confirmed, so
11506c3fb27SDimitry Andric     // default to the integer ABI in that case.
11606c3fb27SDimitry Andric     if (IsFloat && (Size > FRLen || Size < 32))
11706c3fb27SDimitry Andric       return false;
11806c3fb27SDimitry Andric     // Can't be eligible if an integer type was already found (int+int pairs
11906c3fb27SDimitry Andric     // are not eligible).
12006c3fb27SDimitry Andric     if (IsInt && Field1Ty && Field1Ty->isIntegerTy())
12106c3fb27SDimitry Andric       return false;
12206c3fb27SDimitry Andric     if (!Field1Ty) {
12306c3fb27SDimitry Andric       Field1Ty = CGT.ConvertType(Ty);
12406c3fb27SDimitry Andric       Field1Off = CurOff;
12506c3fb27SDimitry Andric       return true;
12606c3fb27SDimitry Andric     }
12706c3fb27SDimitry Andric     if (!Field2Ty) {
12806c3fb27SDimitry Andric       Field2Ty = CGT.ConvertType(Ty);
12906c3fb27SDimitry Andric       Field2Off = CurOff;
13006c3fb27SDimitry Andric       return true;
13106c3fb27SDimitry Andric     }
13206c3fb27SDimitry Andric     return false;
13306c3fb27SDimitry Andric   }
13406c3fb27SDimitry Andric 
13506c3fb27SDimitry Andric   if (auto CTy = Ty->getAs<ComplexType>()) {
13606c3fb27SDimitry Andric     if (Field1Ty)
13706c3fb27SDimitry Andric       return false;
13806c3fb27SDimitry Andric     QualType EltTy = CTy->getElementType();
13906c3fb27SDimitry Andric     if (getContext().getTypeSize(EltTy) > FRLen)
14006c3fb27SDimitry Andric       return false;
14106c3fb27SDimitry Andric     Field1Ty = CGT.ConvertType(EltTy);
14206c3fb27SDimitry Andric     Field1Off = CurOff;
14306c3fb27SDimitry Andric     Field2Ty = Field1Ty;
14406c3fb27SDimitry Andric     Field2Off = Field1Off + getContext().getTypeSizeInChars(EltTy);
14506c3fb27SDimitry Andric     return true;
14606c3fb27SDimitry Andric   }
14706c3fb27SDimitry Andric 
14806c3fb27SDimitry Andric   if (const ConstantArrayType *ATy = getContext().getAsConstantArrayType(Ty)) {
149*0fca6ea1SDimitry Andric     uint64_t ArraySize = ATy->getZExtSize();
15006c3fb27SDimitry Andric     QualType EltTy = ATy->getElementType();
1518a4dda33SDimitry Andric     // Non-zero-length arrays of empty records make the struct ineligible to be
1528a4dda33SDimitry Andric     // passed via FARs in C++.
1538a4dda33SDimitry Andric     if (const auto *RTy = EltTy->getAs<RecordType>()) {
1548a4dda33SDimitry Andric       if (ArraySize != 0 && isa<CXXRecordDecl>(RTy->getDecl()) &&
1558a4dda33SDimitry Andric           isEmptyRecord(getContext(), EltTy, true, true))
1568a4dda33SDimitry Andric         return false;
1578a4dda33SDimitry Andric     }
15806c3fb27SDimitry Andric     CharUnits EltSize = getContext().getTypeSizeInChars(EltTy);
15906c3fb27SDimitry Andric     for (uint64_t i = 0; i < ArraySize; ++i) {
16006c3fb27SDimitry Andric       if (!detectFARsEligibleStructHelper(EltTy, CurOff, Field1Ty, Field1Off,
16106c3fb27SDimitry Andric                                           Field2Ty, Field2Off))
16206c3fb27SDimitry Andric         return false;
16306c3fb27SDimitry Andric       CurOff += EltSize;
16406c3fb27SDimitry Andric     }
16506c3fb27SDimitry Andric     return true;
16606c3fb27SDimitry Andric   }
16706c3fb27SDimitry Andric 
16806c3fb27SDimitry Andric   if (const auto *RTy = Ty->getAs<RecordType>()) {
16906c3fb27SDimitry Andric     // Structures with either a non-trivial destructor or a non-trivial
17006c3fb27SDimitry Andric     // copy constructor are not eligible for the FP calling convention.
17106c3fb27SDimitry Andric     if (getRecordArgABI(Ty, CGT.getCXXABI()))
17206c3fb27SDimitry Andric       return false;
17306c3fb27SDimitry Andric     const RecordDecl *RD = RTy->getDecl();
1745f757f3fSDimitry Andric     if (isEmptyRecord(getContext(), Ty, true, true) &&
1755f757f3fSDimitry Andric         (!RD->isUnion() || !isa<CXXRecordDecl>(RD)))
1765f757f3fSDimitry Andric       return true;
1775f757f3fSDimitry Andric     // Unions aren't eligible unless they're empty in C (which is caught above).
17806c3fb27SDimitry Andric     if (RD->isUnion())
17906c3fb27SDimitry Andric       return false;
18006c3fb27SDimitry Andric     const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
18106c3fb27SDimitry Andric     // If this is a C++ record, check the bases first.
18206c3fb27SDimitry Andric     if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
18306c3fb27SDimitry Andric       for (const CXXBaseSpecifier &B : CXXRD->bases()) {
18406c3fb27SDimitry Andric         const auto *BDecl =
18506c3fb27SDimitry Andric             cast<CXXRecordDecl>(B.getType()->castAs<RecordType>()->getDecl());
18606c3fb27SDimitry Andric         if (!detectFARsEligibleStructHelper(
18706c3fb27SDimitry Andric                 B.getType(), CurOff + Layout.getBaseClassOffset(BDecl),
18806c3fb27SDimitry Andric                 Field1Ty, Field1Off, Field2Ty, Field2Off))
18906c3fb27SDimitry Andric           return false;
19006c3fb27SDimitry Andric       }
19106c3fb27SDimitry Andric     }
19206c3fb27SDimitry Andric     for (const FieldDecl *FD : RD->fields()) {
19306c3fb27SDimitry Andric       QualType QTy = FD->getType();
19406c3fb27SDimitry Andric       if (FD->isBitField()) {
19506c3fb27SDimitry Andric         unsigned BitWidth = FD->getBitWidthValue(getContext());
19606c3fb27SDimitry Andric         // Zero-width bitfields are ignored.
19706c3fb27SDimitry Andric         if (BitWidth == 0)
19806c3fb27SDimitry Andric           continue;
19906c3fb27SDimitry Andric         // Allow a bitfield with a type greater than GRLen as long as the
20006c3fb27SDimitry Andric         // bitwidth is GRLen or less.
20106c3fb27SDimitry Andric         if (getContext().getTypeSize(QTy) > GRLen && BitWidth <= GRLen) {
20206c3fb27SDimitry Andric           QTy = getContext().getIntTypeForBitwidth(GRLen, false);
20306c3fb27SDimitry Andric         }
20406c3fb27SDimitry Andric       }
20506c3fb27SDimitry Andric 
20606c3fb27SDimitry Andric       if (!detectFARsEligibleStructHelper(
20706c3fb27SDimitry Andric               QTy,
20806c3fb27SDimitry Andric               CurOff + getContext().toCharUnitsFromBits(
20906c3fb27SDimitry Andric                            Layout.getFieldOffset(FD->getFieldIndex())),
21006c3fb27SDimitry Andric               Field1Ty, Field1Off, Field2Ty, Field2Off))
21106c3fb27SDimitry Andric         return false;
21206c3fb27SDimitry Andric     }
21306c3fb27SDimitry Andric     return Field1Ty != nullptr;
21406c3fb27SDimitry Andric   }
21506c3fb27SDimitry Andric 
21606c3fb27SDimitry Andric   return false;
21706c3fb27SDimitry Andric }
21806c3fb27SDimitry Andric 
21906c3fb27SDimitry Andric // Determine if a struct is eligible to be passed in FARs (and GARs) (i.e., when
22006c3fb27SDimitry Andric // flattened it contains a single fp value, fp+fp, or int+fp of appropriate
22106c3fb27SDimitry Andric // size). If so, NeededFARs and NeededGARs are incremented appropriately.
detectFARsEligibleStruct(QualType Ty,llvm::Type * & Field1Ty,CharUnits & Field1Off,llvm::Type * & Field2Ty,CharUnits & Field2Off,int & NeededGARs,int & NeededFARs) const22206c3fb27SDimitry Andric bool LoongArchABIInfo::detectFARsEligibleStruct(
22306c3fb27SDimitry Andric     QualType Ty, llvm::Type *&Field1Ty, CharUnits &Field1Off,
22406c3fb27SDimitry Andric     llvm::Type *&Field2Ty, CharUnits &Field2Off, int &NeededGARs,
22506c3fb27SDimitry Andric     int &NeededFARs) const {
22606c3fb27SDimitry Andric   Field1Ty = nullptr;
22706c3fb27SDimitry Andric   Field2Ty = nullptr;
22806c3fb27SDimitry Andric   NeededGARs = 0;
22906c3fb27SDimitry Andric   NeededFARs = 0;
23006c3fb27SDimitry Andric   if (!detectFARsEligibleStructHelper(Ty, CharUnits::Zero(), Field1Ty,
23106c3fb27SDimitry Andric                                       Field1Off, Field2Ty, Field2Off))
23206c3fb27SDimitry Andric     return false;
2338a4dda33SDimitry Andric   if (!Field1Ty)
2348a4dda33SDimitry Andric     return false;
23506c3fb27SDimitry Andric   // Not really a candidate if we have a single int but no float.
23606c3fb27SDimitry Andric   if (Field1Ty && !Field2Ty && !Field1Ty->isFloatingPointTy())
23706c3fb27SDimitry Andric     return false;
23806c3fb27SDimitry Andric   if (Field1Ty && Field1Ty->isFloatingPointTy())
23906c3fb27SDimitry Andric     NeededFARs++;
24006c3fb27SDimitry Andric   else if (Field1Ty)
24106c3fb27SDimitry Andric     NeededGARs++;
24206c3fb27SDimitry Andric   if (Field2Ty && Field2Ty->isFloatingPointTy())
24306c3fb27SDimitry Andric     NeededFARs++;
24406c3fb27SDimitry Andric   else if (Field2Ty)
24506c3fb27SDimitry Andric     NeededGARs++;
24606c3fb27SDimitry Andric   return true;
24706c3fb27SDimitry Andric }
24806c3fb27SDimitry Andric 
24906c3fb27SDimitry Andric // Call getCoerceAndExpand for the two-element flattened struct described by
25006c3fb27SDimitry Andric // Field1Ty, Field1Off, Field2Ty, Field2Off. This method will create an
25106c3fb27SDimitry Andric // appropriate coerceToType and unpaddedCoerceToType.
coerceAndExpandFARsEligibleStruct(llvm::Type * Field1Ty,CharUnits Field1Off,llvm::Type * Field2Ty,CharUnits Field2Off) const25206c3fb27SDimitry Andric ABIArgInfo LoongArchABIInfo::coerceAndExpandFARsEligibleStruct(
25306c3fb27SDimitry Andric     llvm::Type *Field1Ty, CharUnits Field1Off, llvm::Type *Field2Ty,
25406c3fb27SDimitry Andric     CharUnits Field2Off) const {
25506c3fb27SDimitry Andric   SmallVector<llvm::Type *, 3> CoerceElts;
25606c3fb27SDimitry Andric   SmallVector<llvm::Type *, 2> UnpaddedCoerceElts;
25706c3fb27SDimitry Andric   if (!Field1Off.isZero())
25806c3fb27SDimitry Andric     CoerceElts.push_back(llvm::ArrayType::get(
25906c3fb27SDimitry Andric         llvm::Type::getInt8Ty(getVMContext()), Field1Off.getQuantity()));
26006c3fb27SDimitry Andric 
26106c3fb27SDimitry Andric   CoerceElts.push_back(Field1Ty);
26206c3fb27SDimitry Andric   UnpaddedCoerceElts.push_back(Field1Ty);
26306c3fb27SDimitry Andric 
26406c3fb27SDimitry Andric   if (!Field2Ty) {
26506c3fb27SDimitry Andric     return ABIArgInfo::getCoerceAndExpand(
26606c3fb27SDimitry Andric         llvm::StructType::get(getVMContext(), CoerceElts, !Field1Off.isZero()),
26706c3fb27SDimitry Andric         UnpaddedCoerceElts[0]);
26806c3fb27SDimitry Andric   }
26906c3fb27SDimitry Andric 
27006c3fb27SDimitry Andric   CharUnits Field2Align =
27106c3fb27SDimitry Andric       CharUnits::fromQuantity(getDataLayout().getABITypeAlign(Field2Ty));
27206c3fb27SDimitry Andric   CharUnits Field1End =
27306c3fb27SDimitry Andric       Field1Off +
27406c3fb27SDimitry Andric       CharUnits::fromQuantity(getDataLayout().getTypeStoreSize(Field1Ty));
27506c3fb27SDimitry Andric   CharUnits Field2OffNoPadNoPack = Field1End.alignTo(Field2Align);
27606c3fb27SDimitry Andric 
27706c3fb27SDimitry Andric   CharUnits Padding = CharUnits::Zero();
27806c3fb27SDimitry Andric   if (Field2Off > Field2OffNoPadNoPack)
27906c3fb27SDimitry Andric     Padding = Field2Off - Field2OffNoPadNoPack;
28006c3fb27SDimitry Andric   else if (Field2Off != Field2Align && Field2Off > Field1End)
28106c3fb27SDimitry Andric     Padding = Field2Off - Field1End;
28206c3fb27SDimitry Andric 
28306c3fb27SDimitry Andric   bool IsPacked = !Field2Off.isMultipleOf(Field2Align);
28406c3fb27SDimitry Andric 
28506c3fb27SDimitry Andric   if (!Padding.isZero())
28606c3fb27SDimitry Andric     CoerceElts.push_back(llvm::ArrayType::get(
28706c3fb27SDimitry Andric         llvm::Type::getInt8Ty(getVMContext()), Padding.getQuantity()));
28806c3fb27SDimitry Andric 
28906c3fb27SDimitry Andric   CoerceElts.push_back(Field2Ty);
29006c3fb27SDimitry Andric   UnpaddedCoerceElts.push_back(Field2Ty);
29106c3fb27SDimitry Andric 
29206c3fb27SDimitry Andric   return ABIArgInfo::getCoerceAndExpand(
29306c3fb27SDimitry Andric       llvm::StructType::get(getVMContext(), CoerceElts, IsPacked),
29406c3fb27SDimitry Andric       llvm::StructType::get(getVMContext(), UnpaddedCoerceElts, IsPacked));
29506c3fb27SDimitry Andric }
29606c3fb27SDimitry Andric 
classifyArgumentType(QualType Ty,bool IsFixed,int & GARsLeft,int & FARsLeft) const29706c3fb27SDimitry Andric ABIArgInfo LoongArchABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
29806c3fb27SDimitry Andric                                                   int &GARsLeft,
29906c3fb27SDimitry Andric                                                   int &FARsLeft) const {
30006c3fb27SDimitry Andric   assert(GARsLeft <= NumGARs && "GAR tracking underflow");
30106c3fb27SDimitry Andric   Ty = useFirstFieldIfTransparentUnion(Ty);
30206c3fb27SDimitry Andric 
30306c3fb27SDimitry Andric   // Structures with either a non-trivial destructor or a non-trivial
30406c3fb27SDimitry Andric   // copy constructor are always passed indirectly.
30506c3fb27SDimitry Andric   if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
30606c3fb27SDimitry Andric     if (GARsLeft)
30706c3fb27SDimitry Andric       GARsLeft -= 1;
30806c3fb27SDimitry Andric     return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA ==
30906c3fb27SDimitry Andric                                            CGCXXABI::RAA_DirectInMemory);
31006c3fb27SDimitry Andric   }
31106c3fb27SDimitry Andric 
31206c3fb27SDimitry Andric   uint64_t Size = getContext().getTypeSize(Ty);
31306c3fb27SDimitry Andric 
3145f757f3fSDimitry Andric   // Ignore empty struct or union whose size is zero, e.g. `struct { }` in C or
3155f757f3fSDimitry Andric   // `struct { int a[0]; }` in C++. In C++, `struct { }` is empty but it's size
3165f757f3fSDimitry Andric   // is 1 byte and g++ doesn't ignore it; clang++ matches this behaviour.
3175f757f3fSDimitry Andric   if (isEmptyRecord(getContext(), Ty, true) && Size == 0)
3185f757f3fSDimitry Andric     return ABIArgInfo::getIgnore();
3195f757f3fSDimitry Andric 
32006c3fb27SDimitry Andric   // Pass floating point values via FARs if possible.
32106c3fb27SDimitry Andric   if (IsFixed && Ty->isFloatingType() && !Ty->isComplexType() &&
32206c3fb27SDimitry Andric       FRLen >= Size && FARsLeft) {
32306c3fb27SDimitry Andric     FARsLeft--;
32406c3fb27SDimitry Andric     return ABIArgInfo::getDirect();
32506c3fb27SDimitry Andric   }
32606c3fb27SDimitry Andric 
32706c3fb27SDimitry Andric   // Complex types for the *f or *d ABI must be passed directly rather than
32806c3fb27SDimitry Andric   // using CoerceAndExpand.
32906c3fb27SDimitry Andric   if (IsFixed && Ty->isComplexType() && FRLen && FARsLeft >= 2) {
33006c3fb27SDimitry Andric     QualType EltTy = Ty->castAs<ComplexType>()->getElementType();
33106c3fb27SDimitry Andric     if (getContext().getTypeSize(EltTy) <= FRLen) {
33206c3fb27SDimitry Andric       FARsLeft -= 2;
33306c3fb27SDimitry Andric       return ABIArgInfo::getDirect();
33406c3fb27SDimitry Andric     }
33506c3fb27SDimitry Andric   }
33606c3fb27SDimitry Andric 
33706c3fb27SDimitry Andric   if (IsFixed && FRLen && Ty->isStructureOrClassType()) {
33806c3fb27SDimitry Andric     llvm::Type *Field1Ty = nullptr;
33906c3fb27SDimitry Andric     llvm::Type *Field2Ty = nullptr;
34006c3fb27SDimitry Andric     CharUnits Field1Off = CharUnits::Zero();
34106c3fb27SDimitry Andric     CharUnits Field2Off = CharUnits::Zero();
34206c3fb27SDimitry Andric     int NeededGARs = 0;
34306c3fb27SDimitry Andric     int NeededFARs = 0;
34406c3fb27SDimitry Andric     bool IsCandidate = detectFARsEligibleStruct(
34506c3fb27SDimitry Andric         Ty, Field1Ty, Field1Off, Field2Ty, Field2Off, NeededGARs, NeededFARs);
34606c3fb27SDimitry Andric     if (IsCandidate && NeededGARs <= GARsLeft && NeededFARs <= FARsLeft) {
34706c3fb27SDimitry Andric       GARsLeft -= NeededGARs;
34806c3fb27SDimitry Andric       FARsLeft -= NeededFARs;
34906c3fb27SDimitry Andric       return coerceAndExpandFARsEligibleStruct(Field1Ty, Field1Off, Field2Ty,
35006c3fb27SDimitry Andric                                                Field2Off);
35106c3fb27SDimitry Andric     }
35206c3fb27SDimitry Andric   }
35306c3fb27SDimitry Andric 
35406c3fb27SDimitry Andric   uint64_t NeededAlign = getContext().getTypeAlign(Ty);
35506c3fb27SDimitry Andric   // Determine the number of GARs needed to pass the current argument
35606c3fb27SDimitry Andric   // according to the ABI. 2*GRLen-aligned varargs are passed in "aligned"
35706c3fb27SDimitry Andric   // register pairs, so may consume 3 registers.
35806c3fb27SDimitry Andric   int NeededGARs = 1;
35906c3fb27SDimitry Andric   if (!IsFixed && NeededAlign == 2 * GRLen)
36006c3fb27SDimitry Andric     NeededGARs = 2 + (GARsLeft % 2);
36106c3fb27SDimitry Andric   else if (Size > GRLen && Size <= 2 * GRLen)
36206c3fb27SDimitry Andric     NeededGARs = 2;
36306c3fb27SDimitry Andric 
36406c3fb27SDimitry Andric   if (NeededGARs > GARsLeft)
36506c3fb27SDimitry Andric     NeededGARs = GARsLeft;
36606c3fb27SDimitry Andric 
36706c3fb27SDimitry Andric   GARsLeft -= NeededGARs;
36806c3fb27SDimitry Andric 
36906c3fb27SDimitry Andric   if (!isAggregateTypeForABI(Ty) && !Ty->isVectorType()) {
37006c3fb27SDimitry Andric     // Treat an enum type as its underlying type.
37106c3fb27SDimitry Andric     if (const EnumType *EnumTy = Ty->getAs<EnumType>())
37206c3fb27SDimitry Andric       Ty = EnumTy->getDecl()->getIntegerType();
37306c3fb27SDimitry Andric 
37406c3fb27SDimitry Andric     // All integral types are promoted to GRLen width.
37506c3fb27SDimitry Andric     if (Size < GRLen && Ty->isIntegralOrEnumerationType())
37606c3fb27SDimitry Andric       return extendType(Ty);
37706c3fb27SDimitry Andric 
37806c3fb27SDimitry Andric     if (const auto *EIT = Ty->getAs<BitIntType>()) {
37906c3fb27SDimitry Andric       if (EIT->getNumBits() < GRLen)
38006c3fb27SDimitry Andric         return extendType(Ty);
38106c3fb27SDimitry Andric       if (EIT->getNumBits() > 128 ||
38206c3fb27SDimitry Andric           (!getContext().getTargetInfo().hasInt128Type() &&
38306c3fb27SDimitry Andric            EIT->getNumBits() > 64))
38406c3fb27SDimitry Andric         return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
38506c3fb27SDimitry Andric     }
38606c3fb27SDimitry Andric 
38706c3fb27SDimitry Andric     return ABIArgInfo::getDirect();
38806c3fb27SDimitry Andric   }
38906c3fb27SDimitry Andric 
39006c3fb27SDimitry Andric   // Aggregates which are <= 2*GRLen will be passed in registers if possible,
39106c3fb27SDimitry Andric   // so coerce to integers.
39206c3fb27SDimitry Andric   if (Size <= 2 * GRLen) {
39306c3fb27SDimitry Andric     // Use a single GRLen int if possible, 2*GRLen if 2*GRLen alignment is
39406c3fb27SDimitry Andric     // required, and a 2-element GRLen array if only GRLen alignment is
39506c3fb27SDimitry Andric     // required.
39606c3fb27SDimitry Andric     if (Size <= GRLen) {
39706c3fb27SDimitry Andric       return ABIArgInfo::getDirect(
39806c3fb27SDimitry Andric           llvm::IntegerType::get(getVMContext(), GRLen));
39906c3fb27SDimitry Andric     }
40006c3fb27SDimitry Andric     if (getContext().getTypeAlign(Ty) == 2 * GRLen) {
40106c3fb27SDimitry Andric       return ABIArgInfo::getDirect(
40206c3fb27SDimitry Andric           llvm::IntegerType::get(getVMContext(), 2 * GRLen));
40306c3fb27SDimitry Andric     }
40406c3fb27SDimitry Andric     return ABIArgInfo::getDirect(
40506c3fb27SDimitry Andric         llvm::ArrayType::get(llvm::IntegerType::get(getVMContext(), GRLen), 2));
40606c3fb27SDimitry Andric   }
40706c3fb27SDimitry Andric   return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
40806c3fb27SDimitry Andric }
40906c3fb27SDimitry Andric 
classifyReturnType(QualType RetTy) const41006c3fb27SDimitry Andric ABIArgInfo LoongArchABIInfo::classifyReturnType(QualType RetTy) const {
41106c3fb27SDimitry Andric   if (RetTy->isVoidType())
41206c3fb27SDimitry Andric     return ABIArgInfo::getIgnore();
41306c3fb27SDimitry Andric   // The rules for return and argument types are the same, so defer to
41406c3fb27SDimitry Andric   // classifyArgumentType.
41506c3fb27SDimitry Andric   int GARsLeft = 2;
41606c3fb27SDimitry Andric   int FARsLeft = FRLen ? 2 : 0;
41706c3fb27SDimitry Andric   return classifyArgumentType(RetTy, /*IsFixed=*/true, GARsLeft, FARsLeft);
41806c3fb27SDimitry Andric }
41906c3fb27SDimitry Andric 
EmitVAArg(CodeGenFunction & CGF,Address VAListAddr,QualType Ty,AggValueSlot Slot) const420*0fca6ea1SDimitry Andric RValue LoongArchABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
421*0fca6ea1SDimitry Andric                                    QualType Ty, AggValueSlot Slot) const {
42206c3fb27SDimitry Andric   CharUnits SlotSize = CharUnits::fromQuantity(GRLen / 8);
42306c3fb27SDimitry Andric 
42406c3fb27SDimitry Andric   // Empty records are ignored for parameter passing purposes.
42506c3fb27SDimitry Andric   if (isEmptyRecord(getContext(), Ty, true))
426*0fca6ea1SDimitry Andric     return Slot.asRValue();
42706c3fb27SDimitry Andric 
42806c3fb27SDimitry Andric   auto TInfo = getContext().getTypeInfoInChars(Ty);
42906c3fb27SDimitry Andric 
43006c3fb27SDimitry Andric   // Arguments bigger than 2*GRLen bytes are passed indirectly.
43106c3fb27SDimitry Andric   return emitVoidPtrVAArg(CGF, VAListAddr, Ty,
43206c3fb27SDimitry Andric                           /*IsIndirect=*/TInfo.Width > 2 * SlotSize, TInfo,
43306c3fb27SDimitry Andric                           SlotSize,
434*0fca6ea1SDimitry Andric                           /*AllowHigherAlign=*/true, Slot);
43506c3fb27SDimitry Andric }
43606c3fb27SDimitry Andric 
extendType(QualType Ty) const43706c3fb27SDimitry Andric ABIArgInfo LoongArchABIInfo::extendType(QualType Ty) const {
43806c3fb27SDimitry Andric   int TySize = getContext().getTypeSize(Ty);
43906c3fb27SDimitry Andric   // LA64 ABI requires unsigned 32 bit integers to be sign extended.
44006c3fb27SDimitry Andric   if (GRLen == 64 && Ty->isUnsignedIntegerOrEnumerationType() && TySize == 32)
44106c3fb27SDimitry Andric     return ABIArgInfo::getSignExtend(Ty);
44206c3fb27SDimitry Andric   return ABIArgInfo::getExtend(Ty);
44306c3fb27SDimitry Andric }
44406c3fb27SDimitry Andric 
44506c3fb27SDimitry Andric namespace {
44606c3fb27SDimitry Andric class LoongArchTargetCodeGenInfo : public TargetCodeGenInfo {
44706c3fb27SDimitry Andric public:
LoongArchTargetCodeGenInfo(CodeGen::CodeGenTypes & CGT,unsigned GRLen,unsigned FRLen)44806c3fb27SDimitry Andric   LoongArchTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned GRLen,
44906c3fb27SDimitry Andric                              unsigned FRLen)
45006c3fb27SDimitry Andric       : TargetCodeGenInfo(
45106c3fb27SDimitry Andric             std::make_unique<LoongArchABIInfo>(CGT, GRLen, FRLen)) {}
45206c3fb27SDimitry Andric };
45306c3fb27SDimitry Andric } // namespace
45406c3fb27SDimitry Andric 
45506c3fb27SDimitry Andric std::unique_ptr<TargetCodeGenInfo>
createLoongArchTargetCodeGenInfo(CodeGenModule & CGM,unsigned GRLen,unsigned FLen)45606c3fb27SDimitry Andric CodeGen::createLoongArchTargetCodeGenInfo(CodeGenModule &CGM, unsigned GRLen,
45706c3fb27SDimitry Andric                                           unsigned FLen) {
45806c3fb27SDimitry Andric   return std::make_unique<LoongArchTargetCodeGenInfo>(CGM.getTypes(), GRLen,
45906c3fb27SDimitry Andric                                                       FLen);
46006c3fb27SDimitry Andric }
461