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