Koakuma e6f868cf71
[Sparc] Optimize compare instruction (#167140)
If we need to compare the result of a computation with 0, we can
sometimes replace the last instruction in the computation with one that
sets the integer condition codes. We can then branch immediately based
on the zero-flag instead of having to use an extra compare instruction
(a SUBcc instruction).

This is only possible if the result of the compare is not used anywhere
else and that no other instruction modifies the integer condition codes
between the time the result of the computation is defined and the time
it is used.

---------

Co-authored-by: Daniel Cederman <cederman@gaisler.com>
2025-11-14 23:11:38 +07:00

249 lines
6.4 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple=sparc | FileCheck %s
; RUN: llc < %s -mtriple=sparcv9 | FileCheck %s -check-prefix=CHECK64
define i32 @test(i32 %a) nounwind {
; CHECK-LABEL: test:
; CHECK: ! %bb.0: ! %entry
; CHECK-NEXT: andcc %o0, 1, %g0
; CHECK-NEXT: bne .LBB0_2
; CHECK-NEXT: nop
; CHECK-NEXT: ! %bb.1: ! %if.end
; CHECK-NEXT: retl
; CHECK-NEXT: mov 2, %o0
; CHECK-NEXT: .LBB0_2: ! %if.then
; CHECK-NEXT: retl
; CHECK-NEXT: mov 1, %o0
;
; CHECK64-LABEL: test:
; CHECK64: ! %bb.0: ! %entry
; CHECK64-NEXT: andcc %o0, 1, %g0
; CHECK64-NEXT: bne %icc, .LBB0_2
; CHECK64-NEXT: nop
; CHECK64-NEXT: ! %bb.1: ! %if.end
; CHECK64-NEXT: retl
; CHECK64-NEXT: mov 2, %o0
; CHECK64-NEXT: .LBB0_2: ! %if.then
; CHECK64-NEXT: retl
; CHECK64-NEXT: mov 1, %o0
entry:
%and = and i32 %a, 1
%tobool = icmp eq i32 %and, 0
br i1 %tobool, label %if.end, label %if.then
if.then:
ret i32 1
if.end:
ret i32 2
}
; Same as above, with select.
define i32 @test_select(i32 %a) nounwind {
; CHECK-LABEL: test_select:
; CHECK: ! %bb.0:
; CHECK-NEXT: andcc %o0, 1, %g0
; CHECK-NEXT: be .LBB1_2
; CHECK-NEXT: nop
; CHECK-NEXT: ! %bb.1:
; CHECK-NEXT: retl
; CHECK-NEXT: mov 2, %o0
; CHECK-NEXT: .LBB1_2:
; CHECK-NEXT: retl
; CHECK-NEXT: mov 1, %o0
;
; CHECK64-LABEL: test_select:
; CHECK64: ! %bb.0:
; CHECK64-NEXT: andcc %o0, 1, %g0
; CHECK64-NEXT: mov 2, %o0
; CHECK64-NEXT: retl
; CHECK64-NEXT: move %icc, 1, %o0
%and = and i32 %a, 1
%tobool = icmp eq i32 %and, 0
%ret = select i1 %tobool, i32 1, i32 2
ret i32 %ret
}
; No instruction can be changed to set ICC
define i32 @no_candidate(i32 %a) nounwind {
; CHECK-LABEL: no_candidate:
; CHECK: ! %bb.0: ! %entry
; CHECK-NEXT: cmp %o0, 0
; CHECK-NEXT: be .LBB2_2
; CHECK-NEXT: nop
; CHECK-NEXT: ! %bb.1: ! %if.then
; CHECK-NEXT: retl
; CHECK-NEXT: mov 1, %o0
; CHECK-NEXT: .LBB2_2: ! %if.end
; CHECK-NEXT: retl
; CHECK-NEXT: mov 2, %o0
;
; CHECK64-LABEL: no_candidate:
; CHECK64: ! %bb.0: ! %entry
; CHECK64-NEXT: cmp %o0, 0
; CHECK64-NEXT: be %icc, .LBB2_2
; CHECK64-NEXT: nop
; CHECK64-NEXT: ! %bb.1: ! %if.then
; CHECK64-NEXT: retl
; CHECK64-NEXT: mov 1, %o0
; CHECK64-NEXT: .LBB2_2: ! %if.end
; CHECK64-NEXT: retl
; CHECK64-NEXT: mov 2, %o0
entry:
%tobool = icmp eq i32 %a, 0
br i1 %tobool, label %if.end, label %if.then
if.then:
ret i32 1
if.end:
ret i32 2
}
; Defining instruction and compare not in same block
define i32 @not_same_block(i32 %a) nounwind {
; CHECK-LABEL: not_same_block:
; CHECK: ! %bb.0: ! %entry
; CHECK-NEXT: and %o0, 1, %o0
; CHECK-NEXT: .LBB3_1: ! %if.then
; CHECK-NEXT: ! =>This Inner Loop Header: Depth=1
; CHECK-NEXT: cmp %o0, 0
; CHECK-NEXT: bne .LBB3_1
; CHECK-NEXT: nop
; CHECK-NEXT: ! %bb.2: ! %if.end
; CHECK-NEXT: retl
; CHECK-NEXT: mov 2, %o0
;
; CHECK64-LABEL: not_same_block:
; CHECK64: ! %bb.0: ! %entry
; CHECK64-NEXT: and %o0, 1, %o0
; CHECK64-NEXT: .LBB3_1: ! %if.then
; CHECK64-NEXT: ! =>This Inner Loop Header: Depth=1
; CHECK64-NEXT: cmp %o0, 0
; CHECK64-NEXT: bne %icc, .LBB3_1
; CHECK64-NEXT: nop
; CHECK64-NEXT: ! %bb.2: ! %if.end
; CHECK64-NEXT: retl
; CHECK64-NEXT: mov 2, %o0
entry:
%and = and i32 %a, 1
br label %if.then
if.then:
%tobool = icmp eq i32 %and, 0
br i1 %tobool, label %if.end, label %if.then
ret i32 1
if.end:
ret i32 2
}
; Compare instruction is not checking equality
define i32 @not_equality(i32 %a) nounwind {
; CHECK-LABEL: not_equality:
; CHECK: ! %bb.0: ! %entry
; CHECK-NEXT: and %o0, 1, %o1
; CHECK-NEXT: cmp %o1, 0
; CHECK-NEXT: bl .LBB4_2
; CHECK-NEXT: nop
; CHECK-NEXT: ! %bb.1: ! %entry
; CHECK-NEXT: mov %o1, %o0
; CHECK-NEXT: .LBB4_2: ! %entry
; CHECK-NEXT: retl
; CHECK-NEXT: nop
;
; CHECK64-LABEL: not_equality:
; CHECK64: ! %bb.0: ! %entry
; CHECK64-NEXT: and %o0, 1, %o1
; CHECK64-NEXT: cmp %o1, 0
; CHECK64-NEXT: movl %icc, %o0, %o1
; CHECK64-NEXT: retl
; CHECK64-NEXT: mov %o1, %o0
entry:
%and = and i32 %a, 1
%cmp = icmp slt i32 %and, 0
%cond = select i1 %cmp, i32 %a, i32 %and
ret i32 %cond
}
; Instruction that modifies ICC (call) between defining
; and compare instruction.
define i32 @call_between(i32 %a) nounwind {
; CHECK-LABEL: call_between:
; CHECK: ! %bb.0: ! %entry
; CHECK-NEXT: save %sp, -96, %sp
; CHECK-NEXT: and %i0, 1, %i1
; CHECK-NEXT: call not_equality
; CHECK-NEXT: mov %i1, %o0
; CHECK-NEXT: cmp %i1, 0
; CHECK-NEXT: be .LBB5_2
; CHECK-NEXT: nop
; CHECK-NEXT: ! %bb.1: ! %entry
; CHECK-NEXT: mov %i1, %i0
; CHECK-NEXT: .LBB5_2: ! %entry
; CHECK-NEXT: ret
; CHECK-NEXT: restore
;
; CHECK64-LABEL: call_between:
; CHECK64: ! %bb.0: ! %entry
; CHECK64-NEXT: save %sp, -176, %sp
; CHECK64-NEXT: and %i0, 1, %i1
; CHECK64-NEXT: call not_equality
; CHECK64-NEXT: mov %i1, %o0
; CHECK64-NEXT: cmp %i1, 0
; CHECK64-NEXT: move %icc, %i0, %i1
; CHECK64-NEXT: ret
; CHECK64-NEXT: restore %g0, %i1, %o0
entry:
%and = and i32 %a, 1
call i32 @not_equality(i32 %and)
%cmp = icmp eq i32 %and, 0
%cond = select i1 %cmp, i32 %a, i32 %and
ret i32 %cond
}
; ICC is used in successor block.
define i32 @icc_live_out(i32 %a) nounwind {
; CHECK-LABEL: icc_live_out:
; CHECK: ! %bb.0: ! %entry
; CHECK-NEXT: andcc %o0, 1, %o1
; CHECK-NEXT: bne .LBB6_4
; CHECK-NEXT: nop
; CHECK-NEXT: ! %bb.1: ! %case1
; CHECK-NEXT: cmp %o1, 0
; CHECK-NEXT: be .LBB6_3
; CHECK-NEXT: nop
; CHECK-NEXT: ! %bb.2: ! %case1
; CHECK-NEXT: mov %o1, %o0
; CHECK-NEXT: .LBB6_3: ! %case1
; CHECK-NEXT: retl
; CHECK-NEXT: nop
; CHECK-NEXT: .LBB6_4: ! %case2
; CHECK-NEXT: retl
; CHECK-NEXT: mov 2, %o0
;
; CHECK64-LABEL: icc_live_out:
; CHECK64: ! %bb.0: ! %entry
; CHECK64-NEXT: mov %o0, %o1
; CHECK64-NEXT: andcc %o0, 1, %o0
; CHECK64-NEXT: bne %icc, .LBB6_2
; CHECK64-NEXT: nop
; CHECK64-NEXT: ! %bb.1: ! %case1
; CHECK64-NEXT: cmp %o0, 0
; CHECK64-NEXT: retl
; CHECK64-NEXT: move %icc, %o1, %o0
; CHECK64-NEXT: .LBB6_2: ! %case2
; CHECK64-NEXT: retl
; CHECK64-NEXT: mov 2, %o0
entry:
%and = and i32 %a, 1
%cmp = icmp eq i32 %and, 0
br i1 %cmp, label %case1, label %case2
case1:
%cond = select i1 %cmp, i32 %a, i32 %and
ret i32 %cond
case2:
ret i32 2
}