@@ -416,7 +416,9 @@ namespace {
416416 SDValue visitMERGE_VALUES(SDNode *N);
417417 SDValue visitADD(SDNode *N);
418418 SDValue visitADDLike(SDNode *N);
419- SDValue visitADDLikeCommutative(SDValue N0, SDValue N1, SDNode *LocReference);
419+ SDValue visitADDLikeCommutative(SDValue N0, SDValue N1,
420+ SDNode *LocReference);
421+ SDValue visitPTRADD(SDNode *N);
420422 SDValue visitSUB(SDNode *N);
421423 SDValue visitADDSAT(SDNode *N);
422424 SDValue visitSUBSAT(SDNode *N);
@@ -1082,7 +1084,7 @@ bool DAGCombiner::reassociationCanBreakAddressingModePattern(unsigned Opc,
10821084 // (load/store (add, (add, x, y), offset2)) ->
10831085 // (load/store (add, (add, x, offset2), y)).
10841086
1085- if (N0.getOpcode() != ISD::ADD)
1087+ if (N0.getOpcode() != ISD::ADD && N0.getOpcode() != ISD::PTRADD )
10861088 return false;
10871089
10881090 // Check for vscale addressing modes.
@@ -1833,6 +1835,7 @@ SDValue DAGCombiner::visit(SDNode *N) {
18331835 case ISD::TokenFactor: return visitTokenFactor(N);
18341836 case ISD::MERGE_VALUES: return visitMERGE_VALUES(N);
18351837 case ISD::ADD: return visitADD(N);
1838+ case ISD::PTRADD: return visitPTRADD(N);
18361839 case ISD::SUB: return visitSUB(N);
18371840 case ISD::SADDSAT:
18381841 case ISD::UADDSAT: return visitADDSAT(N);
@@ -2349,7 +2352,7 @@ static bool canFoldInAddressingMode(SDNode *N, SDNode *Use, SelectionDAG &DAG,
23492352 }
23502353
23512354 TargetLowering::AddrMode AM;
2352- if (N->getOpcode() == ISD::ADD) {
2355+ if (N->getOpcode() == ISD::ADD || N->getOpcode() == ISD::PTRADD ) {
23532356 AM.HasBaseReg = true;
23542357 ConstantSDNode *Offset = dyn_cast<ConstantSDNode>(N->getOperand(1));
23552358 if (Offset)
@@ -2578,6 +2581,98 @@ SDValue DAGCombiner::foldSubToAvg(SDNode *N, const SDLoc &DL) {
25782581 return SDValue();
25792582}
25802583
2584+ /// Try to fold a pointer arithmetic node.
2585+ /// This needs to be done separately from normal addition, because pointer
2586+ /// addition is not commutative.
2587+ /// This function was adapted from DAGCombiner::visitPTRADD() from the Morello
2588+ /// project, which is based on CHERI.
2589+ SDValue DAGCombiner::visitPTRADD(SDNode *N) {
2590+ SDValue N0 = N->getOperand(0);
2591+ SDValue N1 = N->getOperand(1);
2592+ EVT PtrVT = N0.getValueType();
2593+ EVT IntVT = N1.getValueType();
2594+ SDLoc DL(N);
2595+
2596+ // fold (ptradd undef, y) -> undef
2597+ if (N0.isUndef())
2598+ return N0;
2599+
2600+ // fold (ptradd x, undef) -> undef
2601+ if (N1.isUndef())
2602+ return DAG.getUNDEF(PtrVT);
2603+
2604+ // fold (ptradd x, 0) -> x
2605+ if (isNullConstant(N1))
2606+ return N0;
2607+
2608+ if (N0.getOpcode() == ISD::PTRADD &&
2609+ !reassociationCanBreakAddressingModePattern(ISD::PTRADD, DL, N, N0, N1)) {
2610+ SDValue X = N0.getOperand(0);
2611+ SDValue Y = N0.getOperand(1);
2612+ SDValue Z = N1;
2613+ bool N0OneUse = N0.hasOneUse();
2614+ bool YIsConstant = DAG.isConstantIntBuildVectorOrConstantInt(Y);
2615+ bool ZIsConstant = DAG.isConstantIntBuildVectorOrConstantInt(Z);
2616+
2617+ // (ptradd (ptradd x, y), z) -> (ptradd (ptradd x, z), y) if:
2618+ // * (ptradd x, y) has one use; and
2619+ // * y is a constant; and
2620+ // * z is not a constant.
2621+ // Serves to expose constant y for subsequent folding.
2622+ if (N0OneUse && YIsConstant && !ZIsConstant) {
2623+ SDValue Add = DAG.getNode(ISD::PTRADD, DL, IntVT, {X, Z});
2624+
2625+ // Calling visit() can replace the Add node with ISD::DELETED_NODE if
2626+ // there aren't any users, so keep a handle around whilst we visit it.
2627+ HandleSDNode ADDHandle(Add);
2628+
2629+ SDValue VisitedAdd = visit(Add.getNode());
2630+ if (VisitedAdd) {
2631+ // If visit() returns the same node, it means the SDNode was RAUW'd, and
2632+ // therefore we have to load the new value to perform the checks whether
2633+ // the reassociation fold is profitable.
2634+ if (VisitedAdd.getNode() == Add.getNode())
2635+ Add = ADDHandle.getValue();
2636+ else
2637+ Add = VisitedAdd;
2638+ }
2639+
2640+ return DAG.getMemBasePlusOffset(Add, Y, DL, SDNodeFlags());
2641+ }
2642+
2643+ bool ZOneUse = Z.hasOneUse();
2644+
2645+ // (ptradd (ptradd x, y), z) -> (ptradd x, (add y, z)) if:
2646+ // * x is a null pointer; or
2647+ // * y is a constant and z has one use; or
2648+ // * y is a constant and (ptradd x, y) has one use; or
2649+ // * (ptradd x, y) and z have one use and z is not a constant.
2650+ if (isNullConstant(X) || (YIsConstant && ZOneUse) ||
2651+ (YIsConstant && N0OneUse) || (N0OneUse && ZOneUse && !ZIsConstant)) {
2652+ SDValue Add = DAG.getNode(ISD::ADD, DL, IntVT, {Y, Z});
2653+
2654+ // Calling visit() can replace the Add node with ISD::DELETED_NODE if
2655+ // there aren't any users, so keep a handle around whilst we visit it.
2656+ HandleSDNode ADDHandle(Add);
2657+
2658+ SDValue VisitedAdd = visit(Add.getNode());
2659+ if (VisitedAdd) {
2660+ // If visit() returns the same node, it means the SDNode was RAUW'd, and
2661+ // therefore we have to load the new value to perform the checks whether
2662+ // the reassociation fold is profitable.
2663+ if (VisitedAdd.getNode() == Add.getNode())
2664+ Add = ADDHandle.getValue();
2665+ else
2666+ Add = VisitedAdd;
2667+ }
2668+
2669+ return DAG.getMemBasePlusOffset(X, Add, DL, SDNodeFlags());
2670+ }
2671+ }
2672+
2673+ return SDValue();
2674+ }
2675+
25812676/// Try to fold a 'not' shifted sign-bit with add/sub with constant operand into
25822677/// a shift and add with a different constant.
25832678static SDValue foldAddSubOfSignBit(SDNode *N, const SDLoc &DL,
0 commit comments