@@ -140,6 +140,10 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
140140 setOperationAction(ISD::BITREVERSE, MVT::i32, Legal);
141141 setOperationAction(ISD::BITREVERSE, MVT::i64, Legal);
142142
143+ // Sub-word ATOMIC_CMP_SWAP need to ensure that the input is zero-extended.
144+ setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i32, Custom);
145+ setOperationAction(ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS, MVT::i32, Custom);
146+
143147 // PowerPC has an i16 but no i8 (or i1) SEXTLOAD.
144148 for (MVT VT : MVT::integer_valuetypes()) {
145149 setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote);
@@ -8495,6 +8499,73 @@ SDValue PPCTargetLowering::LowerREM(SDValue Op, SelectionDAG &DAG) const {
84958499 return Op;
84968500}
84978501
8502+ // Test if an SDValue is zero-extended from \p From bits to \p To bits.
8503+ static bool isZeroExtended(SDValue Op, unsigned From, unsigned To) {
8504+ if (To < From)
8505+ return false;
8506+ if (To == From)
8507+ return true;
8508+ unsigned OpWidth = Op.getValueType().getSizeInBits();
8509+ if (OpWidth != To)
8510+ return false;
8511+
8512+ // Explicitly zero-extended values.
8513+ if (Op.getOpcode() == ISD::ZERO_EXTEND)
8514+ return true;
8515+ if (Op.getOpcode() == ISD::AssertZext &&
8516+ cast<VTSDNode>(Op.getOperand(1))->getVT().getSizeInBits() == From)
8517+ return true;
8518+
8519+ // Masked values.
8520+ if (Op.getOpcode() == ISD::AND)
8521+ if (ConstantSDNode *Mask = isConstOrConstSplat(Op.getOperand(1)))
8522+ return Mask->getZExtValue() == ((1U << From) - 1);
8523+
8524+ // ZExt load.
8525+ if (Op.getOpcode() == ISD::LOAD)
8526+ if (LoadSDNode *LD = dyn_cast<LoadSDNode>(Op))
8527+ return LD->getExtensionType() == ISD::ZEXTLOAD;
8528+ return false;
8529+ }
8530+
8531+ // ATOMIC_CMP_SWAP for i8/i16 needs to zero-extend its input since it will be
8532+ // compared to a value that is atomically loaded (atomic loads zero-extend).
8533+ SDValue PPCTargetLowering::LowerATOMIC_CMP_SWAP(SDValue Op,
8534+ SelectionDAG &DAG) const {
8535+ unsigned Opc = Op.getOpcode();
8536+ assert((Opc == ISD::ATOMIC_CMP_SWAP ||
8537+ Opc == ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS) &&
8538+ "Expecting an atomic compare-and-swap here.");
8539+ SDLoc dl(Op);
8540+ auto *AtomicNode = cast<AtomicSDNode>(Op.getNode());
8541+ EVT MemVT = AtomicNode->getMemoryVT();
8542+ bool ToExpand = Opc == ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS;
8543+ if (MemVT.getSizeInBits() >= 32)
8544+ return ToExpand ? SDValue() : Op;
8545+
8546+ SDValue CmpOp = Op.getOperand(2);
8547+ // If this is already correctly zero-extended, leave it alone.
8548+ if (isZeroExtended(CmpOp, MemVT.getSizeInBits(), 32))
8549+ return ToExpand ? SDValue() : Op;
8550+
8551+ // Clear the high bits of the compare operand.
8552+ unsigned MaskVal = (1 << MemVT.getSizeInBits()) - 1;
8553+ SDValue NewCmpOp =
8554+ DAG.getNode(ISD::AND, dl, MVT::i32, CmpOp,
8555+ DAG.getConstant(MaskVal, dl, MVT::i32));
8556+
8557+ // Replace the existing compare operand with the properly zero-extended one.
8558+ SmallVector<SDValue, 4> Ops;
8559+ for (int i = 0, e = AtomicNode->getNumOperands(); i < e; i++)
8560+ Ops.push_back(AtomicNode->getOperand(i));
8561+ Ops[2] = NewCmpOp;
8562+ DAG.UpdateNodeOperands(AtomicNode, Ops);
8563+
8564+ // ATOMIC_CMP_SWAP is Legal and ATOMIC_CMP_SWAP_WITH_SUCCESS needs to be
8565+ // Expanded.
8566+ return ToExpand ? SDValue() : Op;
8567+ }
8568+
84988569SDValue PPCTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op,
84998570 SelectionDAG &DAG) const {
85008571 SDLoc dl(Op);
@@ -8966,6 +9037,9 @@ SDValue PPCTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
89669037 case ISD::SREM:
89679038 case ISD::UREM:
89689039 return LowerREM(Op, DAG);
9040+ case ISD::ATOMIC_CMP_SWAP:
9041+ case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS:
9042+ return LowerATOMIC_CMP_SWAP(Op, DAG);
89699043 }
89709044}
89719045
0 commit comments