1*06c3fb27SDimitry Andric //===- RISCV.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 #include "llvm/TargetParser/RISCVTargetParser.h" 12*06c3fb27SDimitry Andric 13*06c3fb27SDimitry Andric using namespace clang; 14*06c3fb27SDimitry Andric using namespace clang::CodeGen; 15*06c3fb27SDimitry Andric 16*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 17*06c3fb27SDimitry Andric // RISC-V ABI Implementation 18*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 19*06c3fb27SDimitry Andric 20*06c3fb27SDimitry Andric namespace { 21*06c3fb27SDimitry Andric class RISCVABIInfo : public DefaultABIInfo { 22*06c3fb27SDimitry Andric private: 23*06c3fb27SDimitry Andric // Size of the integer ('x') registers in bits. 24*06c3fb27SDimitry Andric unsigned XLen; 25*06c3fb27SDimitry Andric // Size of the floating point ('f') registers in bits. Note that the target 26*06c3fb27SDimitry Andric // ISA might have a wider FLen than the selected ABI (e.g. an RV32IF target 27*06c3fb27SDimitry Andric // with soft float ABI has FLen==0). 28*06c3fb27SDimitry Andric unsigned FLen; 29*06c3fb27SDimitry Andric static const int NumArgGPRs = 8; 30*06c3fb27SDimitry Andric static const int NumArgFPRs = 8; 31*06c3fb27SDimitry Andric bool detectFPCCEligibleStructHelper(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 RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen) 39*06c3fb27SDimitry Andric : DefaultABIInfo(CGT), XLen(XLen), FLen(FLen) {} 40*06c3fb27SDimitry Andric 41*06c3fb27SDimitry Andric // DefaultABIInfo's classifyReturnType and classifyArgumentType are 42*06c3fb27SDimitry Andric // non-virtual, but computeInfo is virtual, so we overload it. 43*06c3fb27SDimitry Andric void computeInfo(CGFunctionInfo &FI) const override; 44*06c3fb27SDimitry Andric 45*06c3fb27SDimitry Andric ABIArgInfo classifyArgumentType(QualType Ty, bool IsFixed, int &ArgGPRsLeft, 46*06c3fb27SDimitry Andric int &ArgFPRsLeft) const; 47*06c3fb27SDimitry Andric ABIArgInfo classifyReturnType(QualType RetTy) const; 48*06c3fb27SDimitry Andric 49*06c3fb27SDimitry Andric Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, 50*06c3fb27SDimitry Andric QualType Ty) const override; 51*06c3fb27SDimitry Andric 52*06c3fb27SDimitry Andric ABIArgInfo extendType(QualType Ty) const; 53*06c3fb27SDimitry Andric 54*06c3fb27SDimitry Andric bool detectFPCCEligibleStruct(QualType Ty, llvm::Type *&Field1Ty, 55*06c3fb27SDimitry Andric CharUnits &Field1Off, llvm::Type *&Field2Ty, 56*06c3fb27SDimitry Andric CharUnits &Field2Off, int &NeededArgGPRs, 57*06c3fb27SDimitry Andric int &NeededArgFPRs) const; 58*06c3fb27SDimitry Andric ABIArgInfo coerceAndExpandFPCCEligibleStruct(llvm::Type *Field1Ty, 59*06c3fb27SDimitry Andric CharUnits Field1Off, 60*06c3fb27SDimitry Andric llvm::Type *Field2Ty, 61*06c3fb27SDimitry Andric CharUnits Field2Off) const; 62*06c3fb27SDimitry Andric 63*06c3fb27SDimitry Andric ABIArgInfo coerceVLSVector(QualType Ty) const; 64*06c3fb27SDimitry Andric }; 65*06c3fb27SDimitry Andric } // end anonymous namespace 66*06c3fb27SDimitry Andric 67*06c3fb27SDimitry Andric void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const { 68*06c3fb27SDimitry Andric QualType RetTy = FI.getReturnType(); 69*06c3fb27SDimitry Andric if (!getCXXABI().classifyReturnType(FI)) 70*06c3fb27SDimitry Andric FI.getReturnInfo() = classifyReturnType(RetTy); 71*06c3fb27SDimitry Andric 72*06c3fb27SDimitry Andric // IsRetIndirect is true if classifyArgumentType indicated the value should 73*06c3fb27SDimitry Andric // be passed indirect, or if the type size is a scalar greater than 2*XLen 74*06c3fb27SDimitry Andric // and not a complex type with elements <= FLen. e.g. fp128 is passed direct 75*06c3fb27SDimitry Andric // in LLVM IR, relying on the backend lowering code to rewrite the argument 76*06c3fb27SDimitry Andric // list and pass indirectly on RV32. 77*06c3fb27SDimitry Andric bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect; 78*06c3fb27SDimitry Andric if (!IsRetIndirect && RetTy->isScalarType() && 79*06c3fb27SDimitry Andric getContext().getTypeSize(RetTy) > (2 * XLen)) { 80*06c3fb27SDimitry Andric if (RetTy->isComplexType() && FLen) { 81*06c3fb27SDimitry Andric QualType EltTy = RetTy->castAs<ComplexType>()->getElementType(); 82*06c3fb27SDimitry Andric IsRetIndirect = getContext().getTypeSize(EltTy) > FLen; 83*06c3fb27SDimitry Andric } else { 84*06c3fb27SDimitry Andric // This is a normal scalar > 2*XLen, such as fp128 on RV32. 85*06c3fb27SDimitry Andric IsRetIndirect = true; 86*06c3fb27SDimitry Andric } 87*06c3fb27SDimitry Andric } 88*06c3fb27SDimitry Andric 89*06c3fb27SDimitry Andric int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs; 90*06c3fb27SDimitry Andric int ArgFPRsLeft = FLen ? NumArgFPRs : 0; 91*06c3fb27SDimitry Andric int NumFixedArgs = FI.getNumRequiredArgs(); 92*06c3fb27SDimitry Andric 93*06c3fb27SDimitry Andric int ArgNum = 0; 94*06c3fb27SDimitry Andric for (auto &ArgInfo : FI.arguments()) { 95*06c3fb27SDimitry Andric bool IsFixed = ArgNum < NumFixedArgs; 96*06c3fb27SDimitry Andric ArgInfo.info = 97*06c3fb27SDimitry Andric classifyArgumentType(ArgInfo.type, IsFixed, ArgGPRsLeft, ArgFPRsLeft); 98*06c3fb27SDimitry Andric ArgNum++; 99*06c3fb27SDimitry Andric } 100*06c3fb27SDimitry Andric } 101*06c3fb27SDimitry Andric 102*06c3fb27SDimitry Andric // Returns true if the struct is a potential candidate for the floating point 103*06c3fb27SDimitry Andric // calling convention. If this function returns true, the caller is 104*06c3fb27SDimitry Andric // responsible for checking that if there is only a single field then that 105*06c3fb27SDimitry Andric // field is a float. 106*06c3fb27SDimitry Andric bool RISCVABIInfo::detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff, 107*06c3fb27SDimitry Andric llvm::Type *&Field1Ty, 108*06c3fb27SDimitry Andric CharUnits &Field1Off, 109*06c3fb27SDimitry Andric llvm::Type *&Field2Ty, 110*06c3fb27SDimitry Andric CharUnits &Field2Off) const { 111*06c3fb27SDimitry Andric bool IsInt = Ty->isIntegralOrEnumerationType(); 112*06c3fb27SDimitry Andric bool IsFloat = Ty->isRealFloatingType(); 113*06c3fb27SDimitry Andric 114*06c3fb27SDimitry Andric if (IsInt || IsFloat) { 115*06c3fb27SDimitry Andric uint64_t Size = getContext().getTypeSize(Ty); 116*06c3fb27SDimitry Andric if (IsInt && Size > XLen) 117*06c3fb27SDimitry Andric return false; 118*06c3fb27SDimitry Andric // Can't be eligible if larger than the FP registers. Handling of half 119*06c3fb27SDimitry Andric // precision values has been specified in the ABI, so don't block those. 120*06c3fb27SDimitry Andric if (IsFloat && Size > FLen) 121*06c3fb27SDimitry Andric return false; 122*06c3fb27SDimitry Andric // Can't be eligible if an integer type was already found (int+int pairs 123*06c3fb27SDimitry Andric // are not eligible). 124*06c3fb27SDimitry Andric if (IsInt && Field1Ty && Field1Ty->isIntegerTy()) 125*06c3fb27SDimitry Andric return false; 126*06c3fb27SDimitry Andric if (!Field1Ty) { 127*06c3fb27SDimitry Andric Field1Ty = CGT.ConvertType(Ty); 128*06c3fb27SDimitry Andric Field1Off = CurOff; 129*06c3fb27SDimitry Andric return true; 130*06c3fb27SDimitry Andric } 131*06c3fb27SDimitry Andric if (!Field2Ty) { 132*06c3fb27SDimitry Andric Field2Ty = CGT.ConvertType(Ty); 133*06c3fb27SDimitry Andric Field2Off = CurOff; 134*06c3fb27SDimitry Andric return true; 135*06c3fb27SDimitry Andric } 136*06c3fb27SDimitry Andric return false; 137*06c3fb27SDimitry Andric } 138*06c3fb27SDimitry Andric 139*06c3fb27SDimitry Andric if (auto CTy = Ty->getAs<ComplexType>()) { 140*06c3fb27SDimitry Andric if (Field1Ty) 141*06c3fb27SDimitry Andric return false; 142*06c3fb27SDimitry Andric QualType EltTy = CTy->getElementType(); 143*06c3fb27SDimitry Andric if (getContext().getTypeSize(EltTy) > FLen) 144*06c3fb27SDimitry Andric return false; 145*06c3fb27SDimitry Andric Field1Ty = CGT.ConvertType(EltTy); 146*06c3fb27SDimitry Andric Field1Off = CurOff; 147*06c3fb27SDimitry Andric Field2Ty = Field1Ty; 148*06c3fb27SDimitry Andric Field2Off = Field1Off + getContext().getTypeSizeInChars(EltTy); 149*06c3fb27SDimitry Andric return true; 150*06c3fb27SDimitry Andric } 151*06c3fb27SDimitry Andric 152*06c3fb27SDimitry Andric if (const ConstantArrayType *ATy = getContext().getAsConstantArrayType(Ty)) { 153*06c3fb27SDimitry Andric uint64_t ArraySize = ATy->getSize().getZExtValue(); 154*06c3fb27SDimitry Andric QualType EltTy = ATy->getElementType(); 155*06c3fb27SDimitry Andric CharUnits EltSize = getContext().getTypeSizeInChars(EltTy); 156*06c3fb27SDimitry Andric for (uint64_t i = 0; i < ArraySize; ++i) { 157*06c3fb27SDimitry Andric bool Ret = detectFPCCEligibleStructHelper(EltTy, CurOff, Field1Ty, 158*06c3fb27SDimitry Andric Field1Off, Field2Ty, Field2Off); 159*06c3fb27SDimitry Andric if (!Ret) 160*06c3fb27SDimitry Andric return false; 161*06c3fb27SDimitry Andric CurOff += EltSize; 162*06c3fb27SDimitry Andric } 163*06c3fb27SDimitry Andric return true; 164*06c3fb27SDimitry Andric } 165*06c3fb27SDimitry Andric 166*06c3fb27SDimitry Andric if (const auto *RTy = Ty->getAs<RecordType>()) { 167*06c3fb27SDimitry Andric // Structures with either a non-trivial destructor or a non-trivial 168*06c3fb27SDimitry Andric // copy constructor are not eligible for the FP calling convention. 169*06c3fb27SDimitry Andric if (getRecordArgABI(Ty, CGT.getCXXABI())) 170*06c3fb27SDimitry Andric return false; 171*06c3fb27SDimitry Andric if (isEmptyRecord(getContext(), Ty, true)) 172*06c3fb27SDimitry Andric return true; 173*06c3fb27SDimitry Andric const RecordDecl *RD = RTy->getDecl(); 174*06c3fb27SDimitry Andric // Unions aren't eligible unless they're empty (which is caught above). 175*06c3fb27SDimitry Andric if (RD->isUnion()) 176*06c3fb27SDimitry Andric return false; 177*06c3fb27SDimitry Andric const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); 178*06c3fb27SDimitry Andric // If this is a C++ record, check the bases first. 179*06c3fb27SDimitry Andric if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { 180*06c3fb27SDimitry Andric for (const CXXBaseSpecifier &B : CXXRD->bases()) { 181*06c3fb27SDimitry Andric const auto *BDecl = 182*06c3fb27SDimitry Andric cast<CXXRecordDecl>(B.getType()->castAs<RecordType>()->getDecl()); 183*06c3fb27SDimitry Andric CharUnits BaseOff = Layout.getBaseClassOffset(BDecl); 184*06c3fb27SDimitry Andric bool Ret = detectFPCCEligibleStructHelper(B.getType(), CurOff + BaseOff, 185*06c3fb27SDimitry Andric Field1Ty, Field1Off, Field2Ty, 186*06c3fb27SDimitry Andric Field2Off); 187*06c3fb27SDimitry Andric if (!Ret) 188*06c3fb27SDimitry Andric return false; 189*06c3fb27SDimitry Andric } 190*06c3fb27SDimitry Andric } 191*06c3fb27SDimitry Andric int ZeroWidthBitFieldCount = 0; 192*06c3fb27SDimitry Andric for (const FieldDecl *FD : RD->fields()) { 193*06c3fb27SDimitry Andric uint64_t FieldOffInBits = Layout.getFieldOffset(FD->getFieldIndex()); 194*06c3fb27SDimitry Andric QualType QTy = FD->getType(); 195*06c3fb27SDimitry Andric if (FD->isBitField()) { 196*06c3fb27SDimitry Andric unsigned BitWidth = FD->getBitWidthValue(getContext()); 197*06c3fb27SDimitry Andric // Allow a bitfield with a type greater than XLen as long as the 198*06c3fb27SDimitry Andric // bitwidth is XLen or less. 199*06c3fb27SDimitry Andric if (getContext().getTypeSize(QTy) > XLen && BitWidth <= XLen) 200*06c3fb27SDimitry Andric QTy = getContext().getIntTypeForBitwidth(XLen, false); 201*06c3fb27SDimitry Andric if (BitWidth == 0) { 202*06c3fb27SDimitry Andric ZeroWidthBitFieldCount++; 203*06c3fb27SDimitry Andric continue; 204*06c3fb27SDimitry Andric } 205*06c3fb27SDimitry Andric } 206*06c3fb27SDimitry Andric 207*06c3fb27SDimitry Andric bool Ret = detectFPCCEligibleStructHelper( 208*06c3fb27SDimitry Andric QTy, CurOff + getContext().toCharUnitsFromBits(FieldOffInBits), 209*06c3fb27SDimitry Andric Field1Ty, Field1Off, Field2Ty, Field2Off); 210*06c3fb27SDimitry Andric if (!Ret) 211*06c3fb27SDimitry Andric return false; 212*06c3fb27SDimitry Andric 213*06c3fb27SDimitry Andric // As a quirk of the ABI, zero-width bitfields aren't ignored for fp+fp 214*06c3fb27SDimitry Andric // or int+fp structs, but are ignored for a struct with an fp field and 215*06c3fb27SDimitry Andric // any number of zero-width bitfields. 216*06c3fb27SDimitry Andric if (Field2Ty && ZeroWidthBitFieldCount > 0) 217*06c3fb27SDimitry Andric return false; 218*06c3fb27SDimitry Andric } 219*06c3fb27SDimitry Andric return Field1Ty != nullptr; 220*06c3fb27SDimitry Andric } 221*06c3fb27SDimitry Andric 222*06c3fb27SDimitry Andric return false; 223*06c3fb27SDimitry Andric } 224*06c3fb27SDimitry Andric 225*06c3fb27SDimitry Andric // Determine if a struct is eligible for passing according to the floating 226*06c3fb27SDimitry Andric // point calling convention (i.e., when flattened it contains a single fp 227*06c3fb27SDimitry Andric // value, fp+fp, or int+fp of appropriate size). If so, NeededArgFPRs and 228*06c3fb27SDimitry Andric // NeededArgGPRs are incremented appropriately. 229*06c3fb27SDimitry Andric bool RISCVABIInfo::detectFPCCEligibleStruct(QualType Ty, llvm::Type *&Field1Ty, 230*06c3fb27SDimitry Andric CharUnits &Field1Off, 231*06c3fb27SDimitry Andric llvm::Type *&Field2Ty, 232*06c3fb27SDimitry Andric CharUnits &Field2Off, 233*06c3fb27SDimitry Andric int &NeededArgGPRs, 234*06c3fb27SDimitry Andric int &NeededArgFPRs) const { 235*06c3fb27SDimitry Andric Field1Ty = nullptr; 236*06c3fb27SDimitry Andric Field2Ty = nullptr; 237*06c3fb27SDimitry Andric NeededArgGPRs = 0; 238*06c3fb27SDimitry Andric NeededArgFPRs = 0; 239*06c3fb27SDimitry Andric bool IsCandidate = detectFPCCEligibleStructHelper( 240*06c3fb27SDimitry Andric Ty, CharUnits::Zero(), Field1Ty, Field1Off, Field2Ty, Field2Off); 241*06c3fb27SDimitry Andric // Not really a candidate if we have a single int but no float. 242*06c3fb27SDimitry Andric if (Field1Ty && !Field2Ty && !Field1Ty->isFloatingPointTy()) 243*06c3fb27SDimitry Andric return false; 244*06c3fb27SDimitry Andric if (!IsCandidate) 245*06c3fb27SDimitry Andric return false; 246*06c3fb27SDimitry Andric if (Field1Ty && Field1Ty->isFloatingPointTy()) 247*06c3fb27SDimitry Andric NeededArgFPRs++; 248*06c3fb27SDimitry Andric else if (Field1Ty) 249*06c3fb27SDimitry Andric NeededArgGPRs++; 250*06c3fb27SDimitry Andric if (Field2Ty && Field2Ty->isFloatingPointTy()) 251*06c3fb27SDimitry Andric NeededArgFPRs++; 252*06c3fb27SDimitry Andric else if (Field2Ty) 253*06c3fb27SDimitry Andric NeededArgGPRs++; 254*06c3fb27SDimitry Andric return true; 255*06c3fb27SDimitry Andric } 256*06c3fb27SDimitry Andric 257*06c3fb27SDimitry Andric // Call getCoerceAndExpand for the two-element flattened struct described by 258*06c3fb27SDimitry Andric // Field1Ty, Field1Off, Field2Ty, Field2Off. This method will create an 259*06c3fb27SDimitry Andric // appropriate coerceToType and unpaddedCoerceToType. 260*06c3fb27SDimitry Andric ABIArgInfo RISCVABIInfo::coerceAndExpandFPCCEligibleStruct( 261*06c3fb27SDimitry Andric llvm::Type *Field1Ty, CharUnits Field1Off, llvm::Type *Field2Ty, 262*06c3fb27SDimitry Andric CharUnits Field2Off) const { 263*06c3fb27SDimitry Andric SmallVector<llvm::Type *, 3> CoerceElts; 264*06c3fb27SDimitry Andric SmallVector<llvm::Type *, 2> UnpaddedCoerceElts; 265*06c3fb27SDimitry Andric if (!Field1Off.isZero()) 266*06c3fb27SDimitry Andric CoerceElts.push_back(llvm::ArrayType::get( 267*06c3fb27SDimitry Andric llvm::Type::getInt8Ty(getVMContext()), Field1Off.getQuantity())); 268*06c3fb27SDimitry Andric 269*06c3fb27SDimitry Andric CoerceElts.push_back(Field1Ty); 270*06c3fb27SDimitry Andric UnpaddedCoerceElts.push_back(Field1Ty); 271*06c3fb27SDimitry Andric 272*06c3fb27SDimitry Andric if (!Field2Ty) { 273*06c3fb27SDimitry Andric return ABIArgInfo::getCoerceAndExpand( 274*06c3fb27SDimitry Andric llvm::StructType::get(getVMContext(), CoerceElts, !Field1Off.isZero()), 275*06c3fb27SDimitry Andric UnpaddedCoerceElts[0]); 276*06c3fb27SDimitry Andric } 277*06c3fb27SDimitry Andric 278*06c3fb27SDimitry Andric CharUnits Field2Align = 279*06c3fb27SDimitry Andric CharUnits::fromQuantity(getDataLayout().getABITypeAlign(Field2Ty)); 280*06c3fb27SDimitry Andric CharUnits Field1End = Field1Off + 281*06c3fb27SDimitry Andric CharUnits::fromQuantity(getDataLayout().getTypeStoreSize(Field1Ty)); 282*06c3fb27SDimitry Andric CharUnits Field2OffNoPadNoPack = Field1End.alignTo(Field2Align); 283*06c3fb27SDimitry Andric 284*06c3fb27SDimitry Andric CharUnits Padding = CharUnits::Zero(); 285*06c3fb27SDimitry Andric if (Field2Off > Field2OffNoPadNoPack) 286*06c3fb27SDimitry Andric Padding = Field2Off - Field2OffNoPadNoPack; 287*06c3fb27SDimitry Andric else if (Field2Off != Field2Align && Field2Off > Field1End) 288*06c3fb27SDimitry Andric Padding = Field2Off - Field1End; 289*06c3fb27SDimitry Andric 290*06c3fb27SDimitry Andric bool IsPacked = !Field2Off.isMultipleOf(Field2Align); 291*06c3fb27SDimitry Andric 292*06c3fb27SDimitry Andric if (!Padding.isZero()) 293*06c3fb27SDimitry Andric CoerceElts.push_back(llvm::ArrayType::get( 294*06c3fb27SDimitry Andric llvm::Type::getInt8Ty(getVMContext()), Padding.getQuantity())); 295*06c3fb27SDimitry Andric 296*06c3fb27SDimitry Andric CoerceElts.push_back(Field2Ty); 297*06c3fb27SDimitry Andric UnpaddedCoerceElts.push_back(Field2Ty); 298*06c3fb27SDimitry Andric 299*06c3fb27SDimitry Andric auto CoerceToType = 300*06c3fb27SDimitry Andric llvm::StructType::get(getVMContext(), CoerceElts, IsPacked); 301*06c3fb27SDimitry Andric auto UnpaddedCoerceToType = 302*06c3fb27SDimitry Andric llvm::StructType::get(getVMContext(), UnpaddedCoerceElts, IsPacked); 303*06c3fb27SDimitry Andric 304*06c3fb27SDimitry Andric return ABIArgInfo::getCoerceAndExpand(CoerceToType, UnpaddedCoerceToType); 305*06c3fb27SDimitry Andric } 306*06c3fb27SDimitry Andric 307*06c3fb27SDimitry Andric // Fixed-length RVV vectors are represented as scalable vectors in function 308*06c3fb27SDimitry Andric // args/return and must be coerced from fixed vectors. 309*06c3fb27SDimitry Andric ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty) const { 310*06c3fb27SDimitry Andric assert(Ty->isVectorType() && "expected vector type!"); 311*06c3fb27SDimitry Andric 312*06c3fb27SDimitry Andric const auto *VT = Ty->castAs<VectorType>(); 313*06c3fb27SDimitry Andric assert(VT->getVectorKind() == VectorType::RVVFixedLengthDataVector && 314*06c3fb27SDimitry Andric "Unexpected vector kind"); 315*06c3fb27SDimitry Andric 316*06c3fb27SDimitry Andric assert(VT->getElementType()->isBuiltinType() && "expected builtin type!"); 317*06c3fb27SDimitry Andric 318*06c3fb27SDimitry Andric const auto *BT = VT->getElementType()->castAs<BuiltinType>(); 319*06c3fb27SDimitry Andric unsigned EltSize = getContext().getTypeSize(BT); 320*06c3fb27SDimitry Andric llvm::ScalableVectorType *ResType = 321*06c3fb27SDimitry Andric llvm::ScalableVectorType::get(CGT.ConvertType(VT->getElementType()), 322*06c3fb27SDimitry Andric llvm::RISCV::RVVBitsPerBlock / EltSize); 323*06c3fb27SDimitry Andric return ABIArgInfo::getDirect(ResType); 324*06c3fb27SDimitry Andric } 325*06c3fb27SDimitry Andric 326*06c3fb27SDimitry Andric ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, 327*06c3fb27SDimitry Andric int &ArgGPRsLeft, 328*06c3fb27SDimitry Andric int &ArgFPRsLeft) const { 329*06c3fb27SDimitry Andric assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow"); 330*06c3fb27SDimitry Andric Ty = useFirstFieldIfTransparentUnion(Ty); 331*06c3fb27SDimitry Andric 332*06c3fb27SDimitry Andric // Structures with either a non-trivial destructor or a non-trivial 333*06c3fb27SDimitry Andric // copy constructor are always passed indirectly. 334*06c3fb27SDimitry Andric if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) { 335*06c3fb27SDimitry Andric if (ArgGPRsLeft) 336*06c3fb27SDimitry Andric ArgGPRsLeft -= 1; 337*06c3fb27SDimitry Andric return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA == 338*06c3fb27SDimitry Andric CGCXXABI::RAA_DirectInMemory); 339*06c3fb27SDimitry Andric } 340*06c3fb27SDimitry Andric 341*06c3fb27SDimitry Andric // Ignore empty structs/unions. 342*06c3fb27SDimitry Andric if (isEmptyRecord(getContext(), Ty, true)) 343*06c3fb27SDimitry Andric return ABIArgInfo::getIgnore(); 344*06c3fb27SDimitry Andric 345*06c3fb27SDimitry Andric uint64_t Size = getContext().getTypeSize(Ty); 346*06c3fb27SDimitry Andric 347*06c3fb27SDimitry Andric // Pass floating point values via FPRs if possible. 348*06c3fb27SDimitry Andric if (IsFixed && Ty->isFloatingType() && !Ty->isComplexType() && 349*06c3fb27SDimitry Andric FLen >= Size && ArgFPRsLeft) { 350*06c3fb27SDimitry Andric ArgFPRsLeft--; 351*06c3fb27SDimitry Andric return ABIArgInfo::getDirect(); 352*06c3fb27SDimitry Andric } 353*06c3fb27SDimitry Andric 354*06c3fb27SDimitry Andric // Complex types for the hard float ABI must be passed direct rather than 355*06c3fb27SDimitry Andric // using CoerceAndExpand. 356*06c3fb27SDimitry Andric if (IsFixed && Ty->isComplexType() && FLen && ArgFPRsLeft >= 2) { 357*06c3fb27SDimitry Andric QualType EltTy = Ty->castAs<ComplexType>()->getElementType(); 358*06c3fb27SDimitry Andric if (getContext().getTypeSize(EltTy) <= FLen) { 359*06c3fb27SDimitry Andric ArgFPRsLeft -= 2; 360*06c3fb27SDimitry Andric return ABIArgInfo::getDirect(); 361*06c3fb27SDimitry Andric } 362*06c3fb27SDimitry Andric } 363*06c3fb27SDimitry Andric 364*06c3fb27SDimitry Andric if (IsFixed && FLen && Ty->isStructureOrClassType()) { 365*06c3fb27SDimitry Andric llvm::Type *Field1Ty = nullptr; 366*06c3fb27SDimitry Andric llvm::Type *Field2Ty = nullptr; 367*06c3fb27SDimitry Andric CharUnits Field1Off = CharUnits::Zero(); 368*06c3fb27SDimitry Andric CharUnits Field2Off = CharUnits::Zero(); 369*06c3fb27SDimitry Andric int NeededArgGPRs = 0; 370*06c3fb27SDimitry Andric int NeededArgFPRs = 0; 371*06c3fb27SDimitry Andric bool IsCandidate = 372*06c3fb27SDimitry Andric detectFPCCEligibleStruct(Ty, Field1Ty, Field1Off, Field2Ty, Field2Off, 373*06c3fb27SDimitry Andric NeededArgGPRs, NeededArgFPRs); 374*06c3fb27SDimitry Andric if (IsCandidate && NeededArgGPRs <= ArgGPRsLeft && 375*06c3fb27SDimitry Andric NeededArgFPRs <= ArgFPRsLeft) { 376*06c3fb27SDimitry Andric ArgGPRsLeft -= NeededArgGPRs; 377*06c3fb27SDimitry Andric ArgFPRsLeft -= NeededArgFPRs; 378*06c3fb27SDimitry Andric return coerceAndExpandFPCCEligibleStruct(Field1Ty, Field1Off, Field2Ty, 379*06c3fb27SDimitry Andric Field2Off); 380*06c3fb27SDimitry Andric } 381*06c3fb27SDimitry Andric } 382*06c3fb27SDimitry Andric 383*06c3fb27SDimitry Andric uint64_t NeededAlign = getContext().getTypeAlign(Ty); 384*06c3fb27SDimitry Andric // Determine the number of GPRs needed to pass the current argument 385*06c3fb27SDimitry Andric // according to the ABI. 2*XLen-aligned varargs are passed in "aligned" 386*06c3fb27SDimitry Andric // register pairs, so may consume 3 registers. 387*06c3fb27SDimitry Andric int NeededArgGPRs = 1; 388*06c3fb27SDimitry Andric if (!IsFixed && NeededAlign == 2 * XLen) 389*06c3fb27SDimitry Andric NeededArgGPRs = 2 + (ArgGPRsLeft % 2); 390*06c3fb27SDimitry Andric else if (Size > XLen && Size <= 2 * XLen) 391*06c3fb27SDimitry Andric NeededArgGPRs = 2; 392*06c3fb27SDimitry Andric 393*06c3fb27SDimitry Andric if (NeededArgGPRs > ArgGPRsLeft) { 394*06c3fb27SDimitry Andric NeededArgGPRs = ArgGPRsLeft; 395*06c3fb27SDimitry Andric } 396*06c3fb27SDimitry Andric 397*06c3fb27SDimitry Andric ArgGPRsLeft -= NeededArgGPRs; 398*06c3fb27SDimitry Andric 399*06c3fb27SDimitry Andric if (!isAggregateTypeForABI(Ty) && !Ty->isVectorType()) { 400*06c3fb27SDimitry Andric // Treat an enum type as its underlying type. 401*06c3fb27SDimitry Andric if (const EnumType *EnumTy = Ty->getAs<EnumType>()) 402*06c3fb27SDimitry Andric Ty = EnumTy->getDecl()->getIntegerType(); 403*06c3fb27SDimitry Andric 404*06c3fb27SDimitry Andric // All integral types are promoted to XLen width 405*06c3fb27SDimitry Andric if (Size < XLen && Ty->isIntegralOrEnumerationType()) { 406*06c3fb27SDimitry Andric return extendType(Ty); 407*06c3fb27SDimitry Andric } 408*06c3fb27SDimitry Andric 409*06c3fb27SDimitry Andric if (const auto *EIT = Ty->getAs<BitIntType>()) { 410*06c3fb27SDimitry Andric if (EIT->getNumBits() < XLen) 411*06c3fb27SDimitry Andric return extendType(Ty); 412*06c3fb27SDimitry Andric if (EIT->getNumBits() > 128 || 413*06c3fb27SDimitry Andric (!getContext().getTargetInfo().hasInt128Type() && 414*06c3fb27SDimitry Andric EIT->getNumBits() > 64)) 415*06c3fb27SDimitry Andric return getNaturalAlignIndirect(Ty, /*ByVal=*/false); 416*06c3fb27SDimitry Andric } 417*06c3fb27SDimitry Andric 418*06c3fb27SDimitry Andric return ABIArgInfo::getDirect(); 419*06c3fb27SDimitry Andric } 420*06c3fb27SDimitry Andric 421*06c3fb27SDimitry Andric if (const VectorType *VT = Ty->getAs<VectorType>()) 422*06c3fb27SDimitry Andric if (VT->getVectorKind() == VectorType::RVVFixedLengthDataVector) 423*06c3fb27SDimitry Andric return coerceVLSVector(Ty); 424*06c3fb27SDimitry Andric 425*06c3fb27SDimitry Andric // Aggregates which are <= 2*XLen will be passed in registers if possible, 426*06c3fb27SDimitry Andric // so coerce to integers. 427*06c3fb27SDimitry Andric if (Size <= 2 * XLen) { 428*06c3fb27SDimitry Andric unsigned Alignment = getContext().getTypeAlign(Ty); 429*06c3fb27SDimitry Andric 430*06c3fb27SDimitry Andric // Use a single XLen int if possible, 2*XLen if 2*XLen alignment is 431*06c3fb27SDimitry Andric // required, and a 2-element XLen array if only XLen alignment is required. 432*06c3fb27SDimitry Andric if (Size <= XLen) { 433*06c3fb27SDimitry Andric return ABIArgInfo::getDirect( 434*06c3fb27SDimitry Andric llvm::IntegerType::get(getVMContext(), XLen)); 435*06c3fb27SDimitry Andric } else if (Alignment == 2 * XLen) { 436*06c3fb27SDimitry Andric return ABIArgInfo::getDirect( 437*06c3fb27SDimitry Andric llvm::IntegerType::get(getVMContext(), 2 * XLen)); 438*06c3fb27SDimitry Andric } else { 439*06c3fb27SDimitry Andric return ABIArgInfo::getDirect(llvm::ArrayType::get( 440*06c3fb27SDimitry Andric llvm::IntegerType::get(getVMContext(), XLen), 2)); 441*06c3fb27SDimitry Andric } 442*06c3fb27SDimitry Andric } 443*06c3fb27SDimitry Andric return getNaturalAlignIndirect(Ty, /*ByVal=*/false); 444*06c3fb27SDimitry Andric } 445*06c3fb27SDimitry Andric 446*06c3fb27SDimitry Andric ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy) const { 447*06c3fb27SDimitry Andric if (RetTy->isVoidType()) 448*06c3fb27SDimitry Andric return ABIArgInfo::getIgnore(); 449*06c3fb27SDimitry Andric 450*06c3fb27SDimitry Andric int ArgGPRsLeft = 2; 451*06c3fb27SDimitry Andric int ArgFPRsLeft = FLen ? 2 : 0; 452*06c3fb27SDimitry Andric 453*06c3fb27SDimitry Andric // The rules for return and argument types are the same, so defer to 454*06c3fb27SDimitry Andric // classifyArgumentType. 455*06c3fb27SDimitry Andric return classifyArgumentType(RetTy, /*IsFixed=*/true, ArgGPRsLeft, 456*06c3fb27SDimitry Andric ArgFPRsLeft); 457*06c3fb27SDimitry Andric } 458*06c3fb27SDimitry Andric 459*06c3fb27SDimitry Andric Address RISCVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, 460*06c3fb27SDimitry Andric QualType Ty) const { 461*06c3fb27SDimitry Andric CharUnits SlotSize = CharUnits::fromQuantity(XLen / 8); 462*06c3fb27SDimitry Andric 463*06c3fb27SDimitry Andric // Empty records are ignored for parameter passing purposes. 464*06c3fb27SDimitry Andric if (isEmptyRecord(getContext(), Ty, true)) { 465*06c3fb27SDimitry Andric return Address(CGF.Builder.CreateLoad(VAListAddr), 466*06c3fb27SDimitry Andric CGF.ConvertTypeForMem(Ty), SlotSize); 467*06c3fb27SDimitry Andric } 468*06c3fb27SDimitry Andric 469*06c3fb27SDimitry Andric auto TInfo = getContext().getTypeInfoInChars(Ty); 470*06c3fb27SDimitry Andric 471*06c3fb27SDimitry Andric // Arguments bigger than 2*Xlen bytes are passed indirectly. 472*06c3fb27SDimitry Andric bool IsIndirect = TInfo.Width > 2 * SlotSize; 473*06c3fb27SDimitry Andric 474*06c3fb27SDimitry Andric return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect, TInfo, 475*06c3fb27SDimitry Andric SlotSize, /*AllowHigherAlign=*/true); 476*06c3fb27SDimitry Andric } 477*06c3fb27SDimitry Andric 478*06c3fb27SDimitry Andric ABIArgInfo RISCVABIInfo::extendType(QualType Ty) const { 479*06c3fb27SDimitry Andric int TySize = getContext().getTypeSize(Ty); 480*06c3fb27SDimitry Andric // RV64 ABI requires unsigned 32 bit integers to be sign extended. 481*06c3fb27SDimitry Andric if (XLen == 64 && Ty->isUnsignedIntegerOrEnumerationType() && TySize == 32) 482*06c3fb27SDimitry Andric return ABIArgInfo::getSignExtend(Ty); 483*06c3fb27SDimitry Andric return ABIArgInfo::getExtend(Ty); 484*06c3fb27SDimitry Andric } 485*06c3fb27SDimitry Andric 486*06c3fb27SDimitry Andric namespace { 487*06c3fb27SDimitry Andric class RISCVTargetCodeGenInfo : public TargetCodeGenInfo { 488*06c3fb27SDimitry Andric public: 489*06c3fb27SDimitry Andric RISCVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, 490*06c3fb27SDimitry Andric unsigned FLen) 491*06c3fb27SDimitry Andric : TargetCodeGenInfo(std::make_unique<RISCVABIInfo>(CGT, XLen, FLen)) {} 492*06c3fb27SDimitry Andric 493*06c3fb27SDimitry Andric void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, 494*06c3fb27SDimitry Andric CodeGen::CodeGenModule &CGM) const override { 495*06c3fb27SDimitry Andric const auto *FD = dyn_cast_or_null<FunctionDecl>(D); 496*06c3fb27SDimitry Andric if (!FD) return; 497*06c3fb27SDimitry Andric 498*06c3fb27SDimitry Andric const auto *Attr = FD->getAttr<RISCVInterruptAttr>(); 499*06c3fb27SDimitry Andric if (!Attr) 500*06c3fb27SDimitry Andric return; 501*06c3fb27SDimitry Andric 502*06c3fb27SDimitry Andric const char *Kind; 503*06c3fb27SDimitry Andric switch (Attr->getInterrupt()) { 504*06c3fb27SDimitry Andric case RISCVInterruptAttr::supervisor: Kind = "supervisor"; break; 505*06c3fb27SDimitry Andric case RISCVInterruptAttr::machine: Kind = "machine"; break; 506*06c3fb27SDimitry Andric } 507*06c3fb27SDimitry Andric 508*06c3fb27SDimitry Andric auto *Fn = cast<llvm::Function>(GV); 509*06c3fb27SDimitry Andric 510*06c3fb27SDimitry Andric Fn->addFnAttr("interrupt", Kind); 511*06c3fb27SDimitry Andric } 512*06c3fb27SDimitry Andric }; 513*06c3fb27SDimitry Andric } // namespace 514*06c3fb27SDimitry Andric 515*06c3fb27SDimitry Andric std::unique_ptr<TargetCodeGenInfo> 516*06c3fb27SDimitry Andric CodeGen::createRISCVTargetCodeGenInfo(CodeGenModule &CGM, unsigned XLen, 517*06c3fb27SDimitry Andric unsigned FLen) { 518*06c3fb27SDimitry Andric return std::make_unique<RISCVTargetCodeGenInfo>(CGM.getTypes(), XLen, FLen); 519*06c3fb27SDimitry Andric } 520