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