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:
RISCVABIInfo(CodeGen::CodeGenTypes & CGT,unsigned XLen,unsigned FLen,bool EABI)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
computeInfo(CGFunctionInfo & FI) const6906c3fb27SDimitry 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.
detectFPCCEligibleStructHelper(QualType Ty,CharUnits CurOff,llvm::Type * & Field1Ty,CharUnits & Field1Off,llvm::Type * & Field2Ty,CharUnits & Field2Off) const10806c3fb27SDimitry 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.
detectFPCCEligibleStruct(QualType Ty,llvm::Type * & Field1Ty,CharUnits & Field1Off,llvm::Type * & Field2Ty,CharUnits & Field2Off,int & NeededArgGPRs,int & NeededArgFPRs) const23806c3fb27SDimitry 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.
coerceAndExpandFPCCEligibleStruct(llvm::Type * Field1Ty,CharUnits Field1Off,llvm::Type * Field2Ty,CharUnits Field2Off) const27106c3fb27SDimitry 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.
coerceVLSVector(QualType Ty) const32006c3fb27SDimitry 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
classifyArgumentType(QualType Ty,bool IsFixed,int & ArgGPRsLeft,int & ArgFPRsLeft) const34906c3fb27SDimitry 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
classifyReturnType(QualType RetTy) const48006c3fb27SDimitry 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
EmitVAArg(CodeGenFunction & CGF,Address VAListAddr,QualType Ty,AggValueSlot Slot) const493*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
extendType(QualType Ty) const51706c3fb27SDimitry 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:
RISCVTargetCodeGenInfo(CodeGen::CodeGenTypes & CGT,unsigned XLen,unsigned FLen,bool EABI)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
setTargetAttributes(const Decl * D,llvm::GlobalValue * GV,CodeGen::CodeGenModule & CGM) const53606c3fb27SDimitry 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>
createRISCVTargetCodeGenInfo(CodeGenModule & CGM,unsigned XLen,unsigned FLen,bool EABI)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