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: 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 6306c3fb27SDimitry 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. 10306c3fb27SDimitry 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. 22206c3fb27SDimitry 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. 25206c3fb27SDimitry 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 29706c3fb27SDimitry 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 41006c3fb27SDimitry 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 420*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 43706c3fb27SDimitry 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: 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> 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