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