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>
249 lines
6.4 KiB
LLVM
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
|
|
}
|