Skip to content

Commit

Permalink
[GCAtomic] Treat single capability structs like a capability
Browse files Browse the repository at this point in the history
This allows emitting inline atomics instead of needing a libcall and
avoids casting such structs to i128.

See https://git.morello-project.org/morello/llvm-project/-/issues/75
  • Loading branch information
arichardson committed Feb 4, 2024
1 parent d712bb9 commit fdaf4d1
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 75 deletions.
23 changes: 15 additions & 8 deletions clang/lib/CodeGen/CGAtomic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ bool isAtomicStoreOp(AtomicExpr::AtomicOp Op) {
}
UseLibcall = !C.getTargetInfo().hasBuiltinAtomic(
AtomicSizeInBits, C.toBits(lvalue.getAlignment()),
AtomicTy->isCHERICapabilityType(CGF.CGM.getContext()));
AtomicTy->isCHERICapabilityType(CGF.getContext()) ||
AtomicTy->isSingleCapabilityRecord(CGF.getContext()));
}

QualType getAtomicType() const { return AtomicTy; }
Expand Down Expand Up @@ -547,7 +548,8 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
bool PostOpMinMax = false;
unsigned PostOp = 0;
QualType AtomicTy = E->getPtr()->getType()->getPointeeType();
bool IsCheriCap = AtomicTy->isCHERICapabilityType(CGF.CGM.getContext());
bool IsCheriCap = AtomicTy->isCHERICapabilityType(CGF.getContext()) ||
AtomicTy->isSingleCapabilityRecord(CGF.getContext());

switch (E->getOp()) {
case AtomicExpr::AO__c11_atomic_init:
Expand Down Expand Up @@ -811,12 +813,14 @@ static void
AddDirectArgument(CodeGenFunction &CGF, CallArgList &Args,
bool UseOptimizedLibcall, llvm::Value *Val, QualType ValTy,
SourceLocation Loc, CharUnits SizeInChars) {
bool IsCapTy = ValTy->isCHERICapabilityType(CGF.getContext()) ||
ValTy->isSingleCapabilityRecord(CGF.getContext());
if (UseOptimizedLibcall) {
// Load value and pass it to the function directly.
CharUnits Align = CGF.getContext().getTypeAlignInChars(ValTy);
int64_t SizeInBits = CGF.getContext().toBits(SizeInChars);
llvm::Type *ITy;
if (ValTy->isCHERICapabilityType(CGF.getContext())) {
if (IsCapTy) {
ValTy = CGF.getContext().getPointerType(CGF.getContext().VoidTy,
PIK_Capability);
ITy = CGF.Int8CheriCapTy;
Expand All @@ -836,7 +840,7 @@ AddDirectArgument(CodeGenFunction &CGF, CallArgList &Args,
} else {
// Non-optimized functions always take a reference.
// NB: Capabilities must be passed directly to the optimized libcall
assert(!ValTy->isCHERICapabilityType(CGF.getContext()) &&
assert(!IsCapTy &&
"Capabilities should not be passed to the generic libcall");
Args.add(RValue::get(CGF.EmitCastToVoidPtr(Val)),
CGF.getContext().VoidPtrTy);
Expand Down Expand Up @@ -866,7 +870,8 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
uint64_t Size = TInfo.Width.getQuantity();
unsigned MaxInlineWidthInBits = getTarget().getMaxAtomicInlineWidth();

bool IsCheriCap = AtomicTy->isCHERICapabilityType(CGM.getContext());
bool IsCheriCap = AtomicTy->isCHERICapabilityType(CGM.getContext()) ||
AtomicTy->isSingleCapabilityRecord(CGM.getContext());
bool Oversized = (!IsCheriCap &&
getContext().toBits(TInfo.Width) > MaxInlineWidthInBits) ||
(IsCheriCap && MaxInlineWidthInBits == 0);
Expand Down Expand Up @@ -1519,14 +1524,16 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {

Address AtomicInfo::emitCastToAtomicIntPointer(Address addr) const {
llvm::Type *ty;
if (AtomicTy->isCHERICapabilityType(CGF.getContext())) {
if (AtomicTy->isCHERICapabilityType(CGF.getContext()) ||
AtomicTy->isSingleCapabilityRecord(CGF.getContext())) {
// If capability atomics are natively supported the instruction expects
// a capability type. We also pass capabilities directly to the atomic
// libcalls (i.e. always use optimized ones) since this is required to
// support the RMW operations and special-casing the load/store/xchg to
// use the generic libcalls (with mutex+memcpy) adds unncessary complexity.
if (!UseLibcall) {
// If we aren't using a libcall there is no need to cast to i8*
if (!UseLibcall && !AtomicTy->isSingleCapabilityRecord(CGF.getContext())) {
// If we aren't using a libcall and aren't using a single-capability
// struct a there is no need to cast to i8*
return CGF.Builder.CreateElementBitCast(
addr, getAtomicAddress().getElementType());
}
Expand Down
Loading

0 comments on commit fdaf4d1

Please sign in to comment.