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