@@ -414,6 +414,7 @@ namespace {
414414 SDValue visitADDLike(SDNode *N);
415415 SDValue visitADDLikeCommutative(SDValue N0, SDValue N1,
416416 SDNode *LocReference);
417+ SDValue visitPTRADD(SDNode *N);
417418 SDValue visitSUB(SDNode *N);
418419 SDValue visitADDSAT(SDNode *N);
419420 SDValue visitSUBSAT(SDNode *N);
@@ -1853,6 +1854,7 @@ SDValue DAGCombiner::visit(SDNode *N) {
18531854 case ISD::TokenFactor: return visitTokenFactor(N);
18541855 case ISD::MERGE_VALUES: return visitMERGE_VALUES(N);
18551856 case ISD::ADD: return visitADD(N);
1857+ case ISD::PTRADD: return visitPTRADD(N);
18561858 case ISD::SUB: return visitSUB(N);
18571859 case ISD::SADDSAT:
18581860 case ISD::UADDSAT: return visitADDSAT(N);
@@ -2618,6 +2620,85 @@ SDValue DAGCombiner::foldSubToAvg(SDNode *N, const SDLoc &DL) {
26182620 return SDValue();
26192621}
26202622
2623+ /// Try to fold a pointer arithmetic node.
2624+ /// This needs to be done separately from normal addition, because pointer
2625+ /// addition is not commutative.
2626+ SDValue DAGCombiner::visitPTRADD(SDNode *N) {
2627+ SDValue N0 = N->getOperand(0);
2628+ SDValue N1 = N->getOperand(1);
2629+ EVT PtrVT = N0.getValueType();
2630+ EVT IntVT = N1.getValueType();
2631+ SDLoc DL(N);
2632+
2633+ // fold (ptradd undef, y) -> undef
2634+ if (N0.isUndef())
2635+ return N0;
2636+
2637+ // fold (ptradd x, undef) -> undef
2638+ if (N1.isUndef())
2639+ return DAG.getUNDEF(PtrVT);
2640+
2641+ // fold (ptradd x, 0) -> x
2642+ if (isNullConstant(N1))
2643+ return N0;
2644+
2645+ if (N0.getOpcode() == ISD::PTRADD &&
2646+ !reassociationCanBreakAddressingModePattern(ISD::PTRADD, DL, N, N0, N1)) {
2647+ SDValue X = N0.getOperand(0);
2648+ SDValue Y = N0.getOperand(1);
2649+ SDValue Z = N1;
2650+ bool N0OneUse = N0.hasOneUse();
2651+ bool YIsConstant = DAG.isConstantIntBuildVectorOrConstantInt(Y);
2652+ bool ZIsConstant = DAG.isConstantIntBuildVectorOrConstantInt(Z);
2653+ bool ZOneUse = Z.hasOneUse();
2654+
2655+ // (ptradd (ptradd x, y), z) -> (ptradd x, (add y, z)) if:
2656+ // * x is a null pointer; or
2657+ // * y is a constant and z has one use; or
2658+ // * y is a constant and (ptradd x, y) has one use; or
2659+ // * y and z are both constants; or
2660+ // * (ptradd x, y) and z have one use and z is not a constant.
2661+ if (isNullConstant(X) || (YIsConstant && ZOneUse) ||
2662+ (YIsConstant && N0OneUse) || (YIsConstant && ZIsConstant) ||
2663+ (N0OneUse && ZOneUse && !ZIsConstant)) {
2664+ SDValue Add = DAG.getNode(ISD::ADD, DL, IntVT, {Y, Z});
2665+ AddToWorklist(Add.getNode());
2666+ return DAG.getMemBasePlusOffset(X, Add, DL, SDNodeFlags());
2667+ }
2668+
2669+ // TODO: There is another possible fold here that was proven useful.
2670+ // It would be this:
2671+ //
2672+ // (ptradd (ptradd x, y), z) -> (ptradd (ptradd x, z), y) if:
2673+ // * (ptradd x, y) has one use; and
2674+ // * y is a constant; and
2675+ // * z is not a constant.
2676+ //
2677+ // In some cases, specifically in AArch64's FEAT_CPA, it exposes the
2678+ // opportunity to select more complex instructions such as SUBPT and
2679+ // MSUBPT. However, a hypothetical corner case has been found that we could
2680+ // not avoid. Consider this (pseudo-POSIX C):
2681+ //
2682+ // char *foo(char *x, int z) {return (x + LARGE_CONSTANT) + z;}
2683+ // char *p = mmap(LARGE_CONSTANT);
2684+ // char *q = foo(p, -LARGE_CONSTANT);
2685+ //
2686+ // Then x + LARGE_CONSTANT is one-past-the-end, so valid, and a
2687+ // further + z takes it back to the start of the mapping, so valid,
2688+ // regardless of the address mmap gave back. However, if mmap gives you an
2689+ // address < LARGE_CONSTANT (ignoring high bits), x - LARGE_CONSTANT will
2690+ // borrow from the high bits (with the subsequent + z carrying back into
2691+ // the high bits to give you a well-defined pointer) and thus trip
2692+ // FEAT_CPA's pointer corruption checks.
2693+ //
2694+ // We leave this fold as an opportunity for future work, addressing the
2695+ // corner case for FEAT_CPA, as well as reconciling the solution with the
2696+ // more general application of pointer arithmetic in other future targets.
2697+ }
2698+
2699+ return SDValue();
2700+ }
2701+
26212702/// Try to fold a 'not' shifted sign-bit with add/sub with constant operand into
26222703/// a shift and add with a different constant.
26232704static SDValue foldAddSubOfSignBit(SDNode *N, const SDLoc &DL,
0 commit comments