65816-llvm-mos/src/llvm/test/CodeGen/W65816/split-loop-exits.ll
2026-10-06 17:01:51 -05:00

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
}