@@ -9188,25 +9188,44 @@ static bool getTypeString(SmallStringEnc &Enc, const Decl *D,
9188
9188
namespace {
9189
9189
class RISCVABIInfo : public DefaultABIInfo {
9190
9190
private:
9191
- unsigned XLen; // Size of the integer ('x') registers in bits.
9191
+ // Size of the integer ('x') registers in bits.
9192
+ unsigned XLen;
9193
+ // Size of the floating point ('f') registers in bits. Note that the target
9194
+ // ISA might have a wider FLen than the selected ABI (e.g. an RV32IF target
9195
+ // with soft float ABI has FLen==0).
9196
+ unsigned FLen;
9192
9197
static const int NumArgGPRs = 8 ;
9198
+ static const int NumArgFPRs = 8 ;
9199
+ bool detectFPCCEligibleStructHelper (QualType Ty, CharUnits CurOff,
9200
+ llvm::Type *&Field1Ty,
9201
+ CharUnits &Field1Off,
9202
+ llvm::Type *&Field2Ty,
9203
+ CharUnits &Field2Off) const ;
9193
9204
9194
9205
public:
9195
- RISCVABIInfo (CodeGen::CodeGenTypes &CGT, unsigned XLen)
9196
- : DefaultABIInfo(CGT), XLen(XLen) {}
9206
+ RISCVABIInfo (CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen )
9207
+ : DefaultABIInfo(CGT), XLen(XLen), FLen(FLen) {}
9197
9208
9198
9209
// DefaultABIInfo's classifyReturnType and classifyArgumentType are
9199
9210
// non-virtual, but computeInfo is virtual, so we overload it.
9200
9211
void computeInfo (CGFunctionInfo &FI) const override ;
9201
9212
9202
- ABIArgInfo classifyArgumentType (QualType Ty, bool IsFixed,
9203
- int &ArgGPRsLeft ) const ;
9213
+ ABIArgInfo classifyArgumentType (QualType Ty, bool IsFixed, int &ArgGPRsLeft,
9214
+ int &ArgFPRsLeft ) const ;
9204
9215
ABIArgInfo classifyReturnType (QualType RetTy) const ;
9205
9216
9206
9217
Address EmitVAArg (CodeGenFunction &CGF, Address VAListAddr,
9207
9218
QualType Ty) const override ;
9208
9219
9209
9220
ABIArgInfo extendType (QualType Ty) const ;
9221
+
9222
+ bool detectFPCCEligibleStruct (QualType Ty, llvm::Type *&Field1Ty, CharUnits &Field1Off,
9223
+ llvm::Type *&Field2Ty, CharUnits &Field2Off,
9224
+ int &NeededArgGPRs, int &NeededArgFPRs) const ;
9225
+ ABIArgInfo coerceAndExpandFPCCEligibleStruct (llvm::Type *Field1Ty,
9226
+ CharUnits Field1Off,
9227
+ llvm::Type *Field2Ty,
9228
+ CharUnits Field2Off) const ;
9210
9229
};
9211
9230
} // end anonymous namespace
9212
9231
@@ -9228,18 +9247,214 @@ void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const {
9228
9247
// different for variadic arguments, we must also track whether we are
9229
9248
// examining a vararg or not.
9230
9249
int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs;
9250
+ int ArgFPRsLeft = FLen ? NumArgFPRs : 0 ;
9231
9251
int NumFixedArgs = FI.getNumRequiredArgs ();
9232
9252
9233
9253
int ArgNum = 0 ;
9234
9254
for (auto &ArgInfo : FI.arguments ()) {
9235
9255
bool IsFixed = ArgNum < NumFixedArgs;
9236
- ArgInfo.info = classifyArgumentType (ArgInfo.type , IsFixed, ArgGPRsLeft);
9256
+ ArgInfo.info =
9257
+ classifyArgumentType (ArgInfo.type , IsFixed, ArgGPRsLeft, ArgFPRsLeft);
9237
9258
ArgNum++;
9238
9259
}
9239
9260
}
9240
9261
9262
+ // Returns true if the struct is a potential candidate for the floating point
9263
+ // calling convention. If this function returns true, the caller is
9264
+ // responsible for checking that if there is only a single field then that
9265
+ // field is a float.
9266
+ bool RISCVABIInfo::detectFPCCEligibleStructHelper (QualType Ty, CharUnits CurOff,
9267
+ llvm::Type *&Field1Ty,
9268
+ CharUnits &Field1Off,
9269
+ llvm::Type *&Field2Ty,
9270
+ CharUnits &Field2Off) const {
9271
+ bool IsInt = Ty->isIntegralOrEnumerationType ();
9272
+ bool IsFloat = Ty->isRealFloatingType ();
9273
+
9274
+ if (IsInt || IsFloat) {
9275
+ uint64_t Size = getContext ().getTypeSize (Ty);
9276
+ if (IsInt && Size > XLen)
9277
+ return false ;
9278
+ // Can't be eligible if larger than the FP registers. Half precision isn't
9279
+ // currently supported on RISC-V and the ABI hasn't been confirmed, so
9280
+ // default to the integer ABI in that case.
9281
+ if (IsFloat && (Size > FLen || Size < 32 ))
9282
+ return false ;
9283
+ // Can't be eligible if an integer type was already found (int+int pairs
9284
+ // are not eligible).
9285
+ if (IsInt && Field1Ty && Field1Ty->isIntegerTy ())
9286
+ return false ;
9287
+ if (!Field1Ty) {
9288
+ Field1Ty = CGT.ConvertType (Ty);
9289
+ Field1Off = CurOff;
9290
+ return true ;
9291
+ }
9292
+ if (!Field2Ty) {
9293
+ Field2Ty = CGT.ConvertType (Ty);
9294
+ Field2Off = CurOff;
9295
+ return true ;
9296
+ }
9297
+ return false ;
9298
+ }
9299
+
9300
+ if (auto CTy = Ty->getAs <ComplexType>()) {
9301
+ if (Field1Ty)
9302
+ return false ;
9303
+ QualType EltTy = CTy->getElementType ();
9304
+ if (getContext ().getTypeSize (EltTy) > FLen)
9305
+ return false ;
9306
+ Field1Ty = CGT.ConvertType (EltTy);
9307
+ Field1Off = CurOff;
9308
+ assert (CurOff.isZero () && " Unexpected offset for first field" );
9309
+ Field2Ty = Field1Ty;
9310
+ Field2Off = Field1Off + getContext ().getTypeSizeInChars (EltTy);
9311
+ return true ;
9312
+ }
9313
+
9314
+ if (const ConstantArrayType *ATy = getContext ().getAsConstantArrayType (Ty)) {
9315
+ uint64_t ArraySize = ATy->getSize ().getZExtValue ();
9316
+ QualType EltTy = ATy->getElementType ();
9317
+ CharUnits EltSize = getContext ().getTypeSizeInChars (EltTy);
9318
+ for (uint64_t i = 0 ; i < ArraySize; ++i) {
9319
+ bool Ret = detectFPCCEligibleStructHelper (EltTy, CurOff, Field1Ty, Field1Off,
9320
+ Field2Ty, Field2Off);
9321
+ if (!Ret)
9322
+ return false ;
9323
+ CurOff += EltSize;
9324
+ }
9325
+ return true ;
9326
+ }
9327
+
9328
+ if (const auto *RTy = Ty->getAs <RecordType>()) {
9329
+ // Structures with either a non-trivial destructor or a non-trivial
9330
+ // copy constructor are not eligible for the FP calling convention.
9331
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI (Ty, CGT.getCXXABI ()))
9332
+ return false ;
9333
+ if (isEmptyRecord (getContext (), Ty, true ))
9334
+ return true ;
9335
+ const RecordDecl *RD = RTy->getDecl ();
9336
+ // Unions aren't eligible unless they're empty (which is caught above).
9337
+ if (RD->isUnion ())
9338
+ return false ;
9339
+ int ZeroWidthBitFieldCount = 0 ;
9340
+ for (const FieldDecl *FD : RD->fields ()) {
9341
+ const ASTRecordLayout &Layout = getContext ().getASTRecordLayout (RD);
9342
+ uint64_t FieldOffInBits = Layout.getFieldOffset (FD->getFieldIndex ());
9343
+ QualType QTy = FD->getType ();
9344
+ if (FD->isBitField ()) {
9345
+ unsigned BitWidth = FD->getBitWidthValue (getContext ());
9346
+ // Allow a bitfield with a type greater than XLen as long as the
9347
+ // bitwidth is XLen or less.
9348
+ if (getContext ().getTypeSize (QTy) > XLen && BitWidth <= XLen)
9349
+ QTy = getContext ().getIntTypeForBitwidth (XLen, false );
9350
+ if (BitWidth == 0 ) {
9351
+ ZeroWidthBitFieldCount++;
9352
+ continue ;
9353
+ }
9354
+ }
9355
+
9356
+ bool Ret = detectFPCCEligibleStructHelper (
9357
+ QTy, CurOff + getContext ().toCharUnitsFromBits (FieldOffInBits),
9358
+ Field1Ty, Field1Off, Field2Ty, Field2Off);
9359
+ if (!Ret)
9360
+ return false ;
9361
+
9362
+ // As a quirk of the ABI, zero-width bitfields aren't ignored for fp+fp
9363
+ // or int+fp structs, but are ignored for a struct with an fp field and
9364
+ // any number of zero-width bitfields.
9365
+ if (Field2Ty && ZeroWidthBitFieldCount > 0 )
9366
+ return false ;
9367
+ }
9368
+ return Field1Ty != nullptr ;
9369
+ }
9370
+
9371
+ return false ;
9372
+ }
9373
+
9374
+ // Determine if a struct is eligible for passing according to the floating
9375
+ // point calling convention (i.e., when flattened it contains a single fp
9376
+ // value, fp+fp, or int+fp of appropriate size). If so, NeededArgFPRs and
9377
+ // NeededArgGPRs are incremented appropriately.
9378
+ bool RISCVABIInfo::detectFPCCEligibleStruct (QualType Ty, llvm::Type *&Field1Ty,
9379
+ CharUnits &Field1Off,
9380
+ llvm::Type *&Field2Ty,
9381
+ CharUnits &Field2Off,
9382
+ int &NeededArgGPRs,
9383
+ int &NeededArgFPRs) const {
9384
+ Field1Ty = nullptr ;
9385
+ Field2Ty = nullptr ;
9386
+ NeededArgGPRs = 0 ;
9387
+ NeededArgFPRs = 0 ;
9388
+ bool IsCandidate = detectFPCCEligibleStructHelper (
9389
+ Ty, CharUnits::Zero (), Field1Ty, Field1Off, Field2Ty, Field2Off);
9390
+ // Not really a candidate if we have a single int but no float.
9391
+ if (Field1Ty && !Field2Ty && !Field1Ty->isFloatingPointTy ())
9392
+ return IsCandidate = false ;
9393
+ if (!IsCandidate)
9394
+ return false ;
9395
+ if (Field1Ty && Field1Ty->isFloatingPointTy ())
9396
+ NeededArgFPRs++;
9397
+ else if (Field1Ty)
9398
+ NeededArgGPRs++;
9399
+ if (Field2Ty && Field2Ty->isFloatingPointTy ())
9400
+ NeededArgFPRs++;
9401
+ else if (Field2Ty)
9402
+ NeededArgGPRs++;
9403
+ return IsCandidate;
9404
+ }
9405
+
9406
+ // Call getCoerceAndExpand for the two-element flattened struct described by
9407
+ // Field1Ty, Field1Off, Field2Ty, Field2Off. This method will create an appropriate
9408
+ // coerceToType and unpaddedCoerceToType.
9409
+ ABIArgInfo RISCVABIInfo::coerceAndExpandFPCCEligibleStruct (
9410
+ llvm::Type *Field1Ty, CharUnits Field1Off, llvm::Type *Field2Ty, CharUnits Field2Off) const {
9411
+ SmallVector<llvm::Type *, 3 > CoerceElts;
9412
+ SmallVector<llvm::Type *, 2 > UnpaddedCoerceElts;
9413
+ if (!Field1Off.isZero ())
9414
+ CoerceElts.push_back (llvm::ArrayType::get (
9415
+ llvm::Type::getInt8Ty (getVMContext ()), Field1Off.getQuantity ()));
9416
+
9417
+ CoerceElts.push_back (Field1Ty);
9418
+ UnpaddedCoerceElts.push_back (Field1Ty);
9419
+
9420
+ if (!Field2Ty) {
9421
+ return ABIArgInfo::getCoerceAndExpand (
9422
+ llvm::StructType::get (getVMContext (), CoerceElts, !Field1Off.isZero ()),
9423
+ UnpaddedCoerceElts[0 ]);
9424
+ }
9425
+
9426
+ CharUnits Field2Align =
9427
+ CharUnits::fromQuantity (getDataLayout ().getABITypeAlignment (Field2Ty));
9428
+ CharUnits Field1Size =
9429
+ CharUnits::fromQuantity (getDataLayout ().getTypeStoreSize (Field1Ty));
9430
+ CharUnits Field2OffNoPadNoPack = Field1Size.alignTo (Field2Align);
9431
+
9432
+ CharUnits Padding = CharUnits::Zero ();
9433
+ if (Field2Off > Field2OffNoPadNoPack)
9434
+ Padding = Field2Off - Field2OffNoPadNoPack;
9435
+ else if (Field2Off != Field2Align && Field2Off > Field1Size)
9436
+ Padding = Field2Off - Field1Size;
9437
+
9438
+ bool IsPacked = !Field2Off.isMultipleOf (Field2Align);
9439
+
9440
+ if (!Padding.isZero ())
9441
+ CoerceElts.push_back (llvm::ArrayType::get (
9442
+ llvm::Type::getInt8Ty (getVMContext ()), Padding.getQuantity ()));
9443
+
9444
+ CoerceElts.push_back (Field2Ty);
9445
+ UnpaddedCoerceElts.push_back (Field2Ty);
9446
+
9447
+ auto CoerceToType =
9448
+ llvm::StructType::get (getVMContext (), CoerceElts, IsPacked);
9449
+ auto UnpaddedCoerceToType =
9450
+ llvm::StructType::get (getVMContext (), UnpaddedCoerceElts, IsPacked);
9451
+
9452
+ return ABIArgInfo::getCoerceAndExpand (CoerceToType, UnpaddedCoerceToType);
9453
+ }
9454
+
9241
9455
ABIArgInfo RISCVABIInfo::classifyArgumentType (QualType Ty, bool IsFixed,
9242
- int &ArgGPRsLeft) const {
9456
+ int &ArgGPRsLeft,
9457
+ int &ArgFPRsLeft) const {
9243
9458
assert (ArgGPRsLeft <= NumArgGPRs && " Arg GPR tracking underflow" );
9244
9459
Ty = useFirstFieldIfTransparentUnion (Ty);
9245
9460
@@ -9257,6 +9472,40 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
9257
9472
return ABIArgInfo::getIgnore ();
9258
9473
9259
9474
uint64_t Size = getContext ().getTypeSize (Ty);
9475
+
9476
+ // Pass floating point values via FPRs if possible.
9477
+ if (IsFixed && Ty->isFloatingType () && FLen >= Size && ArgFPRsLeft) {
9478
+ ArgFPRsLeft--;
9479
+ return ABIArgInfo::getDirect ();
9480
+ }
9481
+
9482
+ // Complex types for the hard float ABI must be passed direct rather than
9483
+ // using CoerceAndExpand.
9484
+ if (IsFixed && Ty->isComplexType () && FLen && ArgFPRsLeft >= 2 ) {
9485
+ QualType EltTy = Ty->getAs <ComplexType>()->getElementType ();
9486
+ if (getContext ().getTypeSize (EltTy) <= FLen) {
9487
+ ArgFPRsLeft -= 2 ;
9488
+ return ABIArgInfo::getDirect ();
9489
+ }
9490
+ }
9491
+
9492
+ if (IsFixed && FLen && Ty->isStructureOrClassType ()) {
9493
+ llvm::Type *Field1Ty = nullptr ;
9494
+ llvm::Type *Field2Ty = nullptr ;
9495
+ CharUnits Field1Off = CharUnits::Zero ();
9496
+ CharUnits Field2Off = CharUnits::Zero ();
9497
+ int NeededArgGPRs;
9498
+ int NeededArgFPRs;
9499
+ bool IsCandidate = detectFPCCEligibleStruct (
9500
+ Ty, Field1Ty, Field1Off, Field2Ty, Field2Off, NeededArgGPRs, NeededArgFPRs);
9501
+ if (IsCandidate && NeededArgGPRs <= ArgGPRsLeft &&
9502
+ NeededArgFPRs <= ArgFPRsLeft) {
9503
+ ArgGPRsLeft -= NeededArgGPRs;
9504
+ ArgFPRsLeft -= NeededArgFPRs;
9505
+ return coerceAndExpandFPCCEligibleStruct (Field1Ty, Field1Off, Field2Ty, Field2Off);
9506
+ }
9507
+ }
9508
+
9260
9509
uint64_t NeededAlign = getContext ().getTypeAlign (Ty);
9261
9510
bool MustUseStack = false ;
9262
9511
// Determine the number of GPRs needed to pass the current argument
@@ -9315,10 +9564,12 @@ ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy) const {
9315
9564
return ABIArgInfo::getIgnore ();
9316
9565
9317
9566
int ArgGPRsLeft = 2 ;
9567
+ int ArgFPRsLeft = FLen ? 2 : 0 ;
9318
9568
9319
9569
// The rules for return and argument types are the same, so defer to
9320
9570
// classifyArgumentType.
9321
- return classifyArgumentType (RetTy, /* IsFixed=*/ true , ArgGPRsLeft);
9571
+ return classifyArgumentType (RetTy, /* IsFixed=*/ true , ArgGPRsLeft,
9572
+ ArgFPRsLeft);
9322
9573
}
9323
9574
9324
9575
Address RISCVABIInfo::EmitVAArg (CodeGenFunction &CGF, Address VAListAddr,
@@ -9353,8 +9604,9 @@ ABIArgInfo RISCVABIInfo::extendType(QualType Ty) const {
9353
9604
namespace {
9354
9605
class RISCVTargetCodeGenInfo : public TargetCodeGenInfo {
9355
9606
public:
9356
- RISCVTargetCodeGenInfo (CodeGen::CodeGenTypes &CGT, unsigned XLen)
9357
- : TargetCodeGenInfo(new RISCVABIInfo(CGT, XLen)) {}
9607
+ RISCVTargetCodeGenInfo (CodeGen::CodeGenTypes &CGT, unsigned XLen,
9608
+ unsigned FLen)
9609
+ : TargetCodeGenInfo(new RISCVABIInfo(CGT, XLen, FLen)) {}
9358
9610
9359
9611
void setTargetAttributes (const Decl *D, llvm::GlobalValue *GV,
9360
9612
CodeGen::CodeGenModule &CGM) const override {
@@ -9493,9 +9745,16 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
9493
9745
return SetCGInfo (new MSP430TargetCodeGenInfo (Types));
9494
9746
9495
9747
case llvm::Triple::riscv32:
9496
- return SetCGInfo (new RISCVTargetCodeGenInfo (Types, 32 ));
9497
- case llvm::Triple::riscv64:
9498
- return SetCGInfo (new RISCVTargetCodeGenInfo (Types, 64 ));
9748
+ case llvm::Triple::riscv64: {
9749
+ StringRef ABIStr = getTarget ().getABI ();
9750
+ unsigned XLen = getTarget ().getPointerWidth (0 );
9751
+ unsigned ABIFLen = 0 ;
9752
+ if (ABIStr.endswith (" f" ))
9753
+ ABIFLen = 32 ;
9754
+ else if (ABIStr.endswith (" d" ))
9755
+ ABIFLen = 64 ;
9756
+ return SetCGInfo (new RISCVTargetCodeGenInfo (Types, XLen, ABIFLen));
9757
+ }
9499
9758
9500
9759
case llvm::Triple::systemz: {
9501
9760
bool HasVector = getTarget ().getABI () == " vector" ;
0 commit comments