@@ -35,6 +35,36 @@ class RISCVABIInfo : public DefaultABIInfo {
3535 llvm::Type *&Field2Ty,
3636 CharUnits &Field2Off) const ;
3737
38+ // / CHERI(oT)-specific: Figure out how many registers are needed to pass a
39+ // / value of the given type and size directly in register(s). The value of
40+ // / `-1` means that the value should be passed indirectly.
41+ // /
42+ // / Note: `Size` is in bits.
43+ int8_t getCapRegsForStruct (uint64_t Size, QualType Ty) const {
44+ auto &T = getTarget ();
45+ auto CapWidth = T.getCHERICapabilityWidth ();
46+
47+ if (Size % CapWidth)
48+ return -1 ;
49+
50+ auto *RT = Ty->getAs <RecordType>();
51+
52+ StringRef TargetABI = T.getABI ();
53+ bool IsCheriot = TargetABI == " cheriot" || TargetABI == " cheriot-baremetal" ;
54+
55+ auto Q = Size / CapWidth;
56+
57+ if (RT && getContext ().containsCapabilities (RT->getDecl ())) {
58+ if (Q == 1 )
59+ return 1 ;
60+
61+ if (IsCheriot && Q == 2 )
62+ return 2 ;
63+ }
64+
65+ return -1 ;
66+ }
67+
3868public:
3969 RISCVABIInfo (CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen,
4070 bool EABI)
@@ -428,19 +458,16 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
428458 if (isEmptyRecord (getContext (), Ty, true ) && Size == 0 )
429459 return ABIArgInfo::getIgnore ();
430460
431- bool IsSingleCapRecord = false ;
432- if (auto *RT = Ty->getAs <RecordType>())
433- IsSingleCapRecord = Size == getTarget ().getCHERICapabilityWidth () &&
434- getContext ().containsCapabilities (RT->getDecl ());
435-
436- bool IsCapability = Ty->isCHERICapabilityType (getContext ()) ||
437- IsSingleCapRecord;
461+ auto CapRegsForStruct = getCapRegsForStruct (Size, Ty);
462+ bool ForcePassInCapRegs = CapRegsForStruct > 0 ;
463+ bool IsSingleCapability =
464+ Ty->isCHERICapabilityType (getContext ()) || CapRegsForStruct == 1 ;
438465
439466 // Capabilities (including single-capability records, which are treated the
440467 // same as a single capability) are passed indirectly for hybrid varargs.
441468 // Anything larger is bigger than 2*XLEN and thus automatically passed
442469 // indirectly anyway.
443- if (!IsFixed && IsCapability &&
470+ if (!IsFixed && IsSingleCapability &&
444471 !getContext ().getTargetInfo ().areAllPointersCapabilities ()) {
445472 if (ArgGPRsLeft)
446473 ArgGPRsLeft -= 1 ;
@@ -495,9 +522,9 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
495522 // TODO: Pairs involving capabilities should be passed in registers too like
496523 // int/fp pairs (requires thought for fp+cap when out of FPRs).
497524 int NeededArgGPRs = 1 ;
498- if (!IsCapability && !IsFixed && NeededAlign == 2 * XLen)
525+ if (!IsSingleCapability && !IsFixed && NeededAlign == 2 * XLen)
499526 NeededArgGPRs = 2 + (EABI && XLen == 32 ? 0 : (ArgGPRsLeft % 2 ));
500- else if (!IsCapability && Size > XLen && Size <= 2 * XLen)
527+ else if (!IsSingleCapability && Size > XLen && Size <= 2 * XLen)
501528 NeededArgGPRs = 2 ;
502529
503530 if (NeededArgGPRs > ArgGPRsLeft) {
@@ -528,7 +555,7 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
528555 return ABIArgInfo::getDirect ();
529556 }
530557
531- if (IsSingleCapRecord )
558+ if (ForcePassInCapRegs )
532559 return ABIArgInfo::getDirect ();
533560
534561 if (const VectorType *VT = Ty->getAs <VectorType>())
@@ -593,21 +620,18 @@ RValue RISCVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
593620 if (EABI && XLen == 32 && !IsCheriot)
594621 TInfo.Align = std::min (TInfo.Align , CharUnits::fromQuantity (4 ));
595622
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 ());
623+ uint64_t Size = TInfo.Width .getQuantity () * 8 ;
602624
603- bool IsCapability = Ty->isCHERICapabilityType (getContext ()) ||
604- IsSingleCapRecord;
625+ auto CapRegsForStruct = getCapRegsForStruct (Size, Ty);
626+ bool IsSingleCapability =
627+ Ty->isCHERICapabilityType (getContext ()) || CapRegsForStruct == 1 ;
605628
606629 // Arguments bigger than 2*Xlen bytes are passed indirectly, as are
607630 // capabilities for the hybrid ABI.
608- bool IsIndirect = TInfo.Width > 2 * SlotSize ||
609- (!getContext ().getTargetInfo ().areAllPointersCapabilities () &&
610- IsCapability);
631+ bool IsIndirect =
632+ TInfo.Width > 2 * SlotSize ||
633+ (!getContext ().getTargetInfo ().areAllPointersCapabilities () &&
634+ IsSingleCapability);
611635
612636 return emitVoidPtrVAArg (CGF, VAListAddr, Ty, IsIndirect, TInfo, SlotSize,
613637 /* AllowHigherAlign=*/ true , Slot);
0 commit comments