Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b26f615
[AArch64] Add CodeGen support for FEAT_CPA
rgwott Aug 22, 2024
b99a0b9
Merge branch main into branch cpa
Jan 20, 2025
fb33270
[SelectionDAG] Refactor use of getMemBasePlusOffset() where applicable
rgwott Jan 20, 2025
6e491cd
[SelectionDAG] Inverted args for PTRADD on getMemBasePlusOffset()
rgwott Jan 22, 2025
eebe538
Fix minor lexical problems
rgwott Jan 22, 2025
76dae60
Satisfy undef deprecator
rgwott Jan 28, 2025
10651fa
Remove fold with unhandeable corner case
rgwott Jan 31, 2025
e64ef52
Add comment explaining removed fold for future work
rgwott Jan 31, 2025
d0b2362
Minor lexical fix
rgwott Jan 31, 2025
82d0550
Merge branch main into branch cpa
rgwott Feb 4, 2025
c70948f
Remove getMemBasePlusOffset inversion logic after #125279
rgwott Feb 4, 2025
4330997
Remove inadequate use of getMemBasePlusOffset()
rgwott Feb 4, 2025
0202b39
Remove obsolete AddedCompletixy in FEAT_CPA tablegen patterns
rgwott Feb 6, 2025
15f8b6b
Modify comment in PTRADD declaration
rgwott Feb 6, 2025
a61a19f
Gate FEAT_CPA CodeGen behind -mcpa-codegen flag
rgwott Feb 6, 2025
3a57e4d
Merge remote-tracking branch 'origin/main' into cpa
rgwott Jun 18, 2025
aec4f71
Autogenerate FEAT_CPA tests with utils/update_llc_test_checks.py
rgwott Jun 18, 2025
0935a57
Fix minor typo
rgwott Jun 18, 2025
df8a380
Fix botched merge from upstream
rgwott Jun 18, 2025
1a7982e
Fix remaining botched merge from upstream
rgwott Jun 18, 2025
d049ea5
Adapt FEAT_CPA SDAG/GISel to shouldPreservePtrArith in targetLowering
rgwott Jun 18, 2025
3e6ccee
Fix missing newline
rgwott Jun 18, 2025
b0b575b
Remove user-facing option -mcpa-codegen and use backend option instead
rgwott Jun 18, 2025
8d8cca7
Remove now-superfluous HasCPACodegen() function
rgwott Jun 18, 2025
ca45208
Remove -global-isel-abort=1 from GlobalISel tests
rgwott Jun 20, 2025
fcde60c
Insert printf() call in CPA tests to prevent case from optimizing away
rgwott Jun 20, 2025
029f1c3
Make (ADDPT|SUBPT) shift operand an i64 as opposed to i32
rgwott Jun 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions llvm/include/llvm/CodeGen/ISDOpcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1452,6 +1452,10 @@ enum NodeType {
// Outputs: [rv], output chain, glue
PATCHPOINT,

// PTRADD represents pointer arithmetic semantics, for those targets which
// benefit from that information.
PTRADD,

// Vector Predication
#define BEGIN_REGISTER_VP_SDNODE(VPSDID, ...) VPSDID,
#include "llvm/IR/VPIntrinsics.def"
Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/Target/TargetMachine.h
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,11 @@ class TargetMachine {
function_ref<void(std::unique_ptr<Module> MPart)> ModuleCallback) {
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; }
};

/// This class describes a target machine that is implemented with the LLVM
Expand Down
4 changes: 2 additions & 2 deletions llvm/include/llvm/Target/TargetSelectionDAG.td
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def SDTOther : SDTypeProfile<1, 0, [SDTCisVT<0, OtherVT>]>; // for 'vt'.
def SDTUNDEF : SDTypeProfile<1, 0, []>; // for 'undef'.
def SDTUnaryOp : SDTypeProfile<1, 1, []>; // for bitconvert.

def SDTPtrAddOp : SDTypeProfile<1, 2, [ // ptradd
def SDTPtrAddOp : SDTypeProfile<1, 2, [ // ptradd
SDTCisSameAs<0, 1>, SDTCisInt<2>, SDTCisPtrTy<1>
]>;
def SDTIntBinOp : SDTypeProfile<1, 2, [ // add, and, or, xor, udiv, etc.
Expand Down Expand Up @@ -390,7 +390,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]>;
Expand Down
101 changes: 98 additions & 3 deletions llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,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);
Expand Down Expand Up @@ -1082,7 +1084,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.
Expand Down Expand Up @@ -1833,6 +1835,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);
Expand Down Expand Up @@ -2349,7 +2352,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)
Expand Down Expand Up @@ -2578,6 +2581,98 @@ 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);

// (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.
// Serves to expose constant y for subsequent folding.
if (N0OneUse && YIsConstant && !ZIsConstant) {
SDValue Add = DAG.getNode(ISD::PTRADD, DL, IntVT, {X, 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(Add, Y, DL, SDNodeFlags());
}

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());
}
}

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,
Expand Down
21 changes: 17 additions & 4 deletions llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4069,8 +4069,14 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) {
else
Index = DAG.getNode(ISD::MUL, dl, Index.getValueType(), Index,
DAG.getConstant(EntrySize, dl, Index.getValueType()));
SDValue Addr = DAG.getNode(ISD::ADD, dl, Index.getValueType(),
Index, Table);
SDValue Addr;
if (!DAG.getTarget().shouldPreservePtrArith(
DAG.getMachineFunction().getFunction())) {
Addr = DAG.getNode(ISD::ADD, dl, Index.getValueType(), Index, Table);
} else {
// PTRADD always takes the pointer first, so the operands are commuted
Addr = DAG.getNode(ISD::PTRADD, dl, Index.getValueType(), Table, Index);
}

EVT MemVT = EVT::getIntegerVT(*DAG.getContext(), EntrySize * 8);
SDValue LD = DAG.getExtLoad(
Expand All @@ -4081,8 +4087,15 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) {
// For PIC, the sequence is:
// BRIND(load(Jumptable + index) + RelocBase)
// RelocBase can be JumpTable, GOT or some sort of global base.
Addr = DAG.getNode(ISD::ADD, dl, PTy, Addr,
TLI.getPICJumpTableRelocBase(Table, DAG));
if (!DAG.getTarget().shouldPreservePtrArith(
DAG.getMachineFunction().getFunction())) {
Addr = DAG.getNode(ISD::ADD, dl, PTy, Addr,
TLI.getPICJumpTableRelocBase(Table, DAG));
} else {
// PTRADD always takes the pointer first, so the operands are commuted
Addr = DAG.getNode(ISD::PTRADD, dl, PTy,
TLI.getPICJumpTableRelocBase(Table, DAG), Addr);
}
}

Tmp1 = TLI.expandIndirectJTBranch(dl, LD.getValue(1), Addr, JTI, DAG);
Expand Down
10 changes: 8 additions & 2 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5387,7 +5387,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, unsigned Depth) const {
Expand Down Expand Up @@ -7785,7 +7786,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.
Expand Down
44 changes: 33 additions & 11 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4293,6 +4293,12 @@ void SelectionDAGBuilder::visitGetElementPtr(const User &I) {
SDLoc dl = getCurSDLoc();
auto &TLI = DAG.getTargetLoweringInfo();
GEPNoWrapFlags NW = cast<GEPOperator>(I).getNoWrapFlags();
unsigned int AddOpcode = ISD::PTRADD;

if (!DAG.getTarget().shouldPreservePtrArith(
DAG.getMachineFunction().getFunction())) {
AddOpcode = ISD::ADD;
}

// Normalize Vector GEP - all scalar operands should be converted to the
// splat vector.
Expand Down Expand Up @@ -4324,7 +4330,7 @@ void SelectionDAGBuilder::visitGetElementPtr(const User &I) {
(int64_t(Offset) >= 0 && NW.hasNoUnsignedSignedWrap()))
Flags.setNoUnsignedWrap(true);

N = DAG.getNode(ISD::ADD, dl, N.getValueType(), N,
N = DAG.getNode(AddOpcode, dl, N.getValueType(), N,
DAG.getConstant(Offset, dl, N.getValueType()), Flags);
}
} else {
Expand Down Expand Up @@ -4368,7 +4374,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.getNode(AddOpcode, dl, N.getValueType(), N, OffsVal, Flags);
continue;
}

Expand Down Expand Up @@ -4411,8 +4417,7 @@ void SelectionDAGBuilder::visitGetElementPtr(const User &I) {
}
}

N = DAG.getNode(ISD::ADD, dl,
N.getValueType(), N, IdxN);
N = DAG.getNode(AddOpcode, dl, N.getValueType(), N, IdxN);
}
}

Expand Down Expand Up @@ -4473,8 +4478,15 @@ void SelectionDAGBuilder::visitAlloca(const AllocaInst &I) {
// an address inside an alloca.
SDNodeFlags Flags;
Flags.setNoUnsignedWrap(true);
AllocSize = DAG.getNode(ISD::ADD, dl, AllocSize.getValueType(), AllocSize,
DAG.getConstant(StackAlignMask, dl, IntPtr), Flags);
if (DAG.getTarget().shouldPreservePtrArith(
DAG.getMachineFunction().getFunction())) {
AllocSize = DAG.getNode(ISD::PTRADD, dl, AllocSize.getValueType(),
DAG.getConstant(StackAlignMask, dl, IntPtr),
AllocSize, Flags);
} else {
AllocSize = DAG.getNode(ISD::ADD, dl, AllocSize.getValueType(), AllocSize,
DAG.getConstant(StackAlignMask, dl, IntPtr), Flags);
}

// Mask out the low bits for alignment purposes.
AllocSize = DAG.getNode(ISD::AND, dl, AllocSize.getValueType(), AllocSize,
Expand Down Expand Up @@ -9071,8 +9083,13 @@ 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);
unsigned int AddOpcode = ISD::PTRADD;
if (!DAG.getTarget().shouldPreservePtrArith(
DAG.getMachineFunction().getFunction())) {
AddOpcode = ISD::ADD;
}
SDValue DstPlusSize =
DAG.getNode(AddOpcode, sdl, Dst.getValueType(), Dst, Size);
setValue(&I, DstPlusSize);
return true;
}
Expand Down Expand Up @@ -11169,9 +11186,14 @@ 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), Flags);
unsigned int AddOpcode = ISD::PTRADD;
if (!CLI.DAG.getTarget().shouldPreservePtrArith(
CLI.DAG.getMachineFunction().getFunction())) {
AddOpcode = ISD::ADD;
}
SDValue Add = CLI.DAG.getNode(
AddOpcode, CLI.DL, PtrVT, DemoteStackSlot,
CLI.DAG.getConstant(Offsets[i], CLI.DL, PtrVT), Flags);
SDValue L = CLI.DAG.getLoad(
RetTys[i], CLI.DL, CLI.Chain, Add,
MachinePointerInfo::getFixedStack(CLI.DAG.getMachineFunction(),
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,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";
Expand Down
20 changes: 20 additions & 0 deletions llvm/lib/Target/AArch64/AArch64InstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -10223,6 +10223,26 @@ let Predicates = [HasCPA] in {
// Scalar multiply-add/subtract
def MADDPT : MulAccumCPA<0, "maddpt">;
def MSUBPT : MulAccumCPA<1, "msubpt">;

// Rules to use CPA instructions in pointer arithmetic patterns which are not
// folded into loads/stores. The AddedComplexity serves to help supersede
// other simpler (non-CPA) patterns and make sure CPA is used instead.
let AddedComplexity = 20 in {
def : Pat<(ptradd GPR64sp:$Rn, GPR64sp:$Rm),
(ADDPT_shift GPR64sp:$Rn, GPR64sp:$Rm, (i32 0))>;
def : Pat<(ptradd GPR64sp:$Rn, (shl GPR64sp:$Rm, (i64 imm0_7:$imm))),
(ADDPT_shift GPR64sp:$Rn, GPR64sp:$Rm,
(i32 (trunc_imm imm0_7:$imm)))>;
def : Pat<(ptradd GPR64sp:$Rn, (ineg GPR64sp:$Rm)),
(SUBPT_shift GPR64sp:$Rn, GPR64sp:$Rm, (i32 0))>;
def : Pat<(ptradd GPR64sp:$Rn, (ineg (shl GPR64sp:$Rm, (i64 imm0_7:$imm)))),
(SUBPT_shift GPR64sp:$Rn, GPR64sp:$Rm,
(i32 (trunc_imm imm0_7:$imm)))>;
def : Pat<(ptradd GPR64:$Ra, (mul GPR64:$Rn, GPR64:$Rm)),
(MADDPT GPR64:$Rn, GPR64:$Rm, GPR64:$Ra)>;
def : Pat<(ptradd GPR64:$Ra, (mul GPR64:$Rn, (ineg GPR64:$Rm))),
(MSUBPT GPR64:$Rn, GPR64:$Rm, GPR64:$Ra)>;
}
}

def round_v4fp32_to_v4bf16 :
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -920,3 +920,7 @@ bool AArch64TargetMachine::parseMachineFunctionInfo(
MF.getInfo<AArch64FunctionInfo>()->initializeBaseYamlFields(YamlMFI);
return false;
}

bool AArch64TargetMachine::shouldPreservePtrArith(const Function &F) const {
return getSubtargetImpl(F)->hasCPA();
}
4 changes: 4 additions & 0 deletions llvm/lib/Target/AArch64/AArch64TargetMachine.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ class AArch64TargetMachine : public LLVMTargetMachine {
return true;
}

/// In AArch64, true if FEAT_CPA is present. Allows pointer arithmetic
/// semantics to be preserved for instruction selection.
bool shouldPreservePtrArith(const Function &F) const override;

private:
bool isLittle;
};
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2091,6 +2091,10 @@ bool AArch64InstructionSelector::preISelLower(MachineInstr &I) {
return Changed;
}
case TargetOpcode::G_PTR_ADD:
// If Checked Pointer Arithmetic (FEAT_CPA) is present, preserve the pointer
// arithmetic semantics instead of falling back to regular arithmetic.
if (TM.shouldPreservePtrArith(MF.getFunction()))
return false;
return convertPtrAddToAdd(I, MRI);
case TargetOpcode::G_LOAD: {
// For scalar loads of pointers, we try to convert the dest type from p0
Expand Down
Loading