| ; 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: add %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: add %o0, -1, %o1 | |
| ; CHECK64-NEXT: cmp %o1, 0 | |
| ; CHECK64-NEXT: movl %icc, %o0, %o1 | |
| ; CHECK64-NEXT: retl | |
| ; CHECK64-NEXT: mov %o1, %o0 | |
| entry: | |
| %sub = sub i32 %a, 1 | |
| %cmp = icmp slt i32 %sub, 0 | |
| %cond = select i1 %cmp, i32 %a, i32 %sub | |
| 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 | |
| } |