@@ -35,6 +35,8 @@ class RISCVABIInfo : public DefaultABIInfo {
3535 llvm::Type *&Field2Ty,
3636 CharUnits &Field2Off) const ;
3737
38+ bool shouldPassStructDirectInCapRegisters (uint64_t Size, QualType Ty) const ;
39+
3840public:
3941 RISCVABIInfo (CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen,
4042 bool EABI)
@@ -406,6 +408,20 @@ ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty) const {
406408 return ABIArgInfo::getDirect (ResType);
407409}
408410
411+ bool RISCVABIInfo::shouldPassStructDirectInCapRegisters (uint64_t Size,
412+ QualType Ty) const {
413+ StringRef TargetABI = getTarget ().getABI ();
414+ bool IsCheriot = TargetABI == " cheriot" || TargetABI == " cheriot-baremetal" ;
415+
416+ if (auto *RT = Ty->getAs <RecordType>()) {
417+ unsigned MaxCapRegs = IsCheriot ? 2 : 1 ;
418+ return Size == MaxCapRegs * getTarget ().getCHERICapabilityWidth () &&
419+ getContext ().containsCapabilities (RT->getDecl ());
420+ }
421+
422+ return false ;
423+ }
424+
409425ABIArgInfo RISCVABIInfo::classifyArgumentType (QualType Ty, bool IsFixed,
410426 int &ArgGPRsLeft,
411427 int &ArgFPRsLeft) const {
@@ -428,19 +444,17 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
428444 if (isEmptyRecord (getContext (), Ty, true ) && Size == 0 )
429445 return ABIArgInfo::getIgnore ();
430446
431- bool IsSingleCapRecord = false ;
432- if (auto *RT = Ty->getAs <RecordType>())
433- IsSingleCapRecord = Size == getTarget ().getCHERICapabilityWidth () &&
434- getContext ().containsCapabilities (RT->getDecl ());
447+ auto CapabilityWidth = getTarget ().getCHERICapabilityWidth ();
448+ bool ForcePassInCapRegs = shouldPassStructDirectInCapRegisters (Size, Ty);
435449
436- bool IsCapability = Ty->isCHERICapabilityType (getContext ()) ||
437- IsSingleCapRecord ;
450+ bool IsSingleCapability = Ty->isCHERICapabilityType (getContext ()) ||
451+ (ForcePassInCapRegs && Size == CapabilityWidth) ;
438452
439453 // Capabilities (including single-capability records, which are treated the
440454 // same as a single capability) are passed indirectly for hybrid varargs.
441455 // Anything larger is bigger than 2*XLEN and thus automatically passed
442456 // indirectly anyway.
443- if (!IsFixed && IsCapability &&
457+ if (!IsFixed && IsSingleCapability &&
444458 !getContext ().getTargetInfo ().areAllPointersCapabilities ()) {
445459 if (ArgGPRsLeft)
446460 ArgGPRsLeft -= 1 ;
@@ -495,9 +509,9 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
495509 // TODO: Pairs involving capabilities should be passed in registers too like
496510 // int/fp pairs (requires thought for fp+cap when out of FPRs).
497511 int NeededArgGPRs = 1 ;
498- if (!IsCapability && !IsFixed && NeededAlign == 2 * XLen)
512+ if (!IsSingleCapability && !IsFixed && NeededAlign == 2 * XLen)
499513 NeededArgGPRs = 2 + (EABI && XLen == 32 ? 0 : (ArgGPRsLeft % 2 ));
500- else if (!IsCapability && Size > XLen && Size <= 2 * XLen)
514+ else if (!IsSingleCapability && Size > XLen && Size <= 2 * XLen)
501515 NeededArgGPRs = 2 ;
502516
503517 if (NeededArgGPRs > ArgGPRsLeft) {
@@ -528,7 +542,7 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
528542 return ABIArgInfo::getDirect ();
529543 }
530544
531- if (IsSingleCapRecord )
545+ if (ForcePassInCapRegs )
532546 return ABIArgInfo::getDirect ();
533547
534548 if (const VectorType *VT = Ty->getAs <VectorType>())
@@ -593,21 +607,19 @@ RValue RISCVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
593607 if (EABI && XLen == 32 && !IsCheriot)
594608 TInfo.Align = std::min (TInfo.Align , CharUnits::fromQuantity (4 ));
595609
596- bool IsSingleCapRecord = false ;
597- CharUnits CapabilityWidth =
598- CharUnits::fromQuantity (getTarget ().getCHERICapabilityWidth () / 8 );
599- if (const auto *RT = Ty->getAs <RecordType>())
600- IsSingleCapRecord = TInfo.Width == CapabilityWidth &&
601- getContext ().containsCapabilities (RT->getDecl ());
610+ uint64_t Size = TInfo.Width .getQuantity () * 8 ;
611+ auto CapabilityWidth = getTarget ().getCHERICapabilityWidth ();
612+ bool ForcePassInCapRegs = shouldPassStructDirectInCapRegisters (Size, Ty);
602613
603- bool IsCapability = Ty->isCHERICapabilityType (getContext ()) ||
604- IsSingleCapRecord ;
614+ bool IsSingleCapability = Ty->isCHERICapabilityType (getContext ()) ||
615+ (ForcePassInCapRegs && Size == CapabilityWidth) ;
605616
606617 // Arguments bigger than 2*Xlen bytes are passed indirectly, as are
607618 // capabilities for the hybrid ABI.
608- bool IsIndirect = TInfo.Width > 2 * SlotSize ||
609- (!getContext ().getTargetInfo ().areAllPointersCapabilities () &&
610- IsCapability);
619+ bool IsIndirect =
620+ TInfo.Width > 2 * SlotSize ||
621+ (!getContext ().getTargetInfo ().areAllPointersCapabilities () &&
622+ IsSingleCapability);
611623
612624 return emitVoidPtrVAArg (CGF, VAListAddr, Ty, IsIndirect, TInfo, SlotSize,
613625 /* AllowHigherAlign=*/ true , Slot);
0 commit comments