xref: /llvm-project/clang/lib/CodeGen/Targets/RISCV.cpp (revision cfe26358e3051755961fb1f3b46328dc2c326895)
1992cb984SSergei Barannikov //===- RISCV.cpp ----------------------------------------------------------===//
2992cb984SSergei Barannikov //
3992cb984SSergei Barannikov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4992cb984SSergei Barannikov // See https://llvm.org/LICENSE.txt for license information.
5992cb984SSergei Barannikov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6992cb984SSergei Barannikov //
7992cb984SSergei Barannikov //===----------------------------------------------------------------------===//
8992cb984SSergei Barannikov 
9992cb984SSergei Barannikov #include "ABIInfoImpl.h"
10992cb984SSergei Barannikov #include "TargetInfo.h"
11992cb984SSergei Barannikov 
12992cb984SSergei Barannikov using namespace clang;
13992cb984SSergei Barannikov using namespace clang::CodeGen;
14992cb984SSergei Barannikov 
15992cb984SSergei Barannikov //===----------------------------------------------------------------------===//
16992cb984SSergei Barannikov // RISC-V ABI Implementation
17992cb984SSergei Barannikov //===----------------------------------------------------------------------===//
18992cb984SSergei Barannikov 
19992cb984SSergei Barannikov namespace {
20992cb984SSergei Barannikov class RISCVABIInfo : public DefaultABIInfo {
21992cb984SSergei Barannikov private:
22992cb984SSergei Barannikov   // Size of the integer ('x') registers in bits.
23992cb984SSergei Barannikov   unsigned XLen;
24992cb984SSergei Barannikov   // Size of the floating point ('f') registers in bits. Note that the target
25992cb984SSergei Barannikov   // ISA might have a wider FLen than the selected ABI (e.g. an RV32IF target
26992cb984SSergei Barannikov   // with soft float ABI has FLen==0).
27992cb984SSergei Barannikov   unsigned FLen;
283ac9fe69SWang Pengcheng   const int NumArgGPRs;
293ac9fe69SWang Pengcheng   const int NumArgFPRs;
303ac9fe69SWang Pengcheng   const bool EABI;
31992cb984SSergei Barannikov   bool detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff,
32992cb984SSergei Barannikov                                       llvm::Type *&Field1Ty,
33992cb984SSergei Barannikov                                       CharUnits &Field1Off,
34992cb984SSergei Barannikov                                       llvm::Type *&Field2Ty,
35992cb984SSergei Barannikov                                       CharUnits &Field2Off) const;
36992cb984SSergei Barannikov 
37992cb984SSergei Barannikov public:
383ac9fe69SWang Pengcheng   RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen,
393ac9fe69SWang Pengcheng                bool EABI)
403ac9fe69SWang Pengcheng       : DefaultABIInfo(CGT), XLen(XLen), FLen(FLen), NumArgGPRs(EABI ? 6 : 8),
413ac9fe69SWang Pengcheng         NumArgFPRs(FLen != 0 ? 8 : 0), EABI(EABI) {}
42992cb984SSergei Barannikov 
43992cb984SSergei Barannikov   // DefaultABIInfo's classifyReturnType and classifyArgumentType are
44992cb984SSergei Barannikov   // non-virtual, but computeInfo is virtual, so we overload it.
45992cb984SSergei Barannikov   void computeInfo(CGFunctionInfo &FI) const override;
46992cb984SSergei Barannikov 
47992cb984SSergei Barannikov   ABIArgInfo classifyArgumentType(QualType Ty, bool IsFixed, int &ArgGPRsLeft,
48992cb984SSergei Barannikov                                   int &ArgFPRsLeft) const;
49992cb984SSergei Barannikov   ABIArgInfo classifyReturnType(QualType RetTy) const;
50992cb984SSergei Barannikov 
516d973b45SMariya Podchishchaeva   RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
526d973b45SMariya Podchishchaeva                    AggValueSlot Slot) const override;
53992cb984SSergei Barannikov 
54ea920450SLei Huang   ABIArgInfo extendType(QualType Ty, llvm::Type *CoerceTy = nullptr) const;
55992cb984SSergei Barannikov 
56992cb984SSergei Barannikov   bool detectFPCCEligibleStruct(QualType Ty, llvm::Type *&Field1Ty,
57992cb984SSergei Barannikov                                 CharUnits &Field1Off, llvm::Type *&Field2Ty,
58992cb984SSergei Barannikov                                 CharUnits &Field2Off, int &NeededArgGPRs,
59992cb984SSergei Barannikov                                 int &NeededArgFPRs) const;
60992cb984SSergei Barannikov   ABIArgInfo coerceAndExpandFPCCEligibleStruct(llvm::Type *Field1Ty,
61992cb984SSergei Barannikov                                                CharUnits Field1Off,
62992cb984SSergei Barannikov                                                llvm::Type *Field2Ty,
63992cb984SSergei Barannikov                                                CharUnits Field2Off) const;
64992cb984SSergei Barannikov 
65992cb984SSergei Barannikov   ABIArgInfo coerceVLSVector(QualType Ty) const;
669cd93774SPiyou Chen 
679cd93774SPiyou Chen   using ABIInfo::appendAttributeMangling;
689cd93774SPiyou Chen   void appendAttributeMangling(TargetClonesAttr *Attr, unsigned Index,
699cd93774SPiyou Chen                                raw_ostream &Out) const override;
709cd93774SPiyou Chen   void appendAttributeMangling(StringRef AttrStr,
719cd93774SPiyou Chen                                raw_ostream &Out) const override;
72992cb984SSergei Barannikov };
73992cb984SSergei Barannikov } // end anonymous namespace
74992cb984SSergei Barannikov 
759cd93774SPiyou Chen void RISCVABIInfo::appendAttributeMangling(TargetClonesAttr *Attr,
769cd93774SPiyou Chen                                            unsigned Index,
779cd93774SPiyou Chen                                            raw_ostream &Out) const {
789cd93774SPiyou Chen   appendAttributeMangling(Attr->getFeatureStr(Index), Out);
799cd93774SPiyou Chen }
809cd93774SPiyou Chen 
819cd93774SPiyou Chen void RISCVABIInfo::appendAttributeMangling(StringRef AttrStr,
829cd93774SPiyou Chen                                            raw_ostream &Out) const {
839cd93774SPiyou Chen   if (AttrStr == "default") {
849cd93774SPiyou Chen     Out << ".default";
859cd93774SPiyou Chen     return;
869cd93774SPiyou Chen   }
879cd93774SPiyou Chen 
889cd93774SPiyou Chen   Out << '.';
899cd93774SPiyou Chen 
909cd93774SPiyou Chen   SmallVector<StringRef, 8> Attrs;
919cd93774SPiyou Chen   AttrStr.split(Attrs, ';');
929cd93774SPiyou Chen 
939cd93774SPiyou Chen   // Only consider the arch string.
949cd93774SPiyou Chen   StringRef ArchStr;
959cd93774SPiyou Chen   for (auto &Attr : Attrs) {
969cd93774SPiyou Chen     if (Attr.starts_with("arch="))
979cd93774SPiyou Chen       ArchStr = Attr;
989cd93774SPiyou Chen   }
999cd93774SPiyou Chen 
1009cd93774SPiyou Chen   // Extract features string.
1019cd93774SPiyou Chen   SmallVector<StringRef, 8> Features;
1029cd93774SPiyou Chen   ArchStr.consume_front("arch=");
1039cd93774SPiyou Chen   ArchStr.split(Features, ',');
1049cd93774SPiyou Chen 
1059cd93774SPiyou Chen   llvm::stable_sort(Features);
1069cd93774SPiyou Chen 
1079cd93774SPiyou Chen   for (auto Feat : Features) {
1089cd93774SPiyou Chen     Feat.consume_front("+");
1099cd93774SPiyou Chen     Out << "_" << Feat;
1109cd93774SPiyou Chen   }
1119cd93774SPiyou Chen }
1129cd93774SPiyou Chen 
113992cb984SSergei Barannikov void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const {
114992cb984SSergei Barannikov   QualType RetTy = FI.getReturnType();
115992cb984SSergei Barannikov   if (!getCXXABI().classifyReturnType(FI))
116992cb984SSergei Barannikov     FI.getReturnInfo() = classifyReturnType(RetTy);
117992cb984SSergei Barannikov 
118992cb984SSergei Barannikov   // IsRetIndirect is true if classifyArgumentType indicated the value should
119992cb984SSergei Barannikov   // be passed indirect, or if the type size is a scalar greater than 2*XLen
120992cb984SSergei Barannikov   // and not a complex type with elements <= FLen. e.g. fp128 is passed direct
121992cb984SSergei Barannikov   // in LLVM IR, relying on the backend lowering code to rewrite the argument
122992cb984SSergei Barannikov   // list and pass indirectly on RV32.
123992cb984SSergei Barannikov   bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect;
124992cb984SSergei Barannikov   if (!IsRetIndirect && RetTy->isScalarType() &&
125992cb984SSergei Barannikov       getContext().getTypeSize(RetTy) > (2 * XLen)) {
126992cb984SSergei Barannikov     if (RetTy->isComplexType() && FLen) {
127992cb984SSergei Barannikov       QualType EltTy = RetTy->castAs<ComplexType>()->getElementType();
128992cb984SSergei Barannikov       IsRetIndirect = getContext().getTypeSize(EltTy) > FLen;
129992cb984SSergei Barannikov     } else {
130992cb984SSergei Barannikov       // This is a normal scalar > 2*XLen, such as fp128 on RV32.
131992cb984SSergei Barannikov       IsRetIndirect = true;
132992cb984SSergei Barannikov     }
133992cb984SSergei Barannikov   }
134992cb984SSergei Barannikov 
135992cb984SSergei Barannikov   int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs;
1363ac9fe69SWang Pengcheng   int ArgFPRsLeft = NumArgFPRs;
137992cb984SSergei Barannikov   int NumFixedArgs = FI.getNumRequiredArgs();
138992cb984SSergei Barannikov 
139992cb984SSergei Barannikov   int ArgNum = 0;
140992cb984SSergei Barannikov   for (auto &ArgInfo : FI.arguments()) {
141992cb984SSergei Barannikov     bool IsFixed = ArgNum < NumFixedArgs;
142992cb984SSergei Barannikov     ArgInfo.info =
143992cb984SSergei Barannikov         classifyArgumentType(ArgInfo.type, IsFixed, ArgGPRsLeft, ArgFPRsLeft);
144992cb984SSergei Barannikov     ArgNum++;
145992cb984SSergei Barannikov   }
146992cb984SSergei Barannikov }
147992cb984SSergei Barannikov 
148992cb984SSergei Barannikov // Returns true if the struct is a potential candidate for the floating point
149992cb984SSergei Barannikov // calling convention. If this function returns true, the caller is
150992cb984SSergei Barannikov // responsible for checking that if there is only a single field then that
151992cb984SSergei Barannikov // field is a float.
152992cb984SSergei Barannikov bool RISCVABIInfo::detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff,
153992cb984SSergei Barannikov                                                   llvm::Type *&Field1Ty,
154992cb984SSergei Barannikov                                                   CharUnits &Field1Off,
155992cb984SSergei Barannikov                                                   llvm::Type *&Field2Ty,
156992cb984SSergei Barannikov                                                   CharUnits &Field2Off) const {
157992cb984SSergei Barannikov   bool IsInt = Ty->isIntegralOrEnumerationType();
158992cb984SSergei Barannikov   bool IsFloat = Ty->isRealFloatingType();
159992cb984SSergei Barannikov 
160992cb984SSergei Barannikov   if (IsInt || IsFloat) {
161992cb984SSergei Barannikov     uint64_t Size = getContext().getTypeSize(Ty);
162992cb984SSergei Barannikov     if (IsInt && Size > XLen)
163992cb984SSergei Barannikov       return false;
164992cb984SSergei Barannikov     // Can't be eligible if larger than the FP registers. Handling of half
165992cb984SSergei Barannikov     // precision values has been specified in the ABI, so don't block those.
166992cb984SSergei Barannikov     if (IsFloat && Size > FLen)
167992cb984SSergei Barannikov       return false;
168992cb984SSergei Barannikov     // Can't be eligible if an integer type was already found (int+int pairs
169992cb984SSergei Barannikov     // are not eligible).
170992cb984SSergei Barannikov     if (IsInt && Field1Ty && Field1Ty->isIntegerTy())
171992cb984SSergei Barannikov       return false;
172992cb984SSergei Barannikov     if (!Field1Ty) {
173992cb984SSergei Barannikov       Field1Ty = CGT.ConvertType(Ty);
174992cb984SSergei Barannikov       Field1Off = CurOff;
175992cb984SSergei Barannikov       return true;
176992cb984SSergei Barannikov     }
177992cb984SSergei Barannikov     if (!Field2Ty) {
178992cb984SSergei Barannikov       Field2Ty = CGT.ConvertType(Ty);
179992cb984SSergei Barannikov       Field2Off = CurOff;
180992cb984SSergei Barannikov       return true;
181992cb984SSergei Barannikov     }
182992cb984SSergei Barannikov     return false;
183992cb984SSergei Barannikov   }
184992cb984SSergei Barannikov 
185992cb984SSergei Barannikov   if (auto CTy = Ty->getAs<ComplexType>()) {
186992cb984SSergei Barannikov     if (Field1Ty)
187992cb984SSergei Barannikov       return false;
188992cb984SSergei Barannikov     QualType EltTy = CTy->getElementType();
189992cb984SSergei Barannikov     if (getContext().getTypeSize(EltTy) > FLen)
190992cb984SSergei Barannikov       return false;
191992cb984SSergei Barannikov     Field1Ty = CGT.ConvertType(EltTy);
192992cb984SSergei Barannikov     Field1Off = CurOff;
193992cb984SSergei Barannikov     Field2Ty = Field1Ty;
194992cb984SSergei Barannikov     Field2Off = Field1Off + getContext().getTypeSizeInChars(EltTy);
195992cb984SSergei Barannikov     return true;
196992cb984SSergei Barannikov   }
197992cb984SSergei Barannikov 
198992cb984SSergei Barannikov   if (const ConstantArrayType *ATy = getContext().getAsConstantArrayType(Ty)) {
19928ddbd4aSChris B     uint64_t ArraySize = ATy->getZExtSize();
200992cb984SSergei Barannikov     QualType EltTy = ATy->getElementType();
201e3c57fddSAlex Bradbury     // Non-zero-length arrays of empty records make the struct ineligible for
202e3c57fddSAlex Bradbury     // the FP calling convention in C++.
203e3c57fddSAlex Bradbury     if (const auto *RTy = EltTy->getAs<RecordType>()) {
204e3c57fddSAlex Bradbury       if (ArraySize != 0 && isa<CXXRecordDecl>(RTy->getDecl()) &&
205e3c57fddSAlex Bradbury           isEmptyRecord(getContext(), EltTy, true, true))
206e3c57fddSAlex Bradbury         return false;
207e3c57fddSAlex Bradbury     }
208992cb984SSergei Barannikov     CharUnits EltSize = getContext().getTypeSizeInChars(EltTy);
209992cb984SSergei Barannikov     for (uint64_t i = 0; i < ArraySize; ++i) {
210992cb984SSergei Barannikov       bool Ret = detectFPCCEligibleStructHelper(EltTy, CurOff, Field1Ty,
211992cb984SSergei Barannikov                                                 Field1Off, Field2Ty, Field2Off);
212992cb984SSergei Barannikov       if (!Ret)
213992cb984SSergei Barannikov         return false;
214992cb984SSergei Barannikov       CurOff += EltSize;
215992cb984SSergei Barannikov     }
216992cb984SSergei Barannikov     return true;
217992cb984SSergei Barannikov   }
218992cb984SSergei Barannikov 
219992cb984SSergei Barannikov   if (const auto *RTy = Ty->getAs<RecordType>()) {
220992cb984SSergei Barannikov     // Structures with either a non-trivial destructor or a non-trivial
221992cb984SSergei Barannikov     // copy constructor are not eligible for the FP calling convention.
222992cb984SSergei Barannikov     if (getRecordArgABI(Ty, CGT.getCXXABI()))
223992cb984SSergei Barannikov       return false;
224e3c57fddSAlex Bradbury     if (isEmptyRecord(getContext(), Ty, true, true))
225992cb984SSergei Barannikov       return true;
226992cb984SSergei Barannikov     const RecordDecl *RD = RTy->getDecl();
227992cb984SSergei Barannikov     // Unions aren't eligible unless they're empty (which is caught above).
228992cb984SSergei Barannikov     if (RD->isUnion())
229992cb984SSergei Barannikov       return false;
230992cb984SSergei Barannikov     const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
231992cb984SSergei Barannikov     // If this is a C++ record, check the bases first.
232992cb984SSergei Barannikov     if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
233992cb984SSergei Barannikov       for (const CXXBaseSpecifier &B : CXXRD->bases()) {
234992cb984SSergei Barannikov         const auto *BDecl =
235992cb984SSergei Barannikov             cast<CXXRecordDecl>(B.getType()->castAs<RecordType>()->getDecl());
236992cb984SSergei Barannikov         CharUnits BaseOff = Layout.getBaseClassOffset(BDecl);
237992cb984SSergei Barannikov         bool Ret = detectFPCCEligibleStructHelper(B.getType(), CurOff + BaseOff,
238992cb984SSergei Barannikov                                                   Field1Ty, Field1Off, Field2Ty,
239992cb984SSergei Barannikov                                                   Field2Off);
240992cb984SSergei Barannikov         if (!Ret)
241992cb984SSergei Barannikov           return false;
242992cb984SSergei Barannikov       }
243992cb984SSergei Barannikov     }
244992cb984SSergei Barannikov     int ZeroWidthBitFieldCount = 0;
245992cb984SSergei Barannikov     for (const FieldDecl *FD : RD->fields()) {
246992cb984SSergei Barannikov       uint64_t FieldOffInBits = Layout.getFieldOffset(FD->getFieldIndex());
247992cb984SSergei Barannikov       QualType QTy = FD->getType();
248992cb984SSergei Barannikov       if (FD->isBitField()) {
249*cfe26358STimm Baeder         unsigned BitWidth = FD->getBitWidthValue();
250992cb984SSergei Barannikov         // Allow a bitfield with a type greater than XLen as long as the
251992cb984SSergei Barannikov         // bitwidth is XLen or less.
252992cb984SSergei Barannikov         if (getContext().getTypeSize(QTy) > XLen && BitWidth <= XLen)
253992cb984SSergei Barannikov           QTy = getContext().getIntTypeForBitwidth(XLen, false);
254992cb984SSergei Barannikov         if (BitWidth == 0) {
255992cb984SSergei Barannikov           ZeroWidthBitFieldCount++;
256992cb984SSergei Barannikov           continue;
257992cb984SSergei Barannikov         }
258992cb984SSergei Barannikov       }
259992cb984SSergei Barannikov 
260992cb984SSergei Barannikov       bool Ret = detectFPCCEligibleStructHelper(
261992cb984SSergei Barannikov           QTy, CurOff + getContext().toCharUnitsFromBits(FieldOffInBits),
262992cb984SSergei Barannikov           Field1Ty, Field1Off, Field2Ty, Field2Off);
263992cb984SSergei Barannikov       if (!Ret)
264992cb984SSergei Barannikov         return false;
265992cb984SSergei Barannikov 
266992cb984SSergei Barannikov       // As a quirk of the ABI, zero-width bitfields aren't ignored for fp+fp
267992cb984SSergei Barannikov       // or int+fp structs, but are ignored for a struct with an fp field and
268992cb984SSergei Barannikov       // any number of zero-width bitfields.
269992cb984SSergei Barannikov       if (Field2Ty && ZeroWidthBitFieldCount > 0)
270992cb984SSergei Barannikov         return false;
271992cb984SSergei Barannikov     }
272992cb984SSergei Barannikov     return Field1Ty != nullptr;
273992cb984SSergei Barannikov   }
274992cb984SSergei Barannikov 
275992cb984SSergei Barannikov   return false;
276992cb984SSergei Barannikov }
277992cb984SSergei Barannikov 
278992cb984SSergei Barannikov // Determine if a struct is eligible for passing according to the floating
279992cb984SSergei Barannikov // point calling convention (i.e., when flattened it contains a single fp
280992cb984SSergei Barannikov // value, fp+fp, or int+fp of appropriate size). If so, NeededArgFPRs and
281992cb984SSergei Barannikov // NeededArgGPRs are incremented appropriately.
282992cb984SSergei Barannikov bool RISCVABIInfo::detectFPCCEligibleStruct(QualType Ty, llvm::Type *&Field1Ty,
283992cb984SSergei Barannikov                                             CharUnits &Field1Off,
284992cb984SSergei Barannikov                                             llvm::Type *&Field2Ty,
285992cb984SSergei Barannikov                                             CharUnits &Field2Off,
286992cb984SSergei Barannikov                                             int &NeededArgGPRs,
287992cb984SSergei Barannikov                                             int &NeededArgFPRs) const {
288992cb984SSergei Barannikov   Field1Ty = nullptr;
289992cb984SSergei Barannikov   Field2Ty = nullptr;
290992cb984SSergei Barannikov   NeededArgGPRs = 0;
291992cb984SSergei Barannikov   NeededArgFPRs = 0;
292992cb984SSergei Barannikov   bool IsCandidate = detectFPCCEligibleStructHelper(
293992cb984SSergei Barannikov       Ty, CharUnits::Zero(), Field1Ty, Field1Off, Field2Ty, Field2Off);
294e3c57fddSAlex Bradbury   if (!Field1Ty)
295e3c57fddSAlex Bradbury     return false;
296992cb984SSergei Barannikov   // Not really a candidate if we have a single int but no float.
297992cb984SSergei Barannikov   if (Field1Ty && !Field2Ty && !Field1Ty->isFloatingPointTy())
298992cb984SSergei Barannikov     return false;
299992cb984SSergei Barannikov   if (!IsCandidate)
300992cb984SSergei Barannikov     return false;
301992cb984SSergei Barannikov   if (Field1Ty && Field1Ty->isFloatingPointTy())
302992cb984SSergei Barannikov     NeededArgFPRs++;
303992cb984SSergei Barannikov   else if (Field1Ty)
304992cb984SSergei Barannikov     NeededArgGPRs++;
305992cb984SSergei Barannikov   if (Field2Ty && Field2Ty->isFloatingPointTy())
306992cb984SSergei Barannikov     NeededArgFPRs++;
307992cb984SSergei Barannikov   else if (Field2Ty)
308992cb984SSergei Barannikov     NeededArgGPRs++;
309992cb984SSergei Barannikov   return true;
310992cb984SSergei Barannikov }
311992cb984SSergei Barannikov 
312992cb984SSergei Barannikov // Call getCoerceAndExpand for the two-element flattened struct described by
313992cb984SSergei Barannikov // Field1Ty, Field1Off, Field2Ty, Field2Off. This method will create an
314992cb984SSergei Barannikov // appropriate coerceToType and unpaddedCoerceToType.
315992cb984SSergei Barannikov ABIArgInfo RISCVABIInfo::coerceAndExpandFPCCEligibleStruct(
316992cb984SSergei Barannikov     llvm::Type *Field1Ty, CharUnits Field1Off, llvm::Type *Field2Ty,
317992cb984SSergei Barannikov     CharUnits Field2Off) const {
318992cb984SSergei Barannikov   SmallVector<llvm::Type *, 3> CoerceElts;
319992cb984SSergei Barannikov   SmallVector<llvm::Type *, 2> UnpaddedCoerceElts;
320992cb984SSergei Barannikov   if (!Field1Off.isZero())
321992cb984SSergei Barannikov     CoerceElts.push_back(llvm::ArrayType::get(
322992cb984SSergei Barannikov         llvm::Type::getInt8Ty(getVMContext()), Field1Off.getQuantity()));
323992cb984SSergei Barannikov 
324992cb984SSergei Barannikov   CoerceElts.push_back(Field1Ty);
325992cb984SSergei Barannikov   UnpaddedCoerceElts.push_back(Field1Ty);
326992cb984SSergei Barannikov 
327992cb984SSergei Barannikov   if (!Field2Ty) {
328992cb984SSergei Barannikov     return ABIArgInfo::getCoerceAndExpand(
329992cb984SSergei Barannikov         llvm::StructType::get(getVMContext(), CoerceElts, !Field1Off.isZero()),
330992cb984SSergei Barannikov         UnpaddedCoerceElts[0]);
331992cb984SSergei Barannikov   }
332992cb984SSergei Barannikov 
333992cb984SSergei Barannikov   CharUnits Field2Align =
334992cb984SSergei Barannikov       CharUnits::fromQuantity(getDataLayout().getABITypeAlign(Field2Ty));
335992cb984SSergei Barannikov   CharUnits Field1End = Field1Off +
336992cb984SSergei Barannikov       CharUnits::fromQuantity(getDataLayout().getTypeStoreSize(Field1Ty));
337992cb984SSergei Barannikov   CharUnits Field2OffNoPadNoPack = Field1End.alignTo(Field2Align);
338992cb984SSergei Barannikov 
339992cb984SSergei Barannikov   CharUnits Padding = CharUnits::Zero();
340992cb984SSergei Barannikov   if (Field2Off > Field2OffNoPadNoPack)
341992cb984SSergei Barannikov     Padding = Field2Off - Field2OffNoPadNoPack;
342992cb984SSergei Barannikov   else if (Field2Off != Field2Align && Field2Off > Field1End)
343992cb984SSergei Barannikov     Padding = Field2Off - Field1End;
344992cb984SSergei Barannikov 
345992cb984SSergei Barannikov   bool IsPacked = !Field2Off.isMultipleOf(Field2Align);
346992cb984SSergei Barannikov 
347992cb984SSergei Barannikov   if (!Padding.isZero())
348992cb984SSergei Barannikov     CoerceElts.push_back(llvm::ArrayType::get(
349992cb984SSergei Barannikov         llvm::Type::getInt8Ty(getVMContext()), Padding.getQuantity()));
350992cb984SSergei Barannikov 
351992cb984SSergei Barannikov   CoerceElts.push_back(Field2Ty);
352992cb984SSergei Barannikov   UnpaddedCoerceElts.push_back(Field2Ty);
353992cb984SSergei Barannikov 
354992cb984SSergei Barannikov   auto CoerceToType =
355992cb984SSergei Barannikov       llvm::StructType::get(getVMContext(), CoerceElts, IsPacked);
356992cb984SSergei Barannikov   auto UnpaddedCoerceToType =
357992cb984SSergei Barannikov       llvm::StructType::get(getVMContext(), UnpaddedCoerceElts, IsPacked);
358992cb984SSergei Barannikov 
359992cb984SSergei Barannikov   return ABIArgInfo::getCoerceAndExpand(CoerceToType, UnpaddedCoerceToType);
360992cb984SSergei Barannikov }
361992cb984SSergei Barannikov 
362992cb984SSergei Barannikov // Fixed-length RVV vectors are represented as scalable vectors in function
363992cb984SSergei Barannikov // args/return and must be coerced from fixed vectors.
364992cb984SSergei Barannikov ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty) const {
365992cb984SSergei Barannikov   assert(Ty->isVectorType() && "expected vector type!");
366992cb984SSergei Barannikov 
367992cb984SSergei Barannikov   const auto *VT = Ty->castAs<VectorType>();
368992cb984SSergei Barannikov   assert(VT->getElementType()->isBuiltinType() && "expected builtin type!");
369992cb984SSergei Barannikov 
370edb50563Swangpc   auto VScale =
371edb50563Swangpc       getContext().getTargetInfo().getVScaleRange(getContext().getLangOpts());
372c92ad411SCraig Topper 
373c92ad411SCraig Topper   unsigned NumElts = VT->getNumElements();
374635d20e9SVladislav Belov   llvm::Type *EltType = llvm::Type::getInt1Ty(getVMContext());
375635d20e9SVladislav Belov   switch (VT->getVectorKind()) {
376635d20e9SVladislav Belov   case VectorKind::RVVFixedLengthMask_1:
377635d20e9SVladislav Belov     break;
378635d20e9SVladislav Belov   case VectorKind::RVVFixedLengthMask_2:
379635d20e9SVladislav Belov     NumElts *= 2;
380635d20e9SVladislav Belov     break;
381635d20e9SVladislav Belov   case VectorKind::RVVFixedLengthMask_4:
382635d20e9SVladislav Belov     NumElts *= 4;
383635d20e9SVladislav Belov     break;
384635d20e9SVladislav Belov   case VectorKind::RVVFixedLengthMask:
385c92ad411SCraig Topper     NumElts *= 8;
386635d20e9SVladislav Belov     break;
387635d20e9SVladislav Belov   default:
388c92ad411SCraig Topper     assert(VT->getVectorKind() == VectorKind::RVVFixedLengthData &&
389c92ad411SCraig Topper            "Unexpected vector kind");
390c92ad411SCraig Topper     EltType = CGT.ConvertType(VT->getElementType());
391c92ad411SCraig Topper   }
392c92ad411SCraig Topper 
393edb50563Swangpc   // The MinNumElts is simplified from equation:
394edb50563Swangpc   // NumElts / VScale =
395edb50563Swangpc   //  (EltSize * NumElts / (VScale * RVVBitsPerBlock))
396edb50563Swangpc   //    * (RVVBitsPerBlock / EltSize)
397992cb984SSergei Barannikov   llvm::ScalableVectorType *ResType =
398c92ad411SCraig Topper       llvm::ScalableVectorType::get(EltType, NumElts / VScale->first);
399992cb984SSergei Barannikov   return ABIArgInfo::getDirect(ResType);
400992cb984SSergei Barannikov }
401992cb984SSergei Barannikov 
402992cb984SSergei Barannikov ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
403992cb984SSergei Barannikov                                               int &ArgGPRsLeft,
404992cb984SSergei Barannikov                                               int &ArgFPRsLeft) const {
405992cb984SSergei Barannikov   assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow");
406992cb984SSergei Barannikov   Ty = useFirstFieldIfTransparentUnion(Ty);
407992cb984SSergei Barannikov 
408992cb984SSergei Barannikov   // Structures with either a non-trivial destructor or a non-trivial
409992cb984SSergei Barannikov   // copy constructor are always passed indirectly.
410992cb984SSergei Barannikov   if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
411992cb984SSergei Barannikov     if (ArgGPRsLeft)
412992cb984SSergei Barannikov       ArgGPRsLeft -= 1;
413992cb984SSergei Barannikov     return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA ==
414992cb984SSergei Barannikov                                            CGCXXABI::RAA_DirectInMemory);
415992cb984SSergei Barannikov   }
416992cb984SSergei Barannikov 
417992cb984SSergei Barannikov   uint64_t Size = getContext().getTypeSize(Ty);
418992cb984SSergei Barannikov 
419d65f4232SSudharsan Veeravalli   // Ignore empty structs/unions whose size is zero. According to the calling
420d65f4232SSudharsan Veeravalli   // convention empty structs/unions are required to be sized types in C++.
421d65f4232SSudharsan Veeravalli   if (isEmptyRecord(getContext(), Ty, true) && Size == 0)
422d65f4232SSudharsan Veeravalli     return ABIArgInfo::getIgnore();
423d65f4232SSudharsan Veeravalli 
424992cb984SSergei Barannikov   // Pass floating point values via FPRs if possible.
425992cb984SSergei Barannikov   if (IsFixed && Ty->isFloatingType() && !Ty->isComplexType() &&
426992cb984SSergei Barannikov       FLen >= Size && ArgFPRsLeft) {
427992cb984SSergei Barannikov     ArgFPRsLeft--;
428992cb984SSergei Barannikov     return ABIArgInfo::getDirect();
429992cb984SSergei Barannikov   }
430992cb984SSergei Barannikov 
431992cb984SSergei Barannikov   // Complex types for the hard float ABI must be passed direct rather than
432992cb984SSergei Barannikov   // using CoerceAndExpand.
433992cb984SSergei Barannikov   if (IsFixed && Ty->isComplexType() && FLen && ArgFPRsLeft >= 2) {
434992cb984SSergei Barannikov     QualType EltTy = Ty->castAs<ComplexType>()->getElementType();
435992cb984SSergei Barannikov     if (getContext().getTypeSize(EltTy) <= FLen) {
436992cb984SSergei Barannikov       ArgFPRsLeft -= 2;
437992cb984SSergei Barannikov       return ABIArgInfo::getDirect();
438992cb984SSergei Barannikov     }
439992cb984SSergei Barannikov   }
440992cb984SSergei Barannikov 
441992cb984SSergei Barannikov   if (IsFixed && FLen && Ty->isStructureOrClassType()) {
442992cb984SSergei Barannikov     llvm::Type *Field1Ty = nullptr;
443992cb984SSergei Barannikov     llvm::Type *Field2Ty = nullptr;
444992cb984SSergei Barannikov     CharUnits Field1Off = CharUnits::Zero();
445992cb984SSergei Barannikov     CharUnits Field2Off = CharUnits::Zero();
446992cb984SSergei Barannikov     int NeededArgGPRs = 0;
447992cb984SSergei Barannikov     int NeededArgFPRs = 0;
448992cb984SSergei Barannikov     bool IsCandidate =
449992cb984SSergei Barannikov         detectFPCCEligibleStruct(Ty, Field1Ty, Field1Off, Field2Ty, Field2Off,
450992cb984SSergei Barannikov                                  NeededArgGPRs, NeededArgFPRs);
451992cb984SSergei Barannikov     if (IsCandidate && NeededArgGPRs <= ArgGPRsLeft &&
452992cb984SSergei Barannikov         NeededArgFPRs <= ArgFPRsLeft) {
453992cb984SSergei Barannikov       ArgGPRsLeft -= NeededArgGPRs;
454992cb984SSergei Barannikov       ArgFPRsLeft -= NeededArgFPRs;
455992cb984SSergei Barannikov       return coerceAndExpandFPCCEligibleStruct(Field1Ty, Field1Off, Field2Ty,
456992cb984SSergei Barannikov                                                Field2Off);
457992cb984SSergei Barannikov     }
458992cb984SSergei Barannikov   }
459992cb984SSergei Barannikov 
460992cb984SSergei Barannikov   uint64_t NeededAlign = getContext().getTypeAlign(Ty);
461992cb984SSergei Barannikov   // Determine the number of GPRs needed to pass the current argument
462992cb984SSergei Barannikov   // according to the ABI. 2*XLen-aligned varargs are passed in "aligned"
463992cb984SSergei Barannikov   // register pairs, so may consume 3 registers.
4643ac9fe69SWang Pengcheng   // TODO: To be compatible with GCC's behaviors, we don't align registers
4653ac9fe69SWang Pengcheng   // currently if we are using ILP32E calling convention. This behavior may be
4663ac9fe69SWang Pengcheng   // changed when RV32E/ILP32E is ratified.
467992cb984SSergei Barannikov   int NeededArgGPRs = 1;
468992cb984SSergei Barannikov   if (!IsFixed && NeededAlign == 2 * XLen)
4693ac9fe69SWang Pengcheng     NeededArgGPRs = 2 + (EABI && XLen == 32 ? 0 : (ArgGPRsLeft % 2));
470992cb984SSergei Barannikov   else if (Size > XLen && Size <= 2 * XLen)
471992cb984SSergei Barannikov     NeededArgGPRs = 2;
472992cb984SSergei Barannikov 
473992cb984SSergei Barannikov   if (NeededArgGPRs > ArgGPRsLeft) {
474992cb984SSergei Barannikov     NeededArgGPRs = ArgGPRsLeft;
475992cb984SSergei Barannikov   }
476992cb984SSergei Barannikov 
477992cb984SSergei Barannikov   ArgGPRsLeft -= NeededArgGPRs;
478992cb984SSergei Barannikov 
479992cb984SSergei Barannikov   if (!isAggregateTypeForABI(Ty) && !Ty->isVectorType()) {
480992cb984SSergei Barannikov     // Treat an enum type as its underlying type.
481992cb984SSergei Barannikov     if (const EnumType *EnumTy = Ty->getAs<EnumType>())
482992cb984SSergei Barannikov       Ty = EnumTy->getDecl()->getIntegerType();
483992cb984SSergei Barannikov 
484992cb984SSergei Barannikov     // All integral types are promoted to XLen width
485992cb984SSergei Barannikov     if (Size < XLen && Ty->isIntegralOrEnumerationType()) {
486ea920450SLei Huang       return extendType(Ty, CGT.ConvertType(Ty));
487992cb984SSergei Barannikov     }
488992cb984SSergei Barannikov 
489992cb984SSergei Barannikov     if (const auto *EIT = Ty->getAs<BitIntType>()) {
490992cb984SSergei Barannikov       if (EIT->getNumBits() < XLen)
491ea920450SLei Huang         return extendType(Ty, CGT.ConvertType(Ty));
492992cb984SSergei Barannikov       if (EIT->getNumBits() > 128 ||
493992cb984SSergei Barannikov           (!getContext().getTargetInfo().hasInt128Type() &&
494992cb984SSergei Barannikov            EIT->getNumBits() > 64))
495992cb984SSergei Barannikov         return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
496992cb984SSergei Barannikov     }
497992cb984SSergei Barannikov 
4988e7f1beeSBrandon Wu     return ABIArgInfo::getDirect();
499992cb984SSergei Barannikov   }
500992cb984SSergei Barannikov 
501992cb984SSergei Barannikov   if (const VectorType *VT = Ty->getAs<VectorType>())
502c92ad411SCraig Topper     if (VT->getVectorKind() == VectorKind::RVVFixedLengthData ||
503635d20e9SVladislav Belov         VT->getVectorKind() == VectorKind::RVVFixedLengthMask ||
504635d20e9SVladislav Belov         VT->getVectorKind() == VectorKind::RVVFixedLengthMask_1 ||
505635d20e9SVladislav Belov         VT->getVectorKind() == VectorKind::RVVFixedLengthMask_2 ||
506635d20e9SVladislav Belov         VT->getVectorKind() == VectorKind::RVVFixedLengthMask_4)
507992cb984SSergei Barannikov       return coerceVLSVector(Ty);
508992cb984SSergei Barannikov 
509992cb984SSergei Barannikov   // Aggregates which are <= 2*XLen will be passed in registers if possible,
510992cb984SSergei Barannikov   // so coerce to integers.
511992cb984SSergei Barannikov   if (Size <= 2 * XLen) {
512992cb984SSergei Barannikov     unsigned Alignment = getContext().getTypeAlign(Ty);
513992cb984SSergei Barannikov 
514992cb984SSergei Barannikov     // Use a single XLen int if possible, 2*XLen if 2*XLen alignment is
515992cb984SSergei Barannikov     // required, and a 2-element XLen array if only XLen alignment is required.
516992cb984SSergei Barannikov     if (Size <= XLen) {
517992cb984SSergei Barannikov       return ABIArgInfo::getDirect(
518992cb984SSergei Barannikov           llvm::IntegerType::get(getVMContext(), XLen));
519992cb984SSergei Barannikov     } else if (Alignment == 2 * XLen) {
520992cb984SSergei Barannikov       return ABIArgInfo::getDirect(
521992cb984SSergei Barannikov           llvm::IntegerType::get(getVMContext(), 2 * XLen));
522992cb984SSergei Barannikov     } else {
523992cb984SSergei Barannikov       return ABIArgInfo::getDirect(llvm::ArrayType::get(
524992cb984SSergei Barannikov           llvm::IntegerType::get(getVMContext(), XLen), 2));
525992cb984SSergei Barannikov     }
526992cb984SSergei Barannikov   }
527992cb984SSergei Barannikov   return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
528992cb984SSergei Barannikov }
529992cb984SSergei Barannikov 
530992cb984SSergei Barannikov ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy) const {
531992cb984SSergei Barannikov   if (RetTy->isVoidType())
532992cb984SSergei Barannikov     return ABIArgInfo::getIgnore();
533992cb984SSergei Barannikov 
534992cb984SSergei Barannikov   int ArgGPRsLeft = 2;
535992cb984SSergei Barannikov   int ArgFPRsLeft = FLen ? 2 : 0;
536992cb984SSergei Barannikov 
537992cb984SSergei Barannikov   // The rules for return and argument types are the same, so defer to
538992cb984SSergei Barannikov   // classifyArgumentType.
539992cb984SSergei Barannikov   return classifyArgumentType(RetTy, /*IsFixed=*/true, ArgGPRsLeft,
540992cb984SSergei Barannikov                               ArgFPRsLeft);
541992cb984SSergei Barannikov }
542992cb984SSergei Barannikov 
5436d973b45SMariya Podchishchaeva RValue RISCVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
5446d973b45SMariya Podchishchaeva                                QualType Ty, AggValueSlot Slot) const {
545992cb984SSergei Barannikov   CharUnits SlotSize = CharUnits::fromQuantity(XLen / 8);
546992cb984SSergei Barannikov 
547992cb984SSergei Barannikov   // Empty records are ignored for parameter passing purposes.
5486d973b45SMariya Podchishchaeva   if (isEmptyRecord(getContext(), Ty, true))
5496d973b45SMariya Podchishchaeva     return Slot.asRValue();
550992cb984SSergei Barannikov 
551992cb984SSergei Barannikov   auto TInfo = getContext().getTypeInfoInChars(Ty);
552992cb984SSergei Barannikov 
5533ac9fe69SWang Pengcheng   // TODO: To be compatible with GCC's behaviors, we force arguments with
5543ac9fe69SWang Pengcheng   // 2×XLEN-bit alignment and size at most 2×XLEN bits like `long long`,
5553ac9fe69SWang Pengcheng   // `unsigned long long` and `double` to have 4-byte alignment. This
5563ac9fe69SWang Pengcheng   // behavior may be changed when RV32E/ILP32E is ratified.
5573ac9fe69SWang Pengcheng   if (EABI && XLen == 32)
5583ac9fe69SWang Pengcheng     TInfo.Align = std::min(TInfo.Align, CharUnits::fromQuantity(4));
5593ac9fe69SWang Pengcheng 
560992cb984SSergei Barannikov   // Arguments bigger than 2*Xlen bytes are passed indirectly.
561992cb984SSergei Barannikov   bool IsIndirect = TInfo.Width > 2 * SlotSize;
562992cb984SSergei Barannikov 
5636d973b45SMariya Podchishchaeva   return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect, TInfo, SlotSize,
5646d973b45SMariya Podchishchaeva                           /*AllowHigherAlign=*/true, Slot);
565992cb984SSergei Barannikov }
566992cb984SSergei Barannikov 
567ea920450SLei Huang ABIArgInfo RISCVABIInfo::extendType(QualType Ty, llvm::Type *CoerceTy) const {
568992cb984SSergei Barannikov   int TySize = getContext().getTypeSize(Ty);
569992cb984SSergei Barannikov   // RV64 ABI requires unsigned 32 bit integers to be sign extended.
570992cb984SSergei Barannikov   if (XLen == 64 && Ty->isUnsignedIntegerOrEnumerationType() && TySize == 32)
571ea920450SLei Huang     return ABIArgInfo::getSignExtend(Ty, CoerceTy);
572ea920450SLei Huang   return ABIArgInfo::getExtend(Ty, CoerceTy);
573992cb984SSergei Barannikov }
574992cb984SSergei Barannikov 
575992cb984SSergei Barannikov namespace {
576992cb984SSergei Barannikov class RISCVTargetCodeGenInfo : public TargetCodeGenInfo {
577992cb984SSergei Barannikov public:
578992cb984SSergei Barannikov   RISCVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen,
5793ac9fe69SWang Pengcheng                          unsigned FLen, bool EABI)
5803ac9fe69SWang Pengcheng       : TargetCodeGenInfo(
581b84ce997SKuba (Brecka) Mracek             std::make_unique<RISCVABIInfo>(CGT, XLen, FLen, EABI)) {
582b84ce997SKuba (Brecka) Mracek     SwiftInfo =
583b84ce997SKuba (Brecka) Mracek         std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false);
584b84ce997SKuba (Brecka) Mracek   }
585992cb984SSergei Barannikov 
586992cb984SSergei Barannikov   void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
587992cb984SSergei Barannikov                            CodeGen::CodeGenModule &CGM) const override {
588992cb984SSergei Barannikov     const auto *FD = dyn_cast_or_null<FunctionDecl>(D);
589992cb984SSergei Barannikov     if (!FD) return;
590992cb984SSergei Barannikov 
591335e68d8SJesse Huang     auto *Fn = cast<llvm::Function>(GV);
592335e68d8SJesse Huang 
593335e68d8SJesse Huang     if (CGM.getCodeGenOpts().CFProtectionReturn)
594335e68d8SJesse Huang       Fn->addFnAttr("hw-shadow-stack");
595335e68d8SJesse Huang 
596992cb984SSergei Barannikov     const auto *Attr = FD->getAttr<RISCVInterruptAttr>();
597992cb984SSergei Barannikov     if (!Attr)
598992cb984SSergei Barannikov       return;
599992cb984SSergei Barannikov 
600992cb984SSergei Barannikov     const char *Kind;
601992cb984SSergei Barannikov     switch (Attr->getInterrupt()) {
602992cb984SSergei Barannikov     case RISCVInterruptAttr::supervisor: Kind = "supervisor"; break;
603992cb984SSergei Barannikov     case RISCVInterruptAttr::machine: Kind = "machine"; break;
604992cb984SSergei Barannikov     }
605992cb984SSergei Barannikov 
606992cb984SSergei Barannikov     Fn->addFnAttr("interrupt", Kind);
607992cb984SSergei Barannikov   }
608992cb984SSergei Barannikov };
609992cb984SSergei Barannikov } // namespace
610992cb984SSergei Barannikov 
611992cb984SSergei Barannikov std::unique_ptr<TargetCodeGenInfo>
612992cb984SSergei Barannikov CodeGen::createRISCVTargetCodeGenInfo(CodeGenModule &CGM, unsigned XLen,
6133ac9fe69SWang Pengcheng                                       unsigned FLen, bool EABI) {
6143ac9fe69SWang Pengcheng   return std::make_unique<RISCVTargetCodeGenInfo>(CGM.getTypes(), XLen, FLen,
6153ac9fe69SWang Pengcheng                                                   EABI);
616992cb984SSergei Barannikov }
617