83 lines
3.1 KiB
LLVM
83 lines
3.1 KiB
LLVM
; Pin: W65816SplitLoopExits gives a critical edge out of a loop into a
|
|
; block with PHIs a block of its own, so PHI elimination's copies run once
|
|
; per exit instead of on every trip. LLVM does that split in PHI
|
|
; elimination only through MachineBasicBlock::SplitCriticalEdge, which
|
|
; needs analyzeBranch to understand the conditional branch -- this target
|
|
; keeps conditional branches opaque. A search loop's two exits (found:
|
|
; return p; end of list: return NULL) copied p into the return value's
|
|
; words and zero into them on every trip (CoreMark's core_list_find:
|
|
; -27% with the copies gone).
|
|
;
|
|
; RUN: llc -mtriple=w65816 -O2 -print-after=w65816-split-loop-exits -o /dev/null < %s 2>&1 | FileCheck %s --check-prefix=IR
|
|
; RUN: llc -mtriple=w65816 -O2 < %s | FileCheck %s
|
|
|
|
target datalayout = "e-m:e-p:32:16-i16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16"
|
|
|
|
%struct.node = type { ptr, ptr }
|
|
|
|
; IR-LABEL: define {{.*}}@find(
|
|
; IR: br i1 %cmp.not, label %land.rhs.while.end_crit_edge, label %while.body
|
|
; IR: land.rhs.while.end_crit_edge:
|
|
; IR-NEXT: br label %while.end
|
|
; IR: br i1 %tobool.not, label %while.body.while.end_crit_edge, label %land.rhs
|
|
; IR: while.body.while.end_crit_edge:
|
|
; IR-NEXT: br label %while.end
|
|
; IR: %r = phi ptr [ null, %entry ], [ %list.addr.05, %land.rhs.while.end_crit_edge ], [ null, %while.body.while.end_crit_edge ]
|
|
|
|
; The loop keeps neither the return value's copy of p nor its zero; the
|
|
; copies sit in the exit blocks.
|
|
; CHECK-LABEL: find:
|
|
; CHECK: Loop Header
|
|
; CHECK-NOT: lda #0x0
|
|
; CHECK: bne .LBB0_[[LOOP:[0-9]+]]
|
|
; CHECK-NEXT: ; %bb.{{[0-9]+}}: ; %while.body.while.end_crit_edge
|
|
; CHECK-NEXT: lda #0x0
|
|
define ptr @find(ptr %list, i16 %want) {
|
|
entry:
|
|
%tobool.not4 = icmp eq ptr %list, null
|
|
br i1 %tobool.not4, label %while.end, label %land.rhs
|
|
|
|
land.rhs:
|
|
%list.addr.05 = phi ptr [ %next, %while.body ], [ %list, %entry ]
|
|
%info = getelementptr inbounds nuw i8, ptr %list.addr.05, i32 4
|
|
%0 = load ptr, ptr %info, align 2
|
|
%idx = getelementptr inbounds nuw i8, ptr %0, i32 2
|
|
%1 = load i16, ptr %idx, align 2
|
|
%cmp.not = icmp eq i16 %1, %want
|
|
br i1 %cmp.not, label %while.end, label %while.body
|
|
|
|
while.body:
|
|
%next = load ptr, ptr %list.addr.05, align 2
|
|
%tobool.not = icmp eq ptr %next, null
|
|
br i1 %tobool.not, label %while.end, label %land.rhs
|
|
|
|
while.end:
|
|
%r = phi ptr [ null, %entry ], [ null, %while.body ], [ %list.addr.05, %land.rhs ]
|
|
ret ptr %r
|
|
}
|
|
|
|
; A running total leaves the loop as the value the loop carries: that
|
|
; copy coalesces into the loop's own register wherever it sits, so the
|
|
; edge stays as it is (splitting it cost sumOfSquares a store a trip).
|
|
; IR-LABEL: define {{.*}}@total(
|
|
; IR-NOT: crit_edge
|
|
; IR: ret i32
|
|
define i32 @total(i16 %n) {
|
|
entry:
|
|
%z = icmp eq i16 %n, 0
|
|
br i1 %z, label %done, label %loop
|
|
|
|
loop:
|
|
%i = phi i16 [ 1, %entry ], [ %i1, %loop ]
|
|
%t = phi i32 [ 0, %entry ], [ %t1, %loop ]
|
|
%w = zext i16 %i to i32
|
|
%sq = mul nuw i32 %w, %w
|
|
%t1 = add i32 %t, %sq
|
|
%i1 = add i16 %i, 1
|
|
%c = icmp ugt i16 %i1, %n
|
|
br i1 %c, label %done, label %loop
|
|
|
|
done:
|
|
%r = phi i32 [ 0, %entry ], [ %t1, %loop ]
|
|
ret i32 %r
|
|
}
|