blob: e9440367fa4e09d932da5ad9001801bbaedd6686 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple=aarch64-linux-gnu | FileCheck %s
; getJumpConditionMergingParams keeps two integer branch conditions split when
; both compare values loaded from memory: merging would pin the loaded operands
; in registers for the CMP/CCMP chain, which the latency-based heuristic prices
; as cheap but can cause spills under register pressure. Other conditions still
; merge into a CCMP chain.
declare void @sink_a()
declare void @sink_b()
; Both sides compare loads (e.g. a bounds guard imin[d] < imax[d]): keep split.
define void @both_loaded(ptr %imin, ptr %imax) {
; CHECK-LABEL: both_loaded:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: ldr w8, [x0]
; CHECK-NEXT: ldr w9, [x1]
; CHECK-NEXT: cmp w8, w9
; CHECK-NEXT: b.ge .LBB0_3
; CHECK-NEXT: // %bb.1: // %entry
; CHECK-NEXT: ldr w8, [x0, #4]
; CHECK-NEXT: ldr w9, [x1, #4]
; CHECK-NEXT: cmp w8, w9
; CHECK-NEXT: b.ge .LBB0_3
; CHECK-NEXT: // %bb.2: // %taken
; CHECK-NEXT: b sink_a
; CHECK-NEXT: .LBB0_3: // %fall
; CHECK-NEXT: b sink_b
entry:
%imin0 = load i32, ptr %imin
%imax0 = load i32, ptr %imax
%c0 = icmp slt i32 %imin0, %imax0
%imin1p = getelementptr inbounds i32, ptr %imin, i64 1
%imax1p = getelementptr inbounds i32, ptr %imax, i64 1
%imin1 = load i32, ptr %imin1p
%imax1 = load i32, ptr %imax1p
%c1 = icmp slt i32 %imin1, %imax1
%and = and i1 %c0, %c1
br i1 %and, label %taken, label %fall
taken:
tail call void @sink_a()
ret void
fall:
tail call void @sink_b()
ret void
}
; Negative control: register operands, not loads -> still merge into a CCMP chain.
define void @both_reg(i32 %a0, i32 %b0, i32 %a1, i32 %b1) {
; CHECK-LABEL: both_reg:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: cmp w2, w3
; CHECK-NEXT: ccmp w0, w1, #0, lt
; CHECK-NEXT: b.ge .LBB1_2
; CHECK-NEXT: // %bb.1: // %taken
; CHECK-NEXT: b sink_a
; CHECK-NEXT: .LBB1_2: // %fall
; CHECK-NEXT: b sink_b
entry:
%c0 = icmp slt i32 %a0, %b0
%c1 = icmp slt i32 %a1, %b1
%and = and i1 %c0, %c1
br i1 %and, label %taken, label %fall
taken:
tail call void @sink_a()
ret void
fall:
tail call void @sink_b()
ret void
}
; Only one side is a load -> "both" requirement not met -> still merges.
define void @one_loaded(ptr %imin, ptr %imax, i32 %a1, i32 %b1) {
; CHECK-LABEL: one_loaded:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: ldr w8, [x1]
; CHECK-NEXT: ldr w9, [x0]
; CHECK-NEXT: cmp w2, w3
; CHECK-NEXT: ccmp w9, w8, #0, lt
; CHECK-NEXT: b.ge .LBB2_2
; CHECK-NEXT: // %bb.1: // %taken
; CHECK-NEXT: b sink_a
; CHECK-NEXT: .LBB2_2: // %fall
; CHECK-NEXT: b sink_b
entry:
%imin0 = load i32, ptr %imin
%imax0 = load i32, ptr %imax
%c0 = icmp slt i32 %imin0, %imax0
%c1 = icmp slt i32 %a1, %b1
%and = and i1 %c0, %c1
br i1 %and, label %taken, label %fall
taken:
tail call void @sink_a()
ret void
fall:
tail call void @sink_b()
ret void
}