xref: /freebsd-src/contrib/llvm-project/clang/lib/CodeGen/Targets/RISCV.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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;
2806c3fb27SDimitry Andric   static const int NumArgGPRs = 8;
2906c3fb27SDimitry Andric   static const int NumArgFPRs = 8;
3006c3fb27SDimitry Andric   bool detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff,
3106c3fb27SDimitry Andric                                       llvm::Type *&Field1Ty,
3206c3fb27SDimitry Andric                                       CharUnits &Field1Off,
3306c3fb27SDimitry Andric                                       llvm::Type *&Field2Ty,
3406c3fb27SDimitry Andric                                       CharUnits &Field2Off) const;
3506c3fb27SDimitry Andric 
3606c3fb27SDimitry Andric public:
3706c3fb27SDimitry Andric   RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen)
3806c3fb27SDimitry Andric       : DefaultABIInfo(CGT), XLen(XLen), FLen(FLen) {}
3906c3fb27SDimitry Andric 
4006c3fb27SDimitry Andric   // DefaultABIInfo's classifyReturnType and classifyArgumentType are
4106c3fb27SDimitry Andric   // non-virtual, but computeInfo is virtual, so we overload it.
4206c3fb27SDimitry Andric   void computeInfo(CGFunctionInfo &FI) const override;
4306c3fb27SDimitry Andric 
4406c3fb27SDimitry Andric   ABIArgInfo classifyArgumentType(QualType Ty, bool IsFixed, int &ArgGPRsLeft,
4506c3fb27SDimitry Andric                                   int &ArgFPRsLeft) const;
4606c3fb27SDimitry Andric   ABIArgInfo classifyReturnType(QualType RetTy) const;
4706c3fb27SDimitry Andric 
4806c3fb27SDimitry Andric   Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
4906c3fb27SDimitry Andric                     QualType Ty) const override;
5006c3fb27SDimitry Andric 
5106c3fb27SDimitry Andric   ABIArgInfo extendType(QualType Ty) const;
5206c3fb27SDimitry Andric 
5306c3fb27SDimitry Andric   bool detectFPCCEligibleStruct(QualType Ty, llvm::Type *&Field1Ty,
5406c3fb27SDimitry Andric                                 CharUnits &Field1Off, llvm::Type *&Field2Ty,
5506c3fb27SDimitry Andric                                 CharUnits &Field2Off, int &NeededArgGPRs,
5606c3fb27SDimitry Andric                                 int &NeededArgFPRs) const;
5706c3fb27SDimitry Andric   ABIArgInfo coerceAndExpandFPCCEligibleStruct(llvm::Type *Field1Ty,
5806c3fb27SDimitry Andric                                                CharUnits Field1Off,
5906c3fb27SDimitry Andric                                                llvm::Type *Field2Ty,
6006c3fb27SDimitry Andric                                                CharUnits Field2Off) const;
6106c3fb27SDimitry Andric 
6206c3fb27SDimitry Andric   ABIArgInfo coerceVLSVector(QualType Ty) const;
6306c3fb27SDimitry Andric };
6406c3fb27SDimitry Andric } // end anonymous namespace
6506c3fb27SDimitry Andric 
6606c3fb27SDimitry Andric void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const {
6706c3fb27SDimitry Andric   QualType RetTy = FI.getReturnType();
6806c3fb27SDimitry Andric   if (!getCXXABI().classifyReturnType(FI))
6906c3fb27SDimitry Andric     FI.getReturnInfo() = classifyReturnType(RetTy);
7006c3fb27SDimitry Andric 
7106c3fb27SDimitry Andric   // IsRetIndirect is true if classifyArgumentType indicated the value should
7206c3fb27SDimitry Andric   // be passed indirect, or if the type size is a scalar greater than 2*XLen
7306c3fb27SDimitry Andric   // and not a complex type with elements <= FLen. e.g. fp128 is passed direct
7406c3fb27SDimitry Andric   // in LLVM IR, relying on the backend lowering code to rewrite the argument
7506c3fb27SDimitry Andric   // list and pass indirectly on RV32.
7606c3fb27SDimitry Andric   bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect;
7706c3fb27SDimitry Andric   if (!IsRetIndirect && RetTy->isScalarType() &&
7806c3fb27SDimitry Andric       getContext().getTypeSize(RetTy) > (2 * XLen)) {
7906c3fb27SDimitry Andric     if (RetTy->isComplexType() && FLen) {
8006c3fb27SDimitry Andric       QualType EltTy = RetTy->castAs<ComplexType>()->getElementType();
8106c3fb27SDimitry Andric       IsRetIndirect = getContext().getTypeSize(EltTy) > FLen;
8206c3fb27SDimitry Andric     } else {
8306c3fb27SDimitry Andric       // This is a normal scalar > 2*XLen, such as fp128 on RV32.
8406c3fb27SDimitry Andric       IsRetIndirect = true;
8506c3fb27SDimitry Andric     }
8606c3fb27SDimitry Andric   }
8706c3fb27SDimitry Andric 
8806c3fb27SDimitry Andric   int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs;
8906c3fb27SDimitry Andric   int ArgFPRsLeft = FLen ? NumArgFPRs : 0;
9006c3fb27SDimitry Andric   int NumFixedArgs = FI.getNumRequiredArgs();
9106c3fb27SDimitry Andric 
9206c3fb27SDimitry Andric   int ArgNum = 0;
9306c3fb27SDimitry Andric   for (auto &ArgInfo : FI.arguments()) {
9406c3fb27SDimitry Andric     bool IsFixed = ArgNum < NumFixedArgs;
9506c3fb27SDimitry Andric     ArgInfo.info =
9606c3fb27SDimitry Andric         classifyArgumentType(ArgInfo.type, IsFixed, ArgGPRsLeft, ArgFPRsLeft);
9706c3fb27SDimitry Andric     ArgNum++;
9806c3fb27SDimitry Andric   }
9906c3fb27SDimitry Andric }
10006c3fb27SDimitry Andric 
10106c3fb27SDimitry Andric // Returns true if the struct is a potential candidate for the floating point
10206c3fb27SDimitry Andric // calling convention. If this function returns true, the caller is
10306c3fb27SDimitry Andric // responsible for checking that if there is only a single field then that
10406c3fb27SDimitry Andric // field is a float.
10506c3fb27SDimitry Andric bool RISCVABIInfo::detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff,
10606c3fb27SDimitry Andric                                                   llvm::Type *&Field1Ty,
10706c3fb27SDimitry Andric                                                   CharUnits &Field1Off,
10806c3fb27SDimitry Andric                                                   llvm::Type *&Field2Ty,
10906c3fb27SDimitry Andric                                                   CharUnits &Field2Off) const {
11006c3fb27SDimitry Andric   bool IsInt = Ty->isIntegralOrEnumerationType();
11106c3fb27SDimitry Andric   bool IsFloat = Ty->isRealFloatingType();
11206c3fb27SDimitry Andric 
11306c3fb27SDimitry Andric   if (IsInt || IsFloat) {
11406c3fb27SDimitry Andric     uint64_t Size = getContext().getTypeSize(Ty);
11506c3fb27SDimitry Andric     if (IsInt && Size > XLen)
11606c3fb27SDimitry Andric       return false;
11706c3fb27SDimitry Andric     // Can't be eligible if larger than the FP registers. Handling of half
11806c3fb27SDimitry Andric     // precision values has been specified in the ABI, so don't block those.
11906c3fb27SDimitry Andric     if (IsFloat && Size > FLen)
12006c3fb27SDimitry Andric       return false;
12106c3fb27SDimitry Andric     // Can't be eligible if an integer type was already found (int+int pairs
12206c3fb27SDimitry Andric     // are not eligible).
12306c3fb27SDimitry Andric     if (IsInt && Field1Ty && Field1Ty->isIntegerTy())
12406c3fb27SDimitry Andric       return false;
12506c3fb27SDimitry Andric     if (!Field1Ty) {
12606c3fb27SDimitry Andric       Field1Ty = CGT.ConvertType(Ty);
12706c3fb27SDimitry Andric       Field1Off = CurOff;
12806c3fb27SDimitry Andric       return true;
12906c3fb27SDimitry Andric     }
13006c3fb27SDimitry Andric     if (!Field2Ty) {
13106c3fb27SDimitry Andric       Field2Ty = CGT.ConvertType(Ty);
13206c3fb27SDimitry Andric       Field2Off = CurOff;
13306c3fb27SDimitry Andric       return true;
13406c3fb27SDimitry Andric     }
13506c3fb27SDimitry Andric     return false;
13606c3fb27SDimitry Andric   }
13706c3fb27SDimitry Andric 
13806c3fb27SDimitry Andric   if (auto CTy = Ty->getAs<ComplexType>()) {
13906c3fb27SDimitry Andric     if (Field1Ty)
14006c3fb27SDimitry Andric       return false;
14106c3fb27SDimitry Andric     QualType EltTy = CTy->getElementType();
14206c3fb27SDimitry Andric     if (getContext().getTypeSize(EltTy) > FLen)
14306c3fb27SDimitry Andric       return false;
14406c3fb27SDimitry Andric     Field1Ty = CGT.ConvertType(EltTy);
14506c3fb27SDimitry Andric     Field1Off = CurOff;
14606c3fb27SDimitry Andric     Field2Ty = Field1Ty;
14706c3fb27SDimitry Andric     Field2Off = Field1Off + getContext().getTypeSizeInChars(EltTy);
14806c3fb27SDimitry Andric     return true;
14906c3fb27SDimitry Andric   }
15006c3fb27SDimitry Andric 
15106c3fb27SDimitry Andric   if (const ConstantArrayType *ATy = getContext().getAsConstantArrayType(Ty)) {
15206c3fb27SDimitry Andric     uint64_t ArraySize = ATy->getSize().getZExtValue();
15306c3fb27SDimitry Andric     QualType EltTy = ATy->getElementType();
1548a4dda33SDimitry Andric     // Non-zero-length arrays of empty records make the struct ineligible for
1558a4dda33SDimitry Andric     // the FP calling convention in C++.
1568a4dda33SDimitry Andric     if (const auto *RTy = EltTy->getAs<RecordType>()) {
1578a4dda33SDimitry Andric       if (ArraySize != 0 && isa<CXXRecordDecl>(RTy->getDecl()) &&
1588a4dda33SDimitry Andric           isEmptyRecord(getContext(), EltTy, true, true))
1598a4dda33SDimitry Andric         return false;
1608a4dda33SDimitry Andric     }
16106c3fb27SDimitry Andric     CharUnits EltSize = getContext().getTypeSizeInChars(EltTy);
16206c3fb27SDimitry Andric     for (uint64_t i = 0; i < ArraySize; ++i) {
16306c3fb27SDimitry Andric       bool Ret = detectFPCCEligibleStructHelper(EltTy, CurOff, Field1Ty,
16406c3fb27SDimitry Andric                                                 Field1Off, Field2Ty, Field2Off);
16506c3fb27SDimitry Andric       if (!Ret)
16606c3fb27SDimitry Andric         return false;
16706c3fb27SDimitry Andric       CurOff += EltSize;
16806c3fb27SDimitry Andric     }
16906c3fb27SDimitry Andric     return true;
17006c3fb27SDimitry Andric   }
17106c3fb27SDimitry Andric 
17206c3fb27SDimitry Andric   if (const auto *RTy = Ty->getAs<RecordType>()) {
17306c3fb27SDimitry Andric     // Structures with either a non-trivial destructor or a non-trivial
17406c3fb27SDimitry Andric     // copy constructor are not eligible for the FP calling convention.
17506c3fb27SDimitry Andric     if (getRecordArgABI(Ty, CGT.getCXXABI()))
17606c3fb27SDimitry Andric       return false;
1778a4dda33SDimitry Andric     if (isEmptyRecord(getContext(), Ty, true, true))
17806c3fb27SDimitry Andric       return true;
17906c3fb27SDimitry Andric     const RecordDecl *RD = RTy->getDecl();
18006c3fb27SDimitry Andric     // Unions aren't eligible unless they're empty (which is caught above).
18106c3fb27SDimitry Andric     if (RD->isUnion())
18206c3fb27SDimitry Andric       return false;
18306c3fb27SDimitry Andric     const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
18406c3fb27SDimitry Andric     // If this is a C++ record, check the bases first.
18506c3fb27SDimitry Andric     if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
18606c3fb27SDimitry Andric       for (const CXXBaseSpecifier &B : CXXRD->bases()) {
18706c3fb27SDimitry Andric         const auto *BDecl =
18806c3fb27SDimitry Andric             cast<CXXRecordDecl>(B.getType()->castAs<RecordType>()->getDecl());
18906c3fb27SDimitry Andric         CharUnits BaseOff = Layout.getBaseClassOffset(BDecl);
19006c3fb27SDimitry Andric         bool Ret = detectFPCCEligibleStructHelper(B.getType(), CurOff + BaseOff,
19106c3fb27SDimitry Andric                                                   Field1Ty, Field1Off, Field2Ty,
19206c3fb27SDimitry Andric                                                   Field2Off);
19306c3fb27SDimitry Andric         if (!Ret)
19406c3fb27SDimitry Andric           return false;
19506c3fb27SDimitry Andric       }
19606c3fb27SDimitry Andric     }
19706c3fb27SDimitry Andric     int ZeroWidthBitFieldCount = 0;
19806c3fb27SDimitry Andric     for (const FieldDecl *FD : RD->fields()) {
19906c3fb27SDimitry Andric       uint64_t FieldOffInBits = Layout.getFieldOffset(FD->getFieldIndex());
20006c3fb27SDimitry Andric       QualType QTy = FD->getType();
20106c3fb27SDimitry Andric       if (FD->isBitField()) {
20206c3fb27SDimitry Andric         unsigned BitWidth = FD->getBitWidthValue(getContext());
20306c3fb27SDimitry Andric         // Allow a bitfield with a type greater than XLen as long as the
20406c3fb27SDimitry Andric         // bitwidth is XLen or less.
20506c3fb27SDimitry Andric         if (getContext().getTypeSize(QTy) > XLen && BitWidth <= XLen)
20606c3fb27SDimitry Andric           QTy = getContext().getIntTypeForBitwidth(XLen, false);
20706c3fb27SDimitry Andric         if (BitWidth == 0) {
20806c3fb27SDimitry Andric           ZeroWidthBitFieldCount++;
20906c3fb27SDimitry Andric           continue;
21006c3fb27SDimitry Andric         }
21106c3fb27SDimitry Andric       }
21206c3fb27SDimitry Andric 
21306c3fb27SDimitry Andric       bool Ret = detectFPCCEligibleStructHelper(
21406c3fb27SDimitry Andric           QTy, CurOff + getContext().toCharUnitsFromBits(FieldOffInBits),
21506c3fb27SDimitry Andric           Field1Ty, Field1Off, Field2Ty, Field2Off);
21606c3fb27SDimitry Andric       if (!Ret)
21706c3fb27SDimitry Andric         return false;
21806c3fb27SDimitry Andric 
21906c3fb27SDimitry Andric       // As a quirk of the ABI, zero-width bitfields aren't ignored for fp+fp
22006c3fb27SDimitry Andric       // or int+fp structs, but are ignored for a struct with an fp field and
22106c3fb27SDimitry Andric       // any number of zero-width bitfields.
22206c3fb27SDimitry Andric       if (Field2Ty && ZeroWidthBitFieldCount > 0)
22306c3fb27SDimitry Andric         return false;
22406c3fb27SDimitry Andric     }
22506c3fb27SDimitry Andric     return Field1Ty != nullptr;
22606c3fb27SDimitry Andric   }
22706c3fb27SDimitry Andric 
22806c3fb27SDimitry Andric   return false;
22906c3fb27SDimitry Andric }
23006c3fb27SDimitry Andric 
23106c3fb27SDimitry Andric // Determine if a struct is eligible for passing according to the floating
23206c3fb27SDimitry Andric // point calling convention (i.e., when flattened it contains a single fp
23306c3fb27SDimitry Andric // value, fp+fp, or int+fp of appropriate size). If so, NeededArgFPRs and
23406c3fb27SDimitry Andric // NeededArgGPRs are incremented appropriately.
23506c3fb27SDimitry Andric bool RISCVABIInfo::detectFPCCEligibleStruct(QualType Ty, llvm::Type *&Field1Ty,
23606c3fb27SDimitry Andric                                             CharUnits &Field1Off,
23706c3fb27SDimitry Andric                                             llvm::Type *&Field2Ty,
23806c3fb27SDimitry Andric                                             CharUnits &Field2Off,
23906c3fb27SDimitry Andric                                             int &NeededArgGPRs,
24006c3fb27SDimitry Andric                                             int &NeededArgFPRs) const {
24106c3fb27SDimitry Andric   Field1Ty = nullptr;
24206c3fb27SDimitry Andric   Field2Ty = nullptr;
24306c3fb27SDimitry Andric   NeededArgGPRs = 0;
24406c3fb27SDimitry Andric   NeededArgFPRs = 0;
24506c3fb27SDimitry Andric   bool IsCandidate = detectFPCCEligibleStructHelper(
24606c3fb27SDimitry Andric       Ty, CharUnits::Zero(), Field1Ty, Field1Off, Field2Ty, Field2Off);
2478a4dda33SDimitry Andric   if (!Field1Ty)
2488a4dda33SDimitry Andric     return false;
24906c3fb27SDimitry Andric   // Not really a candidate if we have a single int but no float.
25006c3fb27SDimitry Andric   if (Field1Ty && !Field2Ty && !Field1Ty->isFloatingPointTy())
25106c3fb27SDimitry Andric     return false;
25206c3fb27SDimitry Andric   if (!IsCandidate)
25306c3fb27SDimitry Andric     return false;
25406c3fb27SDimitry Andric   if (Field1Ty && Field1Ty->isFloatingPointTy())
25506c3fb27SDimitry Andric     NeededArgFPRs++;
25606c3fb27SDimitry Andric   else if (Field1Ty)
25706c3fb27SDimitry Andric     NeededArgGPRs++;
25806c3fb27SDimitry Andric   if (Field2Ty && Field2Ty->isFloatingPointTy())
25906c3fb27SDimitry Andric     NeededArgFPRs++;
26006c3fb27SDimitry Andric   else if (Field2Ty)
26106c3fb27SDimitry Andric     NeededArgGPRs++;
26206c3fb27SDimitry Andric   return true;
26306c3fb27SDimitry Andric }
26406c3fb27SDimitry Andric 
26506c3fb27SDimitry Andric // Call getCoerceAndExpand for the two-element flattened struct described by
26606c3fb27SDimitry Andric // Field1Ty, Field1Off, Field2Ty, Field2Off. This method will create an
26706c3fb27SDimitry Andric // appropriate coerceToType and unpaddedCoerceToType.
26806c3fb27SDimitry Andric ABIArgInfo RISCVABIInfo::coerceAndExpandFPCCEligibleStruct(
26906c3fb27SDimitry Andric     llvm::Type *Field1Ty, CharUnits Field1Off, llvm::Type *Field2Ty,
27006c3fb27SDimitry Andric     CharUnits Field2Off) const {
27106c3fb27SDimitry Andric   SmallVector<llvm::Type *, 3> CoerceElts;
27206c3fb27SDimitry Andric   SmallVector<llvm::Type *, 2> UnpaddedCoerceElts;
27306c3fb27SDimitry Andric   if (!Field1Off.isZero())
27406c3fb27SDimitry Andric     CoerceElts.push_back(llvm::ArrayType::get(
27506c3fb27SDimitry Andric         llvm::Type::getInt8Ty(getVMContext()), Field1Off.getQuantity()));
27606c3fb27SDimitry Andric 
27706c3fb27SDimitry Andric   CoerceElts.push_back(Field1Ty);
27806c3fb27SDimitry Andric   UnpaddedCoerceElts.push_back(Field1Ty);
27906c3fb27SDimitry Andric 
28006c3fb27SDimitry Andric   if (!Field2Ty) {
28106c3fb27SDimitry Andric     return ABIArgInfo::getCoerceAndExpand(
28206c3fb27SDimitry Andric         llvm::StructType::get(getVMContext(), CoerceElts, !Field1Off.isZero()),
28306c3fb27SDimitry Andric         UnpaddedCoerceElts[0]);
28406c3fb27SDimitry Andric   }
28506c3fb27SDimitry Andric 
28606c3fb27SDimitry Andric   CharUnits Field2Align =
28706c3fb27SDimitry Andric       CharUnits::fromQuantity(getDataLayout().getABITypeAlign(Field2Ty));
28806c3fb27SDimitry Andric   CharUnits Field1End = Field1Off +
28906c3fb27SDimitry Andric       CharUnits::fromQuantity(getDataLayout().getTypeStoreSize(Field1Ty));
29006c3fb27SDimitry Andric   CharUnits Field2OffNoPadNoPack = Field1End.alignTo(Field2Align);
29106c3fb27SDimitry Andric 
29206c3fb27SDimitry Andric   CharUnits Padding = CharUnits::Zero();
29306c3fb27SDimitry Andric   if (Field2Off > Field2OffNoPadNoPack)
29406c3fb27SDimitry Andric     Padding = Field2Off - Field2OffNoPadNoPack;
29506c3fb27SDimitry Andric   else if (Field2Off != Field2Align && Field2Off > Field1End)
29606c3fb27SDimitry Andric     Padding = Field2Off - Field1End;
29706c3fb27SDimitry Andric 
29806c3fb27SDimitry Andric   bool IsPacked = !Field2Off.isMultipleOf(Field2Align);
29906c3fb27SDimitry Andric 
30006c3fb27SDimitry Andric   if (!Padding.isZero())
30106c3fb27SDimitry Andric     CoerceElts.push_back(llvm::ArrayType::get(
30206c3fb27SDimitry Andric         llvm::Type::getInt8Ty(getVMContext()), Padding.getQuantity()));
30306c3fb27SDimitry Andric 
30406c3fb27SDimitry Andric   CoerceElts.push_back(Field2Ty);
30506c3fb27SDimitry Andric   UnpaddedCoerceElts.push_back(Field2Ty);
30606c3fb27SDimitry Andric 
30706c3fb27SDimitry Andric   auto CoerceToType =
30806c3fb27SDimitry Andric       llvm::StructType::get(getVMContext(), CoerceElts, IsPacked);
30906c3fb27SDimitry Andric   auto UnpaddedCoerceToType =
31006c3fb27SDimitry Andric       llvm::StructType::get(getVMContext(), UnpaddedCoerceElts, IsPacked);
31106c3fb27SDimitry Andric 
31206c3fb27SDimitry Andric   return ABIArgInfo::getCoerceAndExpand(CoerceToType, UnpaddedCoerceToType);
31306c3fb27SDimitry Andric }
31406c3fb27SDimitry Andric 
31506c3fb27SDimitry Andric // Fixed-length RVV vectors are represented as scalable vectors in function
31606c3fb27SDimitry Andric // args/return and must be coerced from fixed vectors.
31706c3fb27SDimitry Andric ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty) const {
31806c3fb27SDimitry Andric   assert(Ty->isVectorType() && "expected vector type!");
31906c3fb27SDimitry Andric 
32006c3fb27SDimitry Andric   const auto *VT = Ty->castAs<VectorType>();
321*5f757f3fSDimitry Andric   assert(VT->getVectorKind() == VectorKind::RVVFixedLengthData &&
32206c3fb27SDimitry Andric          "Unexpected vector kind");
32306c3fb27SDimitry Andric 
32406c3fb27SDimitry Andric   assert(VT->getElementType()->isBuiltinType() && "expected builtin type!");
32506c3fb27SDimitry Andric 
3268a4dda33SDimitry Andric   auto VScale =
3278a4dda33SDimitry Andric       getContext().getTargetInfo().getVScaleRange(getContext().getLangOpts());
3288a4dda33SDimitry Andric   // The MinNumElts is simplified from equation:
3298a4dda33SDimitry Andric   // NumElts / VScale =
3308a4dda33SDimitry Andric   //  (EltSize * NumElts / (VScale * RVVBitsPerBlock))
3318a4dda33SDimitry Andric   //    * (RVVBitsPerBlock / EltSize)
33206c3fb27SDimitry Andric   llvm::ScalableVectorType *ResType =
33306c3fb27SDimitry Andric       llvm::ScalableVectorType::get(CGT.ConvertType(VT->getElementType()),
3348a4dda33SDimitry Andric                                     VT->getNumElements() / VScale->first);
33506c3fb27SDimitry Andric   return ABIArgInfo::getDirect(ResType);
33606c3fb27SDimitry Andric }
33706c3fb27SDimitry Andric 
33806c3fb27SDimitry Andric ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
33906c3fb27SDimitry Andric                                               int &ArgGPRsLeft,
34006c3fb27SDimitry Andric                                               int &ArgFPRsLeft) const {
34106c3fb27SDimitry Andric   assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow");
34206c3fb27SDimitry Andric   Ty = useFirstFieldIfTransparentUnion(Ty);
34306c3fb27SDimitry Andric 
34406c3fb27SDimitry Andric   // Structures with either a non-trivial destructor or a non-trivial
34506c3fb27SDimitry Andric   // copy constructor are always passed indirectly.
34606c3fb27SDimitry Andric   if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
34706c3fb27SDimitry Andric     if (ArgGPRsLeft)
34806c3fb27SDimitry Andric       ArgGPRsLeft -= 1;
34906c3fb27SDimitry Andric     return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA ==
35006c3fb27SDimitry Andric                                            CGCXXABI::RAA_DirectInMemory);
35106c3fb27SDimitry Andric   }
35206c3fb27SDimitry Andric 
35306c3fb27SDimitry Andric   // Ignore empty structs/unions.
35406c3fb27SDimitry Andric   if (isEmptyRecord(getContext(), Ty, true))
35506c3fb27SDimitry Andric     return ABIArgInfo::getIgnore();
35606c3fb27SDimitry Andric 
35706c3fb27SDimitry Andric   uint64_t Size = getContext().getTypeSize(Ty);
35806c3fb27SDimitry Andric 
35906c3fb27SDimitry Andric   // Pass floating point values via FPRs if possible.
36006c3fb27SDimitry Andric   if (IsFixed && Ty->isFloatingType() && !Ty->isComplexType() &&
36106c3fb27SDimitry Andric       FLen >= Size && ArgFPRsLeft) {
36206c3fb27SDimitry Andric     ArgFPRsLeft--;
36306c3fb27SDimitry Andric     return ABIArgInfo::getDirect();
36406c3fb27SDimitry Andric   }
36506c3fb27SDimitry Andric 
36606c3fb27SDimitry Andric   // Complex types for the hard float ABI must be passed direct rather than
36706c3fb27SDimitry Andric   // using CoerceAndExpand.
36806c3fb27SDimitry Andric   if (IsFixed && Ty->isComplexType() && FLen && ArgFPRsLeft >= 2) {
36906c3fb27SDimitry Andric     QualType EltTy = Ty->castAs<ComplexType>()->getElementType();
37006c3fb27SDimitry Andric     if (getContext().getTypeSize(EltTy) <= FLen) {
37106c3fb27SDimitry Andric       ArgFPRsLeft -= 2;
37206c3fb27SDimitry Andric       return ABIArgInfo::getDirect();
37306c3fb27SDimitry Andric     }
37406c3fb27SDimitry Andric   }
37506c3fb27SDimitry Andric 
37606c3fb27SDimitry Andric   if (IsFixed && FLen && Ty->isStructureOrClassType()) {
37706c3fb27SDimitry Andric     llvm::Type *Field1Ty = nullptr;
37806c3fb27SDimitry Andric     llvm::Type *Field2Ty = nullptr;
37906c3fb27SDimitry Andric     CharUnits Field1Off = CharUnits::Zero();
38006c3fb27SDimitry Andric     CharUnits Field2Off = CharUnits::Zero();
38106c3fb27SDimitry Andric     int NeededArgGPRs = 0;
38206c3fb27SDimitry Andric     int NeededArgFPRs = 0;
38306c3fb27SDimitry Andric     bool IsCandidate =
38406c3fb27SDimitry Andric         detectFPCCEligibleStruct(Ty, Field1Ty, Field1Off, Field2Ty, Field2Off,
38506c3fb27SDimitry Andric                                  NeededArgGPRs, NeededArgFPRs);
38606c3fb27SDimitry Andric     if (IsCandidate && NeededArgGPRs <= ArgGPRsLeft &&
38706c3fb27SDimitry Andric         NeededArgFPRs <= ArgFPRsLeft) {
38806c3fb27SDimitry Andric       ArgGPRsLeft -= NeededArgGPRs;
38906c3fb27SDimitry Andric       ArgFPRsLeft -= NeededArgFPRs;
39006c3fb27SDimitry Andric       return coerceAndExpandFPCCEligibleStruct(Field1Ty, Field1Off, Field2Ty,
39106c3fb27SDimitry Andric                                                Field2Off);
39206c3fb27SDimitry Andric     }
39306c3fb27SDimitry Andric   }
39406c3fb27SDimitry Andric 
39506c3fb27SDimitry Andric   uint64_t NeededAlign = getContext().getTypeAlign(Ty);
39606c3fb27SDimitry Andric   // Determine the number of GPRs needed to pass the current argument
39706c3fb27SDimitry Andric   // according to the ABI. 2*XLen-aligned varargs are passed in "aligned"
39806c3fb27SDimitry Andric   // register pairs, so may consume 3 registers.
39906c3fb27SDimitry Andric   int NeededArgGPRs = 1;
40006c3fb27SDimitry Andric   if (!IsFixed && NeededAlign == 2 * XLen)
40106c3fb27SDimitry Andric     NeededArgGPRs = 2 + (ArgGPRsLeft % 2);
40206c3fb27SDimitry Andric   else if (Size > XLen && Size <= 2 * XLen)
40306c3fb27SDimitry Andric     NeededArgGPRs = 2;
40406c3fb27SDimitry Andric 
40506c3fb27SDimitry Andric   if (NeededArgGPRs > ArgGPRsLeft) {
40606c3fb27SDimitry Andric     NeededArgGPRs = ArgGPRsLeft;
40706c3fb27SDimitry Andric   }
40806c3fb27SDimitry Andric 
40906c3fb27SDimitry Andric   ArgGPRsLeft -= NeededArgGPRs;
41006c3fb27SDimitry Andric 
41106c3fb27SDimitry Andric   if (!isAggregateTypeForABI(Ty) && !Ty->isVectorType()) {
41206c3fb27SDimitry Andric     // Treat an enum type as its underlying type.
41306c3fb27SDimitry Andric     if (const EnumType *EnumTy = Ty->getAs<EnumType>())
41406c3fb27SDimitry Andric       Ty = EnumTy->getDecl()->getIntegerType();
41506c3fb27SDimitry Andric 
41606c3fb27SDimitry Andric     // All integral types are promoted to XLen width
41706c3fb27SDimitry Andric     if (Size < XLen && Ty->isIntegralOrEnumerationType()) {
41806c3fb27SDimitry Andric       return extendType(Ty);
41906c3fb27SDimitry Andric     }
42006c3fb27SDimitry Andric 
42106c3fb27SDimitry Andric     if (const auto *EIT = Ty->getAs<BitIntType>()) {
42206c3fb27SDimitry Andric       if (EIT->getNumBits() < XLen)
42306c3fb27SDimitry Andric         return extendType(Ty);
42406c3fb27SDimitry Andric       if (EIT->getNumBits() > 128 ||
42506c3fb27SDimitry Andric           (!getContext().getTargetInfo().hasInt128Type() &&
42606c3fb27SDimitry Andric            EIT->getNumBits() > 64))
42706c3fb27SDimitry Andric         return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
42806c3fb27SDimitry Andric     }
42906c3fb27SDimitry Andric 
43006c3fb27SDimitry Andric     return ABIArgInfo::getDirect();
43106c3fb27SDimitry Andric   }
43206c3fb27SDimitry Andric 
43306c3fb27SDimitry Andric   if (const VectorType *VT = Ty->getAs<VectorType>())
434*5f757f3fSDimitry Andric     if (VT->getVectorKind() == VectorKind::RVVFixedLengthData)
43506c3fb27SDimitry Andric       return coerceVLSVector(Ty);
43606c3fb27SDimitry Andric 
43706c3fb27SDimitry Andric   // Aggregates which are <= 2*XLen will be passed in registers if possible,
43806c3fb27SDimitry Andric   // so coerce to integers.
43906c3fb27SDimitry Andric   if (Size <= 2 * XLen) {
44006c3fb27SDimitry Andric     unsigned Alignment = getContext().getTypeAlign(Ty);
44106c3fb27SDimitry Andric 
44206c3fb27SDimitry Andric     // Use a single XLen int if possible, 2*XLen if 2*XLen alignment is
44306c3fb27SDimitry Andric     // required, and a 2-element XLen array if only XLen alignment is required.
44406c3fb27SDimitry Andric     if (Size <= XLen) {
44506c3fb27SDimitry Andric       return ABIArgInfo::getDirect(
44606c3fb27SDimitry Andric           llvm::IntegerType::get(getVMContext(), XLen));
44706c3fb27SDimitry Andric     } else if (Alignment == 2 * XLen) {
44806c3fb27SDimitry Andric       return ABIArgInfo::getDirect(
44906c3fb27SDimitry Andric           llvm::IntegerType::get(getVMContext(), 2 * XLen));
45006c3fb27SDimitry Andric     } else {
45106c3fb27SDimitry Andric       return ABIArgInfo::getDirect(llvm::ArrayType::get(
45206c3fb27SDimitry Andric           llvm::IntegerType::get(getVMContext(), XLen), 2));
45306c3fb27SDimitry Andric     }
45406c3fb27SDimitry Andric   }
45506c3fb27SDimitry Andric   return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
45606c3fb27SDimitry Andric }
45706c3fb27SDimitry Andric 
45806c3fb27SDimitry Andric ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy) const {
45906c3fb27SDimitry Andric   if (RetTy->isVoidType())
46006c3fb27SDimitry Andric     return ABIArgInfo::getIgnore();
46106c3fb27SDimitry Andric 
46206c3fb27SDimitry Andric   int ArgGPRsLeft = 2;
46306c3fb27SDimitry Andric   int ArgFPRsLeft = FLen ? 2 : 0;
46406c3fb27SDimitry Andric 
46506c3fb27SDimitry Andric   // The rules for return and argument types are the same, so defer to
46606c3fb27SDimitry Andric   // classifyArgumentType.
46706c3fb27SDimitry Andric   return classifyArgumentType(RetTy, /*IsFixed=*/true, ArgGPRsLeft,
46806c3fb27SDimitry Andric                               ArgFPRsLeft);
46906c3fb27SDimitry Andric }
47006c3fb27SDimitry Andric 
47106c3fb27SDimitry Andric Address RISCVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
47206c3fb27SDimitry Andric                                 QualType Ty) const {
47306c3fb27SDimitry Andric   CharUnits SlotSize = CharUnits::fromQuantity(XLen / 8);
47406c3fb27SDimitry Andric 
47506c3fb27SDimitry Andric   // Empty records are ignored for parameter passing purposes.
47606c3fb27SDimitry Andric   if (isEmptyRecord(getContext(), Ty, true)) {
47706c3fb27SDimitry Andric     return Address(CGF.Builder.CreateLoad(VAListAddr),
47806c3fb27SDimitry Andric                    CGF.ConvertTypeForMem(Ty), SlotSize);
47906c3fb27SDimitry Andric   }
48006c3fb27SDimitry Andric 
48106c3fb27SDimitry Andric   auto TInfo = getContext().getTypeInfoInChars(Ty);
48206c3fb27SDimitry Andric 
48306c3fb27SDimitry Andric   // Arguments bigger than 2*Xlen bytes are passed indirectly.
48406c3fb27SDimitry Andric   bool IsIndirect = TInfo.Width > 2 * SlotSize;
48506c3fb27SDimitry Andric 
48606c3fb27SDimitry Andric   return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect, TInfo,
48706c3fb27SDimitry Andric                           SlotSize, /*AllowHigherAlign=*/true);
48806c3fb27SDimitry Andric }
48906c3fb27SDimitry Andric 
49006c3fb27SDimitry Andric ABIArgInfo RISCVABIInfo::extendType(QualType Ty) const {
49106c3fb27SDimitry Andric   int TySize = getContext().getTypeSize(Ty);
49206c3fb27SDimitry Andric   // RV64 ABI requires unsigned 32 bit integers to be sign extended.
49306c3fb27SDimitry Andric   if (XLen == 64 && Ty->isUnsignedIntegerOrEnumerationType() && TySize == 32)
49406c3fb27SDimitry Andric     return ABIArgInfo::getSignExtend(Ty);
49506c3fb27SDimitry Andric   return ABIArgInfo::getExtend(Ty);
49606c3fb27SDimitry Andric }
49706c3fb27SDimitry Andric 
49806c3fb27SDimitry Andric namespace {
49906c3fb27SDimitry Andric class RISCVTargetCodeGenInfo : public TargetCodeGenInfo {
50006c3fb27SDimitry Andric public:
50106c3fb27SDimitry Andric   RISCVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen,
50206c3fb27SDimitry Andric                          unsigned FLen)
50306c3fb27SDimitry Andric       : TargetCodeGenInfo(std::make_unique<RISCVABIInfo>(CGT, XLen, FLen)) {}
50406c3fb27SDimitry Andric 
50506c3fb27SDimitry Andric   void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
50606c3fb27SDimitry Andric                            CodeGen::CodeGenModule &CGM) const override {
50706c3fb27SDimitry Andric     const auto *FD = dyn_cast_or_null<FunctionDecl>(D);
50806c3fb27SDimitry Andric     if (!FD) return;
50906c3fb27SDimitry Andric 
51006c3fb27SDimitry Andric     const auto *Attr = FD->getAttr<RISCVInterruptAttr>();
51106c3fb27SDimitry Andric     if (!Attr)
51206c3fb27SDimitry Andric       return;
51306c3fb27SDimitry Andric 
51406c3fb27SDimitry Andric     const char *Kind;
51506c3fb27SDimitry Andric     switch (Attr->getInterrupt()) {
51606c3fb27SDimitry Andric     case RISCVInterruptAttr::supervisor: Kind = "supervisor"; break;
51706c3fb27SDimitry Andric     case RISCVInterruptAttr::machine: Kind = "machine"; break;
51806c3fb27SDimitry Andric     }
51906c3fb27SDimitry Andric 
52006c3fb27SDimitry Andric     auto *Fn = cast<llvm::Function>(GV);
52106c3fb27SDimitry Andric 
52206c3fb27SDimitry Andric     Fn->addFnAttr("interrupt", Kind);
52306c3fb27SDimitry Andric   }
52406c3fb27SDimitry Andric };
52506c3fb27SDimitry Andric } // namespace
52606c3fb27SDimitry Andric 
52706c3fb27SDimitry Andric std::unique_ptr<TargetCodeGenInfo>
52806c3fb27SDimitry Andric CodeGen::createRISCVTargetCodeGenInfo(CodeGenModule &CGM, unsigned XLen,
52906c3fb27SDimitry Andric                                       unsigned FLen) {
53006c3fb27SDimitry Andric   return std::make_unique<RISCVTargetCodeGenInfo>(CGM.getTypes(), XLen, FLen);
53106c3fb27SDimitry Andric }
532