Skip to content

Commit 6db66a9

Browse files
xdoardoresistor
authored andcommitted
[CHERIoT] Pass two-cap-sized return values and arguments in registers
1 parent 5d99e3d commit 6db66a9

File tree

3 files changed

+1631
-22
lines changed

3 files changed

+1631
-22
lines changed

clang/lib/CodeGen/Targets/RISCV.cpp

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
3868
public:
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

Comments
 (0)