[llvm] [AMDGPU][SDAG] Add target-specific ISD::PTRADD combines (PR #143673)
Fabian Ritter via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 10 07:16:59 PDT 2025
================
@@ -15089,42 +15094,116 @@ SDValue SITargetLowering::performPtrAddCombine(SDNode *N,
DAGCombinerInfo &DCI) const {
SelectionDAG &DAG = DCI.DAG;
SDLoc DL(N);
+ EVT VT = N->getValueType(0);
SDValue N0 = N->getOperand(0);
SDValue N1 = N->getOperand(1);
- if (N1.getOpcode() == ISD::ADD) {
- // (ptradd x, (add y, z)) -> (ptradd (ptradd x, y), z) if z is a constant,
- // y is not, and (add y, z) is used only once.
- // (ptradd x, (add y, z)) -> (ptradd (ptradd x, z), y) if y is a constant,
- // z is not, and (add y, z) is used only once.
- // The goal is to move constant offsets to the outermost ptradd, to create
- // more opportunities to fold offsets into memory instructions.
- // Together with the generic combines in DAGCombiner.cpp, this also
- // implements (ptradd (ptradd x, y), z) -> (ptradd (ptradd x, z), y)).
- //
- // This transform is here instead of in the general DAGCombiner as it can
- // turn in-bounds pointer arithmetic out-of-bounds, which is problematic for
- // AArch64's CPA.
- SDValue X = N0;
- SDValue Y = N1.getOperand(0);
- SDValue Z = N1.getOperand(1);
- if (N1.hasOneUse()) {
- bool YIsConstant = DAG.isConstantIntBuildVectorOrConstantInt(Y);
- bool ZIsConstant = DAG.isConstantIntBuildVectorOrConstantInt(Z);
- if (ZIsConstant != YIsConstant) {
- // If both additions in the original were NUW, the new ones are as well.
- SDNodeFlags Flags =
- (N->getFlags() & N1->getFlags()) & SDNodeFlags::NoUnsignedWrap;
- if (YIsConstant)
- std::swap(Y, Z);
+ // The following folds transform PTRADDs into regular arithmetic in cases
+ // where the PTRADD wouldn't be folded as an immediate offset into memory
+ // instructions anyway. They are target-specific in that other targets might
+ // prefer to not lose information about the pointer arithmetic.
+
+ // Fold (ptradd x, shl(0 - v, k)) -> sub(x, shl(v, k)).
+ // Adapted from DAGCombiner::visitADDLikeCommutative.
+ SDValue V, K;
+ if (sd_match(N1, m_Shl(m_Neg(m_Value(V)), m_Value(K)))) {
+ SDValue Inner = DAG.getNode(ISD::SHL, DL, VT, V, K);
+ DCI.AddToWorklist(Inner.getNode());
+ return DAG.getNode(ISD::SUB, DL, VT, N0, Inner);
+ }
+
+ // Fold into Mad64 if the right-hand side is a MUL. Analogous to a fold in
+ // performAddCombine.
+ if (N1.getOpcode() == ISD::MUL) {
+ if (Subtarget->hasMad64_32()) {
+ if (SDValue Folded = tryFoldToMad64_32(N, DCI))
+ return Folded;
+ }
+ }
- SDValue Inner = DAG.getMemBasePlusOffset(X, Y, DL, Flags);
+ // If the 32 low bits of the constant are all zero, there is nothing to fold
+ // into an immediate offset, so it's better to eliminate the unnecessary
+ // addition for the lower 32 bits than to preserve the PTRADD.
+ // Analogous to a fold in performAddCombine.
+ if (VT == MVT::i64) {
+ if (SDValue Folded = foldAddSub64WithZeroLowBitsTo32(N, DCI))
+ return Folded;
+ }
+
+ if (N0.getOpcode() == ISD::PTRADD && N1.getOpcode() == ISD::Constant) {
+ // Fold (ptradd (ptradd GA, v), c) -> (ptradd (ptradd GA, c) v) with
+ // global address GA and constant c, such that c can be folded into GA.
+ SDValue GAValue = N0.getOperand(0);
+ if (const GlobalAddressSDNode *GA =
+ dyn_cast<GlobalAddressSDNode>(GAValue)) {
+ const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+ if (DCI.isBeforeLegalizeOps() && TLI.isOffsetFoldingLegal(GA)) {
----------------
ritter-x2a wrote:
We want this check here so that this combine only triggers if [`SelectionDAG::FoldSymbolOffset`](https://github.com/llvm/llvm-project/blob/4a80e9d399ec8a00ec5365747faf5c85f2b60add/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp#L6701-L6721), which also checks `isOffsetFoldingLegal`, direcly folds the offset into the symbol. If this combine is applied without that, we could probably hit an infinite loop with another combine that moves the constant offset towords the use (in the lit tests, that apparently doesn't happen if I drop the `&& isOffsetFoldingLegal(GA)` here; there are no test changes).
I haven't validated what our `isOffsetFoldingLegal` implementation does, I'll have to do some research on how exactly we handle relocations for that.
This combine improves the code for [`complextype_global_gep` in `ptradd-sdag-optimizations.ll`](https://github.com/llvm/llvm-project/blob/4a80e9d399ec8a00ec5365747faf5c85f2b60add/llvm/test/CodeGen/AMDGPU/ptradd-sdag-optimizations.ll#L222-L245); the only previously existing relevant test that I found is [lower-module-lds-via-table.ll](https://github.com/llvm/llvm-project/blob/main/llvm/test/CodeGen/AMDGPU/lower-module-lds-via-table.ll).
https://github.com/llvm/llvm-project/pull/143673
More information about the llvm-commits
mailing list