Skip to content

Commit

Permalink
[SystemZ] Don't lower ATOMIC_LOAD/STORE to LOAD/STORE (#75879)
Browse files Browse the repository at this point in the history
- Instead of lowering float/double ISD::ATOMIC_LOAD / ISD::ATOMIC_STORE
nodes to regular LOAD/STORE nodes, make them legal and select those nodes
properly instead. This avoids exposing them to the DAGCombiner.

- AtomicExpand pass no longer casts float/double atomic load/stores to integer
  (FP128 is still casted).
  • Loading branch information
JonPsson1 committed Mar 18, 2024
1 parent 5d56b34 commit 8b8e1ad
Show file tree
Hide file tree
Showing 22 changed files with 1,293 additions and 318 deletions.
11 changes: 11 additions & 0 deletions llvm/include/llvm/CodeGen/SelectionDAGNodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,7 @@ BEGIN_TWO_BYTE_PACK()

class LoadSDNodeBitfields {
friend class LoadSDNode;
friend class AtomicSDNode;
friend class VPLoadSDNode;
friend class VPStridedLoadSDNode;
friend class MaskedLoadSDNode;
Expand Down Expand Up @@ -1475,6 +1476,16 @@ class AtomicSDNode : public MemSDNode {
MMO->isAtomic()) && "then why are we using an AtomicSDNode?");
}

void setExtensionType(ISD::LoadExtType ETy) {
assert(getOpcode() == ISD::ATOMIC_LOAD && "Only used for atomic loads.");
LoadSDNodeBits.ExtTy = ETy;
}

ISD::LoadExtType getExtensionType() const {
assert(getOpcode() == ISD::ATOMIC_LOAD && "Only used for atomic loads.");
return static_cast<ISD::LoadExtType>(LoadSDNodeBits.ExtTy);
}

const SDValue &getBasePtr() const {
return getOpcode() == ISD::ATOMIC_STORE ? getOperand(2) : getOperand(1);
}
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/Target/TargetSelectionDAG.td
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ def SDTAtomicStore : SDTypeProfile<0, 2, [
SDTCisInt<0>, SDTCisPtrTy<1>
]>;
def SDTAtomicLoad : SDTypeProfile<1, 1, [
SDTCisInt<0>, SDTCisPtrTy<1>
SDTCisPtrTy<1>
]>;

class SDCallSeqStart<list<SDTypeConstraint> constraints> :
Expand Down
20 changes: 20 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,26 @@ SDValue DAGTypeLegalizer::PromoteIntRes_Atomic0(AtomicSDNode *N) {
N->getMemoryVT(), ResVT,
N->getChain(), N->getBasePtr(),
N->getMemOperand());
if (N->getOpcode() == ISD::ATOMIC_LOAD) {
ISD::LoadExtType ETy = cast<AtomicSDNode>(N)->getExtensionType();
if (ETy == ISD::NON_EXTLOAD) {
switch (TLI.getExtendForAtomicOps()) {
case ISD::SIGN_EXTEND:
ETy = ISD::SEXTLOAD;
break;
case ISD::ZERO_EXTEND:
ETy = ISD::ZEXTLOAD;
break;
case ISD::ANY_EXTEND:
ETy = ISD::EXTLOAD;
break;
default:
llvm_unreachable("Invalid atomic op extension");
}
}
cast<AtomicSDNode>(Res)->setExtensionType(ETy);
}

// Legalize the chain result - switch anything that used the old chain to
// use the new one.
ReplaceValueWith(SDValue(N, 1), Res.getValue(1));
Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4070,6 +4070,9 @@ KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts,
if (Op.getResNo() == 0) {
if (TLI->getExtendForAtomicOps() == ISD::ZERO_EXTEND)
Known.Zero.setBitsFrom(MemBits);
else if (Op->getOpcode() == ISD::ATOMIC_LOAD &&
cast<AtomicSDNode>(Op)->getExtensionType() == ISD::ZEXTLOAD)
Known.Zero.setBitsFrom(MemBits);
}
break;
}
Expand Down Expand Up @@ -4875,6 +4878,13 @@ unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, const APInt &DemandedElts,
return VTBits - Tmp + 1;
if (TLI->getExtendForAtomicOps() == ISD::ZERO_EXTEND)
return VTBits - Tmp;
if (Op->getOpcode() == ISD::ATOMIC_LOAD) {
ISD::LoadExtType ETy = cast<AtomicSDNode>(Op)->getExtensionType();
if (ETy == ISD::SEXTLOAD)
return VTBits - Tmp + 1;
if (ETy == ISD::ZEXTLOAD)
return VTBits - Tmp;
}
}
break;
}
Expand Down
12 changes: 12 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,18 @@ void SDNode::print_details(raw_ostream &OS, const SelectionDAG *G) const {
} else if (const MemSDNode *M = dyn_cast<MemSDNode>(this)) {
OS << "<";
printMemOperand(OS, *M->getMemOperand(), G);
if (auto *A = dyn_cast<AtomicSDNode>(M))
if (A->getOpcode() == ISD::ATOMIC_LOAD) {
bool doExt = true;
switch (A->getExtensionType()) {
default: doExt = false; break;
case ISD::EXTLOAD: OS << ", anyext"; break;
case ISD::SEXTLOAD: OS << ", sext"; break;
case ISD::ZEXTLOAD: OS << ", zext"; break;
}
if (doExt)
OS << " from " << A->getMemoryVT();
}
OS << ">";
} else if (const BlockAddressSDNode *BA =
dyn_cast<BlockAddressSDNode>(this)) {
Expand Down
12 changes: 6 additions & 6 deletions llvm/lib/Target/PowerPC/PPCInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -5045,12 +5045,12 @@ defm : TrapExtendedMnemonic<"lng", 6>;
defm : TrapExtendedMnemonic<"u", 31>;

// Atomic loads
def : Pat<(atomic_load_8 DForm:$src), (LBZ memri:$src)>;
def : Pat<(atomic_load_16 DForm:$src), (LHZ memri:$src)>;
def : Pat<(atomic_load_32 DForm:$src), (LWZ memri:$src)>;
def : Pat<(atomic_load_8 XForm:$src), (LBZX memrr:$src)>;
def : Pat<(atomic_load_16 XForm:$src), (LHZX memrr:$src)>;
def : Pat<(atomic_load_32 XForm:$src), (LWZX memrr:$src)>;
def : Pat<(i32 (atomic_load_8 DForm:$src)), (LBZ memri:$src)>;
def : Pat<(i32 (atomic_load_16 DForm:$src)), (LHZ memri:$src)>;
def : Pat<(i32 (atomic_load_32 DForm:$src)), (LWZ memri:$src)>;
def : Pat<(i32 (atomic_load_8 XForm:$src)), (LBZX memrr:$src)>;
def : Pat<(i32 (atomic_load_16 XForm:$src)), (LHZX memrr:$src)>;
def : Pat<(i32 (atomic_load_32 XForm:$src)), (LWZX memrr:$src)>;

// Atomic stores
def : Pat<(atomic_store_8 i32:$val, DForm:$ptr), (STB gprc:$val, memri:$ptr)>;
Expand Down
16 changes: 8 additions & 8 deletions llvm/lib/Target/PowerPC/PPCInstrP10.td
Original file line number Diff line number Diff line change
Expand Up @@ -1289,13 +1289,13 @@ let Predicates = [PCRelativeMemops] in {
(PSTXVpc $XS, $ga, 0)>;

// Atomic Load
def : Pat<(atomic_load_8 (PPCmatpcreladdr PCRelForm:$ga)),
def : Pat<(i32 (atomic_load_8 (PPCmatpcreladdr PCRelForm:$ga))),
(PLBZpc $ga, 0)>;
def : Pat<(atomic_load_16 (PPCmatpcreladdr PCRelForm:$ga)),
def : Pat<(i32 (atomic_load_16 (PPCmatpcreladdr PCRelForm:$ga))),
(PLHZpc $ga, 0)>;
def : Pat<(atomic_load_32 (PPCmatpcreladdr PCRelForm:$ga)),
def : Pat<(i32 (atomic_load_32 (PPCmatpcreladdr PCRelForm:$ga))),
(PLWZpc $ga, 0)>;
def : Pat<(atomic_load_64 (PPCmatpcreladdr PCRelForm:$ga)),
def : Pat<(i64 (atomic_load_64 (PPCmatpcreladdr PCRelForm:$ga))),
(PLDpc $ga, 0)>;

// Atomic Store
Expand Down Expand Up @@ -2347,10 +2347,10 @@ let Predicates = [PrefixInstrs] in {
def : Pat<(store f64:$FRS, PDForm:$dst), (PSTFD $FRS, memri34:$dst)>;

// Atomic Load
def : Pat<(atomic_load_8 PDForm:$src), (PLBZ memri34:$src)>;
def : Pat<(atomic_load_16 PDForm:$src), (PLHZ memri34:$src)>;
def : Pat<(atomic_load_32 PDForm:$src), (PLWZ memri34:$src)>;
def : Pat<(atomic_load_64 PDForm:$src), (PLD memri34:$src)>;
def : Pat<(i32 (atomic_load_8 PDForm:$src)), (PLBZ memri34:$src)>;
def : Pat<(i32 (atomic_load_16 PDForm:$src)), (PLHZ memri34:$src)>;
def : Pat<(i32 (atomic_load_32 PDForm:$src)), (PLWZ memri34:$src)>;
def : Pat<(i64 (atomic_load_64 PDForm:$src)), (PLD memri34:$src)>;

// Atomic Store
def : Pat<(atomic_store_8 i32:$RS, PDForm:$dst), (PSTB $RS, memri34:$dst)>;
Expand Down
40 changes: 38 additions & 2 deletions llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,9 @@ class SystemZDAGToDAGISel : public SelectionDAGISel {
// requirements for a PC-relative access.
bool storeLoadIsAligned(SDNode *N) const;

// Return the load extension type of a load or atomic load.
ISD::LoadExtType getLoadExtType(SDNode *N) const;

// Try to expand a boolean SELECT_CCMASK using an IPM sequence.
SDValue expandSelectBoolean(SDNode *Node);

Expand Down Expand Up @@ -1507,15 +1510,17 @@ bool SystemZDAGToDAGISel::storeLoadCanUseBlockBinary(SDNode *N,

bool SystemZDAGToDAGISel::storeLoadIsAligned(SDNode *N) const {

auto *MemAccess = cast<LSBaseSDNode>(N);
auto *MemAccess = cast<MemSDNode>(N);
auto *LdSt = dyn_cast<LSBaseSDNode>(MemAccess);
TypeSize StoreSize = MemAccess->getMemoryVT().getStoreSize();
SDValue BasePtr = MemAccess->getBasePtr();
MachineMemOperand *MMO = MemAccess->getMemOperand();
assert(MMO && "Expected a memory operand.");

// The memory access must have a proper alignment and no index register.
// Only load and store nodes have the offset operand (atomic loads do not).
if (MemAccess->getAlign().value() < StoreSize ||
!MemAccess->getOffset().isUndef())
(LdSt && !LdSt->getOffset().isUndef()))
return false;

// The MMO must not have an unaligned offset.
Expand Down Expand Up @@ -1545,6 +1550,17 @@ bool SystemZDAGToDAGISel::storeLoadIsAligned(SDNode *N) const {
return true;
}

ISD::LoadExtType SystemZDAGToDAGISel::getLoadExtType(SDNode *N) const {
ISD::LoadExtType ETy;
if (auto *L = dyn_cast<LoadSDNode>(N))
ETy = L->getExtensionType();
else if (auto *AL = dyn_cast<AtomicSDNode>(N))
ETy = AL->getExtensionType();
else
llvm_unreachable("Unkown load node type.");
return ETy;
}

void SystemZDAGToDAGISel::Select(SDNode *Node) {
// If we have a custom node, we already have selected!
if (Node->isMachineOpcode()) {
Expand Down Expand Up @@ -1742,6 +1758,26 @@ void SystemZDAGToDAGISel::Select(SDNode *Node) {
}
break;
}

case ISD::ATOMIC_STORE: {
auto *AtomOp = cast<AtomicSDNode>(Node);
// Replace the atomic_store with a regular store and select it. This is
// ok since we know all store instructions <= 8 bytes are atomic, and the
// 16 byte case is already handled during lowering.
StoreSDNode *St = cast<StoreSDNode>(CurDAG->getTruncStore(
AtomOp->getChain(), SDLoc(AtomOp), AtomOp->getVal(),
AtomOp->getBasePtr(), AtomOp->getMemoryVT(), AtomOp->getMemOperand()));
assert(St->getMemOperand()->isAtomic() && "Broken MMO.");
SDNode *Chain = St;
// We have to enforce sequential consistency by performing a
// serialization operation after the store.
if (AtomOp->getSuccessOrdering() == AtomicOrdering::SequentiallyConsistent)
Chain = CurDAG->getMachineNode(SystemZ::Serialize, SDLoc(AtomOp),
MVT::Other, SDValue(Chain, 0));
ReplaceNode(Node, Chain);
SelectCode(St);
return;
}
}

SelectCode(Node);
Expand Down
102 changes: 62 additions & 40 deletions llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,11 +194,6 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::UADDO_CARRY, VT, Custom);
setOperationAction(ISD::USUBO_CARRY, VT, Custom);

// Lower ATOMIC_LOAD and ATOMIC_STORE into normal volatile loads and
// stores, putting a serialization instruction after the stores.
setOperationAction(ISD::ATOMIC_LOAD, VT, Custom);
setOperationAction(ISD::ATOMIC_STORE, VT, Custom);

// Lower ATOMIC_LOAD_SUB into ATOMIC_LOAD_ADD if LAA and LAAG are
// available, or if the operand is constant.
setOperationAction(ISD::ATOMIC_LOAD_SUB, VT, Custom);
Expand Down Expand Up @@ -920,6 +915,22 @@ bool SystemZTargetLowering::hasInlineStackProbe(const MachineFunction &MF) const
return false;
}

TargetLowering::AtomicExpansionKind
SystemZTargetLowering::shouldCastAtomicLoadInIR(LoadInst *LI) const {
// Lower fp128 the same way as i128.
if (LI->getType()->isFP128Ty())
return AtomicExpansionKind::CastToInteger;
return AtomicExpansionKind::None;
}

TargetLowering::AtomicExpansionKind
SystemZTargetLowering::shouldCastAtomicStoreInIR(StoreInst *SI) const {
// Lower fp128 the same way as i128.
if (SI->getValueOperand()->getType()->isFP128Ty())
return AtomicExpansionKind::CastToInteger;
return AtomicExpansionKind::None;
}

TargetLowering::AtomicExpansionKind
SystemZTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *RMW) const {
// Don't expand subword operations as they require special treatment.
Expand Down Expand Up @@ -4503,40 +4514,14 @@ SDValue SystemZTargetLowering::lowerATOMIC_FENCE(SDValue Op,
return DAG.getNode(ISD::MEMBARRIER, DL, MVT::Other, Op.getOperand(0));
}

// Op is an atomic load. Lower it into a normal volatile load.
SDValue SystemZTargetLowering::lowerATOMIC_LOAD(SDValue Op,
SelectionDAG &DAG) const {
auto *Node = cast<AtomicSDNode>(Op.getNode());
if (Node->getMemoryVT() == MVT::i128) {
// Use same code to handle both legal and non-legal i128 types.
SmallVector<SDValue, 2> Results;
LowerOperationWrapper(Node, Results, DAG);
return DAG.getMergeValues(Results, SDLoc(Op));
}
return DAG.getExtLoad(ISD::EXTLOAD, SDLoc(Op), Op.getValueType(),
Node->getChain(), Node->getBasePtr(),
Node->getMemoryVT(), Node->getMemOperand());
}

// Op is an atomic store. Lower it into a normal volatile store.
SDValue SystemZTargetLowering::lowerATOMIC_STORE(SDValue Op,
SelectionDAG &DAG) const {
SDValue SystemZTargetLowering::lowerATOMIC_LDST_I128(SDValue Op,
SelectionDAG &DAG) const {
auto *Node = cast<AtomicSDNode>(Op.getNode());
if (Node->getMemoryVT() == MVT::i128) {
// Use same code to handle both legal and non-legal i128 types.
SmallVector<SDValue, 1> Results;
LowerOperationWrapper(Node, Results, DAG);
return DAG.getMergeValues(Results, SDLoc(Op));
}
SDValue Chain = DAG.getTruncStore(Node->getChain(), SDLoc(Op), Node->getVal(),
Node->getBasePtr(), Node->getMemoryVT(),
Node->getMemOperand());
// We have to enforce sequential consistency by performing a
// serialization operation after the store.
if (Node->getSuccessOrdering() == AtomicOrdering::SequentiallyConsistent)
Chain = SDValue(DAG.getMachineNode(SystemZ::Serialize, SDLoc(Op),
MVT::Other, Chain), 0);
return Chain;
assert(Node->getMemoryVT() == MVT::i128 && "Only custom lowering i128.");
// Use same code to handle both legal and non-legal i128 types.
SmallVector<SDValue, 2> Results;
LowerOperationWrapper(Node, Results, DAG);
return DAG.getMergeValues(Results, SDLoc(Op));
}

// Prepare for a Compare And Swap for a subword operation. This needs to be
Expand Down Expand Up @@ -5662,6 +5647,9 @@ static SDValue tryBuildVectorShuffle(SelectionDAG &DAG,
bool SystemZTargetLowering::isVectorElementLoad(SDValue Op) const {
if (Op.getOpcode() == ISD::LOAD && cast<LoadSDNode>(Op)->isUnindexed())
return true;
if (auto *AL = dyn_cast<AtomicSDNode>(Op))
if (AL->getOpcode() == ISD::ATOMIC_LOAD)
return true;
if (Subtarget.hasVectorEnhancements2() && Op.getOpcode() == SystemZISD::LRV)
return true;
return false;
Expand Down Expand Up @@ -6138,9 +6126,8 @@ SDValue SystemZTargetLowering::LowerOperation(SDValue Op,
case ISD::ATOMIC_SWAP:
return lowerATOMIC_LOAD_OP(Op, DAG, SystemZISD::ATOMIC_SWAPW);
case ISD::ATOMIC_STORE:
return lowerATOMIC_STORE(Op, DAG);
case ISD::ATOMIC_LOAD:
return lowerATOMIC_LOAD(Op, DAG);
return lowerATOMIC_LDST_I128(Op, DAG);
case ISD::ATOMIC_LOAD_ADD:
return lowerATOMIC_LOAD_OP(Op, DAG, SystemZISD::ATOMIC_LOADW_ADD);
case ISD::ATOMIC_LOAD_SUB:
Expand Down Expand Up @@ -6587,6 +6574,27 @@ SDValue SystemZTargetLowering::combineTruncateExtract(
return SDValue();
}

// Replace ALoad with a new ATOMIC_LOAD with a result that is extended to VT
// per ETy.
static SDValue extendAtomicLoad(AtomicSDNode *ALoad, EVT VT, SelectionDAG &DAG,
ISD::LoadExtType ETy) {
if (VT.getSizeInBits() > 64)
return SDValue();
EVT OrigVT = ALoad->getValueType(0);
assert(OrigVT.getSizeInBits() < VT.getSizeInBits() && "VT should be wider.");
EVT MemoryVT = ALoad->getMemoryVT();
auto *NewALoad = dyn_cast<AtomicSDNode>(DAG.getAtomic(
ISD::ATOMIC_LOAD, SDLoc(ALoad), MemoryVT, VT, ALoad->getChain(),
ALoad->getBasePtr(), ALoad->getMemOperand()));
NewALoad->setExtensionType(ETy);
DAG.ReplaceAllUsesOfValueWith(
SDValue(ALoad, 0),
DAG.getNode(ISD::TRUNCATE, SDLoc(ALoad), OrigVT, SDValue(NewALoad, 0)));
// Update the chain uses.
DAG.ReplaceAllUsesOfValueWith(SDValue(ALoad, 1), SDValue(NewALoad, 1));
return SDValue(NewALoad, 0);
}

SDValue SystemZTargetLowering::combineZERO_EXTEND(
SDNode *N, DAGCombinerInfo &DCI) const {
// Convert (zext (select_ccmask C1, C2)) into (select_ccmask C1', C2')
Expand All @@ -6611,6 +6619,13 @@ SDValue SystemZTargetLowering::combineZERO_EXTEND(
return NewSelect;
}
}

// Fold into ATOMIC_LOAD unless it is already sign extending.
if (auto *ALoad = dyn_cast<AtomicSDNode>(N0))
if (ALoad->getOpcode() == ISD::ATOMIC_LOAD &&
ALoad->getExtensionType() != ISD::SEXTLOAD)
return extendAtomicLoad(ALoad, VT, DAG, ISD::ZEXTLOAD);

return SDValue();
}

Expand Down Expand Up @@ -6662,6 +6677,13 @@ SDValue SystemZTargetLowering::combineSIGN_EXTEND(
}
}
}

// Fold into ATOMIC_LOAD unless it is already zero extending.
if (auto *ALoad = dyn_cast<AtomicSDNode>(N0))
if (ALoad->getOpcode() == ISD::ATOMIC_LOAD &&
ALoad->getExtensionType() != ISD::ZEXTLOAD)
return extendAtomicLoad(ALoad, VT, DAG, ISD::SEXTLOAD);

return SDValue();
}

Expand Down

0 comments on commit 8b8e1ad

Please sign in to comment.