@@ -140,6 +140,10 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
140
140
setOperationAction(ISD::BITREVERSE, MVT::i32, Legal);
141
141
setOperationAction(ISD::BITREVERSE, MVT::i64, Legal);
142
142
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
+
143
147
// PowerPC has an i16 but no i8 (or i1) SEXTLOAD.
144
148
for (MVT VT : MVT::integer_valuetypes()) {
145
149
setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote);
@@ -8495,6 +8499,73 @@ SDValue PPCTargetLowering::LowerREM(SDValue Op, SelectionDAG &DAG) const {
8495
8499
return Op;
8496
8500
}
8497
8501
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
+
8498
8569
SDValue PPCTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op,
8499
8570
SelectionDAG &DAG) const {
8500
8571
SDLoc dl(Op);
@@ -8966,6 +9037,9 @@ SDValue PPCTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
8966
9037
case ISD::SREM:
8967
9038
case ISD::UREM:
8968
9039
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);
8969
9043
}
8970
9044
}
8971
9045
0 commit comments