[llvm] [SelectionDAG] Introduce ISD::PTRADD (PR #140017)
Fabian Ritter via llvm-commits
llvm-commits at lists.llvm.org
Thu May 22 00:11:18 PDT 2025
https://github.com/ritter-x2a updated https://github.com/llvm/llvm-project/pull/140017
>From f3ec47a007c6e8274a7895d8c3348caa78a3ca43 Mon Sep 17 00:00:00 2001
From: David Chisnall <github at theravensnest.org>
Date: Wed, 14 May 2025 10:13:30 -0400
Subject: [PATCH 01/11] [SelectionDAG] Introduce ISD::PTRADD
This opcode represents the addition of a pointer value (first operand) and an
integer offset (second operand). PTRADD nodes are only generated if the
TargetMachine opts in by overriding TargetMachine::shouldPreservePtrArith().
The PTRADD node and respective visitPTRADD() function were adapted by @rgwott
from the CHERI/Morello LLVM tree.
Original authors: @davidchisnall, @jrtc27, @arichardson.
The changes in this PR were extracted from PR #105669.
Co-authored-by: Jessica Clarke <jrtc27 at jrtc27.com>
Co-authored-by: Alexander Richardson <alexrichardson at google.com>
Co-authored-by: Rodolfo Wottrich <rodolfo.wottrich at arm.com>
---
llvm/include/llvm/CodeGen/ISDOpcodes.h | 5 +
llvm/include/llvm/Target/TargetMachine.h | 5 +
.../include/llvm/Target/TargetSelectionDAG.td | 2 +-
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 103 +++++++++++++++++-
.../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 10 +-
.../SelectionDAG/SelectionDAGBuilder.cpp | 19 ++--
.../SelectionDAG/SelectionDAGDumper.cpp | 1 +
7 files changed, 129 insertions(+), 16 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index 80ef32aff62ae..abae3e921117f 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -1502,6 +1502,11 @@ enum NodeType {
// Outputs: [rv], output chain, glue
PATCHPOINT,
+ // PTRADD represents pointer arithmatic semantics, for targets that opt in
+ // using shouldPreservePtrArith().
+ // ptr = PTRADD ptr, offset
+ PTRADD,
+
// Vector Predication
#define BEGIN_REGISTER_VP_SDNODE(VPSDID, ...) VPSDID,
#include "llvm/IR/VPIntrinsics.def"
diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h
index 906926729ed74..8536439f0a2d4 100644
--- a/llvm/include/llvm/Target/TargetMachine.h
+++ b/llvm/include/llvm/Target/TargetMachine.h
@@ -468,6 +468,11 @@ class TargetMachine {
return false;
}
+ /// True if target has some particular form of dealing with pointer arithmetic
+ /// semantics. False if pointer arithmetic should not be preserved for passes
+ /// such as instruction selection, and can fallback to regular arithmetic.
+ virtual bool shouldPreservePtrArith(const Function &F) const { return false; }
+
/// Create a pass configuration object to be used by addPassToEmitX methods
/// for generating a pipeline of CodeGen passes.
virtual TargetPassConfig *createPassConfig(PassManagerBase &PM) {
diff --git a/llvm/include/llvm/Target/TargetSelectionDAG.td b/llvm/include/llvm/Target/TargetSelectionDAG.td
index 41fed692c7025..349fd003ca06e 100644
--- a/llvm/include/llvm/Target/TargetSelectionDAG.td
+++ b/llvm/include/llvm/Target/TargetSelectionDAG.td
@@ -407,7 +407,7 @@ def tblockaddress: SDNode<"ISD::TargetBlockAddress", SDTPtrLeaf, [],
def add : SDNode<"ISD::ADD" , SDTIntBinOp ,
[SDNPCommutative, SDNPAssociative]>;
-def ptradd : SDNode<"ISD::ADD" , SDTPtrAddOp, []>;
+def ptradd : SDNode<"ISD::PTRADD" , SDTPtrAddOp, []>;
def sub : SDNode<"ISD::SUB" , SDTIntBinOp>;
def mul : SDNode<"ISD::MUL" , SDTIntBinOp,
[SDNPCommutative, SDNPAssociative]>;
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index d6e288a59b2ee..6129c1a89912e 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -412,7 +412,9 @@ namespace {
SDValue visitMERGE_VALUES(SDNode *N);
SDValue visitADD(SDNode *N);
SDValue visitADDLike(SDNode *N);
- SDValue visitADDLikeCommutative(SDValue N0, SDValue N1, SDNode *LocReference);
+ SDValue visitADDLikeCommutative(SDValue N0, SDValue N1,
+ SDNode *LocReference);
+ SDValue visitPTRADD(SDNode *N);
SDValue visitSUB(SDNode *N);
SDValue visitADDSAT(SDNode *N);
SDValue visitSUBSAT(SDNode *N);
@@ -1095,7 +1097,7 @@ bool DAGCombiner::reassociationCanBreakAddressingModePattern(unsigned Opc,
// (load/store (add, (add, x, y), offset2)) ->
// (load/store (add, (add, x, offset2), y)).
- if (N0.getOpcode() != ISD::ADD)
+ if (N0.getOpcode() != ISD::ADD && N0.getOpcode() != ISD::PTRADD)
return false;
// Check for vscale addressing modes.
@@ -1852,6 +1854,7 @@ SDValue DAGCombiner::visit(SDNode *N) {
case ISD::TokenFactor: return visitTokenFactor(N);
case ISD::MERGE_VALUES: return visitMERGE_VALUES(N);
case ISD::ADD: return visitADD(N);
+ case ISD::PTRADD: return visitPTRADD(N);
case ISD::SUB: return visitSUB(N);
case ISD::SADDSAT:
case ISD::UADDSAT: return visitADDSAT(N);
@@ -2388,7 +2391,7 @@ static bool canFoldInAddressingMode(SDNode *N, SDNode *Use, SelectionDAG &DAG,
}
TargetLowering::AddrMode AM;
- if (N->getOpcode() == ISD::ADD) {
+ if (N->getOpcode() == ISD::ADD || N->getOpcode() == ISD::PTRADD) {
AM.HasBaseReg = true;
ConstantSDNode *Offset = dyn_cast<ConstantSDNode>(N->getOperand(1));
if (Offset)
@@ -2617,6 +2620,100 @@ SDValue DAGCombiner::foldSubToAvg(SDNode *N, const SDLoc &DL) {
return SDValue();
}
+/// Try to fold a pointer arithmetic node.
+/// This needs to be done separately from normal addition, because pointer
+/// addition is not commutative.
+/// This function was adapted from DAGCombiner::visitPTRADD() from the Morello
+/// project, which is based on CHERI.
+SDValue DAGCombiner::visitPTRADD(SDNode *N) {
+ SDValue N0 = N->getOperand(0);
+ SDValue N1 = N->getOperand(1);
+ EVT PtrVT = N0.getValueType();
+ EVT IntVT = N1.getValueType();
+ SDLoc DL(N);
+
+ // fold (ptradd undef, y) -> undef
+ if (N0.isUndef())
+ return N0;
+
+ // fold (ptradd x, undef) -> undef
+ if (N1.isUndef())
+ return DAG.getUNDEF(PtrVT);
+
+ // fold (ptradd x, 0) -> x
+ if (isNullConstant(N1))
+ return N0;
+
+ if (N0.getOpcode() == ISD::PTRADD &&
+ !reassociationCanBreakAddressingModePattern(ISD::PTRADD, DL, N, N0, N1)) {
+ SDValue X = N0.getOperand(0);
+ SDValue Y = N0.getOperand(1);
+ SDValue Z = N1;
+ bool N0OneUse = N0.hasOneUse();
+ bool YIsConstant = DAG.isConstantIntBuildVectorOrConstantInt(Y);
+ bool ZIsConstant = DAG.isConstantIntBuildVectorOrConstantInt(Z);
+ bool ZOneUse = Z.hasOneUse();
+
+ // (ptradd (ptradd x, y), z) -> (ptradd x, (add y, z)) if:
+ // * x is a null pointer; or
+ // * y is a constant and z has one use; or
+ // * y is a constant and (ptradd x, y) has one use; or
+ // * (ptradd x, y) and z have one use and z is not a constant.
+ if (isNullConstant(X) || (YIsConstant && ZOneUse) ||
+ (YIsConstant && N0OneUse) || (N0OneUse && ZOneUse && !ZIsConstant)) {
+ SDValue Add = DAG.getNode(ISD::ADD, DL, IntVT, {Y, Z});
+
+ // Calling visit() can replace the Add node with ISD::DELETED_NODE if
+ // there aren't any users, so keep a handle around whilst we visit it.
+ HandleSDNode ADDHandle(Add);
+
+ SDValue VisitedAdd = visit(Add.getNode());
+ if (VisitedAdd) {
+ // If visit() returns the same node, it means the SDNode was RAUW'd, and
+ // therefore we have to load the new value to perform the checks whether
+ // the reassociation fold is profitable.
+ if (VisitedAdd.getNode() == Add.getNode())
+ Add = ADDHandle.getValue();
+ else
+ Add = VisitedAdd;
+ }
+
+ return DAG.getMemBasePlusOffset(X, Add, DL, SDNodeFlags());
+ }
+
+ // TODO: There is another possible fold here that was proven useful.
+ // It would be this:
+ //
+ // (ptradd (ptradd x, y), z) -> (ptradd (ptradd x, z), y) if:
+ // * (ptradd x, y) has one use; and
+ // * y is a constant; and
+ // * z is not a constant.
+ //
+ // In some cases, specifically in AArch64's FEAT_CPA, it exposes the
+ // opportunity to select more complex instructions such as SUBPT and
+ // MSUBPT. However, a hypothetical corner case has been found that we could
+ // not avoid. Consider this (pseudo-POSIX C):
+ //
+ // char *foo(char *x, int z) {return (x + LARGE_CONSTANT) + z;}
+ // char *p = mmap(LARGE_CONSTANT);
+ // char *q = foo(p, -LARGE_CONSTANT);
+ //
+ // Then x + LARGE_CONSTANT is one-past-the-end, so valid, and a
+ // further + z takes it back to the start of the mapping, so valid,
+ // regardless of the address mmap gave back. However, if mmap gives you an
+ // address < LARGE_CONSTANT (ignoring high bits), x - LARGE_CONSTANT will
+ // borrow from the high bits (with the subsequent + z carrying back into
+ // the high bits to give you a well-defined pointer) and thus trip
+ // FEAT_CPA's pointer corruption checks.
+ //
+ // We leave this fold as an opportunity for future work, addressing the
+ // corner case for FEAT_CPA, as well as reconciling the solution with the
+ // more general application of pointer arithmetic in other future targets.
+ }
+
+ return SDValue();
+}
+
/// Try to fold a 'not' shifted sign-bit with add/sub with constant operand into
/// a shift and add with a different constant.
static SDValue foldAddSubOfSignBit(SDNode *N, const SDLoc &DL,
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index bbf1b0fd590ef..1483a5f4d5b95 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -5641,7 +5641,8 @@ bool SelectionDAG::isADDLike(SDValue Op, bool NoWrap) const {
bool SelectionDAG::isBaseWithConstantOffset(SDValue Op) const {
return Op.getNumOperands() == 2 && isa<ConstantSDNode>(Op.getOperand(1)) &&
- (Op.getOpcode() == ISD::ADD || isADDLike(Op));
+ (Op.getOpcode() == ISD::ADD || Op.getOpcode() == ISD::PTRADD ||
+ isADDLike(Op));
}
bool SelectionDAG::isKnownNeverNaN(SDValue Op, bool SNaN,
@@ -8144,7 +8145,12 @@ SDValue SelectionDAG::getMemBasePlusOffset(SDValue Ptr, SDValue Offset,
const SDNodeFlags Flags) {
assert(Offset.getValueType().isInteger());
EVT BasePtrVT = Ptr.getValueType();
- return getNode(ISD::ADD, DL, BasePtrVT, Ptr, Offset, Flags);
+ if (!this->getTarget().shouldPreservePtrArith(
+ this->getMachineFunction().getFunction())) {
+ return getNode(ISD::ADD, DL, BasePtrVT, Ptr, Offset, Flags);
+ } else {
+ return getNode(ISD::PTRADD, DL, BasePtrVT, Ptr, Offset, Flags);
+ }
}
/// Returns true if memcpy source is constant data.
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 8e74a076cc013..b3227d9b589dd 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -4284,8 +4284,8 @@ void SelectionDAGBuilder::visitGetElementPtr(const User &I) {
(int64_t(Offset) >= 0 && NW.hasNoUnsignedSignedWrap()))
Flags |= SDNodeFlags::NoUnsignedWrap;
- N = DAG.getNode(ISD::ADD, dl, N.getValueType(), N,
- DAG.getConstant(Offset, dl, N.getValueType()), Flags);
+ N = DAG.getMemBasePlusOffset(
+ N, DAG.getConstant(Offset, dl, N.getValueType()), dl, Flags);
}
} else {
// IdxSize is the width of the arithmetic according to IR semantics.
@@ -4329,7 +4329,7 @@ void SelectionDAGBuilder::visitGetElementPtr(const User &I) {
OffsVal = DAG.getSExtOrTrunc(OffsVal, dl, N.getValueType());
- N = DAG.getNode(ISD::ADD, dl, N.getValueType(), N, OffsVal, Flags);
+ N = DAG.getMemBasePlusOffset(N, OffsVal, dl, Flags);
continue;
}
@@ -4389,7 +4389,7 @@ void SelectionDAGBuilder::visitGetElementPtr(const User &I) {
SDNodeFlags AddFlags;
AddFlags.setNoUnsignedWrap(NW.hasNoUnsignedWrap());
- N = DAG.getNode(ISD::ADD, dl, N.getValueType(), N, IdxN, AddFlags);
+ N = DAG.getMemBasePlusOffset(N, IdxN, dl, AddFlags);
}
}
@@ -9138,8 +9138,8 @@ bool SelectionDAGBuilder::visitMemPCpyCall(const CallInst &I) {
Size = DAG.getSExtOrTrunc(Size, sdl, Dst.getValueType());
// Adjust return pointer to point just past the last dst byte.
- SDValue DstPlusSize = DAG.getNode(ISD::ADD, sdl, Dst.getValueType(),
- Dst, Size);
+ SDNodeFlags Flags;
+ SDValue DstPlusSize = DAG.getMemBasePlusOffset(Dst, Size, sdl, Flags);
setValue(&I, DstPlusSize);
return true;
}
@@ -11230,10 +11230,9 @@ TargetLowering::LowerCallTo(TargetLowering::CallLoweringInfo &CLI) const {
MachineFunction &MF = CLI.DAG.getMachineFunction();
Align HiddenSRetAlign = MF.getFrameInfo().getObjectAlign(DemoteStackIdx);
for (unsigned i = 0; i < NumValues; ++i) {
- SDValue Add =
- CLI.DAG.getNode(ISD::ADD, CLI.DL, PtrVT, DemoteStackSlot,
- CLI.DAG.getConstant(Offsets[i], CLI.DL, PtrVT),
- SDNodeFlags::NoUnsignedWrap);
+ SDValue Add = CLI.DAG.getMemBasePlusOffset(
+ DemoteStackSlot, CLI.DAG.getConstant(Offsets[i], CLI.DL, PtrVT),
+ CLI.DL, SDNodeFlags::NoUnsignedWrap);
SDValue L = CLI.DAG.getLoad(
RetTys[i], CLI.DL, CLI.Chain, Add,
MachinePointerInfo::getFixedStack(CLI.DAG.getMachineFunction(),
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
index 8faf97271d99e..45ef475dffe6e 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
@@ -269,6 +269,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
// Binary operators
case ISD::ADD: return "add";
+ case ISD::PTRADD: return "ptradd";
case ISD::SUB: return "sub";
case ISD::MUL: return "mul";
case ISD::MULHU: return "mulhu";
>From ba0b2ee704eecba0825a332a3c0066bc1a2fa848 Mon Sep 17 00:00:00 2001
From: Fabian Ritter <fabian.ritter at amd.com>
Date: Thu, 15 May 2025 03:24:58 -0400
Subject: [PATCH 02/11] Use AddToWorklist() instead of manually re-visiting a
newly generated node in the DAGCombines. Also: remove else after return and
braces around single-line blocks to match the coding standards.
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 17 +----------------
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 6 ++----
2 files changed, 3 insertions(+), 20 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 6129c1a89912e..18333547535ac 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -2662,22 +2662,7 @@ SDValue DAGCombiner::visitPTRADD(SDNode *N) {
if (isNullConstant(X) || (YIsConstant && ZOneUse) ||
(YIsConstant && N0OneUse) || (N0OneUse && ZOneUse && !ZIsConstant)) {
SDValue Add = DAG.getNode(ISD::ADD, DL, IntVT, {Y, Z});
-
- // Calling visit() can replace the Add node with ISD::DELETED_NODE if
- // there aren't any users, so keep a handle around whilst we visit it.
- HandleSDNode ADDHandle(Add);
-
- SDValue VisitedAdd = visit(Add.getNode());
- if (VisitedAdd) {
- // If visit() returns the same node, it means the SDNode was RAUW'd, and
- // therefore we have to load the new value to perform the checks whether
- // the reassociation fold is profitable.
- if (VisitedAdd.getNode() == Add.getNode())
- Add = ADDHandle.getValue();
- else
- Add = VisitedAdd;
- }
-
+ AddToWorklist(Add.getNode());
return DAG.getMemBasePlusOffset(X, Add, DL, SDNodeFlags());
}
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 1483a5f4d5b95..40695638cf942 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -8146,11 +8146,9 @@ SDValue SelectionDAG::getMemBasePlusOffset(SDValue Ptr, SDValue Offset,
assert(Offset.getValueType().isInteger());
EVT BasePtrVT = Ptr.getValueType();
if (!this->getTarget().shouldPreservePtrArith(
- this->getMachineFunction().getFunction())) {
+ this->getMachineFunction().getFunction()))
return getNode(ISD::ADD, DL, BasePtrVT, Ptr, Offset, Flags);
- } else {
- return getNode(ISD::PTRADD, DL, BasePtrVT, Ptr, Offset, Flags);
- }
+ return getNode(ISD::PTRADD, DL, BasePtrVT, Ptr, Offset, Flags);
}
/// Returns true if memcpy source is constant data.
>From f6a4cda119e7825a571b24feaa21223a86103d15 Mon Sep 17 00:00:00 2001
From: Fabian Ritter <fabian.ritter at amd.com>
Date: Thu, 15 May 2025 09:23:10 -0400
Subject: [PATCH 03/11] Remove DAGCombine comment referring to Morello and
CHERI
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 2 --
1 file changed, 2 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 18333547535ac..ef281c733cc74 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -2623,8 +2623,6 @@ SDValue DAGCombiner::foldSubToAvg(SDNode *N, const SDLoc &DL) {
/// Try to fold a pointer arithmetic node.
/// This needs to be done separately from normal addition, because pointer
/// addition is not commutative.
-/// This function was adapted from DAGCombiner::visitPTRADD() from the Morello
-/// project, which is based on CHERI.
SDValue DAGCombiner::visitPTRADD(SDNode *N) {
SDValue N0 = N->getOperand(0);
SDValue N1 = N->getOperand(1);
>From d5f083ed1dadf2cbfa914c8f886059120f8a7ee0 Mon Sep 17 00:00:00 2001
From: Fabian Ritter <fabian.ritter at amd.com>
Date: Fri, 16 May 2025 03:56:44 -0400
Subject: [PATCH 04/11] Add the pointer's EVT to the signature of
TM::shouldPreservePtrArith()
---
llvm/include/llvm/Target/TargetMachine.h | 11 ++++++++---
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 2 +-
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h
index 8536439f0a2d4..8ce01a84517dd 100644
--- a/llvm/include/llvm/Target/TargetMachine.h
+++ b/llvm/include/llvm/Target/TargetMachine.h
@@ -35,6 +35,7 @@ namespace llvm {
class AAManager;
using ModulePassManager = PassManager<Module>;
+struct EVT;
class Function;
class GlobalValue;
class MachineModuleInfoWrapperPass;
@@ -469,9 +470,13 @@ class TargetMachine {
}
/// True if target has some particular form of dealing with pointer arithmetic
- /// semantics. False if pointer arithmetic should not be preserved for passes
- /// such as instruction selection, and can fallback to regular arithmetic.
- virtual bool shouldPreservePtrArith(const Function &F) const { return false; }
+ /// semantics for pointers with the given value type. False if pointer
+ /// arithmetic should not be preserved for passes such as instruction
+ /// selection, and can fallback to regular arithmetic.
+ virtual bool shouldPreservePtrArith(const Function &F,
+ const EVT &PtrVT) const {
+ return false;
+ }
/// Create a pass configuration object to be used by addPassToEmitX methods
/// for generating a pipeline of CodeGen passes.
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 40695638cf942..826e1f775f95c 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -8146,7 +8146,7 @@ SDValue SelectionDAG::getMemBasePlusOffset(SDValue Ptr, SDValue Offset,
assert(Offset.getValueType().isInteger());
EVT BasePtrVT = Ptr.getValueType();
if (!this->getTarget().shouldPreservePtrArith(
- this->getMachineFunction().getFunction()))
+ this->getMachineFunction().getFunction(), BasePtrVT))
return getNode(ISD::ADD, DL, BasePtrVT, Ptr, Offset, Flags);
return getNode(ISD::PTRADD, DL, BasePtrVT, Ptr, Offset, Flags);
}
>From 759f0656a9bc4e50bdc6add4d218b9425120d8cc Mon Sep 17 00:00:00 2001
From: Fabian Ritter <fabian.ritter at amd.com>
Date: Fri, 16 May 2025 05:22:02 -0400
Subject: [PATCH 05/11] Move shouldPreservePtrArith from TargetMachine to
TargetLoweringBase,
add a comment to state that it should be removed eventually, and reorder
if/else cases to avoid a negated condition where shouldPreservePtrArith
is called.
---
llvm/include/llvm/CodeGen/TargetLowering.h | 9 +++++++++
llvm/include/llvm/Target/TargetMachine.h | 10 ----------
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 8 ++++----
3 files changed, 13 insertions(+), 14 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index 03099e9ad44dc..f9d3d82ab4a84 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -3483,6 +3483,15 @@ class TargetLoweringBase {
/// doing arithmetic on boolean types
virtual bool shouldExpandCmpUsingSelects(EVT VT) const { return false; }
+ /// True if target has some particular form of dealing with pointer arithmetic
+ /// semantics for pointers with the given value type. False if pointer
+ /// arithmetic should not be preserved for passes such as instruction
+ /// selection, and can fallback to regular arithmetic.
+ /// This should be removed when PTRADD nodes are widely supported by backends.
+ virtual bool shouldPreservePtrArith(const Function &F, EVT PtrVT) const {
+ return false;
+ }
+
/// Does this target support complex deinterleaving
virtual bool isComplexDeinterleavingSupported() const { return false; }
diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h
index 8ce01a84517dd..906926729ed74 100644
--- a/llvm/include/llvm/Target/TargetMachine.h
+++ b/llvm/include/llvm/Target/TargetMachine.h
@@ -35,7 +35,6 @@ namespace llvm {
class AAManager;
using ModulePassManager = PassManager<Module>;
-struct EVT;
class Function;
class GlobalValue;
class MachineModuleInfoWrapperPass;
@@ -469,15 +468,6 @@ class TargetMachine {
return false;
}
- /// True if target has some particular form of dealing with pointer arithmetic
- /// semantics for pointers with the given value type. False if pointer
- /// arithmetic should not be preserved for passes such as instruction
- /// selection, and can fallback to regular arithmetic.
- virtual bool shouldPreservePtrArith(const Function &F,
- const EVT &PtrVT) const {
- return false;
- }
-
/// Create a pass configuration object to be used by addPassToEmitX methods
/// for generating a pipeline of CodeGen passes.
virtual TargetPassConfig *createPassConfig(PassManagerBase &PM) {
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 826e1f775f95c..e31b88ab9ea46 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -8145,10 +8145,10 @@ SDValue SelectionDAG::getMemBasePlusOffset(SDValue Ptr, SDValue Offset,
const SDNodeFlags Flags) {
assert(Offset.getValueType().isInteger());
EVT BasePtrVT = Ptr.getValueType();
- if (!this->getTarget().shouldPreservePtrArith(
- this->getMachineFunction().getFunction(), BasePtrVT))
- return getNode(ISD::ADD, DL, BasePtrVT, Ptr, Offset, Flags);
- return getNode(ISD::PTRADD, DL, BasePtrVT, Ptr, Offset, Flags);
+ if (TLI->shouldPreservePtrArith(this->getMachineFunction().getFunction(),
+ BasePtrVT))
+ return getNode(ISD::PTRADD, DL, BasePtrVT, Ptr, Offset, Flags);
+ return getNode(ISD::ADD, DL, BasePtrVT, Ptr, Offset, Flags);
}
/// Returns true if memcpy source is constant data.
>From 3a38633e7782afa0f3336cd0ee2f0614346e801a Mon Sep 17 00:00:00 2001
From: Fabian Ritter <fabian.ritter at amd.com>
Date: Mon, 19 May 2025 04:44:07 -0400
Subject: [PATCH 06/11] Add (YIsConstant && ZIsConstant) case to the
DAGCombine.
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index ef281c733cc74..9f5ad27222b97 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -2656,9 +2656,11 @@ SDValue DAGCombiner::visitPTRADD(SDNode *N) {
// * x is a null pointer; or
// * y is a constant and z has one use; or
// * y is a constant and (ptradd x, y) has one use; or
+ // * y and z are both constants; or
// * (ptradd x, y) and z have one use and z is not a constant.
if (isNullConstant(X) || (YIsConstant && ZOneUse) ||
- (YIsConstant && N0OneUse) || (N0OneUse && ZOneUse && !ZIsConstant)) {
+ (YIsConstant && N0OneUse) || (YIsConstant && ZIsConstant) ||
+ (N0OneUse && ZOneUse && !ZIsConstant)) {
SDValue Add = DAG.getNode(ISD::ADD, DL, IntVT, {Y, Z});
AddToWorklist(Add.getNode());
return DAG.getMemBasePlusOffset(X, Add, DL, SDNodeFlags());
>From 2ccad11fe32f3fbed04c0944d7119fda9c9387e8 Mon Sep 17 00:00:00 2001
From: Fabian Ritter <fabian.ritter at amd.com>
Date: Mon, 19 May 2025 08:46:23 -0400
Subject: [PATCH 07/11] Add ISD::isPtrAdd() and fix a typo.
---
llvm/include/llvm/CodeGen/ISDOpcodes.h | 6 +++++-
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 4 ++--
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 3 +--
3 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index abae3e921117f..e3989ad62d237 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -1502,7 +1502,7 @@ enum NodeType {
// Outputs: [rv], output chain, glue
PATCHPOINT,
- // PTRADD represents pointer arithmatic semantics, for targets that opt in
+ // PTRADD represents pointer arithmetic semantics, for targets that opt in
// using shouldPreservePtrArith().
// ptr = PTRADD ptr, offset
PTRADD,
@@ -1734,6 +1734,10 @@ inline bool isExtVecInRegOpcode(unsigned Opcode) {
Opcode == ISD::SIGN_EXTEND_VECTOR_INREG;
}
+inline bool isPtrAdd(unsigned Opcode) {
+ return (Opcode == ISD::ADD) || (Opcode == ISD::PTRADD);
+}
+
namespace GlobalISel {
/// Return the operation corresponding to !(X op Y), where 'op' is a valid
/// SetCC operation. The U bit of the condition code has different meanings
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 9f5ad27222b97..28211deb87b23 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -1097,7 +1097,7 @@ bool DAGCombiner::reassociationCanBreakAddressingModePattern(unsigned Opc,
// (load/store (add, (add, x, y), offset2)) ->
// (load/store (add, (add, x, offset2), y)).
- if (N0.getOpcode() != ISD::ADD && N0.getOpcode() != ISD::PTRADD)
+ if (!ISD::isPtrAdd(N0.getOpcode()))
return false;
// Check for vscale addressing modes.
@@ -2391,7 +2391,7 @@ static bool canFoldInAddressingMode(SDNode *N, SDNode *Use, SelectionDAG &DAG,
}
TargetLowering::AddrMode AM;
- if (N->getOpcode() == ISD::ADD || N->getOpcode() == ISD::PTRADD) {
+ if (ISD::isPtrAdd(N->getOpcode())) {
AM.HasBaseReg = true;
ConstantSDNode *Offset = dyn_cast<ConstantSDNode>(N->getOperand(1));
if (Offset)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index e31b88ab9ea46..1dce2e951b9bf 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -5641,8 +5641,7 @@ bool SelectionDAG::isADDLike(SDValue Op, bool NoWrap) const {
bool SelectionDAG::isBaseWithConstantOffset(SDValue Op) const {
return Op.getNumOperands() == 2 && isa<ConstantSDNode>(Op.getOperand(1)) &&
- (Op.getOpcode() == ISD::ADD || Op.getOpcode() == ISD::PTRADD ||
- isADDLike(Op));
+ (ISD::isPtrAdd(Op.getOpcode()) || isADDLike(Op));
}
bool SelectionDAG::isKnownNeverNaN(SDValue Op, bool SNaN,
>From 4c6ba494eccd1918050761904f3f9a7b9bc5a8dd Mon Sep 17 00:00:00 2001
From: Fabian Ritter <fabian.ritter at amd.com>
Date: Tue, 20 May 2025 03:19:53 -0400
Subject: [PATCH 08/11] Move isPtrAdd to SDNode/SDValue; rename it to isAnyAdd
---
llvm/include/llvm/CodeGen/ISDOpcodes.h | 4 ----
llvm/include/llvm/CodeGen/SelectionDAGNodes.h | 10 ++++++++++
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 4 ++--
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 2 +-
4 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index e3989ad62d237..3c748b701c9ff 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -1734,10 +1734,6 @@ inline bool isExtVecInRegOpcode(unsigned Opcode) {
Opcode == ISD::SIGN_EXTEND_VECTOR_INREG;
}
-inline bool isPtrAdd(unsigned Opcode) {
- return (Opcode == ISD::ADD) || (Opcode == ISD::PTRADD);
-}
-
namespace GlobalISel {
/// Return the operation corresponding to !(X op Y), where 'op' is a valid
/// SetCC operation. The U bit of the condition code has different meanings
diff --git a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
index cfefceea8f0fe..65cc9152fbbe2 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
@@ -213,6 +213,7 @@ class SDValue {
inline bool isTargetOpcode() const;
inline bool isMachineOpcode() const;
inline bool isUndef() const;
+ inline bool isAnyAdd() const;
inline unsigned getMachineOpcode() const;
inline const DebugLoc &getDebugLoc() const;
inline void dump() const;
@@ -697,6 +698,11 @@ END_TWO_BYTE_PACK()
return NodeType == ISD::UNDEF || NodeType == ISD::POISON;
}
+ /// Returns true if the node type is ADD or PTRADD.
+ bool isAnyAdd() const {
+ return NodeType == ISD::ADD || NodeType == ISD::PTRADD;
+ }
+
/// Test if this node is a memory intrinsic (with valid pointer information).
bool isMemIntrinsic() const { return SDNodeBits.IsMemIntrinsic; }
@@ -1270,6 +1276,10 @@ inline bool SDValue::isUndef() const {
return Node->isUndef();
}
+inline bool SDValue::isAnyAdd() const {
+ return Node->isAnyAdd();
+}
+
inline bool SDValue::use_empty() const {
return !Node->hasAnyUseOfValue(ResNo);
}
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 28211deb87b23..dfcd0d0694780 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -1097,7 +1097,7 @@ bool DAGCombiner::reassociationCanBreakAddressingModePattern(unsigned Opc,
// (load/store (add, (add, x, y), offset2)) ->
// (load/store (add, (add, x, offset2), y)).
- if (!ISD::isPtrAdd(N0.getOpcode()))
+ if (!N0.isAnyAdd())
return false;
// Check for vscale addressing modes.
@@ -2391,7 +2391,7 @@ static bool canFoldInAddressingMode(SDNode *N, SDNode *Use, SelectionDAG &DAG,
}
TargetLowering::AddrMode AM;
- if (ISD::isPtrAdd(N->getOpcode())) {
+ if (N->isAnyAdd()) {
AM.HasBaseReg = true;
ConstantSDNode *Offset = dyn_cast<ConstantSDNode>(N->getOperand(1));
if (Offset)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 1dce2e951b9bf..72bd4f0284ec2 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -5641,7 +5641,7 @@ bool SelectionDAG::isADDLike(SDValue Op, bool NoWrap) const {
bool SelectionDAG::isBaseWithConstantOffset(SDValue Op) const {
return Op.getNumOperands() == 2 && isa<ConstantSDNode>(Op.getOperand(1)) &&
- (ISD::isPtrAdd(Op.getOpcode()) || isADDLike(Op));
+ (Op.isAnyAdd() || isADDLike(Op));
}
bool SelectionDAG::isKnownNeverNaN(SDValue Op, bool SNaN,
>From c0ed6a2f859fff09a39475af12e6321098c5a553 Mon Sep 17 00:00:00 2001
From: Fabian Ritter <fabian.ritter at amd.com>
Date: Tue, 20 May 2025 03:29:19 -0400
Subject: [PATCH 09/11] Fix formatting
---
llvm/include/llvm/CodeGen/SelectionDAGNodes.h | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
index 65cc9152fbbe2..b7a527b81019d 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
@@ -1276,9 +1276,7 @@ inline bool SDValue::isUndef() const {
return Node->isUndef();
}
-inline bool SDValue::isAnyAdd() const {
- return Node->isAnyAdd();
-}
+inline bool SDValue::isAnyAdd() const { return Node->isAnyAdd(); }
inline bool SDValue::use_empty() const {
return !Node->hasAnyUseOfValue(ResNo);
>From 1239537577ae406457928109d8d0cabe78ad588f Mon Sep 17 00:00:00 2001
From: Fabian Ritter <fabian.ritter at amd.com>
Date: Wed, 21 May 2025 04:11:02 -0400
Subject: [PATCH 10/11] Add PTRADD handling to SDAG::getNode()
That involves early folds and (technically overly restrictive)
assertions on the operand types.
---
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 72bd4f0284ec2..ffedec2975a7b 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -7341,10 +7341,18 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT,
case ISD::OR:
case ISD::XOR:
case ISD::ADD:
+ case ISD::PTRADD:
case ISD::SUB:
assert(VT.isInteger() && "This operator does not apply to FP types!");
assert(N1.getValueType() == N2.getValueType() &&
N1.getValueType() == VT && "Binary operator types must match!");
+ // The equal operand types requirement is unnecessarily strong for PTRADD.
+ // However, the SelectionDAGBuilder does not generate PTRADDs with different
+ // operand types, and we'd need to re-implement GEP's non-standard wrapping
+ // logic everywhere where PTRADDs may be folded or combined to properly
+ // support them. If/when we introduce pointer types to the SDAG, we will
+ // need to relax this constraint.
+
// (X ^|+- 0) -> X. This commonly occurs when legalizing i64 values, so
// it's worth handling here.
if (N2CV && N2CV->isZero())
@@ -7696,6 +7704,7 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT,
std::swap(N1, N2);
} else {
switch (Opcode) {
+ case ISD::PTRADD:
case ISD::SUB:
// fold op(undef, arg2) -> undef, fold op(poison, arg2) ->poison.
return N1.getOpcode() == ISD::POISON ? getPOISON(VT) : getUNDEF(VT);
@@ -7723,6 +7732,7 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT,
return getConstant(0, DL, VT);
[[fallthrough]];
case ISD::ADD:
+ case ISD::PTRADD:
case ISD::SUB:
case ISD::UDIV:
case ISD::SDIV:
>From 4edcf2f7ab30158d102cd109af638ecc435b21fe Mon Sep 17 00:00:00 2001
From: Fabian Ritter <fabian.ritter at amd.com>
Date: Thu, 22 May 2025 03:07:23 -0400
Subject: [PATCH 11/11] Split the DAGCombiner::visitPtrAdd() implementation off
to put it into a separate PR.
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 81 -------------------
1 file changed, 81 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index dfcd0d0694780..350895208a4fb 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -414,7 +414,6 @@ namespace {
SDValue visitADDLike(SDNode *N);
SDValue visitADDLikeCommutative(SDValue N0, SDValue N1,
SDNode *LocReference);
- SDValue visitPTRADD(SDNode *N);
SDValue visitSUB(SDNode *N);
SDValue visitADDSAT(SDNode *N);
SDValue visitSUBSAT(SDNode *N);
@@ -1854,7 +1853,6 @@ SDValue DAGCombiner::visit(SDNode *N) {
case ISD::TokenFactor: return visitTokenFactor(N);
case ISD::MERGE_VALUES: return visitMERGE_VALUES(N);
case ISD::ADD: return visitADD(N);
- case ISD::PTRADD: return visitPTRADD(N);
case ISD::SUB: return visitSUB(N);
case ISD::SADDSAT:
case ISD::UADDSAT: return visitADDSAT(N);
@@ -2620,85 +2618,6 @@ SDValue DAGCombiner::foldSubToAvg(SDNode *N, const SDLoc &DL) {
return SDValue();
}
-/// Try to fold a pointer arithmetic node.
-/// This needs to be done separately from normal addition, because pointer
-/// addition is not commutative.
-SDValue DAGCombiner::visitPTRADD(SDNode *N) {
- SDValue N0 = N->getOperand(0);
- SDValue N1 = N->getOperand(1);
- EVT PtrVT = N0.getValueType();
- EVT IntVT = N1.getValueType();
- SDLoc DL(N);
-
- // fold (ptradd undef, y) -> undef
- if (N0.isUndef())
- return N0;
-
- // fold (ptradd x, undef) -> undef
- if (N1.isUndef())
- return DAG.getUNDEF(PtrVT);
-
- // fold (ptradd x, 0) -> x
- if (isNullConstant(N1))
- return N0;
-
- if (N0.getOpcode() == ISD::PTRADD &&
- !reassociationCanBreakAddressingModePattern(ISD::PTRADD, DL, N, N0, N1)) {
- SDValue X = N0.getOperand(0);
- SDValue Y = N0.getOperand(1);
- SDValue Z = N1;
- bool N0OneUse = N0.hasOneUse();
- bool YIsConstant = DAG.isConstantIntBuildVectorOrConstantInt(Y);
- bool ZIsConstant = DAG.isConstantIntBuildVectorOrConstantInt(Z);
- bool ZOneUse = Z.hasOneUse();
-
- // (ptradd (ptradd x, y), z) -> (ptradd x, (add y, z)) if:
- // * x is a null pointer; or
- // * y is a constant and z has one use; or
- // * y is a constant and (ptradd x, y) has one use; or
- // * y and z are both constants; or
- // * (ptradd x, y) and z have one use and z is not a constant.
- if (isNullConstant(X) || (YIsConstant && ZOneUse) ||
- (YIsConstant && N0OneUse) || (YIsConstant && ZIsConstant) ||
- (N0OneUse && ZOneUse && !ZIsConstant)) {
- SDValue Add = DAG.getNode(ISD::ADD, DL, IntVT, {Y, Z});
- AddToWorklist(Add.getNode());
- return DAG.getMemBasePlusOffset(X, Add, DL, SDNodeFlags());
- }
-
- // TODO: There is another possible fold here that was proven useful.
- // It would be this:
- //
- // (ptradd (ptradd x, y), z) -> (ptradd (ptradd x, z), y) if:
- // * (ptradd x, y) has one use; and
- // * y is a constant; and
- // * z is not a constant.
- //
- // In some cases, specifically in AArch64's FEAT_CPA, it exposes the
- // opportunity to select more complex instructions such as SUBPT and
- // MSUBPT. However, a hypothetical corner case has been found that we could
- // not avoid. Consider this (pseudo-POSIX C):
- //
- // char *foo(char *x, int z) {return (x + LARGE_CONSTANT) + z;}
- // char *p = mmap(LARGE_CONSTANT);
- // char *q = foo(p, -LARGE_CONSTANT);
- //
- // Then x + LARGE_CONSTANT is one-past-the-end, so valid, and a
- // further + z takes it back to the start of the mapping, so valid,
- // regardless of the address mmap gave back. However, if mmap gives you an
- // address < LARGE_CONSTANT (ignoring high bits), x - LARGE_CONSTANT will
- // borrow from the high bits (with the subsequent + z carrying back into
- // the high bits to give you a well-defined pointer) and thus trip
- // FEAT_CPA's pointer corruption checks.
- //
- // We leave this fold as an opportunity for future work, addressing the
- // corner case for FEAT_CPA, as well as reconciling the solution with the
- // more general application of pointer arithmetic in other future targets.
- }
-
- return SDValue();
-}
-
/// Try to fold a 'not' shifted sign-bit with add/sub with constant operand into
/// a shift and add with a different constant.
static SDValue foldAddSubOfSignBit(SDNode *N, const SDLoc &DL,
More information about the llvm-commits
mailing list