| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py |
| ; RUN: llc -mtriple=thumbv7m-eabi %s -o - | FileCheck %s --check-prefix V7M |
| ; RUN: llc -mtriple=armv7a-eabi %s -o - | FileCheck %s --check-prefix V7A |
| ; RUN: llc -mtriple=thumbv7a-eabi %s -o - | FileCheck %s --check-prefix V7A-T |
| ; RUN: llc -mtriple=armv6m-eabi %s -o - | FileCheck %s --check-prefix V6M |
| |
| target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" |
| |
| ; Test sink of `and` instructions to fold in to `tst`, `lsls`, do cmov-bfi combine, etc. |
| define void @f(i32 %v, ptr noalias %outp) { |
| ; V7M-LABEL: f: |
| ; V7M: @ %bb.0: @ %entry |
| ; V7M-NEXT: movs r2, #0 |
| ; V7M-NEXT: str r2, [r1] |
| ; V7M-NEXT: lsls r2, r0, #31 |
| ; V7M-NEXT: bne .LBB0_3 |
| ; V7M-NEXT: @ %bb.1: @ %if.then |
| ; V7M-NEXT: tst.w r0, #14 |
| ; V7M-NEXT: beq .LBB0_6 |
| ; V7M-NEXT: @ %bb.2: |
| ; V7M-NEXT: lsls r2, r0, #30 |
| ; V7M-NEXT: mov.w r3, #33024 |
| ; V7M-NEXT: and.w r2, r3, r2, asr #31 |
| ; V7M-NEXT: lsrs r0, r0, #2 |
| ; V7M-NEXT: bfi r2, r0, #7, #1 |
| ; V7M-NEXT: bfi r2, r0, #14, #1 |
| ; V7M-NEXT: b .LBB0_5 |
| ; V7M-NEXT: .LBB0_3: @ %if.else |
| ; V7M-NEXT: tst.w r0, #14 |
| ; V7M-NEXT: it eq |
| ; V7M-NEXT: bxeq lr |
| ; V7M-NEXT: .LBB0_4: |
| ; V7M-NEXT: lsls r2, r0, #30 |
| ; V7M-NEXT: mov.w r3, #8256 |
| ; V7M-NEXT: and.w r2, r3, r2, asr #31 |
| ; V7M-NEXT: lsrs r0, r0, #2 |
| ; V7M-NEXT: bfi r2, r0, #5, #1 |
| ; V7M-NEXT: bfi r2, r0, #12, #1 |
| ; V7M-NEXT: .LBB0_5: @ %if.end |
| ; V7M-NEXT: str r2, [r1] |
| ; V7M-NEXT: .LBB0_6: @ %exit |
| ; V7M-NEXT: bx lr |
| ; |
| ; V7A-LABEL: f: |
| ; V7A: @ %bb.0: @ %entry |
| ; V7A-NEXT: mov r2, #0 |
| ; V7A-NEXT: tst r0, #1 |
| ; V7A-NEXT: str r2, [r1] |
| ; V7A-NEXT: bne .LBB0_3 |
| ; V7A-NEXT: @ %bb.1: @ %if.then |
| ; V7A-NEXT: tst r0, #14 |
| ; V7A-NEXT: beq .LBB0_6 |
| ; V7A-NEXT: @ %bb.2: |
| ; V7A-NEXT: lsl r2, r0, #30 |
| ; V7A-NEXT: mov r3, #33024 |
| ; V7A-NEXT: and r2, r3, r2, asr #31 |
| ; V7A-NEXT: lsr r0, r0, #2 |
| ; V7A-NEXT: bfi r2, r0, #7, #1 |
| ; V7A-NEXT: bfi r2, r0, #14, #1 |
| ; V7A-NEXT: b .LBB0_5 |
| ; V7A-NEXT: .LBB0_3: @ %if.else |
| ; V7A-NEXT: tst r0, #14 |
| ; V7A-NEXT: bxeq lr |
| ; V7A-NEXT: .LBB0_4: |
| ; V7A-NEXT: lsl r2, r0, #30 |
| ; V7A-NEXT: mov r3, #8256 |
| ; V7A-NEXT: and r2, r3, r2, asr #31 |
| ; V7A-NEXT: lsr r0, r0, #2 |
| ; V7A-NEXT: bfi r2, r0, #5, #1 |
| ; V7A-NEXT: bfi r2, r0, #12, #1 |
| ; V7A-NEXT: .LBB0_5: @ %if.end |
| ; V7A-NEXT: str r2, [r1] |
| ; V7A-NEXT: .LBB0_6: @ %exit |
| ; V7A-NEXT: bx lr |
| ; |
| ; V7A-T-LABEL: f: |
| ; V7A-T: @ %bb.0: @ %entry |
| ; V7A-T-NEXT: movs r2, #0 |
| ; V7A-T-NEXT: str r2, [r1] |
| ; V7A-T-NEXT: lsls r2, r0, #31 |
| ; V7A-T-NEXT: bne .LBB0_3 |
| ; V7A-T-NEXT: @ %bb.1: @ %if.then |
| ; V7A-T-NEXT: tst.w r0, #14 |
| ; V7A-T-NEXT: beq .LBB0_6 |
| ; V7A-T-NEXT: @ %bb.2: |
| ; V7A-T-NEXT: lsls r2, r0, #30 |
| ; V7A-T-NEXT: mov.w r3, #33024 |
| ; V7A-T-NEXT: and.w r2, r3, r2, asr #31 |
| ; V7A-T-NEXT: lsrs r0, r0, #2 |
| ; V7A-T-NEXT: bfi r2, r0, #7, #1 |
| ; V7A-T-NEXT: bfi r2, r0, #14, #1 |
| ; V7A-T-NEXT: b .LBB0_5 |
| ; V7A-T-NEXT: .LBB0_3: @ %if.else |
| ; V7A-T-NEXT: tst.w r0, #14 |
| ; V7A-T-NEXT: it eq |
| ; V7A-T-NEXT: bxeq lr |
| ; V7A-T-NEXT: .LBB0_4: |
| ; V7A-T-NEXT: lsls r2, r0, #30 |
| ; V7A-T-NEXT: mov.w r3, #8256 |
| ; V7A-T-NEXT: and.w r2, r3, r2, asr #31 |
| ; V7A-T-NEXT: lsrs r0, r0, #2 |
| ; V7A-T-NEXT: bfi r2, r0, #5, #1 |
| ; V7A-T-NEXT: bfi r2, r0, #12, #1 |
| ; V7A-T-NEXT: .LBB0_5: @ %if.end |
| ; V7A-T-NEXT: str r2, [r1] |
| ; V7A-T-NEXT: .LBB0_6: @ %exit |
| ; V7A-T-NEXT: bx lr |
| ; |
| ; V6M-LABEL: f: |
| ; V6M: @ %bb.0: @ %entry |
| ; V6M-NEXT: .save {r4, lr} |
| ; V6M-NEXT: push {r4, lr} |
| ; V6M-NEXT: movs r2, #0 |
| ; V6M-NEXT: str r2, [r1] |
| ; V6M-NEXT: movs r3, #14 |
| ; V6M-NEXT: ands r3, r0 |
| ; V6M-NEXT: movs r4, #4 |
| ; V6M-NEXT: ands r4, r0 |
| ; V6M-NEXT: movs r2, #2 |
| ; V6M-NEXT: ands r2, r0 |
| ; V6M-NEXT: lsls r0, r0, #31 |
| ; V6M-NEXT: bne .LBB0_5 |
| ; V6M-NEXT: @ %bb.1: @ %if.then |
| ; V6M-NEXT: movs r0, #129 |
| ; V6M-NEXT: cmp r2, #0 |
| ; V6M-NEXT: beq .LBB0_3 |
| ; V6M-NEXT: @ %bb.2: |
| ; V6M-NEXT: lsls r2, r0, #8 |
| ; V6M-NEXT: .LBB0_3: @ %if.then |
| ; V6M-NEXT: cmp r4, #0 |
| ; V6M-NEXT: beq .LBB0_10 |
| ; V6M-NEXT: @ %bb.4: @ %if.then |
| ; V6M-NEXT: lsls r0, r0, #7 |
| ; V6M-NEXT: b .LBB0_9 |
| ; V6M-NEXT: .LBB0_5: @ %if.else |
| ; V6M-NEXT: movs r0, #129 |
| ; V6M-NEXT: cmp r2, #0 |
| ; V6M-NEXT: beq .LBB0_7 |
| ; V6M-NEXT: @ %bb.6: |
| ; V6M-NEXT: lsls r2, r0, #6 |
| ; V6M-NEXT: .LBB0_7: @ %if.else |
| ; V6M-NEXT: cmp r4, #0 |
| ; V6M-NEXT: beq .LBB0_10 |
| ; V6M-NEXT: @ %bb.8: @ %if.else |
| ; V6M-NEXT: lsls r0, r0, #5 |
| ; V6M-NEXT: .LBB0_9: @ %if.else |
| ; V6M-NEXT: adds r2, r2, r0 |
| ; V6M-NEXT: .LBB0_10: @ %if.else |
| ; V6M-NEXT: cmp r3, #0 |
| ; V6M-NEXT: beq .LBB0_12 |
| ; V6M-NEXT: @ %bb.11: @ %if.end |
| ; V6M-NEXT: str r2, [r1] |
| ; V6M-NEXT: .LBB0_12: @ %exit |
| ; V6M-NEXT: pop {r4, pc} |
| entry: |
| store i32 0, ptr %outp, align 4 |
| %and = and i32 %v, 1 |
| %cmp = icmp eq i32 %and, 0 |
| %and1 = and i32 %v, 2 |
| %tobool.not = icmp eq i32 %and1, 0 |
| %and2 = and i32 %v, 4 |
| %tobool1.not = icmp eq i32 %and2, 0 |
| %and3 = and i32 %v, 14 |
| %tobool2.not = icmp eq i32 %and3, 0 |
| br i1 %cmp, label %if.then, label %if.else |
| |
| if.then: |
| %select = select i1 %tobool.not, i32 0, i32 33024 |
| %or = or i32 %select, 16512 |
| %spec.select = select i1 %tobool1.not, i32 %select, i32 %or |
| br i1 %tobool2.not, label %exit, label %if.end |
| |
| if.else: |
| %select1 = select i1 %tobool.not, i32 0, i32 8256 |
| %or1 = or i32 %select1, 4128 |
| %spec.select1 = select i1 %tobool1.not, i32 %select1, i32 %or1 |
| br i1 %tobool2.not, label %exit, label %if.end |
| |
| if.end: |
| %spec.select.sink = phi i32 [ %spec.select, %if.then ], [ %spec.select1, %if.else ] |
| store i32 %spec.select.sink, ptr %outp, align 4 |
| br label %exit |
| |
| exit: |
| ret void |
| } |
| |
| ; Test with a mask that can be encoded with T32 instruction set, but not with A32. |
| define i32 @f0(i1 %c0, i32 %v, ptr %p) { |
| ; V7M-LABEL: f0: |
| ; V7M: @ %bb.0: @ %E |
| ; V7M-NEXT: lsls r0, r0, #31 |
| ; V7M-NEXT: beq .LBB1_2 |
| ; V7M-NEXT: @ %bb.1: @ %A |
| ; V7M-NEXT: tst.w r1, #16843009 |
| ; V7M-NEXT: itt eq |
| ; V7M-NEXT: moveq r0, #0 |
| ; V7M-NEXT: bxeq lr |
| ; V7M-NEXT: b .LBB1_3 |
| ; V7M-NEXT: .LBB1_2: @ %B |
| ; V7M-NEXT: movs r0, #1 |
| ; V7M-NEXT: tst.w r1, #16843009 |
| ; V7M-NEXT: str r0, [r2] |
| ; V7M-NEXT: itt ne |
| ; V7M-NEXT: movne r0, #0 |
| ; V7M-NEXT: bxne lr |
| ; V7M-NEXT: .LBB1_3: @ %D |
| ; V7M-NEXT: movs r0, #1 |
| ; V7M-NEXT: bx lr |
| ; |
| ; V7A-LABEL: f0: |
| ; V7A: @ %bb.0: @ %E |
| ; V7A-NEXT: movw r3, #257 |
| ; V7A-NEXT: tst r0, #1 |
| ; V7A-NEXT: movt r3, #257 |
| ; V7A-NEXT: and r1, r1, r3 |
| ; V7A-NEXT: beq .LBB1_3 |
| ; V7A-NEXT: @ %bb.1: @ %A |
| ; V7A-NEXT: cmp r1, #0 |
| ; V7A-NEXT: moveq r0, #0 |
| ; V7A-NEXT: bxeq lr |
| ; V7A-NEXT: .LBB1_2: @ %D |
| ; V7A-NEXT: mov r0, #1 |
| ; V7A-NEXT: bx lr |
| ; V7A-NEXT: .LBB1_3: @ %B |
| ; V7A-NEXT: mov r0, #1 |
| ; V7A-NEXT: cmp r1, #0 |
| ; V7A-NEXT: str r0, [r2] |
| ; V7A-NEXT: mov r0, #0 |
| ; V7A-NEXT: moveq r0, #1 |
| ; V7A-NEXT: bx lr |
| ; |
| ; V7A-T-LABEL: f0: |
| ; V7A-T: @ %bb.0: @ %E |
| ; V7A-T-NEXT: lsls r0, r0, #31 |
| ; V7A-T-NEXT: beq .LBB1_2 |
| ; V7A-T-NEXT: @ %bb.1: @ %A |
| ; V7A-T-NEXT: tst.w r1, #16843009 |
| ; V7A-T-NEXT: itt eq |
| ; V7A-T-NEXT: moveq r0, #0 |
| ; V7A-T-NEXT: bxeq lr |
| ; V7A-T-NEXT: b .LBB1_3 |
| ; V7A-T-NEXT: .LBB1_2: @ %B |
| ; V7A-T-NEXT: movs r0, #1 |
| ; V7A-T-NEXT: tst.w r1, #16843009 |
| ; V7A-T-NEXT: str r0, [r2] |
| ; V7A-T-NEXT: itt ne |
| ; V7A-T-NEXT: movne r0, #0 |
| ; V7A-T-NEXT: bxne lr |
| ; V7A-T-NEXT: .LBB1_3: @ %D |
| ; V7A-T-NEXT: movs r0, #1 |
| ; V7A-T-NEXT: bx lr |
| ; |
| ; V6M-LABEL: f0: |
| ; V6M: @ %bb.0: @ %E |
| ; V6M-NEXT: ldr r3, .LCPI1_0 |
| ; V6M-NEXT: ands r3, r1 |
| ; V6M-NEXT: lsls r0, r0, #31 |
| ; V6M-NEXT: beq .LBB1_3 |
| ; V6M-NEXT: @ %bb.1: @ %A |
| ; V6M-NEXT: cmp r3, #0 |
| ; V6M-NEXT: bne .LBB1_5 |
| ; V6M-NEXT: @ %bb.2: |
| ; V6M-NEXT: movs r0, #0 |
| ; V6M-NEXT: bx lr |
| ; V6M-NEXT: .LBB1_3: @ %B |
| ; V6M-NEXT: movs r0, #1 |
| ; V6M-NEXT: str r0, [r2] |
| ; V6M-NEXT: cmp r3, #0 |
| ; V6M-NEXT: beq .LBB1_5 |
| ; V6M-NEXT: @ %bb.4: |
| ; V6M-NEXT: movs r0, #0 |
| ; V6M-NEXT: bx lr |
| ; V6M-NEXT: .LBB1_5: @ %D |
| ; V6M-NEXT: movs r0, #1 |
| ; V6M-NEXT: bx lr |
| ; V6M-NEXT: .p2align 2 |
| ; V6M-NEXT: @ %bb.6: |
| ; V6M-NEXT: .LCPI1_0: |
| ; V6M-NEXT: .long 16843009 @ 0x1010101 |
| E: |
| %a = and i32 %v, 16843009 |
| br i1 %c0, label %A, label %B |
| |
| A: |
| %c1 = icmp eq i32 %a, 0 |
| br i1 %c1, label %C, label %D |
| |
| B: |
| %c2 = icmp eq i32 %a, 0 |
| store i32 1, ptr %p, align 4 |
| br i1 %c2, label %D, label %C |
| |
| C: |
| br label %X |
| |
| D: |
| br label %X |
| |
| X: |
| %x = phi i32 [0, %C], [1, %D] |
| ret i32 %x |
| } |
| |
| ; Test with a mask that can be encoded both with T32 and A32 instruction sets. |
| define i32 @f1(i1 %c0, i32 %v, ptr %p) { |
| ; V7M-LABEL: f1: |
| ; V7M: @ %bb.0: @ %E |
| ; V7M-NEXT: lsls r0, r0, #31 |
| ; V7M-NEXT: beq .LBB2_2 |
| ; V7M-NEXT: @ %bb.1: @ %A |
| ; V7M-NEXT: tst.w r1, #100663296 |
| ; V7M-NEXT: itt eq |
| ; V7M-NEXT: moveq r0, #0 |
| ; V7M-NEXT: bxeq lr |
| ; V7M-NEXT: b .LBB2_3 |
| ; V7M-NEXT: .LBB2_2: @ %B |
| ; V7M-NEXT: movs r0, #1 |
| ; V7M-NEXT: tst.w r1, #100663296 |
| ; V7M-NEXT: str r0, [r2] |
| ; V7M-NEXT: itt ne |
| ; V7M-NEXT: movne r0, #0 |
| ; V7M-NEXT: bxne lr |
| ; V7M-NEXT: .LBB2_3: @ %D |
| ; V7M-NEXT: movs r0, #1 |
| ; V7M-NEXT: bx lr |
| ; |
| ; V7A-LABEL: f1: |
| ; V7A: @ %bb.0: @ %E |
| ; V7A-NEXT: tst r0, #1 |
| ; V7A-NEXT: beq .LBB2_3 |
| ; V7A-NEXT: @ %bb.1: @ %A |
| ; V7A-NEXT: tst r1, #100663296 |
| ; V7A-NEXT: moveq r0, #0 |
| ; V7A-NEXT: bxeq lr |
| ; V7A-NEXT: .LBB2_2: @ %D |
| ; V7A-NEXT: mov r0, #1 |
| ; V7A-NEXT: bx lr |
| ; V7A-NEXT: .LBB2_3: @ %B |
| ; V7A-NEXT: mov r0, #1 |
| ; V7A-NEXT: tst r1, #100663296 |
| ; V7A-NEXT: str r0, [r2] |
| ; V7A-NEXT: mov r0, #0 |
| ; V7A-NEXT: moveq r0, #1 |
| ; V7A-NEXT: bx lr |
| ; |
| ; V7A-T-LABEL: f1: |
| ; V7A-T: @ %bb.0: @ %E |
| ; V7A-T-NEXT: lsls r0, r0, #31 |
| ; V7A-T-NEXT: beq .LBB2_2 |
| ; V7A-T-NEXT: @ %bb.1: @ %A |
| ; V7A-T-NEXT: tst.w r1, #100663296 |
| ; V7A-T-NEXT: itt eq |
| ; V7A-T-NEXT: moveq r0, #0 |
| ; V7A-T-NEXT: bxeq lr |
| ; V7A-T-NEXT: b .LBB2_3 |
| ; V7A-T-NEXT: .LBB2_2: @ %B |
| ; V7A-T-NEXT: movs r0, #1 |
| ; V7A-T-NEXT: tst.w r1, #100663296 |
| ; V7A-T-NEXT: str r0, [r2] |
| ; V7A-T-NEXT: itt ne |
| ; V7A-T-NEXT: movne r0, #0 |
| ; V7A-T-NEXT: bxne lr |
| ; V7A-T-NEXT: .LBB2_3: @ %D |
| ; V7A-T-NEXT: movs r0, #1 |
| ; V7A-T-NEXT: bx lr |
| ; |
| ; V6M-LABEL: f1: |
| ; V6M: @ %bb.0: @ %E |
| ; V6M-NEXT: movs r3, #3 |
| ; V6M-NEXT: lsls r3, r3, #25 |
| ; V6M-NEXT: ands r3, r1 |
| ; V6M-NEXT: lsls r0, r0, #31 |
| ; V6M-NEXT: beq .LBB2_3 |
| ; V6M-NEXT: @ %bb.1: @ %A |
| ; V6M-NEXT: cmp r3, #0 |
| ; V6M-NEXT: bne .LBB2_5 |
| ; V6M-NEXT: @ %bb.2: |
| ; V6M-NEXT: movs r0, #0 |
| ; V6M-NEXT: bx lr |
| ; V6M-NEXT: .LBB2_3: @ %B |
| ; V6M-NEXT: movs r0, #1 |
| ; V6M-NEXT: str r0, [r2] |
| ; V6M-NEXT: cmp r3, #0 |
| ; V6M-NEXT: beq .LBB2_5 |
| ; V6M-NEXT: @ %bb.4: |
| ; V6M-NEXT: movs r0, #0 |
| ; V6M-NEXT: bx lr |
| ; V6M-NEXT: .LBB2_5: @ %D |
| ; V6M-NEXT: movs r0, #1 |
| ; V6M-NEXT: bx lr |
| E: |
| %a = and i32 %v, 100663296 |
| br i1 %c0, label %A, label %B |
| |
| A: |
| %c1 = icmp eq i32 %a, 0 |
| br i1 %c1, label %C, label %D |
| |
| B: |
| %c2 = icmp eq i32 %a, 0 |
| store i32 1, ptr %p, align 4 |
| br i1 %c2, label %D, label %C |
| |
| C: |
| br label %X |
| |
| D: |
| br label %X |
| |
| X: |
| %x = phi i32 [0, %C], [1, %D] |
| ret i32 %x |
| } |