@@ -419,6 +419,7 @@ namespace {
419
419
SDValue visitADDLike(SDNode *N);
420
420
SDValue visitADDLikeCommutative(SDValue N0, SDValue N1,
421
421
SDNode *LocReference);
422
+ SDValue visitPTRADD(SDNode *N);
422
423
SDValue visitSUB(SDNode *N);
423
424
SDValue visitADDSAT(SDNode *N);
424
425
SDValue visitSUBSAT(SDNode *N);
@@ -1138,7 +1139,7 @@ bool DAGCombiner::reassociationCanBreakAddressingModePattern(unsigned Opc,
1138
1139
return true;
1139
1140
}
1140
1141
1141
- if (Opc != ISD::ADD)
1142
+ if (Opc != ISD::ADD && Opc != ISD::PTRADD )
1142
1143
return false;
1143
1144
1144
1145
auto *C2 = dyn_cast<ConstantSDNode>(N1);
@@ -1858,6 +1859,7 @@ SDValue DAGCombiner::visit(SDNode *N) {
1858
1859
case ISD::TokenFactor: return visitTokenFactor(N);
1859
1860
case ISD::MERGE_VALUES: return visitMERGE_VALUES(N);
1860
1861
case ISD::ADD: return visitADD(N);
1862
+ case ISD::PTRADD: return visitPTRADD(N);
1861
1863
case ISD::SUB: return visitSUB(N);
1862
1864
case ISD::SADDSAT:
1863
1865
case ISD::UADDSAT: return visitADDSAT(N);
@@ -2628,6 +2630,93 @@ SDValue DAGCombiner::foldSubToAvg(SDNode *N, const SDLoc &DL) {
2628
2630
return SDValue();
2629
2631
}
2630
2632
2633
+ /// Try to fold a pointer arithmetic node.
2634
+ /// This needs to be done separately from normal addition, because pointer
2635
+ /// addition is not commutative.
2636
+ SDValue DAGCombiner::visitPTRADD(SDNode *N) {
2637
+ SDValue N0 = N->getOperand(0);
2638
+ SDValue N1 = N->getOperand(1);
2639
+ EVT PtrVT = N0.getValueType();
2640
+ EVT IntVT = N1.getValueType();
2641
+ SDLoc DL(N);
2642
+
2643
+ // This is already ensured by an assert in SelectionDAG::getNode(). Several
2644
+ // combines here depend on this assumption.
2645
+ assert(PtrVT == IntVT &&
2646
+ "PTRADD with different operand types is not supported");
2647
+
2648
+ // fold (ptradd undef, y) -> undef
2649
+ if (N0.isUndef())
2650
+ return N0;
2651
+
2652
+ // fold (ptradd x, undef) -> undef
2653
+ if (N1.isUndef())
2654
+ return DAG.getUNDEF(PtrVT);
2655
+
2656
+ // fold (ptradd x, 0) -> x
2657
+ if (isNullConstant(N1))
2658
+ return N0;
2659
+
2660
+ // fold (ptradd 0, x) -> x
2661
+ if (isNullConstant(N0))
2662
+ return N1;
2663
+
2664
+ if (N0.getOpcode() == ISD::PTRADD &&
2665
+ !reassociationCanBreakAddressingModePattern(ISD::PTRADD, DL, N, N0, N1)) {
2666
+ SDValue X = N0.getOperand(0);
2667
+ SDValue Y = N0.getOperand(1);
2668
+ SDValue Z = N1;
2669
+ bool N0OneUse = N0.hasOneUse();
2670
+ bool YIsConstant = DAG.isConstantIntBuildVectorOrConstantInt(Y);
2671
+ bool ZIsConstant = DAG.isConstantIntBuildVectorOrConstantInt(Z);
2672
+
2673
+ // (ptradd (ptradd x, y), z) -> (ptradd x, (add y, z)) if:
2674
+ // * y is a constant and (ptradd x, y) has one use; or
2675
+ // * y and z are both constants.
2676
+ if ((YIsConstant && N0OneUse) || (YIsConstant && ZIsConstant)) {
2677
+ SDNodeFlags Flags;
2678
+ // If both additions in the original were NUW, the new ones are as well.
2679
+ if (N->getFlags().hasNoUnsignedWrap() &&
2680
+ N0->getFlags().hasNoUnsignedWrap())
2681
+ Flags |= SDNodeFlags::NoUnsignedWrap;
2682
+ SDValue Add = DAG.getNode(ISD::ADD, DL, IntVT, {Y, Z}, Flags);
2683
+ AddToWorklist(Add.getNode());
2684
+ return DAG.getMemBasePlusOffset(X, Add, DL, Flags);
2685
+ }
2686
+
2687
+ // TODO: There is another possible fold here that was proven useful.
2688
+ // It would be this:
2689
+ //
2690
+ // (ptradd (ptradd x, y), z) -> (ptradd (ptradd x, z), y) if:
2691
+ // * (ptradd x, y) has one use; and
2692
+ // * y is a constant; and
2693
+ // * z is not a constant.
2694
+ //
2695
+ // In some cases, specifically in AArch64's FEAT_CPA, it exposes the
2696
+ // opportunity to select more complex instructions such as SUBPT and
2697
+ // MSUBPT. However, a hypothetical corner case has been found that we could
2698
+ // not avoid. Consider this (pseudo-POSIX C):
2699
+ //
2700
+ // char *foo(char *x, int z) {return (x + LARGE_CONSTANT) + z;}
2701
+ // char *p = mmap(LARGE_CONSTANT);
2702
+ // char *q = foo(p, -LARGE_CONSTANT);
2703
+ //
2704
+ // Then x + LARGE_CONSTANT is one-past-the-end, so valid, and a
2705
+ // further + z takes it back to the start of the mapping, so valid,
2706
+ // regardless of the address mmap gave back. However, if mmap gives you an
2707
+ // address < LARGE_CONSTANT (ignoring high bits), x - LARGE_CONSTANT will
2708
+ // borrow from the high bits (with the subsequent + z carrying back into
2709
+ // the high bits to give you a well-defined pointer) and thus trip
2710
+ // FEAT_CPA's pointer corruption checks.
2711
+ //
2712
+ // We leave this fold as an opportunity for future work, addressing the
2713
+ // corner case for FEAT_CPA, as well as reconciling the solution with the
2714
+ // more general application of pointer arithmetic in other future targets.
2715
+ }
2716
+
2717
+ return SDValue();
2718
+ }
2719
+
2631
2720
/// Try to fold a 'not' shifted sign-bit with add/sub with constant operand into
2632
2721
/// a shift and add with a different constant.
2633
2722
static SDValue foldAddSubOfSignBit(SDNode *N, const SDLoc &DL,
@@ -15026,6 +15115,7 @@ SDValue DAGCombiner::visitAssertAlign(SDNode *N) {
15026
15115
default:
15027
15116
break;
15028
15117
case ISD::ADD:
15118
+ case ISD::PTRADD:
15029
15119
case ISD::SUB: {
15030
15120
unsigned AlignShift = Log2(AL);
15031
15121
SDValue LHS = N0.getOperand(0);
0 commit comments