[clang] [llvm] [AArch64][SelectionDAG] Add CodeGen support for scalar FEAT_CPA (PR #105669)
Rodolfo Wottrich via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 18 08:30:18 PDT 2025
https://github.com/rgwott updated https://github.com/llvm/llvm-project/pull/105669
>From b26f61578c033eb6be0484e7346970176caafce2 Mon Sep 17 00:00:00 2001
From: Rodolfo Wottrich <rodolfo.wottrich at arm.com>
Date: Thu, 22 Aug 2024 15:17:00 +0100
Subject: [PATCH 01/19] [AArch64] Add CodeGen support for FEAT_CPA
CPA stands for Checked Pointer Arithmetic and is part of the 2023 MTE
architecture extensions for A-profile.
The new CPA instructions perform regular pointer arithmetic (such as
base register + offset) but check for overflow in the most significant
bits of the result, enhancing security by detecting address tampering.
In this patch we intend to capture the semantics of pointer arithmetic
when it is not folded into loads/stores, then generate the appropriate
CPA instructions. In order to preserve pointer arithmetic semantics
through the backend, we add the PTRADD SelectionDAG node type.
The PTRADD node and respective visitPTRADD() function are adapted from
the CHERI/Morello LLVM tree.
Mode details about the CPA extension can be found at:
- https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/arm-a-profile-architecture-developments-2023
- https://developer.arm.com/documentation/ddi0602/2023-09/
This PR follows #79569.
---
llvm/include/llvm/CodeGen/ISDOpcodes.h | 4 +
llvm/include/llvm/Target/TargetMachine.h | 5 +
.../include/llvm/Target/TargetSelectionDAG.td | 4 +-
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 101 +++-
llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 21 +-
.../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 10 +-
.../SelectionDAG/SelectionDAGBuilder.cpp | 44 +-
.../SelectionDAG/SelectionDAGDumper.cpp | 1 +
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 20 +
.../Target/AArch64/AArch64TargetMachine.cpp | 4 +
.../lib/Target/AArch64/AArch64TargetMachine.h | 4 +
.../GISel/AArch64InstructionSelector.cpp | 4 +
llvm/test/CodeGen/AArch64/cpa-globalisel.ll | 455 ++++++++++++++++++
llvm/test/CodeGen/AArch64/cpa-selectiondag.ll | 449 +++++++++++++++++
14 files changed, 1104 insertions(+), 22 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/cpa-globalisel.ll
create mode 100644 llvm/test/CodeGen/AArch64/cpa-selectiondag.ll
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index 86ff262897594..305b334930777 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -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"
diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h
index c3e9d41315f61..26425fced5252 100644
--- a/llvm/include/llvm/Target/TargetMachine.h
+++ b/llvm/include/llvm/Target/TargetMachine.h
@@ -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
diff --git a/llvm/include/llvm/Target/TargetSelectionDAG.td b/llvm/include/llvm/Target/TargetSelectionDAG.td
index 172deffbd3177..aeb27ccf921a4 100644
--- a/llvm/include/llvm/Target/TargetSelectionDAG.td
+++ b/llvm/include/llvm/Target/TargetSelectionDAG.td
@@ -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.
@@ -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]>;
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 11935cbc309f0..16a16e1d702c2 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -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);
@@ -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.
@@ -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);
@@ -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)
@@ -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,
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index 74e3a898569be..28e0bdbb549c6 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -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(
@@ -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);
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 27675dce70c26..dd746234e6ad8 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -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 {
@@ -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.
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 60dcb11854278..f6e797dee395a 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -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.
@@ -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 {
@@ -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;
}
@@ -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);
}
}
@@ -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,
@@ -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;
}
@@ -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(),
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
index 001f782f209fd..5e727df0fcab4 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
@@ -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";
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index ec225a5b234a2..0fc31cf912083 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -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 :
diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
index bd5684a287381..3dfc90380ccb8 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
@@ -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();
+}
\ No newline at end of file
diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.h b/llvm/lib/Target/AArch64/AArch64TargetMachine.h
index 1a470ca87127c..c161223fe7fc1 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetMachine.h
+++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.h
@@ -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;
};
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index e9e6b6cb68d0d..158a4b2d0d157 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -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
diff --git a/llvm/test/CodeGen/AArch64/cpa-globalisel.ll b/llvm/test/CodeGen/AArch64/cpa-globalisel.ll
new file mode 100644
index 0000000000000..ffbe4b358ca5a
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/cpa-globalisel.ll
@@ -0,0 +1,455 @@
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=+cpa -O0 -global-isel=1 -global-isel-abort=1 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-CPA-O0
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=+cpa -O3 -global-isel=1 -global-isel-abort=1 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-CPA-O3
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=-cpa -O0 -global-isel=1 -global-isel-abort=1 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-NOCPA-O0
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=-cpa -O3 -global-isel=1 -global-isel-abort=1 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-NOCPA-O3
+
+%struct.my_type = type { i64, i64 }
+%struct.my_type2 = type { i64, i64, i64, i64, i64, i64 }
+
+ at array = external dso_local global [10 x %struct.my_type], align 8
+ at array2 = external dso_local global [10 x %struct.my_type2], align 8
+
+define void @addpt1(i64 %index, i64 %arg) {
+; CHECK-CPA-O0-LABEL: addpt1:
+; CHECK-CPA-O0: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
+; CHECK-CPA-O0: str x{{[0-9]+}}, [[[REG1]], #8]
+;
+; CHECK-CPA-O3-LABEL: addpt1:
+; CHECK-CPA-O3: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
+; CHECK-CPA-O3: str x{{[0-9]+}}, [[[REG1]], #8]
+;
+; CHECK-NOCPA-O0-LABEL: addpt1:
+; CHECK-NOCPA-O0: add [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
+; CHECK-NOCPA-O0: str x{{[0-9]+}}, [[[REG1]], #8]
+;
+; CHECK-NOCPA-O3-LABEL: addpt1:
+; CHECK-NOCPA-O3: add [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
+; CHECK-NOCPA-O3: str x{{[0-9]+}}, [[[REG1]], #8]
+entry:
+ %e2 = getelementptr inbounds %struct.my_type, ptr @array, i64 %index, i32 1
+ store i64 %arg, ptr %e2, align 8
+ ret void
+}
+
+define void @maddpt1(i32 %pos, ptr %val) {
+; CHECK-CPA-O0-LABEL: maddpt1:
+; CHECK-CPA-O0: maddpt x0, x{{[0-9]+}}, x{{[0-9]+}}, x{{[0-9]+}}
+; CHECK-CPA-O0: b memcpy
+;
+; CHECK-CPA-O3-LABEL: maddpt1:
+; CHECK-CPA-O3: maddpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, x{{[0-9]+}}
+; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]]]
+; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]], #16]
+; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]], #32]
+;
+; CHECK-NOCPA-O0-LABEL: maddpt1:
+; CHECK-NOCPA-O0: smaddl x0, w{{[0-9]+}}, w{{[0-9]+}}, x{{[0-9]+}}
+; CHECK-NOCPA-O0: b memcpy
+;
+; CHECK-NOCPA-O3-LABEL: maddpt1:
+; CHECK-NOCPA-O3: smaddl [[REG1:x[0-9]+]], w{{[0-9]+}}, w{{[0-9]+}}, x{{[0-9]+}}
+; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]]]
+; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]], #16]
+; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]], #32]
+entry:
+ %idxprom = sext i32 %pos to i64
+ %arrayidx = getelementptr inbounds [10 x %struct.my_type2], ptr @array2, i64 0, i64 %idxprom
+ tail call void @llvm.memcpy.p0.p0.i64(ptr align 8 dereferenceable(48) %arrayidx, ptr align 8 dereferenceable(48) %val, i64 48, i1 false)
+ ret void
+}
+
+define void @msubpt1(i32 %index, i32 %elem) {
+; CHECK-CPA-O0-LABEL: msubpt1:
+; CHECK-CPA-O0: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}
+; CHECK-CPA-O0: msubpt x0, x{{[0-9]+}}, x{{[0-9]+}}, [[REG1]]
+; CHECK-CPA-O0: addpt x1, x{{[0-9]+}}, x{{[0-9]+}}
+; CHECK-CPA-O0: b memcpy
+;
+; CHECK-CPA-O3-LABEL: msubpt1:
+; CHECK-CPA-O3: msubpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, x{{[0-9]+}}
+; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]], #192]
+; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]], #208]
+; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]], #224]
+;
+; CHECK-NOCPA-O0-LABEL: msubpt1:
+; CHECK-NOCPA-O0: mneg [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}
+; CHECK-NOCPA-O0: add x0, x{{[0-9]+}}, [[REG1]]
+; CHECK-NOCPA-O0: b memcpy
+;
+; CHECK-NOCPA-O3-LABEL: msubpt1:
+; CHECK-NOCPA-O3: mneg [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}
+; CHECK-NOCPA-O3: add [[REG2:x[0-9]+]], x{{[0-9]+}}, [[REG1]]
+; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]], #192]
+; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]], #208]
+; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]], #224]
+entry:
+ %idx.ext = sext i32 %index to i64
+ %idx.neg = sub nsw i64 0, %idx.ext
+ %add.ptr = getelementptr inbounds %struct.my_type2, ptr getelementptr inbounds ([10 x %struct.my_type2], ptr @array2, i64 0, i64 6), i64 %idx.neg
+ tail call void @llvm.memcpy.p0.p0.i64(ptr align 8 dereferenceable(48) %add.ptr, ptr align 8 dereferenceable(48) getelementptr inbounds ([10 x %struct.my_type2], ptr @array2, i64 0, i64 2), i64 48, i1 false), !tbaa.struct !6
+ ret void
+}
+
+define void @subpt1(i32 %index, i32 %elem) {
+; CHECK-CPA-O0-LABEL: subpt1:
+; CHECK-CPA-O0: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}
+; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]], x{{[0-9]+}}, lsl #4]
+;
+; CHECK-CPA-O3-LABEL: subpt1:
+; CHECK-CPA-O3: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
+; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]], #64]
+;
+; CHECK-NOCPA-O0-LABEL: subpt1:
+; CHECK-NOCPA-O0: add [[REG1:x[0-9]+]], x{{[0-9]+}}, #96
+; CHECK-NOCPA-O0: str q{{[0-9]+}}, [[[REG1]], x{{[0-9]+}}, lsl #4]
+;
+; CHECK-NOCPA-O3-LABEL: subpt1:
+; CHECK-NOCPA-O3: add [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
+; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]], #64]
+entry:
+ %conv = sext i32 %index to i64
+ %mul.neg = mul nsw i64 %conv, -16
+ %add.ptr = getelementptr inbounds %struct.my_type, ptr getelementptr inbounds ([10 x %struct.my_type], ptr @array, i64 0, i64 6), i64 %mul.neg
+ tail call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 8 dereferenceable(16) %add.ptr, ptr noundef nonnull align 8 dereferenceable(16) getelementptr inbounds ([10 x %struct.my_type], ptr @array, i64 0, i64 2), i64 16, i1 false), !tbaa.struct !6
+ ret void
+}
+
+define void @subpt2(i32 %index, i32 %elem) {
+; CHECK-CPA-O0-LABEL: subpt2:
+; CHECK-CPA-O0: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}
+; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]], x{{[0-9]+}}, lsl #4]
+;
+; CHECK-CPA-O3-LABEL: subpt2:
+; CHECK-CPA-O3: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
+; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]], #64]
+;
+; CHECK-NOCPA-O0-LABEL: subpt2:
+; CHECK-NOCPA-O0: add [[REG1:x[0-9]+]], x{{[0-9]+}}, #96
+; CHECK-NOCPA-O0: str q{{[0-9]+}}, [[[REG1]], x{{[0-9]+}}, lsl #4]
+;
+; CHECK-NOCPA-O3-LABEL: subpt2:
+; CHECK-NOCPA-O3: add [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
+; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]], #64]
+entry:
+ %idx.ext = sext i32 %index to i64
+ %idx.neg = sub nsw i64 0, %idx.ext
+ %add.ptr = getelementptr inbounds %struct.my_type, ptr getelementptr inbounds ([10 x %struct.my_type], ptr @array, i64 0, i64 6), i64 %idx.neg
+ tail call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 8 dereferenceable(16) %add.ptr, ptr noundef nonnull align 8 dereferenceable(16) getelementptr inbounds ([10 x %struct.my_type], ptr @array, i64 0, i64 2), i64 16, i1 false), !tbaa.struct !11
+ ret void
+}
+
+define ptr @subpt3(ptr %ptr, i32 %index) {
+; CHECK-CPA-O0-LABEL: subpt3:
+; CHECK-CPA-O0: mov [[REG1:x[0-9]+]], #-8
+; CHECK-CPA-O0: addpt x0, x{{[0-9]+}}, [[REG1]]
+; CHECK-CPA-O0: ret
+;
+; CHECK-CPA-O3-LABEL: subpt3:
+; CHECK-CPA-O3: mov [[REG1:x[0-9]+]], #-8
+; CHECK-CPA-O3: addpt x0, x{{[0-9]+}}, [[REG1]]
+; CHECK-CPA-O3: ret
+;
+; CHECK-NOCPA-O0-LABEL: subpt3:
+; CHECK-NOCPA-O0: subs x0, x{{[0-9]+}}, #8
+; CHECK-NOCPA-O0: ret
+;
+; CHECK-NOCPA-O3-LABEL: subpt3:
+; CHECK-NOCPA-O3: sub x0, x{{[0-9]+}}, #8
+; CHECK-NOCPA-O3: ret
+entry:
+ %incdec.ptr.i.i.i = getelementptr inbounds i64, ptr %ptr, i64 -1
+ ret ptr %incdec.ptr.i.i.i
+}
+
+define i64 @subi64(i64 %ptr, i32 %index) {
+; CHECK-CPA-O0-LABEL: subi64:
+; CHECK-CPA-O0: subs x0, x0, #1
+; CHECK-CPA-O0: ret
+;
+; CHECK-CPA-O3-LABEL: subi64:
+; CHECK-CPA-O3: sub x0, x0, #1
+; CHECK-CPA-O3: ret
+;
+; CHECK-NOCPA-O0-LABEL: subi64:
+; CHECK-NOCPA-O0: subs x0, x0, #1
+; CHECK-NOCPA-O0: ret
+;
+; CHECK-NOCPA-O3-LABEL: subi64:
+; CHECK-NOCPA-O3: sub x0, x0, #1
+; CHECK-NOCPA-O3: ret
+entry:
+ %incdec.ptr.i.i.i = add i64 %ptr, -1
+ ret i64 %incdec.ptr.i.i.i
+}
+
+define i32 @subi32(i32 %ptr, i32 %index) {
+; CHECK-CPA-O0-LABEL: subi32:
+; CHECK-CPA-O0: subs w0, w0, #1
+; CHECK-CPA-O0: ret
+;
+; CHECK-CPA-O3-LABEL: subi32:
+; CHECK-CPA-O3: sub w0, w0, #1
+; CHECK-CPA-O3: ret
+;
+; CHECK-NOCPA-O0-LABEL: subi32:
+; CHECK-NOCPA-O0: subs w0, w0, #1
+; CHECK-NOCPA-O0: ret
+;
+; CHECK-NOCPA-O3-LABEL: subi32:
+; CHECK-NOCPA-O3: sub w0, w0, #1
+; CHECK-NOCPA-O3: ret
+entry:
+ %incdec.ptr.i.i.i = add i32 %ptr, -1
+ ret i32 %incdec.ptr.i.i.i
+}
+
+define i16 @subi16(i16 %ptr, i32 %index) {
+; CHECK-CPA-O0-LABEL: subi16:
+; CHECK-CPA-O0: subs w0, w0, #1
+; CHECK-CPA-O0: ret
+;
+; CHECK-CPA-O3-LABEL: subi16:
+; CHECK-CPA-O3: sub w0, w0, #1
+; CHECK-CPA-O3: ret
+;
+; CHECK-NOCPA-O0-LABEL: subi16:
+; CHECK-NOCPA-O0: subs w0, w0, #1
+; CHECK-NOCPA-O0: ret
+;
+; CHECK-NOCPA-O3-LABEL: subi16:
+; CHECK-NOCPA-O3: sub w0, w0, #1
+; CHECK-NOCPA-O3: ret
+entry:
+ %incdec.ptr.i.i.i = add i16 %ptr, -1
+ ret i16 %incdec.ptr.i.i.i
+}
+
+define i64 @addi64(i64 %ptr, i32 %index) {
+; CHECK-CPA-O0-LABEL: addi64:
+; CHECK-CPA-O0: add x0, x0, #1
+; CHECK-CPA-O0: ret
+;
+; CHECK-CPA-O3-LABEL: addi64:
+; CHECK-CPA-O3: add x0, x0, #1
+; CHECK-CPA-O3: ret
+;
+; CHECK-NOCPA-O0-LABEL: addi64:
+; CHECK-NOCPA-O0: add x0, x0, #1
+; CHECK-NOCPA-O0: ret
+;
+; CHECK-NOCPA-O3-LABEL: addi64:
+; CHECK-NOCPA-O3: add x0, x0, #1
+; CHECK-NOCPA-O3: ret
+entry:
+ %incdec.ptr.i.i.i = add i64 %ptr, 1
+ ret i64 %incdec.ptr.i.i.i
+}
+
+define i32 @addi32(i32 %ptr, i32 %index) {
+; CHECK-CPA-O0-LABEL: addi32:
+; CHECK-CPA-O0: add w0, w0, #1
+; CHECK-CPA-O0: ret
+;
+; CHECK-CPA-O3-LABEL: addi32:
+; CHECK-CPA-O3: add w0, w0, #1
+; CHECK-CPA-O3: ret
+;
+; CHECK-NOCPA-O0-LABEL: addi32:
+; CHECK-NOCPA-O0: add w0, w0, #1
+; CHECK-NOCPA-O0: ret
+;
+; CHECK-NOCPA-O3-LABEL: addi32:
+; CHECK-NOCPA-O3: add w0, w0, #1
+; CHECK-NOCPA-O3: ret
+entry:
+ %incdec.ptr.i.i.i = add i32 %ptr, 1
+ ret i32 %incdec.ptr.i.i.i
+}
+
+define i16 @addi16(i16 %ptr, i32 %index) {
+; CHECK-CPA-O0-LABEL: addi16:
+; CHECK-CPA-O0: add w0, w0, #1
+; CHECK-CPA-O0: ret
+;
+; CHECK-CPA-O3-LABEL: addi16:
+; CHECK-CPA-O3: add w0, w0, #1
+; CHECK-CPA-O3: ret
+;
+; CHECK-NOCPA-O0-LABEL: addi16:
+; CHECK-NOCPA-O0: add w0, w0, #1
+; CHECK-NOCPA-O0: ret
+;
+; CHECK-NOCPA-O3-LABEL: addi16:
+; CHECK-NOCPA-O3: add w0, w0, #1
+; CHECK-NOCPA-O3: ret
+entry:
+ %incdec.ptr.i.i.i = add i16 %ptr, 1
+ ret i16 %incdec.ptr.i.i.i
+}
+
+define i64 @arith1(i64 noundef %0, i64 noundef %1, i64 noundef %2) {
+; CHECK-CPA-O0-LABEL: arith1:
+; CHECK-CPA-O0: mul x9, x9, x10
+; CHECK-CPA-O0: add x0, x8, x9
+; CHECK-CPA-O0: add sp, sp, #32
+; CHECK-CPA-O0: ret
+;
+; CHECK-CPA-O3-LABEL: arith1:
+; CHECK-CPA-O3: madd x0, x1, x2, x0
+; CHECK-CPA-O3: add sp, sp, #32
+; CHECK-CPA-O3: ret
+;
+; CHECK-NOCPA-O0-LABEL: arith1:
+; CHECK-NOCPA-O0: mul x9, x9, x10
+; CHECK-NOCPA-O0: add x0, x8, x9
+; CHECK-NOCPA-O0: add sp, sp, #32
+; CHECK-NOCPA-O0: ret
+;
+; CHECK-NOCPA-O3-LABEL: arith1:
+; CHECK-NOCPA-O3: madd x0, x1, x2, x0
+; CHECK-NOCPA-O3: add sp, sp, #32
+; CHECK-NOCPA-O3: ret
+entry:
+ %4 = alloca i64, align 8
+ %5 = alloca i64, align 8
+ %6 = alloca i64, align 8
+ store i64 %0, ptr %4, align 8
+ store i64 %1, ptr %5, align 8
+ store i64 %2, ptr %6, align 8
+ %7 = load i64, ptr %4, align 8
+ %8 = load i64, ptr %5, align 8
+ %9 = load i64, ptr %6, align 8
+ %10 = mul nsw i64 %8, %9
+ %11 = add nsw i64 %7, %10
+ ret i64 %11
+}
+
+define i64 @arith2(ptr noundef %0, i64 noundef %1, i64 noundef %2, i32 noundef %3) {
+; CHECK-CPA-O0-LABEL: arith2:
+; CHECK-CPA-O0: maddpt x8, x8, x9, x10
+; CHECK-CPA-O0: ldr x8, [x8, #24]
+; CHECK-CPA-O0: ldr x10, [sp, #16]
+; CHECK-CPA-O0: ldr x9, [sp, #8]
+; CHECK-CPA-O0: mul x10, x10, x9
+; CHECK-CPA-O0: add x8, x8, x10
+; CHECK-CPA-O0: subs x0, x8, x9
+; CHECK-CPA-O0: add sp, sp, #32
+; CHECK-CPA-O0: ret
+;
+; CHECK-CPA-O3-LABEL: arith2:
+; CHECK-CPA-O3: maddpt x8, x9, x10, x0
+; CHECK-CPA-O3: ldr x8, [x8, #24]
+; CHECK-CPA-O3: madd x8, x1, x2, x8
+; CHECK-CPA-O3: sub x0, x8, x2
+; CHECK-CPA-O3: add sp, sp, #32
+; CHECK-CPA-O3: ret
+;
+; CHECK-NOCPA-O0-LABEL: arith2:
+; CHECK-NOCPA-O0: mul x9, x9, x10
+; CHECK-NOCPA-O0: add x8, x8, x9
+; CHECK-NOCPA-O0: ldr x8, [x8, #24]
+; CHECK-NOCPA-O0: ldr x10, [sp, #16]
+; CHECK-NOCPA-O0: ldr x9, [sp, #8]
+; CHECK-NOCPA-O0: mul x10, x10, x9
+; CHECK-NOCPA-O0: add x8, x8, x10
+; CHECK-NOCPA-O0: subs x0, x8, x9
+; CHECK-NOCPA-O0: add sp, sp, #32
+; CHECK-NOCPA-O0: ret
+;
+; CHECK-NOCPA-O3-LABEL: arith2:
+; CHECK-NOCPA-O3: madd x8, x8, x9, x0
+; CHECK-NOCPA-O3: ldr x8, [x8, #24]
+; CHECK-NOCPA-O3: madd x8, x1, x2, x8
+; CHECK-NOCPA-O3: sub x0, x8, x2
+; CHECK-NOCPA-O3: add sp, sp, #32
+; CHECK-NOCPA-O3: ret
+entry:
+ %5 = alloca ptr, align 8
+ %6 = alloca i64, align 8
+ %7 = alloca i64, align 8
+ %8 = alloca i32, align 4
+ store ptr %0, ptr %5, align 8
+ store i64 %1, ptr %6, align 8
+ store i64 %2, ptr %7, align 8
+ store i32 %3, ptr %8, align 4
+ %9 = load ptr, ptr %5, align 8
+ %10 = load i32, ptr %8, align 4
+ %11 = sext i32 %10 to i64
+ %12 = getelementptr inbounds %struct.my_type2, ptr %9, i64 %11
+ %13 = getelementptr inbounds %struct.my_type2, ptr %12, i32 0, i32 3
+ %14 = load i64, ptr %13, align 8
+ %15 = load i64, ptr %6, align 8
+ %16 = load i64, ptr %7, align 8
+ %17 = mul nsw i64 %15, %16
+ %18 = add nsw i64 %14, %17
+ %19 = sub nsw i64 %18, %16
+ ret i64 %19
+}
+
+ at a = hidden global [2 x [1 x [2 x i8]]] [[1 x [2 x i8]] [[2 x i8] c"\01\01"], [1 x [2 x i8]] [[2 x i8] c"\01\01"]], align 1
+ at b = hidden global i16 0, align 2
+
+define hidden void @multidim() {
+; CHECK-CPA-O0-LABEL: multidim:
+; CHECK-CPA-O0: adrp x8, b
+; CHECK-CPA-O0: ldrh w9, [x8, :lo12:b]
+; CHECK-CPA-O0: mov w10, w9
+; CHECK-CPA-O0: ldrh w8, [x8, :lo12:b]
+; CHECK-CPA-O0: add w9, w8, #1
+; CHECK-CPA-O0: mov w8, w9
+; CHECK-CPA-O0: sxtw x9, w8
+; CHECK-CPA-O0: mov w8, #2 // =0x2
+; CHECK-CPA-O0: mov w11, w8
+; CHECK-CPA-O0: adrp x8, a
+; CHECK-CPA-O0: add x8, x8, :lo12:a
+; CHECK-CPA-O0: addpt x8, x8, x11
+; CHECK-CPA-O0: addpt x8, x8, x10, lsl #1
+; CHECK-CPA-O0: addpt x8, x8, x9
+; CHECK-CPA-O0: ldrb w8, [x8]
+;
+; CHECK-CPA-O3-LABEL: multidim:
+; CHECK-CPA-O3: ret
+;
+; CHECK-NOCPA-O0-LABEL: multidim:
+; CHECK-NOCPA-O0: adrp x8, b
+; CHECK-NOCPA-O0: ldrh w9, [x8, :lo12:b]
+; CHECK-NOCPA-O0: mov w10, w9
+; CHECK-NOCPA-O0: ldrh w8, [x8, :lo12:b]
+; CHECK-NOCPA-O0: add w9, w8, #1
+; CHECK-NOCPA-O0: adrp x8, a
+; CHECK-NOCPA-O0: add x8, x8, :lo12:a
+; CHECK-NOCPA-O0: add x8, x8, #2
+; CHECK-NOCPA-O0: add x8, x8, x10, lsl #1
+; CHECK-NOCPA-O0: add x8, x8, w9, sxtw
+; CHECK-NOCPA-O0: ldrb w8, [x8]
+;
+; CHECK-NOCPA-O3-LABEL: multidim:
+; CHECK-NOCPA-O3: ret
+entry:
+ %0 = load i16, ptr @b, align 2
+ %idxprom = zext i16 %0 to i64
+ %arrayidx = getelementptr inbounds [1 x [2 x i8]], ptr getelementptr inbounds ([2 x [1 x [2 x i8]]], ptr @a, i64 0, i64 1), i64 0, i64 %idxprom
+ %1 = load i16, ptr @b, align 2
+ %conv = zext i16 %1 to i32
+ %add = add nsw i32 %conv, 1
+ %idxprom1 = sext i32 %add to i64
+ %arrayidx2 = getelementptr inbounds [2 x i8], ptr %arrayidx, i64 0, i64 %idxprom1
+ %2 = load i8, ptr %arrayidx2, align 1
+ %tobool = icmp ne i8 %2, 0
+ br i1 %tobool, label %if.then, label %if.end
+
+if.then:
+ br label %if.end
+
+if.end:
+ ret void
+}
+
+declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1)
+
+!6 = !{i64 0, i64 8, !7, i64 8, i64 8, !7, i64 16, i64 8, !7, i64 24, i64 8, !7, i64 32, i64 8, !7, i64 40, i64 8, !7}
+!7 = !{!8, !8, i64 0}
+!8 = !{!"long", !9, i64 0}
+!9 = !{!"omnipotent char", !10, i64 0}
+!10 = !{!"Simple C++ TBAA"}
+!11 = !{i64 0, i64 8, !7, i64 8, i64 8, !7}
diff --git a/llvm/test/CodeGen/AArch64/cpa-selectiondag.ll b/llvm/test/CodeGen/AArch64/cpa-selectiondag.ll
new file mode 100644
index 0000000000000..ea9c9615943d8
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/cpa-selectiondag.ll
@@ -0,0 +1,449 @@
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=+cpa -O0 -global-isel=0 -fast-isel=0 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-CPA-O0
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=+cpa -O3 -global-isel=0 -fast-isel=0 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-CPA-O3
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=-cpa -O0 -global-isel=0 -fast-isel=0 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-NOCPA-O0
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=-cpa -O3 -global-isel=0 -fast-isel=0 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-NOCPA-O3
+
+%struct.my_type = type { i64, i64 }
+%struct.my_type2 = type { i64, i64, i64, i64, i64, i64 }
+
+ at array = external dso_local global [10 x %struct.my_type], align 8
+ at array2 = external dso_local global [10 x %struct.my_type2], align 8
+
+define void @addpt1(i64 %index, i64 %arg) {
+; CHECK-CPA-O0-LABEL: addpt1:
+; CHECK-CPA-O0: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
+; CHECK-CPA-O0: str x{{[0-9]+}}, [[[REG1]], #8]
+;
+; CHECK-CPA-O3-LABEL: addpt1:
+; CHECK-CPA-O3: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
+; CHECK-CPA-O3: str x{{[0-9]+}}, [[[REG1]], #8]
+;
+; CHECK-NOCPA-O0-LABEL: addpt1:
+; CHECK-NOCPA-O0: add [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
+; CHECK-NOCPA-O0: str x{{[0-9]+}}, [[[REG1]], #8]
+
+; CHECK-NOCPA-O3-LABEL: addpt1:
+; CHECK-NOCPA-O3: add [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
+; CHECK-NOCPA-O3: str x{{[0-9]+}}, [[[REG1]], #8]
+entry:
+ %e2 = getelementptr inbounds %struct.my_type, ptr @array, i64 %index, i32 1
+ store i64 %arg, ptr %e2, align 8
+ ret void
+}
+
+define void @maddpt1(i32 %pos, ptr %val) {
+; CHECK-CPA-O0-LABEL: maddpt1:
+; CHECK-CPA-O0: maddpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, x{{[0-9]+}}
+; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]], #32]
+; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]], #16]
+; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]]]
+;
+; CHECK-CPA-O3-LABEL: maddpt1:
+; CHECK-CPA-O3: maddpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, x{{[0-9]+}}
+; CHECK-CPA-O3: stp q{{[0-9]+}}, q{{[0-9]+}}, [[[REG1]], #16]
+; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]]]
+;
+; CHECK-NOCPA-O0-LABEL: maddpt1:
+; CHECK-NOCPA-O0: smaddl [[REG1:x[0-9]+]], w{{[0-9]+}}, w{{[0-9]+}}, x{{[0-9]+}}
+; CHECK-NOCPA-O0: str q{{[0-9]+}}, [[[REG1]], #32]
+; CHECK-NOCPA-O0: str q{{[0-9]+}}, [[[REG1]], #16]
+; CHECK-NOCPA-O0: str q{{[0-9]+}}, [[[REG1]]]
+;
+; CHECK-NOCPA-O3-LABEL: maddpt1:
+; CHECK-NOCPA-O3: smaddl [[REG1:x[0-9]+]], w{{[0-9]+}}, w{{[0-9]+}}, x{{[0-9]+}}
+; CHECK-NOCPA-O3: stp q{{[0-9]+}}, q{{[0-9]+}}, [[[REG1]], #16]
+; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]]]
+entry:
+ %idxprom = sext i32 %pos to i64
+ %arrayidx = getelementptr inbounds [10 x %struct.my_type2], ptr @array2, i64 0, i64 %idxprom
+ tail call void @llvm.memcpy.p0.p0.i64(ptr align 8 dereferenceable(48) %arrayidx, ptr align 8 dereferenceable(48) %val, i64 48, i1 false)
+ ret void
+}
+
+define void @msubpt1(i32 %index, i32 %elem) {
+; CHECK-CPA-O0-LABEL: msubpt1:
+; CHECK-CPA-O0: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
+; CHECK-CPA-O0: addpt [[REG2:x[0-9]+]], [[REG1]], x{{[0-9]+}}
+; CHECK-CPA-O0: addpt [[REG3:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}
+; CHECK-CPA-O0: ldr q{{[0-9]+}}, [[[REG3]], #16]
+; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]], #288]
+; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG2]], #32]
+;
+; CHECK-CPA-O3-LABEL: msubpt1:
+; CHECK-CPA-O3: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
+; CHECK-CPA-O3: addpt [[REG2:x[0-9]+]], [[REG1]], x{{[0-9]+}}
+; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]], #288]
+; CHECK-CPA-O3: stp q{{[0-9]+}}, q{{[0-9]+}}, [[[REG2]], #16]
+;
+; CHECK-NOCPA-O0-LABEL: msubpt1:
+; CHECK-NOCPA-O0: mneg [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}
+; CHECK-NOCPA-O0: add [[REG2:x[0-9]+]], x{{[0-9]+}}, [[REG1]]
+; CHECK-NOCPA-O0: str q{{[0-9]+}}, [[[REG2]], #320]
+; CHECK-NOCPA-O0: str q{{[0-9]+}}, [[[REG2]], #304]
+; CHECK-NOCPA-O0: str q{{[0-9]+}}, [[[REG2]], #288]
+;
+; CHECK-NOCPA-O3-LABEL: msubpt1:
+; CHECK-NOCPA-O3: mneg [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}
+; CHECK-NOCPA-O3: add [[REG2:x[0-9]+]], x{{[0-9]+}}, [[REG1]]
+; CHECK-NOCPA-O3: stp q{{[0-9]+}}, q{{[0-9]+}}, [[[REG2]], #304]
+; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG2]], #288]
+entry:
+ %idx.ext = sext i32 %index to i64
+ %idx.neg = sub nsw i64 0, %idx.ext
+ %add.ptr = getelementptr inbounds %struct.my_type2, ptr getelementptr inbounds ([10 x %struct.my_type2], ptr @array2, i64 0, i64 6), i64 %idx.neg
+ tail call void @llvm.memcpy.p0.p0.i64(ptr align 8 dereferenceable(48) %add.ptr, ptr align 8 dereferenceable(48) getelementptr inbounds ([10 x %struct.my_type2], ptr @array2, i64 0, i64 2), i64 48, i1 false), !tbaa.struct !6
+ ret void
+}
+
+define void @subpt1(i32 %index, i32 %elem) {
+; CHECK-CPA-O0-LABEL: subpt1:
+; CHECK-CPA-O0: subpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}
+; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]], #96]
+;
+; CHECK-CPA-O3-LABEL: subpt1:
+; CHECK-CPA-O3: subpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}
+; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]], #96]
+;
+; CHECK-NOCPA-O0-LABEL: subpt1:
+; CHECK-NOCPA-O0: subs [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #8
+; CHECK-NOCPA-O0: str q{{[0-9]+}}, [[[REG1]], #96]
+;
+; CHECK-NOCPA-O3-LABEL: subpt1:
+; CHECK-NOCPA-O3: sub [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #8
+; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]], #96]
+entry:
+ %conv = sext i32 %index to i64
+ %mul.neg = mul nsw i64 %conv, -16
+ %add.ptr = getelementptr inbounds %struct.my_type, ptr getelementptr inbounds ([10 x %struct.my_type], ptr @array, i64 0, i64 6), i64 %mul.neg
+ tail call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 8 dereferenceable(16) %add.ptr, ptr noundef nonnull align 8 dereferenceable(16) getelementptr inbounds ([10 x %struct.my_type], ptr @array, i64 0, i64 2), i64 16, i1 false), !tbaa.struct !6
+ ret void
+}
+
+define void @subpt2(i32 %index, i32 %elem) {
+; CHECK-CPA-O0-LABEL: subpt2:
+; CHECK-CPA-O0: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
+; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]], #96]
+;
+; CHECK-CPA-O3-LABEL: subpt2:
+; CHECK-CPA-O3: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
+; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]], #96]
+;
+; CHECK-NOCPA-O0-LABEL: subpt2:
+; CHECK-NOCPA-O0: subs [[REG1:x[0-9]+]], x{{[0-9]+}}, w{{[0-9]+}}, sxtw #4
+; CHECK-NOCPA-O0: str q{{[0-9]+}}, [[[REG1]], #96]
+;
+; CHECK-NOCPA-O3-LABEL: subpt2:
+; CHECK-NOCPA-O3: sub [[REG1:x[0-9]+]], x{{[0-9]+}}, w{{[0-9]+}}, sxtw #4
+; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]], #96]
+entry:
+ %idx.ext = sext i32 %index to i64
+ %idx.neg = sub nsw i64 0, %idx.ext
+ %add.ptr = getelementptr inbounds %struct.my_type, ptr getelementptr inbounds ([10 x %struct.my_type], ptr @array, i64 0, i64 6), i64 %idx.neg
+ tail call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 8 dereferenceable(16) %add.ptr, ptr noundef nonnull align 8 dereferenceable(16) getelementptr inbounds ([10 x %struct.my_type], ptr @array, i64 0, i64 2), i64 16, i1 false), !tbaa.struct !11
+ ret void
+}
+
+define ptr @subpt3(ptr %ptr, i32 %index) {
+; CHECK-CPA-O0-LABEL: subpt3:
+; CHECK-CPA-O0: mov [[REG1:x[0-9]+]], #-8
+; CHECK-CPA-O0: addpt x0, x{{[0-9]+}}, [[REG1]]
+; CHECK-CPA-O0: ret
+;
+; CHECK-CPA-O3-LABEL: subpt3:
+; CHECK-CPA-O3: mov [[REG1:x[0-9]+]], #-8
+; CHECK-CPA-O3: addpt x0, x{{[0-9]+}}, [[REG1]]
+; CHECK-CPA-O3: ret
+;
+; CHECK-NOCPA-O0-LABEL: subpt3:
+; CHECK-NOCPA-O0: subs x0, x{{[0-9]+}}, #8
+; CHECK-NOCPA-O0: ret
+;
+; CHECK-NOCPA-O3-LABEL: subpt3:
+; CHECK-NOCPA-O3: sub x0, x{{[0-9]+}}, #8
+; CHECK-NOCPA-O3: ret
+entry:
+ %incdec.ptr.i.i.i = getelementptr inbounds i64, ptr %ptr, i64 -1
+ ret ptr %incdec.ptr.i.i.i
+}
+
+define i64 @subi64(i64 %ptr, i32 %index) {
+; CHECK-CPA-O0-LABEL: subi64:
+; CHECK-CPA-O0: subs x0, x0, #1
+; CHECK-CPA-O0: ret
+;
+; CHECK-CPA-O3-LABEL: subi64:
+; CHECK-CPA-O3: sub x0, x0, #1
+; CHECK-CPA-O3: ret
+;
+; CHECK-NOCPA-O0-LABEL: subi64:
+; CHECK-NOCPA-O0: subs x0, x0, #1
+; CHECK-NOCPA-O0: ret
+;
+; CHECK-NOCPA-O3-LABEL: subi64:
+; CHECK-NOCPA-O3: sub x0, x0, #1
+; CHECK-NOCPA-O3: ret
+entry:
+ %incdec.ptr.i.i.i = add i64 %ptr, -1
+ ret i64 %incdec.ptr.i.i.i
+}
+
+define i32 @subi32(i32 %ptr, i32 %index) {
+; CHECK-CPA-O0-LABEL: subi32:
+; CHECK-CPA-O0: subs w0, w0, #1
+; CHECK-CPA-O0: ret
+;
+; CHECK-CPA-O3-LABEL: subi32:
+; CHECK-CPA-O3: sub w0, w0, #1
+; CHECK-CPA-O3: ret
+;
+; CHECK-NOCPA-O0-LABEL: subi32:
+; CHECK-NOCPA-O0: subs w0, w0, #1
+; CHECK-NOCPA-O0: ret
+;
+; CHECK-NOCPA-O3-LABEL: subi32:
+; CHECK-NOCPA-O3: sub w0, w0, #1
+; CHECK-NOCPA-O3: ret
+entry:
+ %incdec.ptr.i.i.i = add i32 %ptr, -1
+ ret i32 %incdec.ptr.i.i.i
+}
+
+define i16 @subi16(i16 %ptr, i32 %index) {
+; CHECK-CPA-O0-LABEL: subi16:
+; CHECK-CPA-O0: subs w0, w0, #1
+; CHECK-CPA-O0: ret
+;
+; CHECK-CPA-O3-LABEL: subi16:
+; CHECK-CPA-O3: sub w0, w0, #1
+; CHECK-CPA-O3: ret
+;
+; CHECK-NOCPA-O0-LABEL: subi16:
+; CHECK-NOCPA-O0: subs w0, w0, #1
+; CHECK-NOCPA-O0: ret
+;
+; CHECK-NOCPA-O3-LABEL: subi16:
+; CHECK-NOCPA-O3: sub w0, w0, #1
+; CHECK-NOCPA-O3: ret
+entry:
+ %incdec.ptr.i.i.i = add i16 %ptr, -1
+ ret i16 %incdec.ptr.i.i.i
+}
+
+define i64 @addi64(i64 %ptr, i32 %index) {
+; CHECK-CPA-O0-LABEL: addi64:
+; CHECK-CPA-O0: add x0, x0, #1
+; CHECK-CPA-O0: ret
+;
+; CHECK-CPA-O3-LABEL: addi64:
+; CHECK-CPA-O3: add x0, x0, #1
+; CHECK-CPA-O3: ret
+;
+; CHECK-NOCPA-O0-LABEL: addi64:
+; CHECK-NOCPA-O0: add x0, x0, #1
+; CHECK-NOCPA-O0: ret
+;
+; CHECK-NOCPA-O3-LABEL: addi64:
+; CHECK-NOCPA-O3: add x0, x0, #1
+; CHECK-NOCPA-O3: ret
+entry:
+ %incdec.ptr.i.i.i = add i64 %ptr, 1
+ ret i64 %incdec.ptr.i.i.i
+}
+
+define i32 @addi32(i32 %ptr, i32 %index) {
+; CHECK-CPA-O0-LABEL: addi32:
+; CHECK-CPA-O0: add w0, w0, #1
+; CHECK-CPA-O0: ret
+;
+; CHECK-CPA-O3-LABEL: addi32:
+; CHECK-CPA-O3: add w0, w0, #1
+; CHECK-CPA-O3: ret
+;
+; CHECK-NOCPA-O0-LABEL: addi32:
+; CHECK-NOCPA-O0: add w0, w0, #1
+; CHECK-NOCPA-O0: ret
+;
+; CHECK-NOCPA-O3-LABEL: addi32:
+; CHECK-NOCPA-O3: add w0, w0, #1
+; CHECK-NOCPA-O3: ret
+entry:
+ %incdec.ptr.i.i.i = add i32 %ptr, 1
+ ret i32 %incdec.ptr.i.i.i
+}
+
+define i16 @addi16(i16 %ptr, i32 %index) {
+; CHECK-CPA-O0-LABEL: addi16:
+; CHECK-CPA-O0: add w0, w0, #1
+; CHECK-CPA-O0: ret
+;
+; CHECK-CPA-O3-LABEL: addi16:
+; CHECK-CPA-O3: add w0, w0, #1
+; CHECK-CPA-O3: ret
+;
+; CHECK-NOCPA-O0-LABEL: addi16:
+; CHECK-NOCPA-O0: add w0, w0, #1
+; CHECK-NOCPA-O0: ret
+;
+; CHECK-NOCPA-O3-LABEL: addi16:
+; CHECK-NOCPA-O3: add w0, w0, #1
+; CHECK-NOCPA-O3: ret
+entry:
+ %incdec.ptr.i.i.i = add i16 %ptr, 1
+ ret i16 %incdec.ptr.i.i.i
+}
+
+define i64 @arith1(i64 noundef %0, i64 noundef %1, i64 noundef %2) {
+; CHECK-CPA-O0-LABEL: arith1:
+; CHECK-CPA-O0: mul x9, x9, x10
+; CHECK-CPA-O0: add x0, x8, x9
+; CHECK-CPA-O0: add sp, sp, #32
+; CHECK-CPA-O0: ret
+;
+; CHECK-CPA-O3-LABEL: arith1:
+; CHECK-CPA-O3: madd x8, x1, x2, x0
+; CHECK-CPA-O3: mov x0, x8
+; CHECK-CPA-O3: add sp, sp, #32
+; CHECK-CPA-O3: ret
+;
+; CHECK-NOCPA-O0-LABEL: arith1:
+; CHECK-NOCPA-O0: mul x9, x9, x10
+; CHECK-NOCPA-O0: add x0, x8, x9
+; CHECK-NOCPA-O0: add sp, sp, #32
+; CHECK-NOCPA-O0: ret
+;
+; CHECK-NOCPA-O3-LABEL: arith1:
+; CHECK-NOCPA-O3: madd x8, x1, x2, x0
+; CHECK-NOCPA-O3: mov x0, x8
+; CHECK-NOCPA-O3: add sp, sp, #32
+; CHECK-NOCPA-O3: ret
+entry:
+ %4 = alloca i64, align 8
+ %5 = alloca i64, align 8
+ %6 = alloca i64, align 8
+ store i64 %0, ptr %4, align 8
+ store i64 %1, ptr %5, align 8
+ store i64 %2, ptr %6, align 8
+ %7 = load i64, ptr %4, align 8
+ %8 = load i64, ptr %5, align 8
+ %9 = load i64, ptr %6, align 8
+ %10 = mul nsw i64 %8, %9
+ %11 = add nsw i64 %7, %10
+ ret i64 %11
+}
+
+define i64 @arith2(ptr noundef %0, i64 noundef %1, i64 noundef %2, i32 noundef %3) {
+; CHECK-CPA-O0-LABEL: arith2:
+; CHECK-CPA-O0: add x9, x9, x9, lsl #1
+; CHECK-CPA-O0: addpt x8, x8, x9, lsl #4
+; CHECK-CPA-O0: ldr x8, [x8, #24]
+; CHECK-CPA-O0: mul x10, x10, x9
+; CHECK-CPA-O0: add x8, x8, x10
+; CHECK-CPA-O0: subs x0, x8, x9
+; CHECK-CPA-O0: add sp, sp, #32
+; CHECK-CPA-O0: ret
+;
+; CHECK-CPA-O3-LABEL: arith2:
+; CHECK-CPA-O3: mov w9, #48 // =0x30
+; CHECK-CPA-O3: maddpt x8, x8, x9, x0
+; CHECK-CPA-O3: ldr x8, [x8, #24]
+; CHECK-CPA-O3: madd x8, x1, x2, x8
+; CHECK-CPA-O3: sub x0, x8, x2
+; CHECK-CPA-O3: ret
+;
+; CHECK-NOCPA-O0-LABEL: arith2:
+; CHECK-NOCPA-O0: smaddl x8, w8, w9, x10
+; CHECK-NOCPA-O0: mul x10, x10, x9
+; CHECK-NOCPA-O0: add x8, x8, x10
+; CHECK-NOCPA-O0: subs x0, x8, x9
+; CHECK-NOCPA-O0: add sp, sp, #32
+; CHECK-NOCPA-O0: ret
+;
+; CHECK-NOCPA-O3-LABEL: arith2:
+; CHECK-NOCPA-O3: smaddl x8, w3, w8, x0
+; CHECK-NOCPA-O3: ldr x8, [x8, #24]
+; CHECK-NOCPA-O3: madd x8, x1, x2, x8
+; CHECK-NOCPA-O3: sub x0, x8, x2
+; CHECK-NOCPA-O3: add sp, sp, #32
+; CHECK-NOCPA-O3: ret
+entry:
+ %5 = alloca ptr, align 8
+ %6 = alloca i64, align 8
+ %7 = alloca i64, align 8
+ %8 = alloca i32, align 4
+ store ptr %0, ptr %5, align 8
+ store i64 %1, ptr %6, align 8
+ store i64 %2, ptr %7, align 8
+ store i32 %3, ptr %8, align 4
+ %9 = load ptr, ptr %5, align 8
+ %10 = load i32, ptr %8, align 4
+ %11 = sext i32 %10 to i64
+ %12 = getelementptr inbounds %struct.my_type2, ptr %9, i64 %11
+ %13 = getelementptr inbounds %struct.my_type2, ptr %12, i32 0, i32 3
+ %14 = load i64, ptr %13, align 8
+ %15 = load i64, ptr %6, align 8
+ %16 = load i64, ptr %7, align 8
+ %17 = mul nsw i64 %15, %16
+ %18 = add nsw i64 %14, %17
+ %19 = sub nsw i64 %18, %16
+ ret i64 %19
+}
+
+ at a = hidden global [2 x [1 x [2 x i8]]] [[1 x [2 x i8]] [[2 x i8] c"\01\01"], [1 x [2 x i8]] [[2 x i8] c"\01\01"]], align 1
+ at b = hidden global i16 0, align 2
+
+define hidden void @multidim() {
+; CHECK-CPA-O0-LABEL: multidim:
+; CHECK-CPA-O0: adrp x8, b
+; CHECK-CPA-O0: ldrh w10, [x8, :lo12:b]
+; CHECK-CPA-O0: adrp x8, a
+; CHECK-CPA-O0: add x8, x8, :lo12:a
+; CHECK-CPA-O0: add w9, w10, #1
+; CHECK-CPA-O0: mov w9, w9
+; CHECK-CPA-O0: add x9, x9, w10, uxtw #1
+; CHECK-CPA-O0: addpt x8, x8, x9
+; CHECK-CPA-O0: ldrb w8, [x8, #2]
+;
+; CHECK-CPA-O3-LABEL: multidim:
+; CHECK-CPA-O3: ret
+;
+; CHECK-NOCPA-O0-LABEL: multidim:
+; CHECK-NOCPA-O0: adrp x8, b
+; CHECK-NOCPA-O0: ldrh w9, [x8, :lo12:b]
+; CHECK-NOCPA-O0: adrp x8, a
+; CHECK-NOCPA-O0: add x8, x8, :lo12:a
+; CHECK-NOCPA-O0: add x8, x8, w9, uxtw #1
+; CHECK-NOCPA-O0: add w9, w9, #1
+; CHECK-NOCPA-O0: mov w9, w9
+; CHECK-NOCPA-O0: add x8, x8, x9
+; CHECK-NOCPA-O0: ldrb w8, [x8, #2]
+;
+; CHECK-NOCPA-O3-LABEL: multidim:
+; CHECK-NOCPA-O3: ret
+entry:
+ %0 = load i16, ptr @b, align 2
+ %idxprom = zext i16 %0 to i64
+ %arrayidx = getelementptr inbounds [1 x [2 x i8]], ptr getelementptr inbounds ([2 x [1 x [2 x i8]]], ptr @a, i64 0, i64 1), i64 0, i64 %idxprom
+ %1 = load i16, ptr @b, align 2
+ %conv = zext i16 %1 to i32
+ %add = add nsw i32 %conv, 1
+ %idxprom1 = sext i32 %add to i64
+ %arrayidx2 = getelementptr inbounds [2 x i8], ptr %arrayidx, i64 0, i64 %idxprom1
+ %2 = load i8, ptr %arrayidx2, align 1
+ %tobool = icmp ne i8 %2, 0
+ br i1 %tobool, label %if.then, label %if.end
+
+if.then:
+ br label %if.end
+
+if.end:
+ ret void
+}
+
+declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1)
+
+!6 = !{i64 0, i64 8, !7, i64 8, i64 8, !7, i64 16, i64 8, !7, i64 24, i64 8, !7, i64 32, i64 8, !7, i64 40, i64 8, !7}
+!7 = !{!8, !8, i64 0}
+!8 = !{!"long", !9, i64 0}
+!9 = !{!"omnipotent char", !10, i64 0}
+!10 = !{!"Simple C++ TBAA"}
+!11 = !{i64 0, i64 8, !7, i64 8, i64 8, !7}
>From fb332703c772fabf26ab7f509edef79e5403712b Mon Sep 17 00:00:00 2001
From: Rodolfo Wottrich <rodolfo.wottrich at arm.com>
Date: Mon, 20 Jan 2025 16:51:22 +0000
Subject: [PATCH 02/19] [SelectionDAG] Refactor use of getMemBasePlusOffset()
where applicable
Reduce complexity of PTRADD usage logic by harnessing
getMemBasePlusOffset().
Not all uses are applicable, as ADD's order of operands might be inverted
(PTRADD should always have pointer first, offset second).
---
.../SelectionDAG/SelectionDAGBuilder.cpp | 37 +++++--------------
1 file changed, 10 insertions(+), 27 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 5c267b04c2e0f..6ed4f969c938a 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -4304,12 +4304,6 @@ 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.
@@ -4341,8 +4335,8 @@ void SelectionDAGBuilder::visitGetElementPtr(const User &I) {
(int64_t(Offset) >= 0 && NW.hasNoUnsignedSignedWrap()))
Flags |= SDNodeFlags::NoUnsignedWrap;
- N = DAG.getNode(AddOpcode, 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.
@@ -4386,7 +4380,7 @@ void SelectionDAGBuilder::visitGetElementPtr(const User &I) {
OffsVal = DAG.getSExtOrTrunc(OffsVal, dl, N.getValueType());
- N = DAG.getNode(AddOpcode, dl, N.getValueType(), N, OffsVal, Flags);
+ N = DAG.getMemBasePlusOffset(N, OffsVal, dl, Flags);
continue;
}
@@ -4446,7 +4440,7 @@ void SelectionDAGBuilder::visitGetElementPtr(const User &I) {
SDNodeFlags AddFlags;
AddFlags.setNoUnsignedWrap(NW.hasNoUnsignedWrap());
- N = DAG.getNode(AddOpcode, dl, N.getValueType(), N, IdxN, AddFlags);
+ N = DAG.getMemBasePlusOffset(N, IdxN, dl, AddFlags);
}
}
@@ -4515,7 +4509,7 @@ void SelectionDAGBuilder::visitAlloca(const AllocaInst &I) {
} else {
AllocSize = DAG.getNode(ISD::ADD, dl, AllocSize.getValueType(), AllocSize,
DAG.getConstant(StackAlignMask, dl, IntPtr),
- SDNodeFlags::NoUnsignedWrap);
+ SDNodeFlags::NoUnsignedWrap);
}
// Mask out the low bits for alignment purposes.
@@ -9214,13 +9208,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.
- 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);
+ SDNodeFlags Flags;
+ SDValue DstPlusSize = DAG.getMemBasePlusOffset(Dst, Size, sdl, Flags);
setValue(&I, DstPlusSize);
return true;
}
@@ -11317,15 +11306,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) {
- 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),
- SDNodeFlags::NoUnisgnedWrap);
+ 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(),
>From 6e491cd1b70294845a5aa2973ead3dc06f8ac58b Mon Sep 17 00:00:00 2001
From: Rodolfo Wottrich <rodolfo.wottrich at arm.com>
Date: Wed, 22 Jan 2025 18:45:03 +0000
Subject: [PATCH 03/19] [SelectionDAG] Inverted args for PTRADD on
getMemBasePlusOffset()
By allowing getMemBasePlusOffset() to know whether its use for regular
ADDs does not take pointer first and offset second, the generation of
PTRADD on enabled targets can be done correctly, with the arguments
inverted.
This modification is to avoid changing the generation of some ADDs,
thus requiring the rewrite of several tests for several architectures.
---
llvm/include/llvm/CodeGen/SelectionDAG.h | 3 ++-
llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 20 +++----------------
.../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 9 +++++++--
.../SelectionDAG/SelectionDAGBuilder.cpp | 15 +++-----------
4 files changed, 15 insertions(+), 32 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h
index ba0538f7084ee..f71c68a23c6e9 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAG.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAG.h
@@ -1072,7 +1072,8 @@ class SelectionDAG {
SDValue getMemBasePlusOffset(SDValue Base, TypeSize Offset, const SDLoc &DL,
const SDNodeFlags Flags = SDNodeFlags());
SDValue getMemBasePlusOffset(SDValue Base, SDValue Offset, const SDLoc &DL,
- const SDNodeFlags Flags = SDNodeFlags());
+ const SDNodeFlags Flags = SDNodeFlags(),
+ const bool Inverted = false);
/// Create an add instruction with appropriate flags when used for
/// addressing some offset of an object. i.e. if a load is split into multiple
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index d3d86cc591cd6..d27ef9f5c3faf 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -3970,14 +3970,7 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) {
else
Index = DAG.getNode(ISD::MUL, dl, Index.getValueType(), Index,
DAG.getConstant(EntrySize, dl, Index.getValueType()));
- 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);
- }
+ SDValue Addr = DAG.getMemBasePlusOffset(Index, Table, dl, true);
EVT MemVT = EVT::getIntegerVT(*DAG.getContext(), EntrySize * 8);
SDValue LD = DAG.getExtLoad(
@@ -3988,15 +3981,8 @@ 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.
- 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);
- }
+ Addr = DAG.getMemBasePlusOffset(
+ Addr, TLI.getPICJumpTableRelocBase(Table, DAG), dl);
}
Tmp1 = TLI.expandIndirectJTBranch(dl, LD.getValue(1), Addr, JTI, DAG);
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index a0ccbd19c99ee..8444b26daa121 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -8062,14 +8062,19 @@ SDValue SelectionDAG::getMemBasePlusOffset(SDValue Base, TypeSize Offset,
SDValue SelectionDAG::getMemBasePlusOffset(SDValue Ptr, SDValue Offset,
const SDLoc &DL,
- const SDNodeFlags Flags) {
+ const SDNodeFlags Flags,
+ const bool Inverted) {
assert(Offset.getValueType().isInteger());
EVT BasePtrVT = Ptr.getValueType();
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);
+ if (Inverted) {
+ return getNode(ISD::PTRADD, DL, BasePtrVT, Offset, Ptr, Flags);
+ } else {
+ return getNode(ISD::PTRADD, DL, BasePtrVT, Ptr, Offset, Flags);
+ }
}
}
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 6ed4f969c938a..77a7f882e831a 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -4499,18 +4499,9 @@ void SelectionDAGBuilder::visitAlloca(const AllocaInst &I) {
// Round the size of the allocation up to the stack alignment size
// by add SA-1 to the size. This doesn't overflow because we're computing
// an address inside an alloca.
- SDNodeFlags Flags;
- Flags.setNoUnsignedWrap(true);
- if (DAG.getTarget().shouldPreservePtrArith(
- DAG.getMachineFunction().getFunction())) {
- AllocSize = DAG.getNode(ISD::PTRADD, dl, AllocSize.getValueType(),
- DAG.getConstant(StackAlignMask, dl, IntPtr),
- AllocSize, SDNodeFlags::NoUnsignedWrap);
- } else {
- AllocSize = DAG.getNode(ISD::ADD, dl, AllocSize.getValueType(), AllocSize,
- DAG.getConstant(StackAlignMask, dl, IntPtr),
- SDNodeFlags::NoUnsignedWrap);
- }
+ AllocSize = DAG.getMemBasePlusOffset(
+ AllocSize, DAG.getConstant(StackAlignMask, dl, IntPtr), dl,
+ SDNodeFlags::NoUnsignedWrap, true);
// Mask out the low bits for alignment purposes.
AllocSize = DAG.getNode(ISD::AND, dl, AllocSize.getValueType(), AllocSize,
>From eebe5386961842be7554ba207f6608dee8d91e05 Mon Sep 17 00:00:00 2001
From: Rodolfo Wottrich <rodolfo.wottrich at arm.com>
Date: Wed, 22 Jan 2025 18:50:17 +0000
Subject: [PATCH 04/19] Fix minor lexical problems
---
llvm/include/llvm/Target/TargetSelectionDAG.td | 2 +-
llvm/lib/Target/AArch64/AArch64TargetMachine.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/include/llvm/Target/TargetSelectionDAG.td b/llvm/include/llvm/Target/TargetSelectionDAG.td
index 9993332dc16fe..c8b44b3ef4bd0 100644
--- a/llvm/include/llvm/Target/TargetSelectionDAG.td
+++ b/llvm/include/llvm/Target/TargetSelectionDAG.td
@@ -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.
diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
index 0d74e89748bdd..103e1f6c46e81 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
@@ -931,4 +931,4 @@ bool AArch64TargetMachine::parseMachineFunctionInfo(
bool AArch64TargetMachine::shouldPreservePtrArith(const Function &F) const {
return getSubtargetImpl(F)->hasCPA();
-}
\ No newline at end of file
+}
>From 76dae60a16a2de111685ebc1d3c005966117b023 Mon Sep 17 00:00:00 2001
From: Rodolfo Wottrich <rodolfo.wottrich at arm.com>
Date: Tue, 28 Jan 2025 13:03:17 +0000
Subject: [PATCH 05/19] Satisfy undef deprecator
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 9b349c0f69c23..7855e5eec3a9a 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -2627,11 +2627,11 @@ SDValue DAGCombiner::visitPTRADD(SDNode *N) {
EVT IntVT = N1.getValueType();
SDLoc DL(N);
- // fold (ptradd undef, y) -> undef
+ // fold (ptradd und*f, y) -> und*f
if (N0.isUndef())
return N0;
- // fold (ptradd x, undef) -> undef
+ // fold (ptradd x, und*f) -> und*f
if (N1.isUndef())
return DAG.getUNDEF(PtrVT);
>From 10651fa6762b09f97fdb08919ec63af7c97b5a45 Mon Sep 17 00:00:00 2001
From: Rodolfo Wottrich <rodolfo.wottrich at arm.com>
Date: Fri, 31 Jan 2025 11:32:47 +0000
Subject: [PATCH 06/19] Remove fold with unhandeable corner case
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 31 +--------------
llvm/test/CodeGen/AArch64/cpa-selectiondag.ll | 38 ++++++++++---------
2 files changed, 22 insertions(+), 47 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 7855e5eec3a9a..c10fc39120e32 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -2627,11 +2627,11 @@ SDValue DAGCombiner::visitPTRADD(SDNode *N) {
EVT IntVT = N1.getValueType();
SDLoc DL(N);
- // fold (ptradd und*f, y) -> und*f
+ // fold (ptradd undef, y) -> undef
if (N0.isUndef())
return N0;
- // fold (ptradd x, und*f) -> und*f
+ // fold (ptradd x, undef) -> undef
if (N1.isUndef())
return DAG.getUNDEF(PtrVT);
@@ -2647,33 +2647,6 @@ SDValue DAGCombiner::visitPTRADD(SDNode *N) {
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:
diff --git a/llvm/test/CodeGen/AArch64/cpa-selectiondag.ll b/llvm/test/CodeGen/AArch64/cpa-selectiondag.ll
index ea9c9615943d8..158d3e35ea268 100644
--- a/llvm/test/CodeGen/AArch64/cpa-selectiondag.ll
+++ b/llvm/test/CodeGen/AArch64/cpa-selectiondag.ll
@@ -62,18 +62,20 @@ entry:
define void @msubpt1(i32 %index, i32 %elem) {
; CHECK-CPA-O0-LABEL: msubpt1:
-; CHECK-CPA-O0: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
-; CHECK-CPA-O0: addpt [[REG2:x[0-9]+]], [[REG1]], x{{[0-9]+}}
-; CHECK-CPA-O0: addpt [[REG3:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}
-; CHECK-CPA-O0: ldr q{{[0-9]+}}, [[[REG3]], #16]
-; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]], #288]
-; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG2]], #32]
+; CHECK-CPA-O0: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, [[REG1]]
+; CHECK-CPA-O0: addpt [[REG2:x[0-9]+]], x{{[0-9]+}}, [[REG2]]
+; CHECK-CPA-O0: ldr q{{[0-9]+}}, [[[REG2]], #16]
+; CHECK-CPA-O0: ldr q{{[0-9]+}}, [[[REG2]], #32]
+; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]], #32]
+; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]], #16]
+; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]]]
;
; CHECK-CPA-O3-LABEL: msubpt1:
-; CHECK-CPA-O3: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
-; CHECK-CPA-O3: addpt [[REG2:x[0-9]+]], [[REG1]], x{{[0-9]+}}
-; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]], #288]
+; CHECK-CPA-O3: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, [[REG1]]
+; CHECK-CPA-O3: ldp q{{[0-9]+}}, q{{[0-9]+}}, [[[REG1]], #16]
+; CHECK-CPA-O3: addpt [[REG2:x[0-9]+]], x{{[0-9]+}}, [[REG2]]
; CHECK-CPA-O3: stp q{{[0-9]+}}, q{{[0-9]+}}, [[[REG2]], #16]
+; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG2]]]
;
; CHECK-NOCPA-O0-LABEL: msubpt1:
; CHECK-NOCPA-O0: mneg [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}
@@ -97,12 +99,12 @@ entry:
define void @subpt1(i32 %index, i32 %elem) {
; CHECK-CPA-O0-LABEL: subpt1:
-; CHECK-CPA-O0: subpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}
-; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]], #96]
+; CHECK-CPA-O0: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, [[REG1]]
+; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]]]
;
; CHECK-CPA-O3-LABEL: subpt1:
-; CHECK-CPA-O3: subpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}
-; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]], #96]
+; CHECK-CPA-O3: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, [[REG1]]
+; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]]]
;
; CHECK-NOCPA-O0-LABEL: subpt1:
; CHECK-NOCPA-O0: subs [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #8
@@ -121,12 +123,12 @@ entry:
define void @subpt2(i32 %index, i32 %elem) {
; CHECK-CPA-O0-LABEL: subpt2:
-; CHECK-CPA-O0: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
-; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]], #96]
+; CHECK-CPA-O0: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, [[REG1]]
+; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]]]
;
; CHECK-CPA-O3-LABEL: subpt2:
-; CHECK-CPA-O3: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
-; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]], #96]
+; CHECK-CPA-O3: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, [[REG1]]
+; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]]]
;
; CHECK-NOCPA-O0-LABEL: subpt2:
; CHECK-NOCPA-O0: subs [[REG1:x[0-9]+]], x{{[0-9]+}}, w{{[0-9]+}}, sxtw #4
@@ -401,7 +403,7 @@ define hidden void @multidim() {
; CHECK-CPA-O0: mov w9, w9
; CHECK-CPA-O0: add x9, x9, w10, uxtw #1
; CHECK-CPA-O0: addpt x8, x8, x9
-; CHECK-CPA-O0: ldrb w8, [x8, #2]
+; CHECK-CPA-O0: ldrb w8, [x8]
;
; CHECK-CPA-O3-LABEL: multidim:
; CHECK-CPA-O3: ret
>From e64ef52aca3b2016626479ef5cc1377200e1348b Mon Sep 17 00:00:00 2001
From: Rodolfo Wottrich <rodolfo.wottrich at arm.com>
Date: Fri, 31 Jan 2025 17:02:38 +0000
Subject: [PATCH 07/19] Add comment explaining removed fold for future work
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 29 +++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index c10fc39120e32..5c34ade22f0f4 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -2675,6 +2675,35 @@ SDValue DAGCombiner::visitPTRADD(SDNode *N) {
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();
>From d0b2362a9d72b6e39d69990bca01c73a1a7c4b49 Mon Sep 17 00:00:00 2001
From: Rodolfo Wottrich <rodolfo.wottrich at arm.com>
Date: Fri, 31 Jan 2025 17:06:46 +0000
Subject: [PATCH 08/19] Minor lexical fix
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 5c34ade22f0f4..cca860f8b8cb7 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -2685,9 +2685,9 @@ SDValue DAGCombiner::visitPTRADD(SDNode *N) {
// * 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):
+ // 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);
>From c70948f3c8d86f07155d8ba76c49dd2be4a5fadf Mon Sep 17 00:00:00 2001
From: Rodolfo Wottrich <rodolfo.wottrich at arm.com>
Date: Tue, 4 Feb 2025 15:00:39 +0000
Subject: [PATCH 09/19] Remove getMemBasePlusOffset inversion logic after
#125279
---
llvm/include/llvm/CodeGen/SelectionDAG.h | 3 +--
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 9 ++-------
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 2 +-
3 files changed, 4 insertions(+), 10 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h
index b745462441ab1..461c0c1ead16d 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAG.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAG.h
@@ -1073,8 +1073,7 @@ class SelectionDAG {
SDValue getMemBasePlusOffset(SDValue Base, TypeSize Offset, const SDLoc &DL,
const SDNodeFlags Flags = SDNodeFlags());
SDValue getMemBasePlusOffset(SDValue Base, SDValue Offset, const SDLoc &DL,
- const SDNodeFlags Flags = SDNodeFlags(),
- const bool Inverted = false);
+ const SDNodeFlags Flags = SDNodeFlags());
/// Create an add instruction with appropriate flags when used for
/// addressing some offset of an object. i.e. if a load is split into multiple
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 96963fff8d059..2aaa2a0a903b9 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -8069,19 +8069,14 @@ SDValue SelectionDAG::getMemBasePlusOffset(SDValue Base, TypeSize Offset,
SDValue SelectionDAG::getMemBasePlusOffset(SDValue Ptr, SDValue Offset,
const SDLoc &DL,
- const SDNodeFlags Flags,
- const bool Inverted) {
+ const SDNodeFlags Flags) {
assert(Offset.getValueType().isInteger());
EVT BasePtrVT = Ptr.getValueType();
if (!this->getTarget().shouldPreservePtrArith(
this->getMachineFunction().getFunction())) {
return getNode(ISD::ADD, DL, BasePtrVT, Ptr, Offset, Flags);
} else {
- if (Inverted) {
- return getNode(ISD::PTRADD, DL, BasePtrVT, Offset, Ptr, Flags);
- } else {
- return getNode(ISD::PTRADD, DL, BasePtrVT, Ptr, Offset, Flags);
- }
+ return getNode(ISD::PTRADD, DL, BasePtrVT, Ptr, Offset, Flags);
}
}
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 909992bbf97d0..39c63b1dfe4fd 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -4501,7 +4501,7 @@ void SelectionDAGBuilder::visitAlloca(const AllocaInst &I) {
// an address inside an alloca.
AllocSize = DAG.getMemBasePlusOffset(
AllocSize, DAG.getConstant(StackAlignMask, dl, IntPtr), dl,
- SDNodeFlags::NoUnsignedWrap, true);
+ SDNodeFlags::NoUnsignedWrap);
// Mask out the low bits for alignment purposes.
AllocSize = DAG.getNode(ISD::AND, dl, AllocSize.getValueType(), AllocSize,
>From 43309977a759cd78a69fde946f8850bca6a04d92 Mon Sep 17 00:00:00 2001
From: Rodolfo Wottrich <rodolfo.wottrich at arm.com>
Date: Tue, 4 Feb 2025 15:11:36 +0000
Subject: [PATCH 10/19] Remove inadequate use of getMemBasePlusOffset()
---
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 39c63b1dfe4fd..5b74e6c19592f 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -4499,9 +4499,9 @@ void SelectionDAGBuilder::visitAlloca(const AllocaInst &I) {
// Round the size of the allocation up to the stack alignment size
// by add SA-1 to the size. This doesn't overflow because we're computing
// an address inside an alloca.
- AllocSize = DAG.getMemBasePlusOffset(
- AllocSize, DAG.getConstant(StackAlignMask, dl, IntPtr), dl,
- SDNodeFlags::NoUnsignedWrap);
+ AllocSize = DAG.getNode(ISD::ADD, dl, AllocSize.getValueType(), AllocSize,
+ DAG.getConstant(StackAlignMask, dl, IntPtr),
+ SDNodeFlags::NoUnsignedWrap);
// Mask out the low bits for alignment purposes.
AllocSize = DAG.getNode(ISD::AND, dl, AllocSize.getValueType(), AllocSize,
>From 0202b39bb21898da252c6ceab3d14e1fbeda93db Mon Sep 17 00:00:00 2001
From: Rodolfo Wottrich <rodolfo.wottrich at arm.com>
Date: Thu, 6 Feb 2025 11:06:39 +0000
Subject: [PATCH 11/19] Remove obsolete AddedCompletixy in FEAT_CPA tablegen
patterns
---
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 33 +++++++++------------
1 file changed, 14 insertions(+), 19 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index c4cbe9f4b11b3..7f1325a4fe7e4 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -10398,25 +10398,20 @@ let Predicates = [HasCPA] in {
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 : 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 :
>From 15f8b6b017a619b486114d33f2652e40c8af9e6b Mon Sep 17 00:00:00 2001
From: Rodolfo Wottrich <rodolfo.wottrich at arm.com>
Date: Thu, 6 Feb 2025 11:13:13 +0000
Subject: [PATCH 12/19] Modify comment in PTRADD declaration
---
llvm/include/llvm/CodeGen/ISDOpcodes.h | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index 94cce0094ab5b..61997d1d18856 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -1462,8 +1462,9 @@ enum NodeType {
// Outputs: [rv], output chain, glue
PATCHPOINT,
- // PTRADD represents pointer arithmetic semantics, for those targets which
- // benefit from that information.
+ // PTRADD represents pointer arithmatic semantics, for targets that opt in
+ // using shouldPreservePtrArith().
+ // ptr = PTRADD ptr, offset
PTRADD,
// Vector Predication
>From a61a19f158284567ff118ffa23cd15e702668db5 Mon Sep 17 00:00:00 2001
From: Rodolfo Wottrich <rodolfo.wottrich at arm.com>
Date: Thu, 6 Feb 2025 12:57:20 +0000
Subject: [PATCH 13/19] Gate FEAT_CPA CodeGen behind -mcpa-codegen flag
---
clang/include/clang/Driver/Options.td | 5 +++++
clang/lib/Driver/ToolChains/Arch/AArch64.cpp | 5 +++++
llvm/lib/Target/AArch64/AArch64Features.td | 3 +++
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 3 +++
llvm/lib/Target/AArch64/AArch64TargetMachine.cpp | 2 +-
llvm/test/CodeGen/AArch64/cpa-globalisel.ll | 4 ++--
llvm/test/CodeGen/AArch64/cpa-selectiondag.ll | 4 ++--
7 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 0ab923fcdd583..5352a25d7e38e 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -5025,6 +5025,11 @@ def msve_vector_bits_EQ : Joined<["-"], "msve-vector-bits=">, Group<m_aarch64_Fe
Visibility<[ClangOption, FlangOption]>,
HelpText<"Specify the size in bits of an SVE vector register. Defaults to the"
" vector length agnostic value of \"scalable\". (AArch64 only)">;
+
+def mcpa_codegen : Flag<["-"], "mcpa-codegen">,
+ Visibility<[ClangOption]>,
+ Group<m_aarch64_Features_Group>,
+ HelpText<"Generate scalar FEAT_CPA instructions (AArch64 only)">;
} // let Flags = [TargetSpecific]
def mvscale_min_EQ : Joined<["-"], "mvscale-min=">,
diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
index 1e2ac4e501baf..8554fb515fe1f 100644
--- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
@@ -250,6 +250,11 @@ void aarch64::getAArch64TargetFeatures(const Driver &D,
Extensions.disable(llvm::AArch64::AEK_FP);
}
+ // -mcpa-codegen enables generation of scalar FEAT_CPA instructions
+ if (Args.getLastArg(options::OPT_mcpa_codegen)) {
+ Features.push_back("+cpa-codegen");
+ }
+
// En/disable crc
if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) {
if (A->getOption().matches(options::OPT_mcrc))
diff --git a/llvm/lib/Target/AArch64/AArch64Features.td b/llvm/lib/Target/AArch64/AArch64Features.td
index 20db70ee38572..310e42a35f787 100644
--- a/llvm/lib/Target/AArch64/AArch64Features.td
+++ b/llvm/lib/Target/AArch64/AArch64Features.td
@@ -517,6 +517,9 @@ def FeaturePAuthLR : ExtensionWithMArch<"pauth-lr", "PAuthLR", "FEAT_PAuth_LR",
def FeatureTLBIW : ExtensionWithMArch<"tlbiw", "TLBIW", "FEAT_TLBIW",
"Enable Armv9.5-A TLBI VMALL for Dirty State">;
+def FeatureCPACodegen : SubtargetFeature<"cpa-codegen",
+ "HasCPACodegen", "true", "Generate scalar FEAT_CPA instructions">;
+
//===----------------------------------------------------------------------===//
// Armv9.6 Architecture Extensions
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 7f1325a4fe7e4..e6309442b27c9 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -371,6 +371,9 @@ def HasGCS : Predicate<"Subtarget->hasGCS()">,
AssemblerPredicateWithAll<(all_of FeatureGCS), "gcs">;
def HasCPA : Predicate<"Subtarget->hasCPA()">,
AssemblerPredicateWithAll<(all_of FeatureCPA), "cpa">;
+def HasCPACodegen : Predicate<"Subtarget->hasCPACodegen()">,
+ AssemblerPredicateWithAll<(all_of FeatureCPACodegen),
+ "cpa-codegen">;
def IsLE : Predicate<"Subtarget->isLittleEndian()">;
def IsBE : Predicate<"!Subtarget->isLittleEndian()">;
def IsWindows : Predicate<"Subtarget->isTargetWindows()">;
diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
index 103e1f6c46e81..9f0f7ce1d69ca 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
@@ -930,5 +930,5 @@ bool AArch64TargetMachine::parseMachineFunctionInfo(
}
bool AArch64TargetMachine::shouldPreservePtrArith(const Function &F) const {
- return getSubtargetImpl(F)->hasCPA();
+ return getSubtargetImpl(F)->hasCPA() && getSubtargetImpl(F)->hasCPACodegen();
}
diff --git a/llvm/test/CodeGen/AArch64/cpa-globalisel.ll b/llvm/test/CodeGen/AArch64/cpa-globalisel.ll
index ffbe4b358ca5a..db4fb8aa901af 100644
--- a/llvm/test/CodeGen/AArch64/cpa-globalisel.ll
+++ b/llvm/test/CodeGen/AArch64/cpa-globalisel.ll
@@ -1,5 +1,5 @@
-; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=+cpa -O0 -global-isel=1 -global-isel-abort=1 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-CPA-O0
-; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=+cpa -O3 -global-isel=1 -global-isel-abort=1 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-CPA-O3
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=+cpa,cpa-codegen -O0 -global-isel=1 -global-isel-abort=1 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-CPA-O0
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=+cpa,cpa-codegen -O3 -global-isel=1 -global-isel-abort=1 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-CPA-O3
; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=-cpa -O0 -global-isel=1 -global-isel-abort=1 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-NOCPA-O0
; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=-cpa -O3 -global-isel=1 -global-isel-abort=1 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-NOCPA-O3
diff --git a/llvm/test/CodeGen/AArch64/cpa-selectiondag.ll b/llvm/test/CodeGen/AArch64/cpa-selectiondag.ll
index 158d3e35ea268..b3080eabe6809 100644
--- a/llvm/test/CodeGen/AArch64/cpa-selectiondag.ll
+++ b/llvm/test/CodeGen/AArch64/cpa-selectiondag.ll
@@ -1,5 +1,5 @@
-; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=+cpa -O0 -global-isel=0 -fast-isel=0 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-CPA-O0
-; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=+cpa -O3 -global-isel=0 -fast-isel=0 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-CPA-O3
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=+cpa,cpa-codegen -O0 -global-isel=0 -fast-isel=0 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-CPA-O0
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=+cpa,cpa-codegen -O3 -global-isel=0 -fast-isel=0 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-CPA-O3
; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=-cpa -O0 -global-isel=0 -fast-isel=0 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-NOCPA-O0
; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=-cpa -O3 -global-isel=0 -fast-isel=0 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-NOCPA-O3
>From aec4f71b6323e330034783ffe00c16b36bd3437b Mon Sep 17 00:00:00 2001
From: Rodolfo Wottrich <rodolfo.wottrich at arm.com>
Date: Wed, 18 Jun 2025 13:09:43 +0000
Subject: [PATCH 14/19] Autogenerate FEAT_CPA tests with
utils/update_llc_test_checks.py
---
llvm/test/CodeGen/AArch64/cpa-globalisel.ll | 844 ++++++++++++------
llvm/test/CodeGen/AArch64/cpa-selectiondag.ll | 844 ++++++++++++------
2 files changed, 1117 insertions(+), 571 deletions(-)
diff --git a/llvm/test/CodeGen/AArch64/cpa-globalisel.ll b/llvm/test/CodeGen/AArch64/cpa-globalisel.ll
index db4fb8aa901af..1c7a6dd1c9c78 100644
--- a/llvm/test/CodeGen/AArch64/cpa-globalisel.ll
+++ b/llvm/test/CodeGen/AArch64/cpa-globalisel.ll
@@ -1,3 +1,4 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=+cpa,cpa-codegen -O0 -global-isel=1 -global-isel-abort=1 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-CPA-O0
; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=+cpa,cpa-codegen -O3 -global-isel=1 -global-isel-abort=1 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-CPA-O3
; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=-cpa -O0 -global-isel=1 -global-isel-abort=1 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-NOCPA-O0
@@ -10,21 +11,37 @@
@array2 = external dso_local global [10 x %struct.my_type2], align 8
define void @addpt1(i64 %index, i64 %arg) {
-; CHECK-CPA-O0-LABEL: addpt1:
-; CHECK-CPA-O0: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
-; CHECK-CPA-O0: str x{{[0-9]+}}, [[[REG1]], #8]
-;
-; CHECK-CPA-O3-LABEL: addpt1:
-; CHECK-CPA-O3: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
-; CHECK-CPA-O3: str x{{[0-9]+}}, [[[REG1]], #8]
-;
-; CHECK-NOCPA-O0-LABEL: addpt1:
-; CHECK-NOCPA-O0: add [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
-; CHECK-NOCPA-O0: str x{{[0-9]+}}, [[[REG1]], #8]
-;
-; CHECK-NOCPA-O3-LABEL: addpt1:
-; CHECK-NOCPA-O3: add [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
-; CHECK-NOCPA-O3: str x{{[0-9]+}}, [[[REG1]], #8]
+; CHECK-CPA-O0-LABEL: addpt1:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: adrp x8, array
+; CHECK-CPA-O0-NEXT: add x8, x8, :lo12:array
+; CHECK-CPA-O0-NEXT: addpt x8, x8, x0, lsl #4
+; CHECK-CPA-O0-NEXT: str x1, [x8, #8]
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: addpt1:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: adrp x8, array
+; CHECK-CPA-O3-NEXT: add x8, x8, :lo12:array
+; CHECK-CPA-O3-NEXT: addpt x8, x8, x0, lsl #4
+; CHECK-CPA-O3-NEXT: str x1, [x8, #8]
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: addpt1:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: adrp x8, array
+; CHECK-NOCPA-O0-NEXT: add x8, x8, :lo12:array
+; CHECK-NOCPA-O0-NEXT: add x8, x8, x0, lsl #4
+; CHECK-NOCPA-O0-NEXT: str x1, [x8, #8]
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: addpt1:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: adrp x8, array
+; CHECK-NOCPA-O3-NEXT: add x8, x8, :lo12:array
+; CHECK-NOCPA-O3-NEXT: add x8, x8, x0, lsl #4
+; CHECK-NOCPA-O3-NEXT: str x1, [x8, #8]
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%e2 = getelementptr inbounds %struct.my_type, ptr @array, i64 %index, i32 1
store i64 %arg, ptr %e2, align 8
@@ -32,25 +49,59 @@ entry:
}
define void @maddpt1(i32 %pos, ptr %val) {
-; CHECK-CPA-O0-LABEL: maddpt1:
-; CHECK-CPA-O0: maddpt x0, x{{[0-9]+}}, x{{[0-9]+}}, x{{[0-9]+}}
-; CHECK-CPA-O0: b memcpy
-;
-; CHECK-CPA-O3-LABEL: maddpt1:
-; CHECK-CPA-O3: maddpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, x{{[0-9]+}}
-; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]]]
-; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]], #16]
-; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]], #32]
-;
-; CHECK-NOCPA-O0-LABEL: maddpt1:
-; CHECK-NOCPA-O0: smaddl x0, w{{[0-9]+}}, w{{[0-9]+}}, x{{[0-9]+}}
-; CHECK-NOCPA-O0: b memcpy
-;
-; CHECK-NOCPA-O3-LABEL: maddpt1:
-; CHECK-NOCPA-O3: smaddl [[REG1:x[0-9]+]], w{{[0-9]+}}, w{{[0-9]+}}, x{{[0-9]+}}
-; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]]]
-; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]], #16]
-; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]], #32]
+; CHECK-CPA-O0-LABEL: maddpt1:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: // implicit-def: $x8
+; CHECK-CPA-O0-NEXT: mov w8, w0
+; CHECK-CPA-O0-NEXT: sxtw x8, w8
+; CHECK-CPA-O0-NEXT: mov w9, #48 // =0x30
+; CHECK-CPA-O0-NEXT: // kill: def $x9 killed $w9
+; CHECK-CPA-O0-NEXT: adrp x10, array2
+; CHECK-CPA-O0-NEXT: add x10, x10, :lo12:array2
+; CHECK-CPA-O0-NEXT: maddpt x0, x8, x9, x10
+; CHECK-CPA-O0-NEXT: mov w8, #48 // =0x30
+; CHECK-CPA-O0-NEXT: mov w2, w8
+; CHECK-CPA-O0-NEXT: b memcpy
+;
+; CHECK-CPA-O3-LABEL: maddpt1:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: // kill: def $w0 killed $w0 def $x0
+; CHECK-CPA-O3-NEXT: sxtw x9, w0
+; CHECK-CPA-O3-NEXT: mov w8, #48 // =0x30
+; CHECK-CPA-O3-NEXT: ldr q0, [x1]
+; CHECK-CPA-O3-NEXT: adrp x10, array2
+; CHECK-CPA-O3-NEXT: add x10, x10, :lo12:array2
+; CHECK-CPA-O3-NEXT: maddpt x8, x9, x8, x10
+; CHECK-CPA-O3-NEXT: str q0, [x8]
+; CHECK-CPA-O3-NEXT: ldr q0, [x1, #16]
+; CHECK-CPA-O3-NEXT: str q0, [x8, #16]
+; CHECK-CPA-O3-NEXT: ldr q0, [x1, #32]
+; CHECK-CPA-O3-NEXT: str q0, [x8, #32]
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: maddpt1:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: adrp x9, array2
+; CHECK-NOCPA-O0-NEXT: add x9, x9, :lo12:array2
+; CHECK-NOCPA-O0-NEXT: mov w8, #48 // =0x30
+; CHECK-NOCPA-O0-NEXT: smaddl x0, w0, w8, x9
+; CHECK-NOCPA-O0-NEXT: mov w8, #48 // =0x30
+; CHECK-NOCPA-O0-NEXT: mov w2, w8
+; CHECK-NOCPA-O0-NEXT: b memcpy
+;
+; CHECK-NOCPA-O3-LABEL: maddpt1:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: mov w8, #48 // =0x30
+; CHECK-NOCPA-O3-NEXT: adrp x9, array2
+; CHECK-NOCPA-O3-NEXT: add x9, x9, :lo12:array2
+; CHECK-NOCPA-O3-NEXT: smaddl x8, w0, w8, x9
+; CHECK-NOCPA-O3-NEXT: ldr q0, [x1]
+; CHECK-NOCPA-O3-NEXT: str q0, [x8]
+; CHECK-NOCPA-O3-NEXT: ldr q0, [x1, #16]
+; CHECK-NOCPA-O3-NEXT: str q0, [x8, #16]
+; CHECK-NOCPA-O3-NEXT: ldr q0, [x1, #32]
+; CHECK-NOCPA-O3-NEXT: str q0, [x8, #32]
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%idxprom = sext i32 %pos to i64
%arrayidx = getelementptr inbounds [10 x %struct.my_type2], ptr @array2, i64 0, i64 %idxprom
@@ -59,29 +110,75 @@ entry:
}
define void @msubpt1(i32 %index, i32 %elem) {
-; CHECK-CPA-O0-LABEL: msubpt1:
-; CHECK-CPA-O0: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}
-; CHECK-CPA-O0: msubpt x0, x{{[0-9]+}}, x{{[0-9]+}}, [[REG1]]
-; CHECK-CPA-O0: addpt x1, x{{[0-9]+}}, x{{[0-9]+}}
-; CHECK-CPA-O0: b memcpy
-;
-; CHECK-CPA-O3-LABEL: msubpt1:
-; CHECK-CPA-O3: msubpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, x{{[0-9]+}}
-; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]], #192]
-; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]], #208]
-; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]], #224]
-;
-; CHECK-NOCPA-O0-LABEL: msubpt1:
-; CHECK-NOCPA-O0: mneg [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}
-; CHECK-NOCPA-O0: add x0, x{{[0-9]+}}, [[REG1]]
-; CHECK-NOCPA-O0: b memcpy
-;
-; CHECK-NOCPA-O3-LABEL: msubpt1:
-; CHECK-NOCPA-O3: mneg [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}
-; CHECK-NOCPA-O3: add [[REG2:x[0-9]+]], x{{[0-9]+}}, [[REG1]]
-; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]], #192]
-; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]], #208]
-; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]], #224]
+; CHECK-CPA-O0-LABEL: msubpt1:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: // implicit-def: $x8
+; CHECK-CPA-O0-NEXT: mov w8, w0
+; CHECK-CPA-O0-NEXT: sxtw x10, w8
+; CHECK-CPA-O0-NEXT: mov w8, #48 // =0x30
+; CHECK-CPA-O0-NEXT: mov w9, w8
+; CHECK-CPA-O0-NEXT: mov w8, #288 // =0x120
+; CHECK-CPA-O0-NEXT: mov w11, w8
+; CHECK-CPA-O0-NEXT: adrp x8, array2
+; CHECK-CPA-O0-NEXT: add x8, x8, :lo12:array2
+; CHECK-CPA-O0-NEXT: addpt x11, x8, x11
+; CHECK-CPA-O0-NEXT: msubpt x0, x9, x10, x11
+; CHECK-CPA-O0-NEXT: mov w9, #48 // =0x30
+; CHECK-CPA-O0-NEXT: mov w2, w9
+; CHECK-CPA-O0-NEXT: mov w9, #96 // =0x60
+; CHECK-CPA-O0-NEXT: // kill: def $x9 killed $w9
+; CHECK-CPA-O0-NEXT: addpt x1, x8, x9
+; CHECK-CPA-O0-NEXT: b memcpy
+;
+; CHECK-CPA-O3-LABEL: msubpt1:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: // kill: def $w0 killed $w0 def $x0
+; CHECK-CPA-O3-NEXT: sxtw x9, w0
+; CHECK-CPA-O3-NEXT: adrp x10, array2+96
+; CHECK-CPA-O3-NEXT: add x10, x10, :lo12:array2+96
+; CHECK-CPA-O3-NEXT: mov w8, #48 // =0x30
+; CHECK-CPA-O3-NEXT: ldr q0, [x10]
+; CHECK-CPA-O3-NEXT: msubpt x8, x8, x9, x10
+; CHECK-CPA-O3-NEXT: str q0, [x8, #192]
+; CHECK-CPA-O3-NEXT: ldr q0, [x10, #16]
+; CHECK-CPA-O3-NEXT: str q0, [x8, #208]
+; CHECK-CPA-O3-NEXT: ldr q0, [x10, #32]
+; CHECK-CPA-O3-NEXT: str q0, [x8, #224]
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: msubpt1:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: // implicit-def: $x8
+; CHECK-NOCPA-O0-NEXT: mov w8, w0
+; CHECK-NOCPA-O0-NEXT: sxtw x8, w8
+; CHECK-NOCPA-O0-NEXT: mov w9, #48 // =0x30
+; CHECK-NOCPA-O0-NEXT: // kill: def $x9 killed $w9
+; CHECK-NOCPA-O0-NEXT: mneg x10, x8, x9
+; CHECK-NOCPA-O0-NEXT: adrp x8, array2
+; CHECK-NOCPA-O0-NEXT: add x8, x8, :lo12:array2
+; CHECK-NOCPA-O0-NEXT: add x9, x8, #288
+; CHECK-NOCPA-O0-NEXT: add x0, x9, x10
+; CHECK-NOCPA-O0-NEXT: mov w9, #48 // =0x30
+; CHECK-NOCPA-O0-NEXT: mov w2, w9
+; CHECK-NOCPA-O0-NEXT: add x1, x8, #96
+; CHECK-NOCPA-O0-NEXT: b memcpy
+;
+; CHECK-NOCPA-O3-LABEL: msubpt1:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: // kill: def $w0 killed $w0 def $x0
+; CHECK-NOCPA-O3-NEXT: sxtw x8, w0
+; CHECK-NOCPA-O3-NEXT: mov w9, #48 // =0x30
+; CHECK-NOCPA-O3-NEXT: mneg x8, x8, x9
+; CHECK-NOCPA-O3-NEXT: adrp x9, array2+96
+; CHECK-NOCPA-O3-NEXT: add x9, x9, :lo12:array2+96
+; CHECK-NOCPA-O3-NEXT: ldr q0, [x9]
+; CHECK-NOCPA-O3-NEXT: add x8, x9, x8
+; CHECK-NOCPA-O3-NEXT: str q0, [x8, #192]
+; CHECK-NOCPA-O3-NEXT: ldr q0, [x9, #16]
+; CHECK-NOCPA-O3-NEXT: str q0, [x8, #208]
+; CHECK-NOCPA-O3-NEXT: ldr q0, [x9, #32]
+; CHECK-NOCPA-O3-NEXT: str q0, [x8, #224]
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%idx.ext = sext i32 %index to i64
%idx.neg = sub nsw i64 0, %idx.ext
@@ -91,21 +188,51 @@ entry:
}
define void @subpt1(i32 %index, i32 %elem) {
-; CHECK-CPA-O0-LABEL: subpt1:
-; CHECK-CPA-O0: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}
-; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]], x{{[0-9]+}}, lsl #4]
-;
-; CHECK-CPA-O3-LABEL: subpt1:
-; CHECK-CPA-O3: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
-; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]], #64]
-;
-; CHECK-NOCPA-O0-LABEL: subpt1:
-; CHECK-NOCPA-O0: add [[REG1:x[0-9]+]], x{{[0-9]+}}, #96
-; CHECK-NOCPA-O0: str q{{[0-9]+}}, [[[REG1]], x{{[0-9]+}}, lsl #4]
-;
-; CHECK-NOCPA-O3-LABEL: subpt1:
-; CHECK-NOCPA-O3: add [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
-; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]], #64]
+; CHECK-CPA-O0-LABEL: subpt1:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: mov w8, #-16 // =0xfffffff0
+; CHECK-CPA-O0-NEXT: smull x9, w0, w8
+; CHECK-CPA-O0-NEXT: adrp x8, array
+; CHECK-CPA-O0-NEXT: add x8, x8, :lo12:array
+; CHECK-CPA-O0-NEXT: ldr q0, [x8, #32]
+; CHECK-CPA-O0-NEXT: mov w10, #96 // =0x60
+; CHECK-CPA-O0-NEXT: // kill: def $x10 killed $w10
+; CHECK-CPA-O0-NEXT: addpt x8, x8, x10
+; CHECK-CPA-O0-NEXT: str q0, [x8, x9, lsl #4]
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: subpt1:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: mov w8, #-16 // =0xfffffff0
+; CHECK-CPA-O3-NEXT: adrp x9, array+32
+; CHECK-CPA-O3-NEXT: add x9, x9, :lo12:array+32
+; CHECK-CPA-O3-NEXT: smull x8, w0, w8
+; CHECK-CPA-O3-NEXT: ldr q0, [x9]
+; CHECK-CPA-O3-NEXT: addpt x8, x9, x8, lsl #4
+; CHECK-CPA-O3-NEXT: str q0, [x8, #64]
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: subpt1:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: mov w8, #-16 // =0xfffffff0
+; CHECK-NOCPA-O0-NEXT: smull x9, w0, w8
+; CHECK-NOCPA-O0-NEXT: adrp x8, array
+; CHECK-NOCPA-O0-NEXT: add x8, x8, :lo12:array
+; CHECK-NOCPA-O0-NEXT: ldr q0, [x8, #32]
+; CHECK-NOCPA-O0-NEXT: add x8, x8, #96
+; CHECK-NOCPA-O0-NEXT: str q0, [x8, x9, lsl #4]
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: subpt1:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: mov w8, #-16 // =0xfffffff0
+; CHECK-NOCPA-O3-NEXT: adrp x9, array+32
+; CHECK-NOCPA-O3-NEXT: add x9, x9, :lo12:array+32
+; CHECK-NOCPA-O3-NEXT: smull x8, w0, w8
+; CHECK-NOCPA-O3-NEXT: ldr q0, [x9]
+; CHECK-NOCPA-O3-NEXT: add x8, x9, x8, lsl #4
+; CHECK-NOCPA-O3-NEXT: str q0, [x8, #64]
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%conv = sext i32 %index to i64
%mul.neg = mul nsw i64 %conv, -16
@@ -115,21 +242,51 @@ entry:
}
define void @subpt2(i32 %index, i32 %elem) {
-; CHECK-CPA-O0-LABEL: subpt2:
-; CHECK-CPA-O0: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}
-; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]], x{{[0-9]+}}, lsl #4]
-;
-; CHECK-CPA-O3-LABEL: subpt2:
-; CHECK-CPA-O3: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
-; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]], #64]
-;
-; CHECK-NOCPA-O0-LABEL: subpt2:
-; CHECK-NOCPA-O0: add [[REG1:x[0-9]+]], x{{[0-9]+}}, #96
-; CHECK-NOCPA-O0: str q{{[0-9]+}}, [[[REG1]], x{{[0-9]+}}, lsl #4]
-;
-; CHECK-NOCPA-O3-LABEL: subpt2:
-; CHECK-NOCPA-O3: add [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
-; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]], #64]
+; CHECK-CPA-O0-LABEL: subpt2:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: mov x8, xzr
+; CHECK-CPA-O0-NEXT: subs x9, x8, w0, sxtw
+; CHECK-CPA-O0-NEXT: adrp x8, array
+; CHECK-CPA-O0-NEXT: add x8, x8, :lo12:array
+; CHECK-CPA-O0-NEXT: ldr q0, [x8, #32]
+; CHECK-CPA-O0-NEXT: mov w10, #96 // =0x60
+; CHECK-CPA-O0-NEXT: // kill: def $x10 killed $w10
+; CHECK-CPA-O0-NEXT: addpt x8, x8, x10
+; CHECK-CPA-O0-NEXT: str q0, [x8, x9, lsl #4]
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: subpt2:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: mov x8, xzr
+; CHECK-CPA-O3-NEXT: adrp x9, array+32
+; CHECK-CPA-O3-NEXT: add x9, x9, :lo12:array+32
+; CHECK-CPA-O3-NEXT: sub x8, x8, w0, sxtw
+; CHECK-CPA-O3-NEXT: ldr q0, [x9]
+; CHECK-CPA-O3-NEXT: addpt x8, x9, x8, lsl #4
+; CHECK-CPA-O3-NEXT: str q0, [x8, #64]
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: subpt2:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: mov x8, xzr
+; CHECK-NOCPA-O0-NEXT: subs x9, x8, w0, sxtw
+; CHECK-NOCPA-O0-NEXT: adrp x8, array
+; CHECK-NOCPA-O0-NEXT: add x8, x8, :lo12:array
+; CHECK-NOCPA-O0-NEXT: ldr q0, [x8, #32]
+; CHECK-NOCPA-O0-NEXT: add x8, x8, #96
+; CHECK-NOCPA-O0-NEXT: str q0, [x8, x9, lsl #4]
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: subpt2:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: mov x8, xzr
+; CHECK-NOCPA-O3-NEXT: adrp x9, array+32
+; CHECK-NOCPA-O3-NEXT: add x9, x9, :lo12:array+32
+; CHECK-NOCPA-O3-NEXT: sub x8, x8, w0, sxtw
+; CHECK-NOCPA-O3-NEXT: ldr q0, [x9]
+; CHECK-NOCPA-O3-NEXT: add x8, x9, x8, lsl #4
+; CHECK-NOCPA-O3-NEXT: str q0, [x8, #64]
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%idx.ext = sext i32 %index to i64
%idx.neg = sub nsw i64 0, %idx.ext
@@ -139,176 +296,232 @@ entry:
}
define ptr @subpt3(ptr %ptr, i32 %index) {
-; CHECK-CPA-O0-LABEL: subpt3:
-; CHECK-CPA-O0: mov [[REG1:x[0-9]+]], #-8
-; CHECK-CPA-O0: addpt x0, x{{[0-9]+}}, [[REG1]]
-; CHECK-CPA-O0: ret
-;
-; CHECK-CPA-O3-LABEL: subpt3:
-; CHECK-CPA-O3: mov [[REG1:x[0-9]+]], #-8
-; CHECK-CPA-O3: addpt x0, x{{[0-9]+}}, [[REG1]]
-; CHECK-CPA-O3: ret
-;
-; CHECK-NOCPA-O0-LABEL: subpt3:
-; CHECK-NOCPA-O0: subs x0, x{{[0-9]+}}, #8
-; CHECK-NOCPA-O0: ret
-;
-; CHECK-NOCPA-O3-LABEL: subpt3:
-; CHECK-NOCPA-O3: sub x0, x{{[0-9]+}}, #8
-; CHECK-NOCPA-O3: ret
+; CHECK-CPA-O0-LABEL: subpt3:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: mov x8, #-8 // =0xfffffffffffffff8
+; CHECK-CPA-O0-NEXT: addpt x0, x0, x8
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: subpt3:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: mov x8, #-8 // =0xfffffffffffffff8
+; CHECK-CPA-O3-NEXT: addpt x0, x0, x8
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: subpt3:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: subs x0, x0, #8
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: subpt3:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: sub x0, x0, #8
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%incdec.ptr.i.i.i = getelementptr inbounds i64, ptr %ptr, i64 -1
ret ptr %incdec.ptr.i.i.i
}
define i64 @subi64(i64 %ptr, i32 %index) {
-; CHECK-CPA-O0-LABEL: subi64:
-; CHECK-CPA-O0: subs x0, x0, #1
-; CHECK-CPA-O0: ret
-;
-; CHECK-CPA-O3-LABEL: subi64:
-; CHECK-CPA-O3: sub x0, x0, #1
-; CHECK-CPA-O3: ret
-;
-; CHECK-NOCPA-O0-LABEL: subi64:
-; CHECK-NOCPA-O0: subs x0, x0, #1
-; CHECK-NOCPA-O0: ret
-;
-; CHECK-NOCPA-O3-LABEL: subi64:
-; CHECK-NOCPA-O3: sub x0, x0, #1
-; CHECK-NOCPA-O3: ret
+; CHECK-CPA-O0-LABEL: subi64:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: subs x0, x0, #1
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: subi64:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: sub x0, x0, #1
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: subi64:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: subs x0, x0, #1
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: subi64:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: sub x0, x0, #1
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%incdec.ptr.i.i.i = add i64 %ptr, -1
ret i64 %incdec.ptr.i.i.i
}
define i32 @subi32(i32 %ptr, i32 %index) {
-; CHECK-CPA-O0-LABEL: subi32:
-; CHECK-CPA-O0: subs w0, w0, #1
-; CHECK-CPA-O0: ret
-;
-; CHECK-CPA-O3-LABEL: subi32:
-; CHECK-CPA-O3: sub w0, w0, #1
-; CHECK-CPA-O3: ret
-;
-; CHECK-NOCPA-O0-LABEL: subi32:
-; CHECK-NOCPA-O0: subs w0, w0, #1
-; CHECK-NOCPA-O0: ret
-;
-; CHECK-NOCPA-O3-LABEL: subi32:
-; CHECK-NOCPA-O3: sub w0, w0, #1
-; CHECK-NOCPA-O3: ret
+; CHECK-CPA-O0-LABEL: subi32:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: subs w0, w0, #1
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: subi32:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: sub w0, w0, #1
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: subi32:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: subs w0, w0, #1
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: subi32:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: sub w0, w0, #1
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%incdec.ptr.i.i.i = add i32 %ptr, -1
ret i32 %incdec.ptr.i.i.i
}
define i16 @subi16(i16 %ptr, i32 %index) {
-; CHECK-CPA-O0-LABEL: subi16:
-; CHECK-CPA-O0: subs w0, w0, #1
-; CHECK-CPA-O0: ret
-;
-; CHECK-CPA-O3-LABEL: subi16:
-; CHECK-CPA-O3: sub w0, w0, #1
-; CHECK-CPA-O3: ret
-;
-; CHECK-NOCPA-O0-LABEL: subi16:
-; CHECK-NOCPA-O0: subs w0, w0, #1
-; CHECK-NOCPA-O0: ret
-;
-; CHECK-NOCPA-O3-LABEL: subi16:
-; CHECK-NOCPA-O3: sub w0, w0, #1
-; CHECK-NOCPA-O3: ret
+; CHECK-CPA-O0-LABEL: subi16:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: subs w0, w0, #1
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: subi16:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: sub w0, w0, #1
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: subi16:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: subs w0, w0, #1
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: subi16:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: sub w0, w0, #1
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%incdec.ptr.i.i.i = add i16 %ptr, -1
ret i16 %incdec.ptr.i.i.i
}
define i64 @addi64(i64 %ptr, i32 %index) {
-; CHECK-CPA-O0-LABEL: addi64:
-; CHECK-CPA-O0: add x0, x0, #1
-; CHECK-CPA-O0: ret
-;
-; CHECK-CPA-O3-LABEL: addi64:
-; CHECK-CPA-O3: add x0, x0, #1
-; CHECK-CPA-O3: ret
-;
-; CHECK-NOCPA-O0-LABEL: addi64:
-; CHECK-NOCPA-O0: add x0, x0, #1
-; CHECK-NOCPA-O0: ret
-;
-; CHECK-NOCPA-O3-LABEL: addi64:
-; CHECK-NOCPA-O3: add x0, x0, #1
-; CHECK-NOCPA-O3: ret
+; CHECK-CPA-O0-LABEL: addi64:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: add x0, x0, #1
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: addi64:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: add x0, x0, #1
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: addi64:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: add x0, x0, #1
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: addi64:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: add x0, x0, #1
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%incdec.ptr.i.i.i = add i64 %ptr, 1
ret i64 %incdec.ptr.i.i.i
}
define i32 @addi32(i32 %ptr, i32 %index) {
-; CHECK-CPA-O0-LABEL: addi32:
-; CHECK-CPA-O0: add w0, w0, #1
-; CHECK-CPA-O0: ret
-;
-; CHECK-CPA-O3-LABEL: addi32:
-; CHECK-CPA-O3: add w0, w0, #1
-; CHECK-CPA-O3: ret
-;
-; CHECK-NOCPA-O0-LABEL: addi32:
-; CHECK-NOCPA-O0: add w0, w0, #1
-; CHECK-NOCPA-O0: ret
-;
-; CHECK-NOCPA-O3-LABEL: addi32:
-; CHECK-NOCPA-O3: add w0, w0, #1
-; CHECK-NOCPA-O3: ret
+; CHECK-CPA-O0-LABEL: addi32:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: add w0, w0, #1
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: addi32:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: add w0, w0, #1
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: addi32:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: add w0, w0, #1
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: addi32:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: add w0, w0, #1
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%incdec.ptr.i.i.i = add i32 %ptr, 1
ret i32 %incdec.ptr.i.i.i
}
define i16 @addi16(i16 %ptr, i32 %index) {
-; CHECK-CPA-O0-LABEL: addi16:
-; CHECK-CPA-O0: add w0, w0, #1
-; CHECK-CPA-O0: ret
-;
-; CHECK-CPA-O3-LABEL: addi16:
-; CHECK-CPA-O3: add w0, w0, #1
-; CHECK-CPA-O3: ret
-;
-; CHECK-NOCPA-O0-LABEL: addi16:
-; CHECK-NOCPA-O0: add w0, w0, #1
-; CHECK-NOCPA-O0: ret
-;
-; CHECK-NOCPA-O3-LABEL: addi16:
-; CHECK-NOCPA-O3: add w0, w0, #1
-; CHECK-NOCPA-O3: ret
+; CHECK-CPA-O0-LABEL: addi16:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: add w0, w0, #1
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: addi16:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: add w0, w0, #1
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: addi16:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: add w0, w0, #1
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: addi16:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: add w0, w0, #1
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%incdec.ptr.i.i.i = add i16 %ptr, 1
ret i16 %incdec.ptr.i.i.i
}
define i64 @arith1(i64 noundef %0, i64 noundef %1, i64 noundef %2) {
-; CHECK-CPA-O0-LABEL: arith1:
-; CHECK-CPA-O0: mul x9, x9, x10
-; CHECK-CPA-O0: add x0, x8, x9
-; CHECK-CPA-O0: add sp, sp, #32
-; CHECK-CPA-O0: ret
-;
-; CHECK-CPA-O3-LABEL: arith1:
-; CHECK-CPA-O3: madd x0, x1, x2, x0
-; CHECK-CPA-O3: add sp, sp, #32
-; CHECK-CPA-O3: ret
-;
-; CHECK-NOCPA-O0-LABEL: arith1:
-; CHECK-NOCPA-O0: mul x9, x9, x10
-; CHECK-NOCPA-O0: add x0, x8, x9
-; CHECK-NOCPA-O0: add sp, sp, #32
-; CHECK-NOCPA-O0: ret
-;
-; CHECK-NOCPA-O3-LABEL: arith1:
-; CHECK-NOCPA-O3: madd x0, x1, x2, x0
-; CHECK-NOCPA-O3: add sp, sp, #32
-; CHECK-NOCPA-O3: ret
+; CHECK-CPA-O0-LABEL: arith1:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: sub sp, sp, #32
+; CHECK-CPA-O0-NEXT: .cfi_def_cfa_offset 32
+; CHECK-CPA-O0-NEXT: str x0, [sp, #24]
+; CHECK-CPA-O0-NEXT: str x1, [sp, #16]
+; CHECK-CPA-O0-NEXT: str x2, [sp, #8]
+; CHECK-CPA-O0-NEXT: ldr x8, [sp, #24]
+; CHECK-CPA-O0-NEXT: ldr x9, [sp, #16]
+; CHECK-CPA-O0-NEXT: ldr x10, [sp, #8]
+; CHECK-CPA-O0-NEXT: mul x9, x9, x10
+; CHECK-CPA-O0-NEXT: add x0, x8, x9
+; CHECK-CPA-O0-NEXT: add sp, sp, #32
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: arith1:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: sub sp, sp, #32
+; CHECK-CPA-O3-NEXT: .cfi_def_cfa_offset 32
+; CHECK-CPA-O3-NEXT: stp x2, x1, [sp, #8]
+; CHECK-CPA-O3-NEXT: str x0, [sp, #24]
+; CHECK-CPA-O3-NEXT: madd x0, x1, x2, x0
+; CHECK-CPA-O3-NEXT: add sp, sp, #32
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: arith1:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: sub sp, sp, #32
+; CHECK-NOCPA-O0-NEXT: .cfi_def_cfa_offset 32
+; CHECK-NOCPA-O0-NEXT: str x0, [sp, #24]
+; CHECK-NOCPA-O0-NEXT: str x1, [sp, #16]
+; CHECK-NOCPA-O0-NEXT: str x2, [sp, #8]
+; CHECK-NOCPA-O0-NEXT: ldr x8, [sp, #24]
+; CHECK-NOCPA-O0-NEXT: ldr x9, [sp, #16]
+; CHECK-NOCPA-O0-NEXT: ldr x10, [sp, #8]
+; CHECK-NOCPA-O0-NEXT: mul x9, x9, x10
+; CHECK-NOCPA-O0-NEXT: add x0, x8, x9
+; CHECK-NOCPA-O0-NEXT: add sp, sp, #32
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: arith1:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: sub sp, sp, #32
+; CHECK-NOCPA-O3-NEXT: .cfi_def_cfa_offset 32
+; CHECK-NOCPA-O3-NEXT: stp x2, x1, [sp, #8]
+; CHECK-NOCPA-O3-NEXT: str x0, [sp, #24]
+; CHECK-NOCPA-O3-NEXT: madd x0, x1, x2, x0
+; CHECK-NOCPA-O3-NEXT: add sp, sp, #32
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%4 = alloca i64, align 8
%5 = alloca i64, align 8
@@ -325,44 +538,82 @@ entry:
}
define i64 @arith2(ptr noundef %0, i64 noundef %1, i64 noundef %2, i32 noundef %3) {
-; CHECK-CPA-O0-LABEL: arith2:
-; CHECK-CPA-O0: maddpt x8, x8, x9, x10
-; CHECK-CPA-O0: ldr x8, [x8, #24]
-; CHECK-CPA-O0: ldr x10, [sp, #16]
-; CHECK-CPA-O0: ldr x9, [sp, #8]
-; CHECK-CPA-O0: mul x10, x10, x9
-; CHECK-CPA-O0: add x8, x8, x10
-; CHECK-CPA-O0: subs x0, x8, x9
-; CHECK-CPA-O0: add sp, sp, #32
-; CHECK-CPA-O0: ret
-;
-; CHECK-CPA-O3-LABEL: arith2:
-; CHECK-CPA-O3: maddpt x8, x9, x10, x0
-; CHECK-CPA-O3: ldr x8, [x8, #24]
-; CHECK-CPA-O3: madd x8, x1, x2, x8
-; CHECK-CPA-O3: sub x0, x8, x2
-; CHECK-CPA-O3: add sp, sp, #32
-; CHECK-CPA-O3: ret
-;
-; CHECK-NOCPA-O0-LABEL: arith2:
-; CHECK-NOCPA-O0: mul x9, x9, x10
-; CHECK-NOCPA-O0: add x8, x8, x9
-; CHECK-NOCPA-O0: ldr x8, [x8, #24]
-; CHECK-NOCPA-O0: ldr x10, [sp, #16]
-; CHECK-NOCPA-O0: ldr x9, [sp, #8]
-; CHECK-NOCPA-O0: mul x10, x10, x9
-; CHECK-NOCPA-O0: add x8, x8, x10
-; CHECK-NOCPA-O0: subs x0, x8, x9
-; CHECK-NOCPA-O0: add sp, sp, #32
-; CHECK-NOCPA-O0: ret
-;
-; CHECK-NOCPA-O3-LABEL: arith2:
-; CHECK-NOCPA-O3: madd x8, x8, x9, x0
-; CHECK-NOCPA-O3: ldr x8, [x8, #24]
-; CHECK-NOCPA-O3: madd x8, x1, x2, x8
-; CHECK-NOCPA-O3: sub x0, x8, x2
-; CHECK-NOCPA-O3: add sp, sp, #32
-; CHECK-NOCPA-O3: ret
+; CHECK-CPA-O0-LABEL: arith2:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: sub sp, sp, #32
+; CHECK-CPA-O0-NEXT: .cfi_def_cfa_offset 32
+; CHECK-CPA-O0-NEXT: str x0, [sp, #24]
+; CHECK-CPA-O0-NEXT: str x1, [sp, #16]
+; CHECK-CPA-O0-NEXT: str x2, [sp, #8]
+; CHECK-CPA-O0-NEXT: str w3, [sp, #4]
+; CHECK-CPA-O0-NEXT: ldr x10, [sp, #24]
+; CHECK-CPA-O0-NEXT: ldrsw x8, [sp, #4]
+; CHECK-CPA-O0-NEXT: mov w9, #48 // =0x30
+; CHECK-CPA-O0-NEXT: // kill: def $x9 killed $w9
+; CHECK-CPA-O0-NEXT: maddpt x8, x8, x9, x10
+; CHECK-CPA-O0-NEXT: ldr x8, [x8, #24]
+; CHECK-CPA-O0-NEXT: ldr x10, [sp, #16]
+; CHECK-CPA-O0-NEXT: ldr x9, [sp, #8]
+; CHECK-CPA-O0-NEXT: mul x10, x10, x9
+; CHECK-CPA-O0-NEXT: add x8, x8, x10
+; CHECK-CPA-O0-NEXT: subs x0, x8, x9
+; CHECK-CPA-O0-NEXT: add sp, sp, #32
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: arith2:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: sub sp, sp, #32
+; CHECK-CPA-O3-NEXT: .cfi_def_cfa_offset 32
+; CHECK-CPA-O3-NEXT: str w3, [sp, #4]
+; CHECK-CPA-O3-NEXT: mov w10, #48 // =0x30
+; CHECK-CPA-O3-NEXT: ldrsw x9, [sp, #4]
+; CHECK-CPA-O3-NEXT: stp x1, x0, [sp, #16]
+; CHECK-CPA-O3-NEXT: maddpt x8, x9, x10, x0
+; CHECK-CPA-O3-NEXT: str x2, [sp, #8]
+; CHECK-CPA-O3-NEXT: ldr x8, [x8, #24]
+; CHECK-CPA-O3-NEXT: madd x8, x1, x2, x8
+; CHECK-CPA-O3-NEXT: sub x0, x8, x2
+; CHECK-CPA-O3-NEXT: add sp, sp, #32
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: arith2:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: sub sp, sp, #32
+; CHECK-NOCPA-O0-NEXT: .cfi_def_cfa_offset 32
+; CHECK-NOCPA-O0-NEXT: str x0, [sp, #24]
+; CHECK-NOCPA-O0-NEXT: str x1, [sp, #16]
+; CHECK-NOCPA-O0-NEXT: str x2, [sp, #8]
+; CHECK-NOCPA-O0-NEXT: str w3, [sp, #4]
+; CHECK-NOCPA-O0-NEXT: ldr x8, [sp, #24]
+; CHECK-NOCPA-O0-NEXT: ldrsw x9, [sp, #4]
+; CHECK-NOCPA-O0-NEXT: mov w10, #48 // =0x30
+; CHECK-NOCPA-O0-NEXT: // kill: def $x10 killed $w10
+; CHECK-NOCPA-O0-NEXT: mul x9, x9, x10
+; CHECK-NOCPA-O0-NEXT: add x8, x8, x9
+; CHECK-NOCPA-O0-NEXT: ldr x8, [x8, #24]
+; CHECK-NOCPA-O0-NEXT: ldr x10, [sp, #16]
+; CHECK-NOCPA-O0-NEXT: ldr x9, [sp, #8]
+; CHECK-NOCPA-O0-NEXT: mul x10, x10, x9
+; CHECK-NOCPA-O0-NEXT: add x8, x8, x10
+; CHECK-NOCPA-O0-NEXT: subs x0, x8, x9
+; CHECK-NOCPA-O0-NEXT: add sp, sp, #32
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: arith2:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: sub sp, sp, #32
+; CHECK-NOCPA-O3-NEXT: .cfi_def_cfa_offset 32
+; CHECK-NOCPA-O3-NEXT: str w3, [sp, #4]
+; CHECK-NOCPA-O3-NEXT: mov w9, #48 // =0x30
+; CHECK-NOCPA-O3-NEXT: ldrsw x8, [sp, #4]
+; CHECK-NOCPA-O3-NEXT: stp x1, x0, [sp, #16]
+; CHECK-NOCPA-O3-NEXT: str x2, [sp, #8]
+; CHECK-NOCPA-O3-NEXT: madd x8, x8, x9, x0
+; CHECK-NOCPA-O3-NEXT: ldr x8, [x8, #24]
+; CHECK-NOCPA-O3-NEXT: madd x8, x1, x2, x8
+; CHECK-NOCPA-O3-NEXT: sub x0, x8, x2
+; CHECK-NOCPA-O3-NEXT: add sp, sp, #32
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%5 = alloca ptr, align 8
%6 = alloca i64, align 8
@@ -390,41 +641,58 @@ entry:
@b = hidden global i16 0, align 2
define hidden void @multidim() {
-; CHECK-CPA-O0-LABEL: multidim:
-; CHECK-CPA-O0: adrp x8, b
-; CHECK-CPA-O0: ldrh w9, [x8, :lo12:b]
-; CHECK-CPA-O0: mov w10, w9
-; CHECK-CPA-O0: ldrh w8, [x8, :lo12:b]
-; CHECK-CPA-O0: add w9, w8, #1
-; CHECK-CPA-O0: mov w8, w9
-; CHECK-CPA-O0: sxtw x9, w8
-; CHECK-CPA-O0: mov w8, #2 // =0x2
-; CHECK-CPA-O0: mov w11, w8
-; CHECK-CPA-O0: adrp x8, a
-; CHECK-CPA-O0: add x8, x8, :lo12:a
-; CHECK-CPA-O0: addpt x8, x8, x11
-; CHECK-CPA-O0: addpt x8, x8, x10, lsl #1
-; CHECK-CPA-O0: addpt x8, x8, x9
-; CHECK-CPA-O0: ldrb w8, [x8]
-;
-; CHECK-CPA-O3-LABEL: multidim:
-; CHECK-CPA-O3: ret
-;
-; CHECK-NOCPA-O0-LABEL: multidim:
-; CHECK-NOCPA-O0: adrp x8, b
-; CHECK-NOCPA-O0: ldrh w9, [x8, :lo12:b]
-; CHECK-NOCPA-O0: mov w10, w9
-; CHECK-NOCPA-O0: ldrh w8, [x8, :lo12:b]
-; CHECK-NOCPA-O0: add w9, w8, #1
-; CHECK-NOCPA-O0: adrp x8, a
-; CHECK-NOCPA-O0: add x8, x8, :lo12:a
-; CHECK-NOCPA-O0: add x8, x8, #2
-; CHECK-NOCPA-O0: add x8, x8, x10, lsl #1
-; CHECK-NOCPA-O0: add x8, x8, w9, sxtw
-; CHECK-NOCPA-O0: ldrb w8, [x8]
-;
-; CHECK-NOCPA-O3-LABEL: multidim:
-; CHECK-NOCPA-O3: ret
+; CHECK-CPA-O0-LABEL: multidim:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: adrp x8, b
+; CHECK-CPA-O0-NEXT: ldrh w9, [x8, :lo12:b]
+; CHECK-CPA-O0-NEXT: mov w10, w9
+; CHECK-CPA-O0-NEXT: ldrh w8, [x8, :lo12:b]
+; CHECK-CPA-O0-NEXT: add w9, w8, #1
+; CHECK-CPA-O0-NEXT: // implicit-def: $x8
+; CHECK-CPA-O0-NEXT: mov w8, w9
+; CHECK-CPA-O0-NEXT: sxtw x9, w8
+; CHECK-CPA-O0-NEXT: mov w8, #2 // =0x2
+; CHECK-CPA-O0-NEXT: mov w11, w8
+; CHECK-CPA-O0-NEXT: adrp x8, a
+; CHECK-CPA-O0-NEXT: add x8, x8, :lo12:a
+; CHECK-CPA-O0-NEXT: addpt x8, x8, x11
+; CHECK-CPA-O0-NEXT: addpt x8, x8, x10, lsl #1
+; CHECK-CPA-O0-NEXT: addpt x8, x8, x9
+; CHECK-CPA-O0-NEXT: ldrb w8, [x8]
+; CHECK-CPA-O0-NEXT: cbz w8, .LBB14_2
+; CHECK-CPA-O0-NEXT: b .LBB14_1
+; CHECK-CPA-O0-NEXT: .LBB14_1: // %if.then
+; CHECK-CPA-O0-NEXT: b .LBB14_2
+; CHECK-CPA-O0-NEXT: .LBB14_2: // %if.end
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: multidim:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: multidim:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: adrp x8, b
+; CHECK-NOCPA-O0-NEXT: ldrh w9, [x8, :lo12:b]
+; CHECK-NOCPA-O0-NEXT: mov w10, w9
+; CHECK-NOCPA-O0-NEXT: ldrh w8, [x8, :lo12:b]
+; CHECK-NOCPA-O0-NEXT: add w9, w8, #1
+; CHECK-NOCPA-O0-NEXT: adrp x8, a
+; CHECK-NOCPA-O0-NEXT: add x8, x8, :lo12:a
+; CHECK-NOCPA-O0-NEXT: add x8, x8, #2
+; CHECK-NOCPA-O0-NEXT: add x8, x8, x10, lsl #1
+; CHECK-NOCPA-O0-NEXT: add x8, x8, w9, sxtw
+; CHECK-NOCPA-O0-NEXT: ldrb w8, [x8]
+; CHECK-NOCPA-O0-NEXT: cbz w8, .LBB14_2
+; CHECK-NOCPA-O0-NEXT: b .LBB14_1
+; CHECK-NOCPA-O0-NEXT: .LBB14_1: // %if.then
+; CHECK-NOCPA-O0-NEXT: b .LBB14_2
+; CHECK-NOCPA-O0-NEXT: .LBB14_2: // %if.end
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: multidim:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%0 = load i16, ptr @b, align 2
%idxprom = zext i16 %0 to i64
diff --git a/llvm/test/CodeGen/AArch64/cpa-selectiondag.ll b/llvm/test/CodeGen/AArch64/cpa-selectiondag.ll
index b3080eabe6809..adca31bf47daa 100644
--- a/llvm/test/CodeGen/AArch64/cpa-selectiondag.ll
+++ b/llvm/test/CodeGen/AArch64/cpa-selectiondag.ll
@@ -1,3 +1,4 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=+cpa,cpa-codegen -O0 -global-isel=0 -fast-isel=0 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-CPA-O0
; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=+cpa,cpa-codegen -O3 -global-isel=0 -fast-isel=0 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-CPA-O3
; RUN: llc -mtriple=aarch64 -verify-machineinstrs --mattr=-cpa -O0 -global-isel=0 -fast-isel=0 %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK-NOCPA-O0
@@ -10,21 +11,38 @@
@array2 = external dso_local global [10 x %struct.my_type2], align 8
define void @addpt1(i64 %index, i64 %arg) {
-; CHECK-CPA-O0-LABEL: addpt1:
-; CHECK-CPA-O0: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
-; CHECK-CPA-O0: str x{{[0-9]+}}, [[[REG1]], #8]
-;
-; CHECK-CPA-O3-LABEL: addpt1:
-; CHECK-CPA-O3: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
-; CHECK-CPA-O3: str x{{[0-9]+}}, [[[REG1]], #8]
-;
-; CHECK-NOCPA-O0-LABEL: addpt1:
-; CHECK-NOCPA-O0: add [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
-; CHECK-NOCPA-O0: str x{{[0-9]+}}, [[[REG1]], #8]
+; CHECK-CPA-O0-LABEL: addpt1:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: adrp x8, array
+; CHECK-CPA-O0-NEXT: add x8, x8, :lo12:array
+; CHECK-CPA-O0-NEXT: addpt x8, x8, x0, lsl #4
+; CHECK-CPA-O0-NEXT: str x1, [x8, #8]
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: addpt1:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: adrp x8, array
+; CHECK-CPA-O3-NEXT: add x8, x8, :lo12:array
+; CHECK-CPA-O3-NEXT: addpt x8, x8, x0, lsl #4
+; CHECK-CPA-O3-NEXT: str x1, [x8, #8]
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: addpt1:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: adrp x8, array
+; CHECK-NOCPA-O0-NEXT: add x8, x8, :lo12:array
+; CHECK-NOCPA-O0-NEXT: add x8, x8, x0, lsl #4
+; CHECK-NOCPA-O0-NEXT: str x1, [x8, #8]
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: addpt1:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: adrp x8, array
+; CHECK-NOCPA-O3-NEXT: add x8, x8, :lo12:array
+; CHECK-NOCPA-O3-NEXT: add x8, x8, x0, lsl #4
+; CHECK-NOCPA-O3-NEXT: str x1, [x8, #8]
+; CHECK-NOCPA-O3-NEXT: ret
-; CHECK-NOCPA-O3-LABEL: addpt1:
-; CHECK-NOCPA-O3: add [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #4
-; CHECK-NOCPA-O3: str x{{[0-9]+}}, [[[REG1]], #8]
entry:
%e2 = getelementptr inbounds %struct.my_type, ptr @array, i64 %index, i32 1
store i64 %arg, ptr %e2, align 8
@@ -32,27 +50,63 @@ entry:
}
define void @maddpt1(i32 %pos, ptr %val) {
-; CHECK-CPA-O0-LABEL: maddpt1:
-; CHECK-CPA-O0: maddpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, x{{[0-9]+}}
-; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]], #32]
-; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]], #16]
-; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]]]
-;
-; CHECK-CPA-O3-LABEL: maddpt1:
-; CHECK-CPA-O3: maddpt [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, x{{[0-9]+}}
-; CHECK-CPA-O3: stp q{{[0-9]+}}, q{{[0-9]+}}, [[[REG1]], #16]
-; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]]]
-;
-; CHECK-NOCPA-O0-LABEL: maddpt1:
-; CHECK-NOCPA-O0: smaddl [[REG1:x[0-9]+]], w{{[0-9]+}}, w{{[0-9]+}}, x{{[0-9]+}}
-; CHECK-NOCPA-O0: str q{{[0-9]+}}, [[[REG1]], #32]
-; CHECK-NOCPA-O0: str q{{[0-9]+}}, [[[REG1]], #16]
-; CHECK-NOCPA-O0: str q{{[0-9]+}}, [[[REG1]]]
-;
-; CHECK-NOCPA-O3-LABEL: maddpt1:
-; CHECK-NOCPA-O3: smaddl [[REG1:x[0-9]+]], w{{[0-9]+}}, w{{[0-9]+}}, x{{[0-9]+}}
-; CHECK-NOCPA-O3: stp q{{[0-9]+}}, q{{[0-9]+}}, [[[REG1]], #16]
-; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]]]
+; CHECK-CPA-O0-LABEL: maddpt1:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: // implicit-def: $x8
+; CHECK-CPA-O0-NEXT: mov w8, w0
+; CHECK-CPA-O0-NEXT: sxtw x8, w8
+; CHECK-CPA-O0-NEXT: adrp x10, array2
+; CHECK-CPA-O0-NEXT: add x10, x10, :lo12:array2
+; CHECK-CPA-O0-NEXT: mov w9, #48 // =0x30
+; CHECK-CPA-O0-NEXT: // kill: def $x9 killed $w9
+; CHECK-CPA-O0-NEXT: maddpt x8, x8, x9, x10
+; CHECK-CPA-O0-NEXT: ldr q0, [x1]
+; CHECK-CPA-O0-NEXT: ldr q1, [x1, #16]
+; CHECK-CPA-O0-NEXT: ldr q2, [x1, #32]
+; CHECK-CPA-O0-NEXT: str q2, [x8, #32]
+; CHECK-CPA-O0-NEXT: str q1, [x8, #16]
+; CHECK-CPA-O0-NEXT: str q0, [x8]
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: maddpt1:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: // kill: def $w0 killed $w0 def $x0
+; CHECK-CPA-O3-NEXT: sxtw x9, w0
+; CHECK-CPA-O3-NEXT: ldp q1, q0, [x1, #16]
+; CHECK-CPA-O3-NEXT: mov w8, #48 // =0x30
+; CHECK-CPA-O3-NEXT: adrp x10, array2
+; CHECK-CPA-O3-NEXT: add x10, x10, :lo12:array2
+; CHECK-CPA-O3-NEXT: ldr q2, [x1]
+; CHECK-CPA-O3-NEXT: maddpt x8, x9, x8, x10
+; CHECK-CPA-O3-NEXT: stp q1, q0, [x8, #16]
+; CHECK-CPA-O3-NEXT: str q2, [x8]
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: maddpt1:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: adrp x9, array2
+; CHECK-NOCPA-O0-NEXT: add x9, x9, :lo12:array2
+; CHECK-NOCPA-O0-NEXT: mov w8, #48 // =0x30
+; CHECK-NOCPA-O0-NEXT: smaddl x8, w0, w8, x9
+; CHECK-NOCPA-O0-NEXT: ldr q0, [x1]
+; CHECK-NOCPA-O0-NEXT: ldr q1, [x1, #16]
+; CHECK-NOCPA-O0-NEXT: ldr q2, [x1, #32]
+; CHECK-NOCPA-O0-NEXT: str q2, [x8, #32]
+; CHECK-NOCPA-O0-NEXT: str q1, [x8, #16]
+; CHECK-NOCPA-O0-NEXT: str q0, [x8]
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: maddpt1:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: mov w8, #48 // =0x30
+; CHECK-NOCPA-O3-NEXT: adrp x9, array2
+; CHECK-NOCPA-O3-NEXT: add x9, x9, :lo12:array2
+; CHECK-NOCPA-O3-NEXT: smaddl x8, w0, w8, x9
+; CHECK-NOCPA-O3-NEXT: ldp q1, q0, [x1, #16]
+; CHECK-NOCPA-O3-NEXT: ldr q2, [x1]
+; CHECK-NOCPA-O3-NEXT: stp q1, q0, [x8, #16]
+; CHECK-NOCPA-O3-NEXT: str q2, [x8]
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%idxprom = sext i32 %pos to i64
%arrayidx = getelementptr inbounds [10 x %struct.my_type2], ptr @array2, i64 0, i64 %idxprom
@@ -61,34 +115,80 @@ entry:
}
define void @msubpt1(i32 %index, i32 %elem) {
-; CHECK-CPA-O0-LABEL: msubpt1:
-; CHECK-CPA-O0: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, [[REG1]]
-; CHECK-CPA-O0: addpt [[REG2:x[0-9]+]], x{{[0-9]+}}, [[REG2]]
-; CHECK-CPA-O0: ldr q{{[0-9]+}}, [[[REG2]], #16]
-; CHECK-CPA-O0: ldr q{{[0-9]+}}, [[[REG2]], #32]
-; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]], #32]
-; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]], #16]
-; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]]]
-;
-; CHECK-CPA-O3-LABEL: msubpt1:
-; CHECK-CPA-O3: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, [[REG1]]
-; CHECK-CPA-O3: ldp q{{[0-9]+}}, q{{[0-9]+}}, [[[REG1]], #16]
-; CHECK-CPA-O3: addpt [[REG2:x[0-9]+]], x{{[0-9]+}}, [[REG2]]
-; CHECK-CPA-O3: stp q{{[0-9]+}}, q{{[0-9]+}}, [[[REG2]], #16]
-; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG2]]]
-;
-; CHECK-NOCPA-O0-LABEL: msubpt1:
-; CHECK-NOCPA-O0: mneg [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}
-; CHECK-NOCPA-O0: add [[REG2:x[0-9]+]], x{{[0-9]+}}, [[REG1]]
-; CHECK-NOCPA-O0: str q{{[0-9]+}}, [[[REG2]], #320]
-; CHECK-NOCPA-O0: str q{{[0-9]+}}, [[[REG2]], #304]
-; CHECK-NOCPA-O0: str q{{[0-9]+}}, [[[REG2]], #288]
-;
-; CHECK-NOCPA-O3-LABEL: msubpt1:
-; CHECK-NOCPA-O3: mneg [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}
-; CHECK-NOCPA-O3: add [[REG2:x[0-9]+]], x{{[0-9]+}}, [[REG1]]
-; CHECK-NOCPA-O3: stp q{{[0-9]+}}, q{{[0-9]+}}, [[[REG2]], #304]
-; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG2]], #288]
+; CHECK-CPA-O0-LABEL: msubpt1:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: // implicit-def: $x8
+; CHECK-CPA-O0-NEXT: mov w8, w0
+; CHECK-CPA-O0-NEXT: sxtw x8, w8
+; CHECK-CPA-O0-NEXT: mov w9, #48 // =0x30
+; CHECK-CPA-O0-NEXT: // kill: def $x9 killed $w9
+; CHECK-CPA-O0-NEXT: mneg x8, x8, x9
+; CHECK-CPA-O0-NEXT: add x8, x8, #288
+; CHECK-CPA-O0-NEXT: adrp x9, array2
+; CHECK-CPA-O0-NEXT: add x9, x9, :lo12:array2
+; CHECK-CPA-O0-NEXT: addpt x8, x9, x8
+; CHECK-CPA-O0-NEXT: mov w10, #96 // =0x60
+; CHECK-CPA-O0-NEXT: // kill: def $x10 killed $w10
+; CHECK-CPA-O0-NEXT: addpt x10, x9, x10
+; CHECK-CPA-O0-NEXT: ldr q1, [x10, #16]
+; CHECK-CPA-O0-NEXT: ldr q2, [x10, #32]
+; CHECK-CPA-O0-NEXT: ldr q0, [x9, #96]
+; CHECK-CPA-O0-NEXT: str q2, [x8, #32]
+; CHECK-CPA-O0-NEXT: str q1, [x8, #16]
+; CHECK-CPA-O0-NEXT: str q0, [x8]
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: msubpt1:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: // kill: def $w0 killed $w0 def $x0
+; CHECK-CPA-O3-NEXT: sxtw x8, w0
+; CHECK-CPA-O3-NEXT: mov w9, #48 // =0x30
+; CHECK-CPA-O3-NEXT: adrp x10, array2
+; CHECK-CPA-O3-NEXT: add x10, x10, :lo12:array2
+; CHECK-CPA-O3-NEXT: mneg x8, x8, x9
+; CHECK-CPA-O3-NEXT: mov w9, #96 // =0x60
+; CHECK-CPA-O3-NEXT: ldr q2, [x10, #96]
+; CHECK-CPA-O3-NEXT: addpt x9, x10, x9
+; CHECK-CPA-O3-NEXT: ldp q1, q0, [x9, #16]
+; CHECK-CPA-O3-NEXT: add x8, x8, #288
+; CHECK-CPA-O3-NEXT: addpt x8, x10, x8
+; CHECK-CPA-O3-NEXT: stp q1, q0, [x8, #16]
+; CHECK-CPA-O3-NEXT: str q2, [x8]
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: msubpt1:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: // implicit-def: $x8
+; CHECK-NOCPA-O0-NEXT: mov w8, w0
+; CHECK-NOCPA-O0-NEXT: sxtw x8, w8
+; CHECK-NOCPA-O0-NEXT: mov w9, #48 // =0x30
+; CHECK-NOCPA-O0-NEXT: // kill: def $x9 killed $w9
+; CHECK-NOCPA-O0-NEXT: mneg x8, x8, x9
+; CHECK-NOCPA-O0-NEXT: adrp x9, array2
+; CHECK-NOCPA-O0-NEXT: add x9, x9, :lo12:array2
+; CHECK-NOCPA-O0-NEXT: add x8, x9, x8
+; CHECK-NOCPA-O0-NEXT: ldr q0, [x9, #96]
+; CHECK-NOCPA-O0-NEXT: ldr q1, [x9, #112]
+; CHECK-NOCPA-O0-NEXT: ldr q2, [x9, #128]
+; CHECK-NOCPA-O0-NEXT: str q2, [x8, #320]
+; CHECK-NOCPA-O0-NEXT: str q1, [x8, #304]
+; CHECK-NOCPA-O0-NEXT: str q0, [x8, #288]
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: msubpt1:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: // kill: def $w0 killed $w0 def $x0
+; CHECK-NOCPA-O3-NEXT: sxtw x8, w0
+; CHECK-NOCPA-O3-NEXT: mov w9, #48 // =0x30
+; CHECK-NOCPA-O3-NEXT: mneg x8, x8, x9
+; CHECK-NOCPA-O3-NEXT: adrp x9, array2
+; CHECK-NOCPA-O3-NEXT: add x9, x9, :lo12:array2
+; CHECK-NOCPA-O3-NEXT: ldp q1, q0, [x9, #112]
+; CHECK-NOCPA-O3-NEXT: ldr q2, [x9, #96]
+; CHECK-NOCPA-O3-NEXT: add x8, x9, x8
+; CHECK-NOCPA-O3-NEXT: stp q1, q0, [x8, #304]
+; CHECK-NOCPA-O3-NEXT: str q2, [x8, #288]
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%idx.ext = sext i32 %index to i64
%idx.neg = sub nsw i64 0, %idx.ext
@@ -98,21 +198,56 @@ entry:
}
define void @subpt1(i32 %index, i32 %elem) {
-; CHECK-CPA-O0-LABEL: subpt1:
-; CHECK-CPA-O0: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, [[REG1]]
-; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]]]
-;
-; CHECK-CPA-O3-LABEL: subpt1:
-; CHECK-CPA-O3: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, [[REG1]]
-; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]]]
-;
-; CHECK-NOCPA-O0-LABEL: subpt1:
-; CHECK-NOCPA-O0: subs [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #8
-; CHECK-NOCPA-O0: str q{{[0-9]+}}, [[[REG1]], #96]
-;
-; CHECK-NOCPA-O3-LABEL: subpt1:
-; CHECK-NOCPA-O3: sub [[REG1:x[0-9]+]], x{{[0-9]+}}, x{{[0-9]+}}, lsl #8
-; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]], #96]
+; CHECK-CPA-O0-LABEL: subpt1:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: // implicit-def: $x8
+; CHECK-CPA-O0-NEXT: mov w8, w0
+; CHECK-CPA-O0-NEXT: sxtw x9, w8
+; CHECK-CPA-O0-NEXT: mov w8, #96 // =0x60
+; CHECK-CPA-O0-NEXT: // kill: def $x8 killed $w8
+; CHECK-CPA-O0-NEXT: subs x8, x8, x9, lsl #8
+; CHECK-CPA-O0-NEXT: adrp x9, array
+; CHECK-CPA-O0-NEXT: add x9, x9, :lo12:array
+; CHECK-CPA-O0-NEXT: addpt x8, x9, x8
+; CHECK-CPA-O0-NEXT: ldr q0, [x9, #32]
+; CHECK-CPA-O0-NEXT: str q0, [x8]
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: subpt1:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: // kill: def $w0 killed $w0 def $x0
+; CHECK-CPA-O3-NEXT: sxtw x8, w0
+; CHECK-CPA-O3-NEXT: mov w9, #96 // =0x60
+; CHECK-CPA-O3-NEXT: sub x8, x9, x8, lsl #8
+; CHECK-CPA-O3-NEXT: adrp x9, array
+; CHECK-CPA-O3-NEXT: add x9, x9, :lo12:array
+; CHECK-CPA-O3-NEXT: ldr q0, [x9, #32]
+; CHECK-CPA-O3-NEXT: addpt x8, x9, x8
+; CHECK-CPA-O3-NEXT: str q0, [x8]
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: subpt1:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: // implicit-def: $x8
+; CHECK-NOCPA-O0-NEXT: mov w8, w0
+; CHECK-NOCPA-O0-NEXT: sxtw x8, w8
+; CHECK-NOCPA-O0-NEXT: adrp x9, array
+; CHECK-NOCPA-O0-NEXT: add x9, x9, :lo12:array
+; CHECK-NOCPA-O0-NEXT: subs x8, x9, x8, lsl #8
+; CHECK-NOCPA-O0-NEXT: ldr q0, [x9, #32]
+; CHECK-NOCPA-O0-NEXT: str q0, [x8, #96]
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: subpt1:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: // kill: def $w0 killed $w0 def $x0
+; CHECK-NOCPA-O3-NEXT: sxtw x9, w0
+; CHECK-NOCPA-O3-NEXT: adrp x8, array
+; CHECK-NOCPA-O3-NEXT: add x8, x8, :lo12:array
+; CHECK-NOCPA-O3-NEXT: ldr q0, [x8, #32]
+; CHECK-NOCPA-O3-NEXT: sub x9, x8, x9, lsl #8
+; CHECK-NOCPA-O3-NEXT: str q0, [x9, #96]
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%conv = sext i32 %index to i64
%mul.neg = mul nsw i64 %conv, -16
@@ -122,21 +257,46 @@ entry:
}
define void @subpt2(i32 %index, i32 %elem) {
-; CHECK-CPA-O0-LABEL: subpt2:
-; CHECK-CPA-O0: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, [[REG1]]
-; CHECK-CPA-O0: str q{{[0-9]+}}, [[[REG1]]]
-;
-; CHECK-CPA-O3-LABEL: subpt2:
-; CHECK-CPA-O3: addpt [[REG1:x[0-9]+]], x{{[0-9]+}}, [[REG1]]
-; CHECK-CPA-O3: str q{{[0-9]+}}, [[[REG1]]]
-;
-; CHECK-NOCPA-O0-LABEL: subpt2:
-; CHECK-NOCPA-O0: subs [[REG1:x[0-9]+]], x{{[0-9]+}}, w{{[0-9]+}}, sxtw #4
-; CHECK-NOCPA-O0: str q{{[0-9]+}}, [[[REG1]], #96]
-;
-; CHECK-NOCPA-O3-LABEL: subpt2:
-; CHECK-NOCPA-O3: sub [[REG1:x[0-9]+]], x{{[0-9]+}}, w{{[0-9]+}}, sxtw #4
-; CHECK-NOCPA-O3: str q{{[0-9]+}}, [[[REG1]], #96]
+; CHECK-CPA-O0-LABEL: subpt2:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: mov w8, #96 // =0x60
+; CHECK-CPA-O0-NEXT: // kill: def $x8 killed $w8
+; CHECK-CPA-O0-NEXT: subs x8, x8, w0, sxtw #4
+; CHECK-CPA-O0-NEXT: adrp x9, array
+; CHECK-CPA-O0-NEXT: add x9, x9, :lo12:array
+; CHECK-CPA-O0-NEXT: addpt x8, x9, x8
+; CHECK-CPA-O0-NEXT: ldr q0, [x9, #32]
+; CHECK-CPA-O0-NEXT: str q0, [x8]
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: subpt2:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: mov w8, #96 // =0x60
+; CHECK-CPA-O3-NEXT: adrp x9, array
+; CHECK-CPA-O3-NEXT: add x9, x9, :lo12:array
+; CHECK-CPA-O3-NEXT: sub x8, x8, w0, sxtw #4
+; CHECK-CPA-O3-NEXT: ldr q0, [x9, #32]
+; CHECK-CPA-O3-NEXT: addpt x8, x9, x8
+; CHECK-CPA-O3-NEXT: str q0, [x8]
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: subpt2:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: adrp x9, array
+; CHECK-NOCPA-O0-NEXT: add x9, x9, :lo12:array
+; CHECK-NOCPA-O0-NEXT: subs x8, x9, w0, sxtw #4
+; CHECK-NOCPA-O0-NEXT: ldr q0, [x9, #32]
+; CHECK-NOCPA-O0-NEXT: str q0, [x8, #96]
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: subpt2:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: adrp x8, array
+; CHECK-NOCPA-O3-NEXT: add x8, x8, :lo12:array
+; CHECK-NOCPA-O3-NEXT: sub x9, x8, w0, sxtw #4
+; CHECK-NOCPA-O3-NEXT: ldr q0, [x8, #32]
+; CHECK-NOCPA-O3-NEXT: str q0, [x9, #96]
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%idx.ext = sext i32 %index to i64
%idx.neg = sub nsw i64 0, %idx.ext
@@ -146,178 +306,234 @@ entry:
}
define ptr @subpt3(ptr %ptr, i32 %index) {
-; CHECK-CPA-O0-LABEL: subpt3:
-; CHECK-CPA-O0: mov [[REG1:x[0-9]+]], #-8
-; CHECK-CPA-O0: addpt x0, x{{[0-9]+}}, [[REG1]]
-; CHECK-CPA-O0: ret
-;
-; CHECK-CPA-O3-LABEL: subpt3:
-; CHECK-CPA-O3: mov [[REG1:x[0-9]+]], #-8
-; CHECK-CPA-O3: addpt x0, x{{[0-9]+}}, [[REG1]]
-; CHECK-CPA-O3: ret
-;
-; CHECK-NOCPA-O0-LABEL: subpt3:
-; CHECK-NOCPA-O0: subs x0, x{{[0-9]+}}, #8
-; CHECK-NOCPA-O0: ret
-;
-; CHECK-NOCPA-O3-LABEL: subpt3:
-; CHECK-NOCPA-O3: sub x0, x{{[0-9]+}}, #8
-; CHECK-NOCPA-O3: ret
+; CHECK-CPA-O0-LABEL: subpt3:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: mov x8, #-8 // =0xfffffffffffffff8
+; CHECK-CPA-O0-NEXT: addpt x0, x0, x8
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: subpt3:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: mov x8, #-8 // =0xfffffffffffffff8
+; CHECK-CPA-O3-NEXT: addpt x0, x0, x8
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: subpt3:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: subs x0, x0, #8
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: subpt3:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: sub x0, x0, #8
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%incdec.ptr.i.i.i = getelementptr inbounds i64, ptr %ptr, i64 -1
ret ptr %incdec.ptr.i.i.i
}
define i64 @subi64(i64 %ptr, i32 %index) {
-; CHECK-CPA-O0-LABEL: subi64:
-; CHECK-CPA-O0: subs x0, x0, #1
-; CHECK-CPA-O0: ret
-;
-; CHECK-CPA-O3-LABEL: subi64:
-; CHECK-CPA-O3: sub x0, x0, #1
-; CHECK-CPA-O3: ret
-;
-; CHECK-NOCPA-O0-LABEL: subi64:
-; CHECK-NOCPA-O0: subs x0, x0, #1
-; CHECK-NOCPA-O0: ret
-;
-; CHECK-NOCPA-O3-LABEL: subi64:
-; CHECK-NOCPA-O3: sub x0, x0, #1
-; CHECK-NOCPA-O3: ret
+; CHECK-CPA-O0-LABEL: subi64:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: subs x0, x0, #1
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: subi64:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: sub x0, x0, #1
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: subi64:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: subs x0, x0, #1
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: subi64:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: sub x0, x0, #1
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%incdec.ptr.i.i.i = add i64 %ptr, -1
ret i64 %incdec.ptr.i.i.i
}
define i32 @subi32(i32 %ptr, i32 %index) {
-; CHECK-CPA-O0-LABEL: subi32:
-; CHECK-CPA-O0: subs w0, w0, #1
-; CHECK-CPA-O0: ret
-;
-; CHECK-CPA-O3-LABEL: subi32:
-; CHECK-CPA-O3: sub w0, w0, #1
-; CHECK-CPA-O3: ret
-;
-; CHECK-NOCPA-O0-LABEL: subi32:
-; CHECK-NOCPA-O0: subs w0, w0, #1
-; CHECK-NOCPA-O0: ret
-;
-; CHECK-NOCPA-O3-LABEL: subi32:
-; CHECK-NOCPA-O3: sub w0, w0, #1
-; CHECK-NOCPA-O3: ret
+; CHECK-CPA-O0-LABEL: subi32:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: subs w0, w0, #1
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: subi32:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: sub w0, w0, #1
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: subi32:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: subs w0, w0, #1
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: subi32:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: sub w0, w0, #1
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%incdec.ptr.i.i.i = add i32 %ptr, -1
ret i32 %incdec.ptr.i.i.i
}
define i16 @subi16(i16 %ptr, i32 %index) {
-; CHECK-CPA-O0-LABEL: subi16:
-; CHECK-CPA-O0: subs w0, w0, #1
-; CHECK-CPA-O0: ret
-;
-; CHECK-CPA-O3-LABEL: subi16:
-; CHECK-CPA-O3: sub w0, w0, #1
-; CHECK-CPA-O3: ret
-;
-; CHECK-NOCPA-O0-LABEL: subi16:
-; CHECK-NOCPA-O0: subs w0, w0, #1
-; CHECK-NOCPA-O0: ret
-;
-; CHECK-NOCPA-O3-LABEL: subi16:
-; CHECK-NOCPA-O3: sub w0, w0, #1
-; CHECK-NOCPA-O3: ret
+; CHECK-CPA-O0-LABEL: subi16:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: subs w0, w0, #1
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: subi16:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: sub w0, w0, #1
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: subi16:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: subs w0, w0, #1
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: subi16:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: sub w0, w0, #1
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%incdec.ptr.i.i.i = add i16 %ptr, -1
ret i16 %incdec.ptr.i.i.i
}
define i64 @addi64(i64 %ptr, i32 %index) {
-; CHECK-CPA-O0-LABEL: addi64:
-; CHECK-CPA-O0: add x0, x0, #1
-; CHECK-CPA-O0: ret
-;
-; CHECK-CPA-O3-LABEL: addi64:
-; CHECK-CPA-O3: add x0, x0, #1
-; CHECK-CPA-O3: ret
-;
-; CHECK-NOCPA-O0-LABEL: addi64:
-; CHECK-NOCPA-O0: add x0, x0, #1
-; CHECK-NOCPA-O0: ret
-;
-; CHECK-NOCPA-O3-LABEL: addi64:
-; CHECK-NOCPA-O3: add x0, x0, #1
-; CHECK-NOCPA-O3: ret
+; CHECK-CPA-O0-LABEL: addi64:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: add x0, x0, #1
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: addi64:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: add x0, x0, #1
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: addi64:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: add x0, x0, #1
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: addi64:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: add x0, x0, #1
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%incdec.ptr.i.i.i = add i64 %ptr, 1
ret i64 %incdec.ptr.i.i.i
}
define i32 @addi32(i32 %ptr, i32 %index) {
-; CHECK-CPA-O0-LABEL: addi32:
-; CHECK-CPA-O0: add w0, w0, #1
-; CHECK-CPA-O0: ret
-;
-; CHECK-CPA-O3-LABEL: addi32:
-; CHECK-CPA-O3: add w0, w0, #1
-; CHECK-CPA-O3: ret
-;
-; CHECK-NOCPA-O0-LABEL: addi32:
-; CHECK-NOCPA-O0: add w0, w0, #1
-; CHECK-NOCPA-O0: ret
-;
-; CHECK-NOCPA-O3-LABEL: addi32:
-; CHECK-NOCPA-O3: add w0, w0, #1
-; CHECK-NOCPA-O3: ret
+; CHECK-CPA-O0-LABEL: addi32:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: add w0, w0, #1
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: addi32:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: add w0, w0, #1
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: addi32:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: add w0, w0, #1
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: addi32:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: add w0, w0, #1
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%incdec.ptr.i.i.i = add i32 %ptr, 1
ret i32 %incdec.ptr.i.i.i
}
define i16 @addi16(i16 %ptr, i32 %index) {
-; CHECK-CPA-O0-LABEL: addi16:
-; CHECK-CPA-O0: add w0, w0, #1
-; CHECK-CPA-O0: ret
-;
-; CHECK-CPA-O3-LABEL: addi16:
-; CHECK-CPA-O3: add w0, w0, #1
-; CHECK-CPA-O3: ret
-;
-; CHECK-NOCPA-O0-LABEL: addi16:
-; CHECK-NOCPA-O0: add w0, w0, #1
-; CHECK-NOCPA-O0: ret
-;
-; CHECK-NOCPA-O3-LABEL: addi16:
-; CHECK-NOCPA-O3: add w0, w0, #1
-; CHECK-NOCPA-O3: ret
+; CHECK-CPA-O0-LABEL: addi16:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: add w0, w0, #1
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: addi16:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: add w0, w0, #1
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: addi16:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: add w0, w0, #1
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: addi16:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: add w0, w0, #1
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%incdec.ptr.i.i.i = add i16 %ptr, 1
ret i16 %incdec.ptr.i.i.i
}
define i64 @arith1(i64 noundef %0, i64 noundef %1, i64 noundef %2) {
-; CHECK-CPA-O0-LABEL: arith1:
-; CHECK-CPA-O0: mul x9, x9, x10
-; CHECK-CPA-O0: add x0, x8, x9
-; CHECK-CPA-O0: add sp, sp, #32
-; CHECK-CPA-O0: ret
-;
-; CHECK-CPA-O3-LABEL: arith1:
-; CHECK-CPA-O3: madd x8, x1, x2, x0
-; CHECK-CPA-O3: mov x0, x8
-; CHECK-CPA-O3: add sp, sp, #32
-; CHECK-CPA-O3: ret
-;
-; CHECK-NOCPA-O0-LABEL: arith1:
-; CHECK-NOCPA-O0: mul x9, x9, x10
-; CHECK-NOCPA-O0: add x0, x8, x9
-; CHECK-NOCPA-O0: add sp, sp, #32
-; CHECK-NOCPA-O0: ret
-;
-; CHECK-NOCPA-O3-LABEL: arith1:
-; CHECK-NOCPA-O3: madd x8, x1, x2, x0
-; CHECK-NOCPA-O3: mov x0, x8
-; CHECK-NOCPA-O3: add sp, sp, #32
-; CHECK-NOCPA-O3: ret
+; CHECK-CPA-O0-LABEL: arith1:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: sub sp, sp, #32
+; CHECK-CPA-O0-NEXT: .cfi_def_cfa_offset 32
+; CHECK-CPA-O0-NEXT: str x0, [sp, #24]
+; CHECK-CPA-O0-NEXT: str x1, [sp, #16]
+; CHECK-CPA-O0-NEXT: str x2, [sp, #8]
+; CHECK-CPA-O0-NEXT: ldr x8, [sp, #24]
+; CHECK-CPA-O0-NEXT: ldr x9, [sp, #16]
+; CHECK-CPA-O0-NEXT: ldr x10, [sp, #8]
+; CHECK-CPA-O0-NEXT: mul x9, x9, x10
+; CHECK-CPA-O0-NEXT: add x0, x8, x9
+; CHECK-CPA-O0-NEXT: add sp, sp, #32
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: arith1:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: sub sp, sp, #32
+; CHECK-CPA-O3-NEXT: .cfi_def_cfa_offset 32
+; CHECK-CPA-O3-NEXT: madd x8, x1, x2, x0
+; CHECK-CPA-O3-NEXT: stp x1, x0, [sp, #16]
+; CHECK-CPA-O3-NEXT: str x2, [sp, #8]
+; CHECK-CPA-O3-NEXT: mov x0, x8
+; CHECK-CPA-O3-NEXT: add sp, sp, #32
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: arith1:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: sub sp, sp, #32
+; CHECK-NOCPA-O0-NEXT: .cfi_def_cfa_offset 32
+; CHECK-NOCPA-O0-NEXT: str x0, [sp, #24]
+; CHECK-NOCPA-O0-NEXT: str x1, [sp, #16]
+; CHECK-NOCPA-O0-NEXT: str x2, [sp, #8]
+; CHECK-NOCPA-O0-NEXT: ldr x8, [sp, #24]
+; CHECK-NOCPA-O0-NEXT: ldr x9, [sp, #16]
+; CHECK-NOCPA-O0-NEXT: ldr x10, [sp, #8]
+; CHECK-NOCPA-O0-NEXT: mul x9, x9, x10
+; CHECK-NOCPA-O0-NEXT: add x0, x8, x9
+; CHECK-NOCPA-O0-NEXT: add sp, sp, #32
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: arith1:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: sub sp, sp, #32
+; CHECK-NOCPA-O3-NEXT: .cfi_def_cfa_offset 32
+; CHECK-NOCPA-O3-NEXT: madd x8, x1, x2, x0
+; CHECK-NOCPA-O3-NEXT: stp x1, x0, [sp, #16]
+; CHECK-NOCPA-O3-NEXT: str x2, [sp, #8]
+; CHECK-NOCPA-O3-NEXT: mov x0, x8
+; CHECK-NOCPA-O3-NEXT: add sp, sp, #32
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%4 = alloca i64, align 8
%5 = alloca i64, align 8
@@ -334,39 +550,82 @@ entry:
}
define i64 @arith2(ptr noundef %0, i64 noundef %1, i64 noundef %2, i32 noundef %3) {
-; CHECK-CPA-O0-LABEL: arith2:
-; CHECK-CPA-O0: add x9, x9, x9, lsl #1
-; CHECK-CPA-O0: addpt x8, x8, x9, lsl #4
-; CHECK-CPA-O0: ldr x8, [x8, #24]
-; CHECK-CPA-O0: mul x10, x10, x9
-; CHECK-CPA-O0: add x8, x8, x10
-; CHECK-CPA-O0: subs x0, x8, x9
-; CHECK-CPA-O0: add sp, sp, #32
-; CHECK-CPA-O0: ret
-;
-; CHECK-CPA-O3-LABEL: arith2:
-; CHECK-CPA-O3: mov w9, #48 // =0x30
-; CHECK-CPA-O3: maddpt x8, x8, x9, x0
-; CHECK-CPA-O3: ldr x8, [x8, #24]
-; CHECK-CPA-O3: madd x8, x1, x2, x8
-; CHECK-CPA-O3: sub x0, x8, x2
-; CHECK-CPA-O3: ret
-;
-; CHECK-NOCPA-O0-LABEL: arith2:
-; CHECK-NOCPA-O0: smaddl x8, w8, w9, x10
-; CHECK-NOCPA-O0: mul x10, x10, x9
-; CHECK-NOCPA-O0: add x8, x8, x10
-; CHECK-NOCPA-O0: subs x0, x8, x9
-; CHECK-NOCPA-O0: add sp, sp, #32
-; CHECK-NOCPA-O0: ret
-;
-; CHECK-NOCPA-O3-LABEL: arith2:
-; CHECK-NOCPA-O3: smaddl x8, w3, w8, x0
-; CHECK-NOCPA-O3: ldr x8, [x8, #24]
-; CHECK-NOCPA-O3: madd x8, x1, x2, x8
-; CHECK-NOCPA-O3: sub x0, x8, x2
-; CHECK-NOCPA-O3: add sp, sp, #32
-; CHECK-NOCPA-O3: ret
+; CHECK-CPA-O0-LABEL: arith2:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: sub sp, sp, #32
+; CHECK-CPA-O0-NEXT: .cfi_def_cfa_offset 32
+; CHECK-CPA-O0-NEXT: str x0, [sp, #24]
+; CHECK-CPA-O0-NEXT: str x1, [sp, #16]
+; CHECK-CPA-O0-NEXT: str x2, [sp, #8]
+; CHECK-CPA-O0-NEXT: str w3, [sp, #4]
+; CHECK-CPA-O0-NEXT: ldr x8, [sp, #24]
+; CHECK-CPA-O0-NEXT: ldrsw x9, [sp, #4]
+; CHECK-CPA-O0-NEXT: add x9, x9, x9, lsl #1
+; CHECK-CPA-O0-NEXT: addpt x8, x8, x9, lsl #4
+; CHECK-CPA-O0-NEXT: ldr x8, [x8, #24]
+; CHECK-CPA-O0-NEXT: ldr x10, [sp, #16]
+; CHECK-CPA-O0-NEXT: ldr x9, [sp, #8]
+; CHECK-CPA-O0-NEXT: mul x10, x10, x9
+; CHECK-CPA-O0-NEXT: add x8, x8, x10
+; CHECK-CPA-O0-NEXT: subs x0, x8, x9
+; CHECK-CPA-O0-NEXT: add sp, sp, #32
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: arith2:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: sub sp, sp, #32
+; CHECK-CPA-O3-NEXT: .cfi_def_cfa_offset 32
+; CHECK-CPA-O3-NEXT: // kill: def $w3 killed $w3 def $x3
+; CHECK-CPA-O3-NEXT: sxtw x8, w3
+; CHECK-CPA-O3-NEXT: mov w9, #48 // =0x30
+; CHECK-CPA-O3-NEXT: stp x1, x0, [sp, #16]
+; CHECK-CPA-O3-NEXT: str x2, [sp, #8]
+; CHECK-CPA-O3-NEXT: maddpt x8, x8, x9, x0
+; CHECK-CPA-O3-NEXT: str w3, [sp, #4]
+; CHECK-CPA-O3-NEXT: ldr x8, [x8, #24]
+; CHECK-CPA-O3-NEXT: madd x8, x1, x2, x8
+; CHECK-CPA-O3-NEXT: sub x0, x8, x2
+; CHECK-CPA-O3-NEXT: add sp, sp, #32
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: arith2:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: sub sp, sp, #32
+; CHECK-NOCPA-O0-NEXT: .cfi_def_cfa_offset 32
+; CHECK-NOCPA-O0-NEXT: str x0, [sp, #24]
+; CHECK-NOCPA-O0-NEXT: str x1, [sp, #16]
+; CHECK-NOCPA-O0-NEXT: str x2, [sp, #8]
+; CHECK-NOCPA-O0-NEXT: str w3, [sp, #4]
+; CHECK-NOCPA-O0-NEXT: ldr x10, [sp, #24]
+; CHECK-NOCPA-O0-NEXT: ldrsw x8, [sp, #4]
+; CHECK-NOCPA-O0-NEXT: mov w9, #48 // =0x30
+; CHECK-NOCPA-O0-NEXT: mov w0, w9
+; CHECK-NOCPA-O0-NEXT: mov w9, w0
+; CHECK-NOCPA-O0-NEXT: // kill: def $w8 killed $w8 killed $x8
+; CHECK-NOCPA-O0-NEXT: smaddl x8, w8, w9, x10
+; CHECK-NOCPA-O0-NEXT: ldr x8, [x8, #24]
+; CHECK-NOCPA-O0-NEXT: ldr x10, [sp, #16]
+; CHECK-NOCPA-O0-NEXT: ldr x9, [sp, #8]
+; CHECK-NOCPA-O0-NEXT: mul x10, x10, x9
+; CHECK-NOCPA-O0-NEXT: add x8, x8, x10
+; CHECK-NOCPA-O0-NEXT: subs x0, x8, x9
+; CHECK-NOCPA-O0-NEXT: add sp, sp, #32
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: arith2:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: sub sp, sp, #32
+; CHECK-NOCPA-O3-NEXT: .cfi_def_cfa_offset 32
+; CHECK-NOCPA-O3-NEXT: mov w8, #48 // =0x30
+; CHECK-NOCPA-O3-NEXT: stp x1, x0, [sp, #16]
+; CHECK-NOCPA-O3-NEXT: smaddl x8, w3, w8, x0
+; CHECK-NOCPA-O3-NEXT: str x2, [sp, #8]
+; CHECK-NOCPA-O3-NEXT: str w3, [sp, #4]
+; CHECK-NOCPA-O3-NEXT: ldr x8, [x8, #24]
+; CHECK-NOCPA-O3-NEXT: madd x8, x1, x2, x8
+; CHECK-NOCPA-O3-NEXT: sub x0, x8, x2
+; CHECK-NOCPA-O3-NEXT: add sp, sp, #32
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%5 = alloca ptr, align 8
%6 = alloca i64, align 8
@@ -394,33 +653,52 @@ entry:
@b = hidden global i16 0, align 2
define hidden void @multidim() {
-; CHECK-CPA-O0-LABEL: multidim:
-; CHECK-CPA-O0: adrp x8, b
-; CHECK-CPA-O0: ldrh w10, [x8, :lo12:b]
-; CHECK-CPA-O0: adrp x8, a
-; CHECK-CPA-O0: add x8, x8, :lo12:a
-; CHECK-CPA-O0: add w9, w10, #1
-; CHECK-CPA-O0: mov w9, w9
-; CHECK-CPA-O0: add x9, x9, w10, uxtw #1
-; CHECK-CPA-O0: addpt x8, x8, x9
-; CHECK-CPA-O0: ldrb w8, [x8]
-;
-; CHECK-CPA-O3-LABEL: multidim:
-; CHECK-CPA-O3: ret
-;
-; CHECK-NOCPA-O0-LABEL: multidim:
-; CHECK-NOCPA-O0: adrp x8, b
-; CHECK-NOCPA-O0: ldrh w9, [x8, :lo12:b]
-; CHECK-NOCPA-O0: adrp x8, a
-; CHECK-NOCPA-O0: add x8, x8, :lo12:a
-; CHECK-NOCPA-O0: add x8, x8, w9, uxtw #1
-; CHECK-NOCPA-O0: add w9, w9, #1
-; CHECK-NOCPA-O0: mov w9, w9
-; CHECK-NOCPA-O0: add x8, x8, x9
-; CHECK-NOCPA-O0: ldrb w8, [x8, #2]
-;
-; CHECK-NOCPA-O3-LABEL: multidim:
-; CHECK-NOCPA-O3: ret
+; CHECK-CPA-O0-LABEL: multidim:
+; CHECK-CPA-O0: // %bb.0: // %entry
+; CHECK-CPA-O0-NEXT: adrp x8, b
+; CHECK-CPA-O0-NEXT: ldrh w10, [x8, :lo12:b]
+; CHECK-CPA-O0-NEXT: adrp x8, a
+; CHECK-CPA-O0-NEXT: add x8, x8, :lo12:a
+; CHECK-CPA-O0-NEXT: add w9, w10, #1
+; CHECK-CPA-O0-NEXT: mov w9, w9
+; CHECK-CPA-O0-NEXT: // kill: def $x9 killed $w9
+; CHECK-CPA-O0-NEXT: add x9, x9, w10, uxtw #1
+; CHECK-CPA-O0-NEXT: add x9, x9, #2
+; CHECK-CPA-O0-NEXT: addpt x8, x8, x9
+; CHECK-CPA-O0-NEXT: ldrb w8, [x8]
+; CHECK-CPA-O0-NEXT: cbz w8, .LBB14_2
+; CHECK-CPA-O0-NEXT: b .LBB14_1
+; CHECK-CPA-O0-NEXT: .LBB14_1: // %if.then
+; CHECK-CPA-O0-NEXT: b .LBB14_2
+; CHECK-CPA-O0-NEXT: .LBB14_2: // %if.end
+; CHECK-CPA-O0-NEXT: ret
+;
+; CHECK-CPA-O3-LABEL: multidim:
+; CHECK-CPA-O3: // %bb.0: // %entry
+; CHECK-CPA-O3-NEXT: ret
+;
+; CHECK-NOCPA-O0-LABEL: multidim:
+; CHECK-NOCPA-O0: // %bb.0: // %entry
+; CHECK-NOCPA-O0-NEXT: adrp x8, b
+; CHECK-NOCPA-O0-NEXT: ldrh w9, [x8, :lo12:b]
+; CHECK-NOCPA-O0-NEXT: adrp x8, a
+; CHECK-NOCPA-O0-NEXT: add x8, x8, :lo12:a
+; CHECK-NOCPA-O0-NEXT: add x8, x8, w9, uxtw #1
+; CHECK-NOCPA-O0-NEXT: add w9, w9, #1
+; CHECK-NOCPA-O0-NEXT: mov w9, w9
+; CHECK-NOCPA-O0-NEXT: // kill: def $x9 killed $w9
+; CHECK-NOCPA-O0-NEXT: add x8, x8, x9
+; CHECK-NOCPA-O0-NEXT: ldrb w8, [x8, #2]
+; CHECK-NOCPA-O0-NEXT: cbz w8, .LBB14_2
+; CHECK-NOCPA-O0-NEXT: b .LBB14_1
+; CHECK-NOCPA-O0-NEXT: .LBB14_1: // %if.then
+; CHECK-NOCPA-O0-NEXT: b .LBB14_2
+; CHECK-NOCPA-O0-NEXT: .LBB14_2: // %if.end
+; CHECK-NOCPA-O0-NEXT: ret
+;
+; CHECK-NOCPA-O3-LABEL: multidim:
+; CHECK-NOCPA-O3: // %bb.0: // %entry
+; CHECK-NOCPA-O3-NEXT: ret
entry:
%0 = load i16, ptr @b, align 2
%idxprom = zext i16 %0 to i64
>From 0935a57a9890ca4198ae2d2a39ce30a704e03870 Mon Sep 17 00:00:00 2001
From: Rodolfo Wottrich <rodolfo.wottrich at arm.com>
Date: Wed, 18 Jun 2025 13:12:52 +0000
Subject: [PATCH 15/19] Fix minor typo
---
llvm/include/llvm/CodeGen/ISDOpcodes.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index 9c7548fa6a549..465e4a0a9d0d8 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -1522,7 +1522,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,
>From df8a3807fa8fee69587bedebe69e458d190acd02 Mon Sep 17 00:00:00 2001
From: Rodolfo Wottrich <rodolfo.wottrich at arm.com>
Date: Wed, 18 Jun 2025 13:27:51 +0000
Subject: [PATCH 16/19] Fix botched merge from upstream
---
llvm/include/llvm/Target/TargetMachine.h | 5 -
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 99 +------------------
.../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 11 +--
.../SelectionDAG/SelectionDAGBuilder.cpp | 3 +-
4 files changed, 7 insertions(+), 111 deletions(-)
diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h
index a9612be7cdf60..b286efdea3c19 100644
--- a/llvm/include/llvm/Target/TargetMachine.h
+++ b/llvm/include/llvm/Target/TargetMachine.h
@@ -469,11 +469,6 @@ class LLVM_ABI 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/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index ef09c504a57a9..5610c6ee9ea32 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -1104,7 +1104,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 (!N0.isAnyAdd())
return false;
// Check for vscale addressing modes.
@@ -1861,7 +1861,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);
@@ -2399,7 +2398,7 @@ static bool canFoldInAddressingMode(SDNode *N, SDNode *Use, SelectionDAG &DAG,
}
TargetLowering::AddrMode AM;
- if (N->getOpcode() == ISD::ADD || N->getOpcode() == ISD::PTRADD) {
+ if (N->isAnyAdd()) {
AM.HasBaseReg = true;
ConstantSDNode *Offset = dyn_cast<ConstantSDNode>(N->getOperand(1));
if (Offset)
@@ -2632,100 +2631,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.
-/// 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 3e2f9fa0bc259..b0e3f534e2aaa 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -5649,8 +5649,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));
+ (Op.isAnyAdd() || isADDLike(Op));
}
bool SelectionDAG::isKnownNeverNaN(SDValue Op, bool SNaN,
@@ -8202,12 +8201,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())) {
- return getNode(ISD::ADD, DL, BasePtrVT, Ptr, Offset, Flags);
- } else {
+ 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.
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index c2a03fda2adc6..ec0c5473b0db0 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -9250,8 +9250,7 @@ bool SelectionDAGBuilder::visitMemPCpyCall(const CallInst &I) {
Size = DAG.getSExtOrTrunc(Size, sdl, Dst.getValueType());
// Adjust return pointer to point just past the last dst byte.
- SDNodeFlags Flags;
- SDValue DstPlusSize = DAG.getMemBasePlusOffset(Dst, Size, sdl, Flags);
+ SDValue DstPlusSize = DAG.getMemBasePlusOffset(Dst, Size, sdl);
setValue(&I, DstPlusSize);
return true;
}
>From 1a7982e24572eeebc0e815a08843f819acca7faa Mon Sep 17 00:00:00 2001
From: Rodolfo Wottrich <rodolfo.wottrich at arm.com>
Date: Wed, 18 Jun 2025 13:29:34 +0000
Subject: [PATCH 17/19] Fix remaining botched merge from upstream
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 5610c6ee9ea32..934199e414c7b 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -421,7 +421,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);
>From d049ea51427b3dac3579d758a81fc7b45aae1781 Mon Sep 17 00:00:00 2001
From: Rodolfo Wottrich <rodolfo.wottrich at arm.com>
Date: Wed, 18 Jun 2025 15:28:17 +0000
Subject: [PATCH 18/19] Adapt FEAT_CPA SDAG/GISel to shouldPreservePtrArith in
targetLowering
---
.../Target/AArch64/AArch64ISelLowering.cpp | 5 +
llvm/lib/Target/AArch64/AArch64ISelLowering.h | 4 +
.../Target/AArch64/AArch64TargetMachine.cpp | 4 -
.../lib/Target/AArch64/AArch64TargetMachine.h | 4 -
.../GISel/AArch64InstructionSelector.cpp | 6 +-
llvm/test/CodeGen/AArch64/cpa-selectiondag.ll | 99 +++++++++++--------
6 files changed, 69 insertions(+), 53 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 1169efce3123f..45e0e055463dc 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -30416,3 +30416,8 @@ bool AArch64TargetLowering::isTypeDesirableForOp(unsigned Opc, EVT VT) const {
return TargetLowering::isTypeDesirableForOp(Opc, VT);
}
+
+bool AArch64TargetLowering::shouldPreservePtrArith(const Function &F,
+ EVT VT) const {
+ return Subtarget->hasCPA() && Subtarget->hasCPACodegen();
+}
\ No newline at end of file
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
index e0b6c1b8c0baf..89f90ee2b7707 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
@@ -539,6 +539,10 @@ class AArch64TargetLowering : public TargetLowering {
/// True if stack clash protection is enabled for this functions.
bool hasInlineStackProbe(const MachineFunction &MF) const override;
+ /// In AArch64, true if FEAT_CPA is present. Allows pointer arithmetic
+ /// semantics to be preserved for instruction selection.
+ bool shouldPreservePtrArith(const Function &F, EVT PtrVT) const override;
+
private:
/// Keep a pointer to the AArch64Subtarget around so that we can
/// make the right decision when generating code for different targets.
diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
index 862668672589b..8150e91c8ba52 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
@@ -932,7 +932,3 @@ bool AArch64TargetMachine::parseMachineFunctionInfo(
MF.getInfo<AArch64FunctionInfo>()->initializeBaseYamlFields(YamlMFI);
return false;
}
-
-bool AArch64TargetMachine::shouldPreservePtrArith(const Function &F) const {
- return getSubtargetImpl(F)->hasCPA() && getSubtargetImpl(F)->hasCPACodegen();
-}
diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.h b/llvm/lib/Target/AArch64/AArch64TargetMachine.h
index 0d25dcd2b887c..f8ba41f215430 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetMachine.h
+++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.h
@@ -76,10 +76,6 @@ class AArch64TargetMachine : public CodeGenTargetMachineImpl {
ScheduleDAGInstrs *
createPostMachineScheduler(MachineSchedContext *C) const override;
- /// 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;
};
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index fd487e95b6c64..5081cc4bba144 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -2197,12 +2197,14 @@ bool AArch64InstructionSelector::preISelLower(MachineInstr &I) {
}
return Changed;
}
- case TargetOpcode::G_PTR_ADD:
+ 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()))
+ const auto &TL = STI.getTargetLowering();
+ if (TL->shouldPreservePtrArith(MF.getFunction(), EVT()))
return false;
return convertPtrAddToAdd(I, MRI);
+ }
case TargetOpcode::G_LOAD: {
// For scalar loads of pointers, we try to convert the dest type from p0
// to s64 so that our imported patterns can match. Like with the G_PTR_ADD
diff --git a/llvm/test/CodeGen/AArch64/cpa-selectiondag.ll b/llvm/test/CodeGen/AArch64/cpa-selectiondag.ll
index adca31bf47daa..829c96dd8ad10 100644
--- a/llvm/test/CodeGen/AArch64/cpa-selectiondag.ll
+++ b/llvm/test/CodeGen/AArch64/cpa-selectiondag.ll
@@ -119,14 +119,17 @@ define void @msubpt1(i32 %index, i32 %elem) {
; CHECK-CPA-O0: // %bb.0: // %entry
; CHECK-CPA-O0-NEXT: // implicit-def: $x8
; CHECK-CPA-O0-NEXT: mov w8, w0
-; CHECK-CPA-O0-NEXT: sxtw x8, w8
-; CHECK-CPA-O0-NEXT: mov w9, #48 // =0x30
-; CHECK-CPA-O0-NEXT: // kill: def $x9 killed $w9
-; CHECK-CPA-O0-NEXT: mneg x8, x8, x9
-; CHECK-CPA-O0-NEXT: add x8, x8, #288
+; CHECK-CPA-O0-NEXT: sxtw x9, w8
+; CHECK-CPA-O0-NEXT: mov x8, xzr
+; CHECK-CPA-O0-NEXT: subs x8, x8, x9
+; CHECK-CPA-O0-NEXT: lsl x8, x8, #1
+; CHECK-CPA-O0-NEXT: subs x10, x8, x9
; CHECK-CPA-O0-NEXT: adrp x9, array2
; CHECK-CPA-O0-NEXT: add x9, x9, :lo12:array2
+; CHECK-CPA-O0-NEXT: mov w8, #288 // =0x120
+; CHECK-CPA-O0-NEXT: // kill: def $x8 killed $w8
; CHECK-CPA-O0-NEXT: addpt x8, x9, x8
+; CHECK-CPA-O0-NEXT: addpt x8, x8, x10, lsl #4
; CHECK-CPA-O0-NEXT: mov w10, #96 // =0x60
; CHECK-CPA-O0-NEXT: // kill: def $x10 killed $w10
; CHECK-CPA-O0-NEXT: addpt x10, x9, x10
@@ -141,19 +144,21 @@ define void @msubpt1(i32 %index, i32 %elem) {
; CHECK-CPA-O3-LABEL: msubpt1:
; CHECK-CPA-O3: // %bb.0: // %entry
; CHECK-CPA-O3-NEXT: // kill: def $w0 killed $w0 def $x0
-; CHECK-CPA-O3-NEXT: sxtw x8, w0
-; CHECK-CPA-O3-NEXT: mov w9, #48 // =0x30
-; CHECK-CPA-O3-NEXT: adrp x10, array2
-; CHECK-CPA-O3-NEXT: add x10, x10, :lo12:array2
-; CHECK-CPA-O3-NEXT: mneg x8, x8, x9
-; CHECK-CPA-O3-NEXT: mov w9, #96 // =0x60
-; CHECK-CPA-O3-NEXT: ldr q2, [x10, #96]
-; CHECK-CPA-O3-NEXT: addpt x9, x10, x9
-; CHECK-CPA-O3-NEXT: ldp q1, q0, [x9, #16]
-; CHECK-CPA-O3-NEXT: add x8, x8, #288
-; CHECK-CPA-O3-NEXT: addpt x8, x10, x8
-; CHECK-CPA-O3-NEXT: stp q1, q0, [x8, #16]
-; CHECK-CPA-O3-NEXT: str q2, [x8]
+; CHECK-CPA-O3-NEXT: sxtw x9, w0
+; CHECK-CPA-O3-NEXT: adrp x8, array2
+; CHECK-CPA-O3-NEXT: add x8, x8, :lo12:array2
+; CHECK-CPA-O3-NEXT: mov w11, #96 // =0x60
+; CHECK-CPA-O3-NEXT: mov w12, #288 // =0x120
+; CHECK-CPA-O3-NEXT: ldr q2, [x8, #96]
+; CHECK-CPA-O3-NEXT: neg x10, x9
+; CHECK-CPA-O3-NEXT: addpt x11, x8, x11
+; CHECK-CPA-O3-NEXT: lsl x10, x10, #1
+; CHECK-CPA-O3-NEXT: ldp q1, q0, [x11, #16]
+; CHECK-CPA-O3-NEXT: sub x9, x10, x9
+; CHECK-CPA-O3-NEXT: addpt x10, x8, x12
+; CHECK-CPA-O3-NEXT: addpt x9, x10, x9, lsl #4
+; CHECK-CPA-O3-NEXT: stp q1, q0, [x9, #16]
+; CHECK-CPA-O3-NEXT: str q2, [x9]
; CHECK-CPA-O3-NEXT: ret
;
; CHECK-NOCPA-O0-LABEL: msubpt1:
@@ -200,15 +205,15 @@ entry:
define void @subpt1(i32 %index, i32 %elem) {
; CHECK-CPA-O0-LABEL: subpt1:
; CHECK-CPA-O0: // %bb.0: // %entry
-; CHECK-CPA-O0-NEXT: // implicit-def: $x8
-; CHECK-CPA-O0-NEXT: mov w8, w0
-; CHECK-CPA-O0-NEXT: sxtw x9, w8
-; CHECK-CPA-O0-NEXT: mov w8, #96 // =0x60
-; CHECK-CPA-O0-NEXT: // kill: def $x8 killed $w8
-; CHECK-CPA-O0-NEXT: subs x8, x8, x9, lsl #8
; CHECK-CPA-O0-NEXT: adrp x9, array
; CHECK-CPA-O0-NEXT: add x9, x9, :lo12:array
+; CHECK-CPA-O0-NEXT: mov w8, #96 // =0x60
+; CHECK-CPA-O0-NEXT: // kill: def $x8 killed $w8
; CHECK-CPA-O0-NEXT: addpt x8, x9, x8
+; CHECK-CPA-O0-NEXT: // implicit-def: $x10
+; CHECK-CPA-O0-NEXT: mov w10, w0
+; CHECK-CPA-O0-NEXT: sbfiz x10, x10, #8, #32
+; CHECK-CPA-O0-NEXT: subpt x8, x8, x10
; CHECK-CPA-O0-NEXT: ldr q0, [x9, #32]
; CHECK-CPA-O0-NEXT: str q0, [x8]
; CHECK-CPA-O0-NEXT: ret
@@ -216,13 +221,13 @@ define void @subpt1(i32 %index, i32 %elem) {
; CHECK-CPA-O3-LABEL: subpt1:
; CHECK-CPA-O3: // %bb.0: // %entry
; CHECK-CPA-O3-NEXT: // kill: def $w0 killed $w0 def $x0
-; CHECK-CPA-O3-NEXT: sxtw x8, w0
+; CHECK-CPA-O3-NEXT: adrp x8, array
+; CHECK-CPA-O3-NEXT: add x8, x8, :lo12:array
; CHECK-CPA-O3-NEXT: mov w9, #96 // =0x60
-; CHECK-CPA-O3-NEXT: sub x8, x9, x8, lsl #8
-; CHECK-CPA-O3-NEXT: adrp x9, array
-; CHECK-CPA-O3-NEXT: add x9, x9, :lo12:array
-; CHECK-CPA-O3-NEXT: ldr q0, [x9, #32]
-; CHECK-CPA-O3-NEXT: addpt x8, x9, x8
+; CHECK-CPA-O3-NEXT: sbfiz x10, x0, #8, #32
+; CHECK-CPA-O3-NEXT: addpt x9, x8, x9
+; CHECK-CPA-O3-NEXT: ldr q0, [x8, #32]
+; CHECK-CPA-O3-NEXT: subpt x8, x9, x10
; CHECK-CPA-O3-NEXT: str q0, [x8]
; CHECK-CPA-O3-NEXT: ret
;
@@ -259,24 +264,28 @@ entry:
define void @subpt2(i32 %index, i32 %elem) {
; CHECK-CPA-O0-LABEL: subpt2:
; CHECK-CPA-O0: // %bb.0: // %entry
-; CHECK-CPA-O0-NEXT: mov w8, #96 // =0x60
-; CHECK-CPA-O0-NEXT: // kill: def $x8 killed $w8
-; CHECK-CPA-O0-NEXT: subs x8, x8, w0, sxtw #4
+; CHECK-CPA-O0-NEXT: mov x8, xzr
+; CHECK-CPA-O0-NEXT: subs x10, x8, w0, sxtw
; CHECK-CPA-O0-NEXT: adrp x9, array
; CHECK-CPA-O0-NEXT: add x9, x9, :lo12:array
+; CHECK-CPA-O0-NEXT: mov w8, #96 // =0x60
+; CHECK-CPA-O0-NEXT: // kill: def $x8 killed $w8
; CHECK-CPA-O0-NEXT: addpt x8, x9, x8
+; CHECK-CPA-O0-NEXT: addpt x8, x8, x10, lsl #4
; CHECK-CPA-O0-NEXT: ldr q0, [x9, #32]
; CHECK-CPA-O0-NEXT: str q0, [x8]
; CHECK-CPA-O0-NEXT: ret
;
; CHECK-CPA-O3-LABEL: subpt2:
; CHECK-CPA-O3: // %bb.0: // %entry
-; CHECK-CPA-O3-NEXT: mov w8, #96 // =0x60
-; CHECK-CPA-O3-NEXT: adrp x9, array
-; CHECK-CPA-O3-NEXT: add x9, x9, :lo12:array
-; CHECK-CPA-O3-NEXT: sub x8, x8, w0, sxtw #4
-; CHECK-CPA-O3-NEXT: ldr q0, [x9, #32]
-; CHECK-CPA-O3-NEXT: addpt x8, x9, x8
+; CHECK-CPA-O3-NEXT: mov x8, xzr
+; CHECK-CPA-O3-NEXT: mov w9, #96 // =0x60
+; CHECK-CPA-O3-NEXT: adrp x10, array
+; CHECK-CPA-O3-NEXT: add x10, x10, :lo12:array
+; CHECK-CPA-O3-NEXT: sub x8, x8, w0, sxtw
+; CHECK-CPA-O3-NEXT: addpt x9, x10, x9
+; CHECK-CPA-O3-NEXT: ldr q0, [x10, #32]
+; CHECK-CPA-O3-NEXT: addpt x8, x9, x8, lsl #4
; CHECK-CPA-O3-NEXT: str q0, [x8]
; CHECK-CPA-O3-NEXT: ret
;
@@ -656,14 +665,18 @@ define hidden void @multidim() {
; CHECK-CPA-O0-LABEL: multidim:
; CHECK-CPA-O0: // %bb.0: // %entry
; CHECK-CPA-O0-NEXT: adrp x8, b
-; CHECK-CPA-O0-NEXT: ldrh w10, [x8, :lo12:b]
+; CHECK-CPA-O0-NEXT: ldrh w9, [x8, :lo12:b]
+; CHECK-CPA-O0-NEXT: mov w8, w9
+; CHECK-CPA-O0-NEXT: mov w10, w8
; CHECK-CPA-O0-NEXT: adrp x8, a
; CHECK-CPA-O0-NEXT: add x8, x8, :lo12:a
-; CHECK-CPA-O0-NEXT: add w9, w10, #1
+; CHECK-CPA-O0-NEXT: mov w11, #2 // =0x2
+; CHECK-CPA-O0-NEXT: // kill: def $x11 killed $w11
+; CHECK-CPA-O0-NEXT: addpt x8, x8, x11
+; CHECK-CPA-O0-NEXT: addpt x8, x8, x10, lsl #1
+; CHECK-CPA-O0-NEXT: add w9, w9, #1
; CHECK-CPA-O0-NEXT: mov w9, w9
; CHECK-CPA-O0-NEXT: // kill: def $x9 killed $w9
-; CHECK-CPA-O0-NEXT: add x9, x9, w10, uxtw #1
-; CHECK-CPA-O0-NEXT: add x9, x9, #2
; CHECK-CPA-O0-NEXT: addpt x8, x8, x9
; CHECK-CPA-O0-NEXT: ldrb w8, [x8]
; CHECK-CPA-O0-NEXT: cbz w8, .LBB14_2
>From 3e6cceee5c0d36db96a825990e8a87d28b928e41 Mon Sep 17 00:00:00 2001
From: Rodolfo Wottrich <rodolfo.wottrich at arm.com>
Date: Wed, 18 Jun 2025 15:29:53 +0000
Subject: [PATCH 19/19] Fix missing newline
---
llvm/lib/Target/AArch64/AArch64ISelLowering.cpp | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 45e0e055463dc..5585ec57dc8b6 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -153,6 +153,14 @@ cl::opt<bool> EnableSVEGISel(
cl::desc("Enable / disable SVE scalable vectors in Global ISel"),
cl::init(false));
+// TODO: This option should be removed once we switch to always using PTRADD in
+// the SelectionDAG.
+static cl::opt<bool> UseFEATCPACodegen(
+ "aarch64-use-featcpa-codegen", cl::Hidden,
+ cl::desc("Generate ISD::PTRADD nodes for pointer arithmetic in "
+ "SelectionDAG for FEAT_CPA"),
+ cl::init(false));
+
/// Value type used for condition codes.
static const MVT MVT_CC = MVT::i32;
@@ -30420,4 +30428,4 @@ bool AArch64TargetLowering::isTypeDesirableForOp(unsigned Opc, EVT VT) const {
bool AArch64TargetLowering::shouldPreservePtrArith(const Function &F,
EVT VT) const {
return Subtarget->hasCPA() && Subtarget->hasCPACodegen();
-}
\ No newline at end of file
+}
More information about the llvm-commits
mailing list