@@ -429,9 +429,43 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
429429 return ABIArgInfo::getIgnore ();
430430
431431 bool IsSingleCapRecord = false ;
432- if (auto *RT = Ty->getAs <RecordType>())
432+ bool FitsInTwoRegs = false ;
433+ auto *RD = dyn_cast_if_present<RecordDecl>(Ty->getAsTagDecl ());
434+ if (RD) {
433435 IsSingleCapRecord = Size == getTarget ().getCHERICapabilityWidth () &&
434- getContext ().containsCapabilities (RT->getDecl ());
436+ getContext ().containsCapabilities (RD);
437+ FitsInTwoRegs = IsSingleCapRecord;
438+
439+ StringRef TargetABI = getTarget ().getABI ();
440+ bool IsCheriot = TargetABI == " cheriot" || TargetABI == " cheriot-baremetal" ;
441+
442+ // If the target platform is CHERIoT, Check if the record fits in two
443+ // registers, that is:
444+ // 1. it has two fields
445+ // 2. any of the two fields is either a capability or a type whose size can
446+ // fit in the data part of a register
447+ if (!IsSingleCapRecord && IsCheriot) {
448+ int SeenFields = 0 ;
449+ for (const FieldDecl *Field : RD->fields ()) {
450+ if (++SeenFields > 2 ) {
451+ FitsInTwoRegs = false ;
452+ break ;
453+ }
454+
455+ auto FieldTy = Field->getType ();
456+ auto FieldInfo = Field->getASTContext ().getTypeInfo (FieldTy);
457+ if (!FieldTy->isAnyPointerType () &&
458+ FieldInfo.Width > getTarget ().getRegisterWidth ()) {
459+ FitsInTwoRegs = false ;
460+ break ;
461+ }
462+
463+ if (SeenFields == 2 ) {
464+ FitsInTwoRegs = true ;
465+ }
466+ }
467+ }
468+ }
435469
436470 bool IsCapability = Ty->isCHERICapabilityType (getContext ()) ||
437471 IsSingleCapRecord;
@@ -528,7 +562,7 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
528562 return ABIArgInfo::getDirect ();
529563 }
530564
531- if (IsSingleCapRecord )
565+ if (FitsInTwoRegs )
532566 return ABIArgInfo::getDirect ();
533567
534568 if (const VectorType *VT = Ty->getAs <VectorType>())
0 commit comments