106c3fb27SDimitry Andric //===- RISCV.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 //===----------------------------------------------------------------------===// 1606c3fb27SDimitry Andric // RISC-V ABI Implementation 1706c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 1806c3fb27SDimitry Andric 1906c3fb27SDimitry Andric namespace { 2006c3fb27SDimitry Andric class RISCVABIInfo : public DefaultABIInfo { 2106c3fb27SDimitry Andric private: 2206c3fb27SDimitry Andric // Size of the integer ('x') registers in bits. 2306c3fb27SDimitry Andric unsigned XLen; 2406c3fb27SDimitry Andric // Size of the floating point ('f') registers in bits. Note that the target 2506c3fb27SDimitry Andric // ISA might have a wider FLen than the selected ABI (e.g. an RV32IF target 2606c3fb27SDimitry Andric // with soft float ABI has FLen==0). 2706c3fb27SDimitry Andric unsigned FLen; 287a6dacacSDimitry Andric const int NumArgGPRs; 297a6dacacSDimitry Andric const int NumArgFPRs; 307a6dacacSDimitry Andric const bool EABI; 3106c3fb27SDimitry Andric bool detectFPCCEligibleStructHelper(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: 387a6dacacSDimitry Andric RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen, 397a6dacacSDimitry Andric bool EABI) 407a6dacacSDimitry Andric : DefaultABIInfo(CGT), XLen(XLen), FLen(FLen), NumArgGPRs(EABI ? 6 : 8), 417a6dacacSDimitry Andric NumArgFPRs(FLen != 0 ? 8 : 0), EABI(EABI) {} 4206c3fb27SDimitry Andric 4306c3fb27SDimitry Andric // DefaultABIInfo's classifyReturnType and classifyArgumentType are 4406c3fb27SDimitry Andric // non-virtual, but computeInfo is virtual, so we overload it. 4506c3fb27SDimitry Andric void computeInfo(CGFunctionInfo &FI) const override; 4606c3fb27SDimitry Andric 4706c3fb27SDimitry Andric ABIArgInfo classifyArgumentType(QualType Ty, bool IsFixed, int &ArgGPRsLeft, 4806c3fb27SDimitry Andric int &ArgFPRsLeft) const; 4906c3fb27SDimitry Andric ABIArgInfo classifyReturnType(QualType RetTy) const; 5006c3fb27SDimitry Andric 51*0fca6ea1SDimitry Andric RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty, 52*0fca6ea1SDimitry Andric AggValueSlot Slot) const override; 5306c3fb27SDimitry Andric 5406c3fb27SDimitry Andric ABIArgInfo extendType(QualType Ty) const; 5506c3fb27SDimitry Andric 5606c3fb27SDimitry Andric bool detectFPCCEligibleStruct(QualType Ty, llvm::Type *&Field1Ty, 5706c3fb27SDimitry Andric CharUnits &Field1Off, llvm::Type *&Field2Ty, 5806c3fb27SDimitry Andric CharUnits &Field2Off, int &NeededArgGPRs, 5906c3fb27SDimitry Andric int &NeededArgFPRs) const; 6006c3fb27SDimitry Andric ABIArgInfo coerceAndExpandFPCCEligibleStruct(llvm::Type *Field1Ty, 6106c3fb27SDimitry Andric CharUnits Field1Off, 6206c3fb27SDimitry Andric llvm::Type *Field2Ty, 6306c3fb27SDimitry Andric CharUnits Field2Off) const; 6406c3fb27SDimitry Andric 6506c3fb27SDimitry Andric ABIArgInfo coerceVLSVector(QualType Ty) const; 6606c3fb27SDimitry Andric }; 6706c3fb27SDimitry Andric } // end anonymous namespace 6806c3fb27SDimitry Andric 6906c3fb27SDimitry Andric void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const { 7006c3fb27SDimitry Andric QualType RetTy = FI.getReturnType(); 7106c3fb27SDimitry Andric if (!getCXXABI().classifyReturnType(FI)) 7206c3fb27SDimitry Andric FI.getReturnInfo() = classifyReturnType(RetTy); 7306c3fb27SDimitry Andric 7406c3fb27SDimitry Andric // IsRetIndirect is true if classifyArgumentType indicated the value should 7506c3fb27SDimitry Andric // be passed indirect, or if the type size is a scalar greater than 2*XLen 7606c3fb27SDimitry Andric // and not a complex type with elements <= FLen. e.g. fp128 is passed direct 7706c3fb27SDimitry Andric // in LLVM IR, relying on the backend lowering code to rewrite the argument 7806c3fb27SDimitry Andric // list and pass indirectly on RV32. 7906c3fb27SDimitry Andric bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect; 8006c3fb27SDimitry Andric if (!IsRetIndirect && RetTy->isScalarType() && 8106c3fb27SDimitry Andric getContext().getTypeSize(RetTy) > (2 * XLen)) { 8206c3fb27SDimitry Andric if (RetTy->isComplexType() && FLen) { 8306c3fb27SDimitry Andric QualType EltTy = RetTy->castAs<ComplexType>()->getElementType(); 8406c3fb27SDimitry Andric IsRetIndirect = getContext().getTypeSize(EltTy) > FLen; 8506c3fb27SDimitry Andric } else { 8606c3fb27SDimitry Andric // This is a normal scalar > 2*XLen, such as fp128 on RV32. 8706c3fb27SDimitry Andric IsRetIndirect = true; 8806c3fb27SDimitry Andric } 8906c3fb27SDimitry Andric } 9006c3fb27SDimitry Andric 9106c3fb27SDimitry Andric int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs; 927a6dacacSDimitry Andric int ArgFPRsLeft = NumArgFPRs; 9306c3fb27SDimitry Andric int NumFixedArgs = FI.getNumRequiredArgs(); 9406c3fb27SDimitry Andric 9506c3fb27SDimitry Andric int ArgNum = 0; 9606c3fb27SDimitry Andric for (auto &ArgInfo : FI.arguments()) { 9706c3fb27SDimitry Andric bool IsFixed = ArgNum < NumFixedArgs; 9806c3fb27SDimitry Andric ArgInfo.info = 9906c3fb27SDimitry Andric classifyArgumentType(ArgInfo.type, IsFixed, ArgGPRsLeft, ArgFPRsLeft); 10006c3fb27SDimitry Andric ArgNum++; 10106c3fb27SDimitry Andric } 10206c3fb27SDimitry Andric } 10306c3fb27SDimitry Andric 10406c3fb27SDimitry Andric // Returns true if the struct is a potential candidate for the floating point 10506c3fb27SDimitry Andric // calling convention. If this function returns true, the caller is 10606c3fb27SDimitry Andric // responsible for checking that if there is only a single field then that 10706c3fb27SDimitry Andric // field is a float. 10806c3fb27SDimitry Andric bool RISCVABIInfo::detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff, 10906c3fb27SDimitry Andric llvm::Type *&Field1Ty, 11006c3fb27SDimitry Andric CharUnits &Field1Off, 11106c3fb27SDimitry Andric llvm::Type *&Field2Ty, 11206c3fb27SDimitry Andric CharUnits &Field2Off) const { 11306c3fb27SDimitry Andric bool IsInt = Ty->isIntegralOrEnumerationType(); 11406c3fb27SDimitry Andric bool IsFloat = Ty->isRealFloatingType(); 11506c3fb27SDimitry Andric 11606c3fb27SDimitry Andric if (IsInt || IsFloat) { 11706c3fb27SDimitry Andric uint64_t Size = getContext().getTypeSize(Ty); 11806c3fb27SDimitry Andric if (IsInt && Size > XLen) 11906c3fb27SDimitry Andric return false; 12006c3fb27SDimitry Andric // Can't be eligible if larger than the FP registers. Handling of half 12106c3fb27SDimitry Andric // precision values has been specified in the ABI, so don't block those. 12206c3fb27SDimitry Andric if (IsFloat && Size > FLen) 12306c3fb27SDimitry Andric return false; 12406c3fb27SDimitry Andric // Can't be eligible if an integer type was already found (int+int pairs 12506c3fb27SDimitry Andric // are not eligible). 12606c3fb27SDimitry Andric if (IsInt && Field1Ty && Field1Ty->isIntegerTy()) 12706c3fb27SDimitry Andric return false; 12806c3fb27SDimitry Andric if (!Field1Ty) { 12906c3fb27SDimitry Andric Field1Ty = CGT.ConvertType(Ty); 13006c3fb27SDimitry Andric Field1Off = CurOff; 13106c3fb27SDimitry Andric return true; 13206c3fb27SDimitry Andric } 13306c3fb27SDimitry Andric if (!Field2Ty) { 13406c3fb27SDimitry Andric Field2Ty = CGT.ConvertType(Ty); 13506c3fb27SDimitry Andric Field2Off = CurOff; 13606c3fb27SDimitry Andric return true; 13706c3fb27SDimitry Andric } 13806c3fb27SDimitry Andric return false; 13906c3fb27SDimitry Andric } 14006c3fb27SDimitry Andric 14106c3fb27SDimitry Andric if (auto CTy = Ty->getAs<ComplexType>()) { 14206c3fb27SDimitry Andric if (Field1Ty) 14306c3fb27SDimitry Andric return false; 14406c3fb27SDimitry Andric QualType EltTy = CTy->getElementType(); 14506c3fb27SDimitry Andric if (getContext().getTypeSize(EltTy) > FLen) 14606c3fb27SDimitry Andric return false; 14706c3fb27SDimitry Andric Field1Ty = CGT.ConvertType(EltTy); 14806c3fb27SDimitry Andric Field1Off = CurOff; 14906c3fb27SDimitry Andric Field2Ty = Field1Ty; 15006c3fb27SDimitry Andric Field2Off = Field1Off + getContext().getTypeSizeInChars(EltTy); 15106c3fb27SDimitry Andric return true; 15206c3fb27SDimitry Andric } 15306c3fb27SDimitry Andric 15406c3fb27SDimitry Andric if (const ConstantArrayType *ATy = getContext().getAsConstantArrayType(Ty)) { 155*0fca6ea1SDimitry Andric uint64_t ArraySize = ATy->getZExtSize(); 15606c3fb27SDimitry Andric QualType EltTy = ATy->getElementType(); 1578a4dda33SDimitry Andric // Non-zero-length arrays of empty records make the struct ineligible for 1588a4dda33SDimitry Andric // the FP calling convention in C++. 1598a4dda33SDimitry Andric if (const auto *RTy = EltTy->getAs<RecordType>()) { 1608a4dda33SDimitry Andric if (ArraySize != 0 && isa<CXXRecordDecl>(RTy->getDecl()) && 1618a4dda33SDimitry Andric isEmptyRecord(getContext(), EltTy, true, true)) 1628a4dda33SDimitry Andric return false; 1638a4dda33SDimitry Andric } 16406c3fb27SDimitry Andric CharUnits EltSize = getContext().getTypeSizeInChars(EltTy); 16506c3fb27SDimitry Andric for (uint64_t i = 0; i < ArraySize; ++i) { 16606c3fb27SDimitry Andric bool Ret = detectFPCCEligibleStructHelper(EltTy, CurOff, Field1Ty, 16706c3fb27SDimitry Andric Field1Off, Field2Ty, Field2Off); 16806c3fb27SDimitry Andric if (!Ret) 16906c3fb27SDimitry Andric return false; 17006c3fb27SDimitry Andric CurOff += EltSize; 17106c3fb27SDimitry Andric } 17206c3fb27SDimitry Andric return true; 17306c3fb27SDimitry Andric } 17406c3fb27SDimitry Andric 17506c3fb27SDimitry Andric if (const auto *RTy = Ty->getAs<RecordType>()) { 17606c3fb27SDimitry Andric // Structures with either a non-trivial destructor or a non-trivial 17706c3fb27SDimitry Andric // copy constructor are not eligible for the FP calling convention. 17806c3fb27SDimitry Andric if (getRecordArgABI(Ty, CGT.getCXXABI())) 17906c3fb27SDimitry Andric return false; 1808a4dda33SDimitry Andric if (isEmptyRecord(getContext(), Ty, true, true)) 18106c3fb27SDimitry Andric return true; 18206c3fb27SDimitry Andric const RecordDecl *RD = RTy->getDecl(); 18306c3fb27SDimitry Andric // Unions aren't eligible unless they're empty (which is caught above). 18406c3fb27SDimitry Andric if (RD->isUnion()) 18506c3fb27SDimitry Andric return false; 18606c3fb27SDimitry Andric const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); 18706c3fb27SDimitry Andric // If this is a C++ record, check the bases first. 18806c3fb27SDimitry Andric if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { 18906c3fb27SDimitry Andric for (const CXXBaseSpecifier &B : CXXRD->bases()) { 19006c3fb27SDimitry Andric const auto *BDecl = 19106c3fb27SDimitry Andric cast<CXXRecordDecl>(B.getType()->castAs<RecordType>()->getDecl()); 19206c3fb27SDimitry Andric CharUnits BaseOff = Layout.getBaseClassOffset(BDecl); 19306c3fb27SDimitry Andric bool Ret = detectFPCCEligibleStructHelper(B.getType(), CurOff + BaseOff, 19406c3fb27SDimitry Andric Field1Ty, Field1Off, Field2Ty, 19506c3fb27SDimitry Andric Field2Off); 19606c3fb27SDimitry Andric if (!Ret) 19706c3fb27SDimitry Andric return false; 19806c3fb27SDimitry Andric } 19906c3fb27SDimitry Andric } 20006c3fb27SDimitry Andric int ZeroWidthBitFieldCount = 0; 20106c3fb27SDimitry Andric for (const FieldDecl *FD : RD->fields()) { 20206c3fb27SDimitry Andric uint64_t FieldOffInBits = Layout.getFieldOffset(FD->getFieldIndex()); 20306c3fb27SDimitry Andric QualType QTy = FD->getType(); 20406c3fb27SDimitry Andric if (FD->isBitField()) { 20506c3fb27SDimitry Andric unsigned BitWidth = FD->getBitWidthValue(getContext()); 20606c3fb27SDimitry Andric // Allow a bitfield with a type greater than XLen as long as the 20706c3fb27SDimitry Andric // bitwidth is XLen or less. 20806c3fb27SDimitry Andric if (getContext().getTypeSize(QTy) > XLen && BitWidth <= XLen) 20906c3fb27SDimitry Andric QTy = getContext().getIntTypeForBitwidth(XLen, false); 21006c3fb27SDimitry Andric if (BitWidth == 0) { 21106c3fb27SDimitry Andric ZeroWidthBitFieldCount++; 21206c3fb27SDimitry Andric continue; 21306c3fb27SDimitry Andric } 21406c3fb27SDimitry Andric } 21506c3fb27SDimitry Andric 21606c3fb27SDimitry Andric bool Ret = detectFPCCEligibleStructHelper( 21706c3fb27SDimitry Andric QTy, CurOff + getContext().toCharUnitsFromBits(FieldOffInBits), 21806c3fb27SDimitry Andric Field1Ty, Field1Off, Field2Ty, Field2Off); 21906c3fb27SDimitry Andric if (!Ret) 22006c3fb27SDimitry Andric return false; 22106c3fb27SDimitry Andric 22206c3fb27SDimitry Andric // As a quirk of the ABI, zero-width bitfields aren't ignored for fp+fp 22306c3fb27SDimitry Andric // or int+fp structs, but are ignored for a struct with an fp field and 22406c3fb27SDimitry Andric // any number of zero-width bitfields. 22506c3fb27SDimitry Andric if (Field2Ty && ZeroWidthBitFieldCount > 0) 22606c3fb27SDimitry Andric return false; 22706c3fb27SDimitry Andric } 22806c3fb27SDimitry Andric return Field1Ty != nullptr; 22906c3fb27SDimitry Andric } 23006c3fb27SDimitry Andric 23106c3fb27SDimitry Andric return false; 23206c3fb27SDimitry Andric } 23306c3fb27SDimitry Andric 23406c3fb27SDimitry Andric // Determine if a struct is eligible for passing according to the floating 23506c3fb27SDimitry Andric // point calling convention (i.e., when flattened it contains a single fp 23606c3fb27SDimitry Andric // value, fp+fp, or int+fp of appropriate size). If so, NeededArgFPRs and 23706c3fb27SDimitry Andric // NeededArgGPRs are incremented appropriately. 23806c3fb27SDimitry Andric bool RISCVABIInfo::detectFPCCEligibleStruct(QualType Ty, llvm::Type *&Field1Ty, 23906c3fb27SDimitry Andric CharUnits &Field1Off, 24006c3fb27SDimitry Andric llvm::Type *&Field2Ty, 24106c3fb27SDimitry Andric CharUnits &Field2Off, 24206c3fb27SDimitry Andric int &NeededArgGPRs, 24306c3fb27SDimitry Andric int &NeededArgFPRs) const { 24406c3fb27SDimitry Andric Field1Ty = nullptr; 24506c3fb27SDimitry Andric Field2Ty = nullptr; 24606c3fb27SDimitry Andric NeededArgGPRs = 0; 24706c3fb27SDimitry Andric NeededArgFPRs = 0; 24806c3fb27SDimitry Andric bool IsCandidate = detectFPCCEligibleStructHelper( 24906c3fb27SDimitry Andric Ty, CharUnits::Zero(), Field1Ty, Field1Off, Field2Ty, Field2Off); 2508a4dda33SDimitry Andric if (!Field1Ty) 2518a4dda33SDimitry Andric return false; 25206c3fb27SDimitry Andric // Not really a candidate if we have a single int but no float. 25306c3fb27SDimitry Andric if (Field1Ty && !Field2Ty && !Field1Ty->isFloatingPointTy()) 25406c3fb27SDimitry Andric return false; 25506c3fb27SDimitry Andric if (!IsCandidate) 25606c3fb27SDimitry Andric return false; 25706c3fb27SDimitry Andric if (Field1Ty && Field1Ty->isFloatingPointTy()) 25806c3fb27SDimitry Andric NeededArgFPRs++; 25906c3fb27SDimitry Andric else if (Field1Ty) 26006c3fb27SDimitry Andric NeededArgGPRs++; 26106c3fb27SDimitry Andric if (Field2Ty && Field2Ty->isFloatingPointTy()) 26206c3fb27SDimitry Andric NeededArgFPRs++; 26306c3fb27SDimitry Andric else if (Field2Ty) 26406c3fb27SDimitry Andric NeededArgGPRs++; 26506c3fb27SDimitry Andric return true; 26606c3fb27SDimitry Andric } 26706c3fb27SDimitry Andric 26806c3fb27SDimitry Andric // Call getCoerceAndExpand for the two-element flattened struct described by 26906c3fb27SDimitry Andric // Field1Ty, Field1Off, Field2Ty, Field2Off. This method will create an 27006c3fb27SDimitry Andric // appropriate coerceToType and unpaddedCoerceToType. 27106c3fb27SDimitry Andric ABIArgInfo RISCVABIInfo::coerceAndExpandFPCCEligibleStruct( 27206c3fb27SDimitry Andric llvm::Type *Field1Ty, CharUnits Field1Off, llvm::Type *Field2Ty, 27306c3fb27SDimitry Andric CharUnits Field2Off) const { 27406c3fb27SDimitry Andric SmallVector<llvm::Type *, 3> CoerceElts; 27506c3fb27SDimitry Andric SmallVector<llvm::Type *, 2> UnpaddedCoerceElts; 27606c3fb27SDimitry Andric if (!Field1Off.isZero()) 27706c3fb27SDimitry Andric CoerceElts.push_back(llvm::ArrayType::get( 27806c3fb27SDimitry Andric llvm::Type::getInt8Ty(getVMContext()), Field1Off.getQuantity())); 27906c3fb27SDimitry Andric 28006c3fb27SDimitry Andric CoerceElts.push_back(Field1Ty); 28106c3fb27SDimitry Andric UnpaddedCoerceElts.push_back(Field1Ty); 28206c3fb27SDimitry Andric 28306c3fb27SDimitry Andric if (!Field2Ty) { 28406c3fb27SDimitry Andric return ABIArgInfo::getCoerceAndExpand( 28506c3fb27SDimitry Andric llvm::StructType::get(getVMContext(), CoerceElts, !Field1Off.isZero()), 28606c3fb27SDimitry Andric UnpaddedCoerceElts[0]); 28706c3fb27SDimitry Andric } 28806c3fb27SDimitry Andric 28906c3fb27SDimitry Andric CharUnits Field2Align = 29006c3fb27SDimitry Andric CharUnits::fromQuantity(getDataLayout().getABITypeAlign(Field2Ty)); 29106c3fb27SDimitry Andric CharUnits Field1End = Field1Off + 29206c3fb27SDimitry Andric CharUnits::fromQuantity(getDataLayout().getTypeStoreSize(Field1Ty)); 29306c3fb27SDimitry Andric CharUnits Field2OffNoPadNoPack = Field1End.alignTo(Field2Align); 29406c3fb27SDimitry Andric 29506c3fb27SDimitry Andric CharUnits Padding = CharUnits::Zero(); 29606c3fb27SDimitry Andric if (Field2Off > Field2OffNoPadNoPack) 29706c3fb27SDimitry Andric Padding = Field2Off - Field2OffNoPadNoPack; 29806c3fb27SDimitry Andric else if (Field2Off != Field2Align && Field2Off > Field1End) 29906c3fb27SDimitry Andric Padding = Field2Off - Field1End; 30006c3fb27SDimitry Andric 30106c3fb27SDimitry Andric bool IsPacked = !Field2Off.isMultipleOf(Field2Align); 30206c3fb27SDimitry Andric 30306c3fb27SDimitry Andric if (!Padding.isZero()) 30406c3fb27SDimitry Andric CoerceElts.push_back(llvm::ArrayType::get( 30506c3fb27SDimitry Andric llvm::Type::getInt8Ty(getVMContext()), Padding.getQuantity())); 30606c3fb27SDimitry Andric 30706c3fb27SDimitry Andric CoerceElts.push_back(Field2Ty); 30806c3fb27SDimitry Andric UnpaddedCoerceElts.push_back(Field2Ty); 30906c3fb27SDimitry Andric 31006c3fb27SDimitry Andric auto CoerceToType = 31106c3fb27SDimitry Andric llvm::StructType::get(getVMContext(), CoerceElts, IsPacked); 31206c3fb27SDimitry Andric auto UnpaddedCoerceToType = 31306c3fb27SDimitry Andric llvm::StructType::get(getVMContext(), UnpaddedCoerceElts, IsPacked); 31406c3fb27SDimitry Andric 31506c3fb27SDimitry Andric return ABIArgInfo::getCoerceAndExpand(CoerceToType, UnpaddedCoerceToType); 31606c3fb27SDimitry Andric } 31706c3fb27SDimitry Andric 31806c3fb27SDimitry Andric // Fixed-length RVV vectors are represented as scalable vectors in function 31906c3fb27SDimitry Andric // args/return and must be coerced from fixed vectors. 32006c3fb27SDimitry Andric ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty) const { 32106c3fb27SDimitry Andric assert(Ty->isVectorType() && "expected vector type!"); 32206c3fb27SDimitry Andric 32306c3fb27SDimitry Andric const auto *VT = Ty->castAs<VectorType>(); 32406c3fb27SDimitry Andric assert(VT->getElementType()->isBuiltinType() && "expected builtin type!"); 32506c3fb27SDimitry Andric 3268a4dda33SDimitry Andric auto VScale = 3278a4dda33SDimitry Andric getContext().getTargetInfo().getVScaleRange(getContext().getLangOpts()); 328b3edf446SDimitry Andric 329b3edf446SDimitry Andric unsigned NumElts = VT->getNumElements(); 330b3edf446SDimitry Andric llvm::Type *EltType; 331b3edf446SDimitry Andric if (VT->getVectorKind() == VectorKind::RVVFixedLengthMask) { 332b3edf446SDimitry Andric NumElts *= 8; 333b3edf446SDimitry Andric EltType = llvm::Type::getInt1Ty(getVMContext()); 334b3edf446SDimitry Andric } else { 335b3edf446SDimitry Andric assert(VT->getVectorKind() == VectorKind::RVVFixedLengthData && 336b3edf446SDimitry Andric "Unexpected vector kind"); 337b3edf446SDimitry Andric EltType = CGT.ConvertType(VT->getElementType()); 338b3edf446SDimitry Andric } 339b3edf446SDimitry Andric 3408a4dda33SDimitry Andric // The MinNumElts is simplified from equation: 3418a4dda33SDimitry Andric // NumElts / VScale = 3428a4dda33SDimitry Andric // (EltSize * NumElts / (VScale * RVVBitsPerBlock)) 3438a4dda33SDimitry Andric // * (RVVBitsPerBlock / EltSize) 34406c3fb27SDimitry Andric llvm::ScalableVectorType *ResType = 345b3edf446SDimitry Andric llvm::ScalableVectorType::get(EltType, NumElts / VScale->first); 34606c3fb27SDimitry Andric return ABIArgInfo::getDirect(ResType); 34706c3fb27SDimitry Andric } 34806c3fb27SDimitry Andric 34906c3fb27SDimitry Andric ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, 35006c3fb27SDimitry Andric int &ArgGPRsLeft, 35106c3fb27SDimitry Andric int &ArgFPRsLeft) const { 35206c3fb27SDimitry Andric assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow"); 35306c3fb27SDimitry Andric Ty = useFirstFieldIfTransparentUnion(Ty); 35406c3fb27SDimitry Andric 35506c3fb27SDimitry Andric // Structures with either a non-trivial destructor or a non-trivial 35606c3fb27SDimitry Andric // copy constructor are always passed indirectly. 35706c3fb27SDimitry Andric if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) { 35806c3fb27SDimitry Andric if (ArgGPRsLeft) 35906c3fb27SDimitry Andric ArgGPRsLeft -= 1; 36006c3fb27SDimitry Andric return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA == 36106c3fb27SDimitry Andric CGCXXABI::RAA_DirectInMemory); 36206c3fb27SDimitry Andric } 36306c3fb27SDimitry Andric 36406c3fb27SDimitry Andric uint64_t Size = getContext().getTypeSize(Ty); 36506c3fb27SDimitry Andric 366*0fca6ea1SDimitry Andric // Ignore empty structs/unions whose size is zero. According to the calling 367*0fca6ea1SDimitry Andric // convention empty structs/unions are required to be sized types in C++. 368*0fca6ea1SDimitry Andric if (isEmptyRecord(getContext(), Ty, true) && Size == 0) 369*0fca6ea1SDimitry Andric return ABIArgInfo::getIgnore(); 370*0fca6ea1SDimitry Andric 37106c3fb27SDimitry Andric // Pass floating point values via FPRs if possible. 37206c3fb27SDimitry Andric if (IsFixed && Ty->isFloatingType() && !Ty->isComplexType() && 37306c3fb27SDimitry Andric FLen >= Size && ArgFPRsLeft) { 37406c3fb27SDimitry Andric ArgFPRsLeft--; 37506c3fb27SDimitry Andric return ABIArgInfo::getDirect(); 37606c3fb27SDimitry Andric } 37706c3fb27SDimitry Andric 37806c3fb27SDimitry Andric // Complex types for the hard float ABI must be passed direct rather than 37906c3fb27SDimitry Andric // using CoerceAndExpand. 38006c3fb27SDimitry Andric if (IsFixed && Ty->isComplexType() && FLen && ArgFPRsLeft >= 2) { 38106c3fb27SDimitry Andric QualType EltTy = Ty->castAs<ComplexType>()->getElementType(); 38206c3fb27SDimitry Andric if (getContext().getTypeSize(EltTy) <= FLen) { 38306c3fb27SDimitry Andric ArgFPRsLeft -= 2; 38406c3fb27SDimitry Andric return ABIArgInfo::getDirect(); 38506c3fb27SDimitry Andric } 38606c3fb27SDimitry Andric } 38706c3fb27SDimitry Andric 38806c3fb27SDimitry Andric if (IsFixed && FLen && Ty->isStructureOrClassType()) { 38906c3fb27SDimitry Andric llvm::Type *Field1Ty = nullptr; 39006c3fb27SDimitry Andric llvm::Type *Field2Ty = nullptr; 39106c3fb27SDimitry Andric CharUnits Field1Off = CharUnits::Zero(); 39206c3fb27SDimitry Andric CharUnits Field2Off = CharUnits::Zero(); 39306c3fb27SDimitry Andric int NeededArgGPRs = 0; 39406c3fb27SDimitry Andric int NeededArgFPRs = 0; 39506c3fb27SDimitry Andric bool IsCandidate = 39606c3fb27SDimitry Andric detectFPCCEligibleStruct(Ty, Field1Ty, Field1Off, Field2Ty, Field2Off, 39706c3fb27SDimitry Andric NeededArgGPRs, NeededArgFPRs); 39806c3fb27SDimitry Andric if (IsCandidate && NeededArgGPRs <= ArgGPRsLeft && 39906c3fb27SDimitry Andric NeededArgFPRs <= ArgFPRsLeft) { 40006c3fb27SDimitry Andric ArgGPRsLeft -= NeededArgGPRs; 40106c3fb27SDimitry Andric ArgFPRsLeft -= NeededArgFPRs; 40206c3fb27SDimitry Andric return coerceAndExpandFPCCEligibleStruct(Field1Ty, Field1Off, Field2Ty, 40306c3fb27SDimitry Andric Field2Off); 40406c3fb27SDimitry Andric } 40506c3fb27SDimitry Andric } 40606c3fb27SDimitry Andric 40706c3fb27SDimitry Andric uint64_t NeededAlign = getContext().getTypeAlign(Ty); 40806c3fb27SDimitry Andric // Determine the number of GPRs needed to pass the current argument 40906c3fb27SDimitry Andric // according to the ABI. 2*XLen-aligned varargs are passed in "aligned" 41006c3fb27SDimitry Andric // register pairs, so may consume 3 registers. 4117a6dacacSDimitry Andric // TODO: To be compatible with GCC's behaviors, we don't align registers 4127a6dacacSDimitry Andric // currently if we are using ILP32E calling convention. This behavior may be 4137a6dacacSDimitry Andric // changed when RV32E/ILP32E is ratified. 41406c3fb27SDimitry Andric int NeededArgGPRs = 1; 41506c3fb27SDimitry Andric if (!IsFixed && NeededAlign == 2 * XLen) 4167a6dacacSDimitry Andric NeededArgGPRs = 2 + (EABI && XLen == 32 ? 0 : (ArgGPRsLeft % 2)); 41706c3fb27SDimitry Andric else if (Size > XLen && Size <= 2 * XLen) 41806c3fb27SDimitry Andric NeededArgGPRs = 2; 41906c3fb27SDimitry Andric 42006c3fb27SDimitry Andric if (NeededArgGPRs > ArgGPRsLeft) { 42106c3fb27SDimitry Andric NeededArgGPRs = ArgGPRsLeft; 42206c3fb27SDimitry Andric } 42306c3fb27SDimitry Andric 42406c3fb27SDimitry Andric ArgGPRsLeft -= NeededArgGPRs; 42506c3fb27SDimitry Andric 42606c3fb27SDimitry Andric if (!isAggregateTypeForABI(Ty) && !Ty->isVectorType()) { 42706c3fb27SDimitry Andric // Treat an enum type as its underlying type. 42806c3fb27SDimitry Andric if (const EnumType *EnumTy = Ty->getAs<EnumType>()) 42906c3fb27SDimitry Andric Ty = EnumTy->getDecl()->getIntegerType(); 43006c3fb27SDimitry Andric 43106c3fb27SDimitry Andric // All integral types are promoted to XLen width 43206c3fb27SDimitry Andric if (Size < XLen && Ty->isIntegralOrEnumerationType()) { 43306c3fb27SDimitry Andric return extendType(Ty); 43406c3fb27SDimitry Andric } 43506c3fb27SDimitry Andric 43606c3fb27SDimitry Andric if (const auto *EIT = Ty->getAs<BitIntType>()) { 43706c3fb27SDimitry Andric if (EIT->getNumBits() < XLen) 43806c3fb27SDimitry Andric return extendType(Ty); 43906c3fb27SDimitry Andric if (EIT->getNumBits() > 128 || 44006c3fb27SDimitry Andric (!getContext().getTargetInfo().hasInt128Type() && 44106c3fb27SDimitry Andric EIT->getNumBits() > 64)) 44206c3fb27SDimitry Andric return getNaturalAlignIndirect(Ty, /*ByVal=*/false); 44306c3fb27SDimitry Andric } 44406c3fb27SDimitry Andric 445*0fca6ea1SDimitry Andric ABIArgInfo Info = ABIArgInfo::getDirect(); 446*0fca6ea1SDimitry Andric 447*0fca6ea1SDimitry Andric // If it is tuple type, it can't be flattened. 448*0fca6ea1SDimitry Andric if (llvm::StructType *STy = dyn_cast<llvm::StructType>(CGT.ConvertType(Ty))) 449*0fca6ea1SDimitry Andric Info.setCanBeFlattened(!STy->containsHomogeneousScalableVectorTypes()); 450*0fca6ea1SDimitry Andric 451*0fca6ea1SDimitry Andric return Info; 45206c3fb27SDimitry Andric } 45306c3fb27SDimitry Andric 45406c3fb27SDimitry Andric if (const VectorType *VT = Ty->getAs<VectorType>()) 455b3edf446SDimitry Andric if (VT->getVectorKind() == VectorKind::RVVFixedLengthData || 456b3edf446SDimitry Andric VT->getVectorKind() == VectorKind::RVVFixedLengthMask) 45706c3fb27SDimitry Andric return coerceVLSVector(Ty); 45806c3fb27SDimitry Andric 45906c3fb27SDimitry Andric // Aggregates which are <= 2*XLen will be passed in registers if possible, 46006c3fb27SDimitry Andric // so coerce to integers. 46106c3fb27SDimitry Andric if (Size <= 2 * XLen) { 46206c3fb27SDimitry Andric unsigned Alignment = getContext().getTypeAlign(Ty); 46306c3fb27SDimitry Andric 46406c3fb27SDimitry Andric // Use a single XLen int if possible, 2*XLen if 2*XLen alignment is 46506c3fb27SDimitry Andric // required, and a 2-element XLen array if only XLen alignment is required. 46606c3fb27SDimitry Andric if (Size <= XLen) { 46706c3fb27SDimitry Andric return ABIArgInfo::getDirect( 46806c3fb27SDimitry Andric llvm::IntegerType::get(getVMContext(), XLen)); 46906c3fb27SDimitry Andric } else if (Alignment == 2 * XLen) { 47006c3fb27SDimitry Andric return ABIArgInfo::getDirect( 47106c3fb27SDimitry Andric llvm::IntegerType::get(getVMContext(), 2 * XLen)); 47206c3fb27SDimitry Andric } else { 47306c3fb27SDimitry Andric return ABIArgInfo::getDirect(llvm::ArrayType::get( 47406c3fb27SDimitry Andric llvm::IntegerType::get(getVMContext(), XLen), 2)); 47506c3fb27SDimitry Andric } 47606c3fb27SDimitry Andric } 47706c3fb27SDimitry Andric return getNaturalAlignIndirect(Ty, /*ByVal=*/false); 47806c3fb27SDimitry Andric } 47906c3fb27SDimitry Andric 48006c3fb27SDimitry Andric ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy) const { 48106c3fb27SDimitry Andric if (RetTy->isVoidType()) 48206c3fb27SDimitry Andric return ABIArgInfo::getIgnore(); 48306c3fb27SDimitry Andric 48406c3fb27SDimitry Andric int ArgGPRsLeft = 2; 48506c3fb27SDimitry Andric int ArgFPRsLeft = FLen ? 2 : 0; 48606c3fb27SDimitry Andric 48706c3fb27SDimitry Andric // The rules for return and argument types are the same, so defer to 48806c3fb27SDimitry Andric // classifyArgumentType. 48906c3fb27SDimitry Andric return classifyArgumentType(RetTy, /*IsFixed=*/true, ArgGPRsLeft, 49006c3fb27SDimitry Andric ArgFPRsLeft); 49106c3fb27SDimitry Andric } 49206c3fb27SDimitry Andric 493*0fca6ea1SDimitry Andric RValue RISCVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, 494*0fca6ea1SDimitry Andric QualType Ty, AggValueSlot Slot) const { 49506c3fb27SDimitry Andric CharUnits SlotSize = CharUnits::fromQuantity(XLen / 8); 49606c3fb27SDimitry Andric 49706c3fb27SDimitry Andric // Empty records are ignored for parameter passing purposes. 498*0fca6ea1SDimitry Andric if (isEmptyRecord(getContext(), Ty, true)) 499*0fca6ea1SDimitry Andric return Slot.asRValue(); 50006c3fb27SDimitry Andric 50106c3fb27SDimitry Andric auto TInfo = getContext().getTypeInfoInChars(Ty); 50206c3fb27SDimitry Andric 5037a6dacacSDimitry Andric // TODO: To be compatible with GCC's behaviors, we force arguments with 5047a6dacacSDimitry Andric // 2×XLEN-bit alignment and size at most 2×XLEN bits like `long long`, 5057a6dacacSDimitry Andric // `unsigned long long` and `double` to have 4-byte alignment. This 5067a6dacacSDimitry Andric // behavior may be changed when RV32E/ILP32E is ratified. 5077a6dacacSDimitry Andric if (EABI && XLen == 32) 5087a6dacacSDimitry Andric TInfo.Align = std::min(TInfo.Align, CharUnits::fromQuantity(4)); 5097a6dacacSDimitry Andric 51006c3fb27SDimitry Andric // Arguments bigger than 2*Xlen bytes are passed indirectly. 51106c3fb27SDimitry Andric bool IsIndirect = TInfo.Width > 2 * SlotSize; 51206c3fb27SDimitry Andric 513*0fca6ea1SDimitry Andric return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect, TInfo, SlotSize, 514*0fca6ea1SDimitry Andric /*AllowHigherAlign=*/true, Slot); 51506c3fb27SDimitry Andric } 51606c3fb27SDimitry Andric 51706c3fb27SDimitry Andric ABIArgInfo RISCVABIInfo::extendType(QualType Ty) const { 51806c3fb27SDimitry Andric int TySize = getContext().getTypeSize(Ty); 51906c3fb27SDimitry Andric // RV64 ABI requires unsigned 32 bit integers to be sign extended. 52006c3fb27SDimitry Andric if (XLen == 64 && Ty->isUnsignedIntegerOrEnumerationType() && TySize == 32) 52106c3fb27SDimitry Andric return ABIArgInfo::getSignExtend(Ty); 52206c3fb27SDimitry Andric return ABIArgInfo::getExtend(Ty); 52306c3fb27SDimitry Andric } 52406c3fb27SDimitry Andric 52506c3fb27SDimitry Andric namespace { 52606c3fb27SDimitry Andric class RISCVTargetCodeGenInfo : public TargetCodeGenInfo { 52706c3fb27SDimitry Andric public: 52806c3fb27SDimitry Andric RISCVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, 5297a6dacacSDimitry Andric unsigned FLen, bool EABI) 5307a6dacacSDimitry Andric : TargetCodeGenInfo( 531*0fca6ea1SDimitry Andric std::make_unique<RISCVABIInfo>(CGT, XLen, FLen, EABI)) { 532*0fca6ea1SDimitry Andric SwiftInfo = 533*0fca6ea1SDimitry Andric std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false); 534*0fca6ea1SDimitry Andric } 53506c3fb27SDimitry Andric 53606c3fb27SDimitry Andric void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, 53706c3fb27SDimitry Andric CodeGen::CodeGenModule &CGM) const override { 53806c3fb27SDimitry Andric const auto *FD = dyn_cast_or_null<FunctionDecl>(D); 53906c3fb27SDimitry Andric if (!FD) return; 54006c3fb27SDimitry Andric 54106c3fb27SDimitry Andric const auto *Attr = FD->getAttr<RISCVInterruptAttr>(); 54206c3fb27SDimitry Andric if (!Attr) 54306c3fb27SDimitry Andric return; 54406c3fb27SDimitry Andric 54506c3fb27SDimitry Andric const char *Kind; 54606c3fb27SDimitry Andric switch (Attr->getInterrupt()) { 54706c3fb27SDimitry Andric case RISCVInterruptAttr::supervisor: Kind = "supervisor"; break; 54806c3fb27SDimitry Andric case RISCVInterruptAttr::machine: Kind = "machine"; break; 54906c3fb27SDimitry Andric } 55006c3fb27SDimitry Andric 55106c3fb27SDimitry Andric auto *Fn = cast<llvm::Function>(GV); 55206c3fb27SDimitry Andric 55306c3fb27SDimitry Andric Fn->addFnAttr("interrupt", Kind); 55406c3fb27SDimitry Andric } 55506c3fb27SDimitry Andric }; 55606c3fb27SDimitry Andric } // namespace 55706c3fb27SDimitry Andric 55806c3fb27SDimitry Andric std::unique_ptr<TargetCodeGenInfo> 55906c3fb27SDimitry Andric CodeGen::createRISCVTargetCodeGenInfo(CodeGenModule &CGM, unsigned XLen, 5607a6dacacSDimitry Andric unsigned FLen, bool EABI) { 5617a6dacacSDimitry Andric return std::make_unique<RISCVTargetCodeGenInfo>(CGM.getTypes(), XLen, FLen, 5627a6dacacSDimitry Andric EABI); 56306c3fb27SDimitry Andric } 564