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