[llvm] r275540 - [Thumb-1] Select post-increment load and store where possible
James Molloy via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 15 01:03:56 PDT 2016
Author: jamesm
Date: Fri Jul 15 03:03:56 2016
New Revision: 275540
URL: http://llvm.org/viewvc/llvm-project?rev=275540&view=rev
Log:
[Thumb-1] Select post-increment load and store where possible
Thumb-1 doesn't have post-inc or pre-inc load or store instructions. However the LDM/STM instructions with writeback can function as post-inc load/store:
ldm r0!, {r1} @ load from r0 into r1 and increment r0 by 4
Obviously, this only works if the post increment is 4.
Added:
llvm/trunk/test/CodeGen/Thumb/ldm-stm-postinc.ll
Modified:
llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp
llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp
llvm/trunk/lib/Target/ARM/ARMInstrThumb.td
Modified: llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp?rev=275540&r1=275539&r2=275540&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp (original)
+++ llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp Fri Jul 15 03:03:56 2016
@@ -195,6 +195,7 @@ public:
private:
/// Indexed (pre/post inc/dec) load matching code for ARM.
bool tryARMIndexedLoad(SDNode *N);
+ bool tryT1IndexedLoad(SDNode *N);
bool tryT2IndexedLoad(SDNode *N);
/// SelectVLD - Select NEON load intrinsics. NumVecs should be
@@ -1543,6 +1544,31 @@ bool ARMDAGToDAGISel::tryARMIndexedLoad(
return false;
}
+bool ARMDAGToDAGISel::tryT1IndexedLoad(SDNode *N) {
+ LoadSDNode *LD = cast<LoadSDNode>(N);
+ EVT LoadedVT = LD->getMemoryVT();
+ ISD::MemIndexedMode AM = LD->getAddressingMode();
+ if (AM == ISD::UNINDEXED || LD->getExtensionType() != ISD::NON_EXTLOAD ||
+ AM != ISD::POST_INC || LoadedVT.getSimpleVT().SimpleTy != MVT::i32)
+ return false;
+
+ auto *COffs = dyn_cast<ConstantSDNode>(LD->getOffset());
+ if (!COffs || COffs->getZExtValue() != 4)
+ return false;
+
+ // A T1 post-indexed load is just a single register LDM: LDM r0!, {r1}.
+ // The encoding of LDM is not how the rest of ISel expects a post-inc load to
+ // look however, so we use a pseudo here and switch it for a tLDMIA_UPD after
+ // ISel.
+ SDValue Chain = LD->getChain();
+ SDValue Base = LD->getBasePtr();
+ SDValue Ops[]= { Base, getAL(CurDAG, SDLoc(N)),
+ CurDAG->getRegister(0, MVT::i32), Chain };
+ ReplaceNode(N, CurDAG->getMachineNode(ARM::tLDR_postidx, SDLoc(N), MVT::i32, MVT::i32,
+ MVT::Other, Ops));
+ return true;
+}
+
bool ARMDAGToDAGISel::tryT2IndexedLoad(SDNode *N) {
LoadSDNode *LD = cast<LoadSDNode>(N);
ISD::MemIndexedMode AM = LD->getAddressingMode();
@@ -3015,6 +3041,9 @@ void ARMDAGToDAGISel::Select(SDNode *N)
if (Subtarget->isThumb() && Subtarget->hasThumb2()) {
if (tryT2IndexedLoad(N))
return;
+ } else if (Subtarget->isThumb()) {
+ if (tryT1IndexedLoad(N))
+ return;
} else if (tryARMIndexedLoad(N))
return;
// Other cases are autogenerated.
Modified: llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp?rev=275540&r1=275539&r2=275540&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp Fri Jul 15 03:03:56 2016
@@ -715,6 +715,10 @@ ARMTargetLowering::ARMTargetLowering(con
setIndexedStoreAction(im, MVT::i16, Legal);
setIndexedStoreAction(im, MVT::i32, Legal);
}
+ } else {
+ // Thumb-1 has limited post-inc load/store support - LDM r0!, {r1}.
+ setIndexedLoadAction(ISD::POST_INC, MVT::i32, Legal);
+ setIndexedStoreAction(ISD::POST_INC, MVT::i32, Legal);
}
setOperationAction(ISD::SADDO, MVT::i32, Custom);
@@ -8247,6 +8251,19 @@ ARMTargetLowering::EmitInstrWithCustomIn
MI.dump();
llvm_unreachable("Unexpected instr type to insert");
}
+
+ // Thumb1 post-indexed loads are really just single-register LDMs.
+ case ARM::tLDR_postidx: {
+ BuildMI(*BB, MI, dl, TII->get(ARM::tLDMIA_UPD))
+ .addOperand(MI->getOperand(1)) // Rn_wb
+ .addOperand(MI->getOperand(2)) // Rn
+ .addOperand(MI->getOperand(3)) // PredImm
+ .addOperand(MI->getOperand(4)) // PredReg
+ .addOperand(MI->getOperand(0)); // Rt
+ MI->eraseFromParent();
+ return BB;
+ }
+
// The Thumb2 pre-indexed stores have the same MI operands, they just
// define them differently in the .td files from the isel patterns, so
// they need pseudos.
@@ -11596,22 +11613,37 @@ bool ARMTargetLowering::getPostIndexedAd
SDValue &Offset,
ISD::MemIndexedMode &AM,
SelectionDAG &DAG) const {
- if (Subtarget->isThumb1Only())
- return false;
-
EVT VT;
SDValue Ptr;
- bool isSEXTLoad = false;
+ bool isSEXTLoad = false, isNonExt;
if (LoadSDNode *LD = dyn_cast<LoadSDNode>(N)) {
VT = LD->getMemoryVT();
Ptr = LD->getBasePtr();
isSEXTLoad = LD->getExtensionType() == ISD::SEXTLOAD;
+ isNonExt = LD->getExtensionType() == ISD::NON_EXTLOAD;
} else if (StoreSDNode *ST = dyn_cast<StoreSDNode>(N)) {
VT = ST->getMemoryVT();
Ptr = ST->getBasePtr();
+ isNonExt = !ST->isTruncatingStore();
} else
return false;
+ if (Subtarget->isThumb1Only()) {
+ // Thumb-1 can do a limited post-inc load or store as an updating LDM. It
+ // must be non-extending/truncating, i32, with an offset of 4.
+ assert(Op->getValueType(0) == MVT::i32 && "Non-i32 post-inc op?!");
+ if (Op->getOpcode() != ISD::ADD || !isNonExt)
+ return false;
+ auto *RHS = dyn_cast<ConstantSDNode>(Op->getOperand(1));
+ if (!RHS || RHS->getZExtValue() != 4)
+ return false;
+
+ Offset = Op->getOperand(1);
+ Base = Op->getOperand(0);
+ AM = ISD::POST_INC;
+ return true;
+ }
+
bool isInc;
bool isLegal = false;
if (Subtarget->isThumb2())
Modified: llvm/trunk/lib/Target/ARM/ARMInstrThumb.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrThumb.td?rev=275540&r1=275539&r2=275540&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMInstrThumb.td (original)
+++ llvm/trunk/lib/Target/ARM/ARMInstrThumb.td Fri Jul 15 03:03:56 2016
@@ -1451,6 +1451,24 @@ def : T1Pat<(extloadi8 t_addrmode_rr:$a
def : T1Pat<(extloadi16 t_addrmode_is2:$addr), (tLDRHi t_addrmode_is2:$addr)>;
def : T1Pat<(extloadi16 t_addrmode_rr:$addr), (tLDRHr t_addrmode_rr:$addr)>;
+// post-inc loads and stores
+
+// post-inc LDR -> LDM r0!, {r1}. The way operands are layed out in LDMs is
+// different to how ISel expects them for a post-inc load, so use a pseudo
+// and expand it just after ISel.
+let usesCustomInserter = 1,
+ Constraints = "$Rn = $Rn_wb, at earlyclobber $Rn_wb" in
+ def tLDR_postidx: tPseudoInst<(outs rGPR:$Rt, rGPR:$Rn_wb),
+ (ins rGPR:$Rn, pred:$p),
+ 4, IIC_iStore_ru,
+ []>;
+
+// post-inc STR -> STM r0!, {r1}. The layout of this (because it doesn't def
+// multiple registers) is the same in ISel as MachineInstr, so there's no need
+// for a pseudo.
+def : T1Pat<(post_store rGPR:$Rt, rGPR:$Rn, 4),
+ (tSTMIA_UPD rGPR:$Rn, rGPR:$Rt)>;
+
// If it's impossible to use [r,r] address mode for sextload, select to
// ldr{b|h} + sxt{b|h} instead.
def : T1Pat<(sextloadi8 t_addrmode_is1:$addr),
Added: llvm/trunk/test/CodeGen/Thumb/ldm-stm-postinc.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb/ldm-stm-postinc.ll?rev=275540&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Thumb/ldm-stm-postinc.ll (added)
+++ llvm/trunk/test/CodeGen/Thumb/ldm-stm-postinc.ll Fri Jul 15 03:03:56 2016
@@ -0,0 +1,81 @@
+; RUN: llc -mtriple=thumbv7 -mcpu=cortex-m0 < %s -disable-lsr | FileCheck %s
+; FIXME: LSR mangles the last two testcases pretty badly. When this is fixed, remove
+; the -disable-lsr above.
+
+; CHECK-LABEL: @f
+; CHECK: ldm {{r[0-9]}}!, {r{{[0-9]}}}
+define i32 @f(i32* readonly %a, i32* readnone %b) {
+ %1 = icmp eq i32* %a, %b
+ br i1 %1, label %._crit_edge, label %.lr.ph
+
+.lr.ph: ; preds = %.lr.ph, %0
+ %i.02 = phi i32 [ %3, %.lr.ph ], [ 0, %0 ]
+ %.01 = phi i32* [ %4, %.lr.ph ], [ %a, %0 ]
+ %2 = load i32, i32* %.01, align 4
+ %3 = add nsw i32 %2, %i.02
+ %4 = getelementptr inbounds i32, i32* %.01, i32 1
+ %5 = icmp eq i32* %4, %b
+ br i1 %5, label %._crit_edge, label %.lr.ph
+
+._crit_edge: ; preds = %.lr.ph, %0
+ %i.0.lcssa = phi i32 [ 0, %0 ], [ %3, %.lr.ph ]
+ ret i32 %i.0.lcssa
+}
+
+; CHECK-LABEL: @g
+; CHECK-NOT: ldm
+define i32 @g(i32* readonly %a, i32* readnone %b) {
+ %1 = icmp eq i32* %a, %b
+ br i1 %1, label %._crit_edge, label %.lr.ph
+
+.lr.ph: ; preds = %.lr.ph, %0
+ %i.02 = phi i32 [ %3, %.lr.ph ], [ 0, %0 ]
+ %.01 = phi i32* [ %4, %.lr.ph ], [ %a, %0 ]
+ %2 = load i32, i32* %.01, align 4
+ %3 = add nsw i32 %2, %i.02
+ %4 = getelementptr inbounds i32, i32* %.01, i32 2
+ %5 = icmp eq i32* %4, %b
+ br i1 %5, label %._crit_edge, label %.lr.ph
+
+._crit_edge: ; preds = %.lr.ph, %0
+ %i.0.lcssa = phi i32 [ 0, %0 ], [ %3, %.lr.ph ]
+ ret i32 %i.0.lcssa
+}
+
+; CHECK-LABEL: @h
+; CHECK: stm {{r[0-9]}}!, {r{{[0-9]}}}
+define void @h(i32* %a, i32* readnone %b) {
+ %1 = icmp eq i32* %a, %b
+ br i1 %1, label %._crit_edge, label %.lr.ph
+
+.lr.ph: ; preds = %.lr.ph, %0
+ %i.02 = phi i32 [ %2, %.lr.ph ], [ 0, %0 ]
+ %.01 = phi i32* [ %3, %.lr.ph ], [ %a, %0 ]
+ %2 = add nsw i32 %i.02, 1
+ store i32 %i.02, i32* %.01, align 4
+ %3 = getelementptr inbounds i32, i32* %.01, i32 1
+ %4 = icmp eq i32* %3, %b
+ br i1 %4, label %._crit_edge, label %.lr.ph
+
+._crit_edge: ; preds = %.lr.ph, %0
+ ret void
+}
+
+; CHECK-LABEL: @j
+; CHECK-NOT: stm
+define void @j(i32* %a, i32* readnone %b) {
+ %1 = icmp eq i32* %a, %b
+ br i1 %1, label %._crit_edge, label %.lr.ph
+
+.lr.ph: ; preds = %.lr.ph, %0
+ %i.02 = phi i32 [ %2, %.lr.ph ], [ 0, %0 ]
+ %.01 = phi i32* [ %3, %.lr.ph ], [ %a, %0 ]
+ %2 = add nsw i32 %i.02, 1
+ store i32 %i.02, i32* %.01, align 4
+ %3 = getelementptr inbounds i32, i32* %.01, i32 2
+ %4 = icmp eq i32* %3, %b
+ br i1 %4, label %._crit_edge, label %.lr.ph
+
+._crit_edge: ; preds = %.lr.ph, %0
+ ret void
+}
More information about the llvm-commits
mailing list