Files
clang-p2996/llvm/test/CodeGen/Thumb2/LowOverheadLoops/minloop.ll
David Green 0447f3508f [ARM][RegAlloc] Add t2LoopEndDec
We currently have problems with the way that low overhead loops are
specified, with LR being spilled between the t2LoopDec and the t2LoopEnd
forcing the entire loop to be reverted late in the backend. As they will
eventually become a single instruction, this patch introduces a
t2LoopEndDec which is the combination of the two, combined before
registry allocation to make sure this does not fail.

Unfortunately this instruction is a terminator that produces a value
(and also branches - it only produces the value around the branching
edge). So this needs some adjustment to phi elimination and the register
allocator to make sure that we do not spill this LR def around the loop
(needing to put a spill after the terminator). We treat the loop very
carefully, making sure that there is nothing else like calls that would
break it's ability to use LR. For that, this adds a
isUnspillableTerminator to opt in the new behaviour.

There is a chance that this could cause problems, and so I have added an
escape option incase. But I have not seen any problems in the testing
that I've tried, and not reverting Low overhead loops is important for
our performance. If this does work then we can hopefully do the same for
t2WhileLoopStart and t2DoLoopStart instructions.

This patch also contains the code needed to convert or revert the
t2LoopEndDec in the backend (which just needs a subs; bne) and the code
pre-ra to create them.

Differential Revision: https://reviews.llvm.org/D91358
2020-12-10 12:14:23 +00:00

184 lines
9.0 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=thumbv8.1m.main-none-none-eabi -mattr=+mve -verify-machineinstrs %s -o - | FileCheck %s
define void @arm_min_q31(i32* nocapture readonly %pSrc, i32 %blockSize, i32* nocapture %pResult, i32* nocapture %pIndex) {
; CHECK-LABEL: arm_min_q31:
; CHECK: @ %bb.0: @ %entry
; CHECK-NEXT: .save {r4, r5, r6, r7, r8, r9, r10, r11, lr}
; CHECK-NEXT: push.w {r4, r5, r6, r7, r8, r9, r10, r11, lr}
; CHECK-NEXT: ldr.w r12, [r0]
; CHECK-NEXT: subs.w r9, r1, #1
; CHECK-NEXT: beq .LBB0_3
; CHECK-NEXT: @ %bb.1: @ %while.body.preheader
; CHECK-NEXT: subs r7, r1, #2
; CHECK-NEXT: and r8, r9, #3
; CHECK-NEXT: cmp r7, #3
; CHECK-NEXT: bhs .LBB0_4
; CHECK-NEXT: @ %bb.2:
; CHECK-NEXT: movs r6, #0
; CHECK-NEXT: b .LBB0_6
; CHECK-NEXT: .LBB0_3:
; CHECK-NEXT: movs r6, #0
; CHECK-NEXT: b .LBB0_10
; CHECK-NEXT: .LBB0_4: @ %while.body.preheader.new
; CHECK-NEXT: bic r7, r9, #3
; CHECK-NEXT: movs r6, #1
; CHECK-NEXT: subs r7, #4
; CHECK-NEXT: add.w lr, r6, r7, lsr #2
; CHECK-NEXT: movs r6, #0
; CHECK-NEXT: dls lr, lr
; CHECK-NEXT: movs r7, #4
; CHECK-NEXT: .LBB0_5: @ %while.body
; CHECK-NEXT: @ =>This Inner Loop Header: Depth=1
; CHECK-NEXT: ldr r10, [r0, #16]!
; CHECK-NEXT: sub.w r9, r9, #4
; CHECK-NEXT: ldrd r5, r4, [r0, #-12]
; CHECK-NEXT: ldr r11, [r0, #-4]
; CHECK-NEXT: cmp r12, r5
; CHECK-NEXT: it gt
; CHECK-NEXT: subgt r6, r7, #3
; CHECK-NEXT: csel r5, r5, r12, gt
; CHECK-NEXT: cmp r5, r4
; CHECK-NEXT: it gt
; CHECK-NEXT: subgt r6, r7, #2
; CHECK-NEXT: csel r5, r4, r5, gt
; CHECK-NEXT: cmp r5, r11
; CHECK-NEXT: it gt
; CHECK-NEXT: subgt r6, r7, #1
; CHECK-NEXT: csel r5, r11, r5, gt
; CHECK-NEXT: cmp r5, r10
; CHECK-NEXT: csel r6, r7, r6, gt
; CHECK-NEXT: add.w r7, r7, #4
; CHECK-NEXT: csel r12, r10, r5, gt
; CHECK-NEXT: le lr, .LBB0_5
; CHECK-NEXT: .LBB0_6: @ %while.end.loopexit.unr-lcssa
; CHECK-NEXT: cmp.w r8, #0
; CHECK-NEXT: beq .LBB0_10
; CHECK-NEXT: @ %bb.7: @ %while.body.epil
; CHECK-NEXT: ldr r7, [r0, #4]
; CHECK-NEXT: sub.w r1, r1, r9
; CHECK-NEXT: cmp r12, r7
; CHECK-NEXT: csel r6, r1, r6, gt
; CHECK-NEXT: csel r12, r7, r12, gt
; CHECK-NEXT: cmp.w r8, #1
; CHECK-NEXT: beq .LBB0_10
; CHECK-NEXT: @ %bb.8: @ %while.body.epil.1
; CHECK-NEXT: ldr r7, [r0, #8]
; CHECK-NEXT: cmp r12, r7
; CHECK-NEXT: csinc r6, r6, r1, le
; CHECK-NEXT: csel r12, r7, r12, gt
; CHECK-NEXT: cmp.w r8, #2
; CHECK-NEXT: beq .LBB0_10
; CHECK-NEXT: @ %bb.9: @ %while.body.epil.2
; CHECK-NEXT: ldr r0, [r0, #12]
; CHECK-NEXT: cmp r12, r0
; CHECK-NEXT: it gt
; CHECK-NEXT: addgt r6, r1, #2
; CHECK-NEXT: csel r12, r0, r12, gt
; CHECK-NEXT: .LBB0_10: @ %while.end
; CHECK-NEXT: str.w r12, [r2]
; CHECK-NEXT: str r6, [r3]
; CHECK-NEXT: pop.w {r4, r5, r6, r7, r8, r9, r10, r11, pc}
entry:
%0 = load i32, i32* %pSrc, align 4
%blkCnt.015 = add i32 %blockSize, -1
%cmp.not17 = icmp eq i32 %blkCnt.015, 0
br i1 %cmp.not17, label %while.end, label %while.body.preheader
while.body.preheader: ; preds = %entry
%1 = add i32 %blockSize, -2
%xtraiter = and i32 %blkCnt.015, 3
%2 = icmp ult i32 %1, 3
br i1 %2, label %while.end.loopexit.unr-lcssa, label %while.body.preheader.new
while.body.preheader.new: ; preds = %while.body.preheader
%unroll_iter = and i32 %blkCnt.015, -4
br label %while.body
while.body: ; preds = %while.body, %while.body.preheader.new
%pSrc.addr.021.pn = phi i32* [ %pSrc, %while.body.preheader.new ], [ %pSrc.addr.021.3, %while.body ]
%blkCnt.020 = phi i32 [ %blkCnt.015, %while.body.preheader.new ], [ %blkCnt.0.3, %while.body ]
%outIndex.019 = phi i32 [ 0, %while.body.preheader.new ], [ %spec.select14.3, %while.body ]
%out.018 = phi i32 [ %0, %while.body.preheader.new ], [ %spec.select.3, %while.body ]
%niter = phi i32 [ %unroll_iter, %while.body.preheader.new ], [ %niter.nsub.3, %while.body ]
%pSrc.addr.021 = getelementptr inbounds i32, i32* %pSrc.addr.021.pn, i32 1
%3 = load i32, i32* %pSrc.addr.021, align 4
%cmp2 = icmp sgt i32 %out.018, %3
%sub3 = sub i32 %blockSize, %blkCnt.020
%spec.select = select i1 %cmp2, i32 %3, i32 %out.018
%spec.select14 = select i1 %cmp2, i32 %sub3, i32 %outIndex.019
%blkCnt.0 = add i32 %blkCnt.020, -1
%pSrc.addr.021.1 = getelementptr inbounds i32, i32* %pSrc.addr.021.pn, i32 2
%4 = load i32, i32* %pSrc.addr.021.1, align 4
%cmp2.1 = icmp sgt i32 %spec.select, %4
%sub3.1 = sub i32 %blockSize, %blkCnt.0
%spec.select.1 = select i1 %cmp2.1, i32 %4, i32 %spec.select
%spec.select14.1 = select i1 %cmp2.1, i32 %sub3.1, i32 %spec.select14
%blkCnt.0.1 = add i32 %blkCnt.020, -2
%pSrc.addr.021.2 = getelementptr inbounds i32, i32* %pSrc.addr.021.pn, i32 3
%5 = load i32, i32* %pSrc.addr.021.2, align 4
%cmp2.2 = icmp sgt i32 %spec.select.1, %5
%sub3.2 = sub i32 %blockSize, %blkCnt.0.1
%spec.select.2 = select i1 %cmp2.2, i32 %5, i32 %spec.select.1
%spec.select14.2 = select i1 %cmp2.2, i32 %sub3.2, i32 %spec.select14.1
%blkCnt.0.2 = add i32 %blkCnt.020, -3
%pSrc.addr.021.3 = getelementptr inbounds i32, i32* %pSrc.addr.021.pn, i32 4
%6 = load i32, i32* %pSrc.addr.021.3, align 4
%cmp2.3 = icmp sgt i32 %spec.select.2, %6
%sub3.3 = sub i32 %blockSize, %blkCnt.0.2
%spec.select.3 = select i1 %cmp2.3, i32 %6, i32 %spec.select.2
%spec.select14.3 = select i1 %cmp2.3, i32 %sub3.3, i32 %spec.select14.2
%blkCnt.0.3 = add i32 %blkCnt.020, -4
%niter.nsub.3 = add i32 %niter, -4
%niter.ncmp.3 = icmp eq i32 %niter.nsub.3, 0
br i1 %niter.ncmp.3, label %while.end.loopexit.unr-lcssa, label %while.body
while.end.loopexit.unr-lcssa: ; preds = %while.body, %while.body.preheader
%spec.select.lcssa.ph = phi i32 [ undef, %while.body.preheader ], [ %spec.select.3, %while.body ]
%spec.select14.lcssa.ph = phi i32 [ undef, %while.body.preheader ], [ %spec.select14.3, %while.body ]
%pSrc.addr.021.pn.unr = phi i32* [ %pSrc, %while.body.preheader ], [ %pSrc.addr.021.3, %while.body ]
%blkCnt.020.unr = phi i32 [ %blkCnt.015, %while.body.preheader ], [ %blkCnt.0.3, %while.body ]
%outIndex.019.unr = phi i32 [ 0, %while.body.preheader ], [ %spec.select14.3, %while.body ]
%out.018.unr = phi i32 [ %0, %while.body.preheader ], [ %spec.select.3, %while.body ]
%lcmp.mod.not = icmp eq i32 %xtraiter, 0
br i1 %lcmp.mod.not, label %while.end, label %while.body.epil
while.body.epil: ; preds = %while.end.loopexit.unr-lcssa
%pSrc.addr.021.epil = getelementptr inbounds i32, i32* %pSrc.addr.021.pn.unr, i32 1
%7 = load i32, i32* %pSrc.addr.021.epil, align 4
%cmp2.epil = icmp sgt i32 %out.018.unr, %7
%sub3.epil = sub i32 %blockSize, %blkCnt.020.unr
%spec.select.epil = select i1 %cmp2.epil, i32 %7, i32 %out.018.unr
%spec.select14.epil = select i1 %cmp2.epil, i32 %sub3.epil, i32 %outIndex.019.unr
%epil.iter.cmp.not = icmp eq i32 %xtraiter, 1
br i1 %epil.iter.cmp.not, label %while.end, label %while.body.epil.1
while.end: ; preds = %while.end.loopexit.unr-lcssa, %while.body.epil.2, %while.body.epil.1, %while.body.epil, %entry
%out.0.lcssa = phi i32 [ %0, %entry ], [ %spec.select.lcssa.ph, %while.end.loopexit.unr-lcssa ], [ %spec.select.epil, %while.body.epil ], [ %spec.select.epil.1, %while.body.epil.1 ], [ %spec.select.epil.2, %while.body.epil.2 ]
%outIndex.0.lcssa = phi i32 [ 0, %entry ], [ %spec.select14.lcssa.ph, %while.end.loopexit.unr-lcssa ], [ %spec.select14.epil, %while.body.epil ], [ %spec.select14.epil.1, %while.body.epil.1 ], [ %spec.select14.epil.2, %while.body.epil.2 ]
store i32 %out.0.lcssa, i32* %pResult, align 4
store i32 %outIndex.0.lcssa, i32* %pIndex, align 4
ret void
while.body.epil.1: ; preds = %while.body.epil
%blkCnt.0.epil = add i32 %blkCnt.020.unr, -1
%pSrc.addr.021.epil.1 = getelementptr inbounds i32, i32* %pSrc.addr.021.pn.unr, i32 2
%8 = load i32, i32* %pSrc.addr.021.epil.1, align 4
%cmp2.epil.1 = icmp sgt i32 %spec.select.epil, %8
%sub3.epil.1 = sub i32 %blockSize, %blkCnt.0.epil
%spec.select.epil.1 = select i1 %cmp2.epil.1, i32 %8, i32 %spec.select.epil
%spec.select14.epil.1 = select i1 %cmp2.epil.1, i32 %sub3.epil.1, i32 %spec.select14.epil
%epil.iter.cmp.1.not = icmp eq i32 %xtraiter, 2
br i1 %epil.iter.cmp.1.not, label %while.end, label %while.body.epil.2
while.body.epil.2: ; preds = %while.body.epil.1
%blkCnt.0.epil.1 = add i32 %blkCnt.020.unr, -2
%pSrc.addr.021.epil.2 = getelementptr inbounds i32, i32* %pSrc.addr.021.pn.unr, i32 3
%9 = load i32, i32* %pSrc.addr.021.epil.2, align 4
%cmp2.epil.2 = icmp sgt i32 %spec.select.epil.1, %9
%sub3.epil.2 = sub i32 %blockSize, %blkCnt.0.epil.1
%spec.select.epil.2 = select i1 %cmp2.epil.2, i32 %9, i32 %spec.select.epil.1
%spec.select14.epil.2 = select i1 %cmp2.epil.2, i32 %sub3.epil.2, i32 %spec.select14.epil.1
br label %while.end
}