Skip to content

Commit c890fbc

Browse files
committed
[CHERIoT] Pass two-cap-sized return values and arguments in registers
1 parent d2286ce commit c890fbc

File tree

3 files changed

+1520
-21
lines changed

3 files changed

+1520
-21
lines changed

clang/lib/CodeGen/Targets/RISCV.cpp

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
3840
public:
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+
409425
ABIArgInfo 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

Comments
 (0)