Skip to content

Commit 62947c5

Browse files
ritter-x2adavidchisnalljrtc27arichardsonrgwott
committed
[SelectionDAG] Add DAGCombines for ISD::PTRADD
This change was split from PR llvm#140017, which is based on a part of PR llvm#105669 by @rgwott, which was adapted from work by @jrtc27, @arichardson, @davidchisnall in the CHERI/Morello LLVM tree. Co-authored-by: David Chisnall <[email protected]> Co-authored-by: Jessica Clarke <[email protected]> Co-authored-by: Alexander Richardson <[email protected]> Co-authored-by: Rodolfo Wottrich <[email protected]>
1 parent 7329a37 commit 62947c5

File tree

1 file changed

+81
-0
lines changed

1 file changed

+81
-0
lines changed

llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
26232704
static SDValue foldAddSubOfSignBit(SDNode *N, const SDLoc &DL,

0 commit comments

Comments
 (0)