blob: 4db9db91852065a8b7b229fee1fa0545b55ac30d [file] [log] [blame] [edit]
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=aarch64-none-linux-gnu -verify-machineinstrs < %s | FileCheck %s
define i8 @test1(i32 %a) {
; CHECK-LABEL: test1:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: and w8, w0, #0x3ffc00
; CHECK-NEXT: and w8, w8, #0xffe007ff
; CHECK-NEXT: cmp w8, #1024
; CHECK-NEXT: cset w0, eq
; CHECK-NEXT: ret
entry:
%and = and i32 %a, 2098176
%cmp = icmp eq i32 %and, 1024
%conv = zext i1 %cmp to i8
ret i8 %conv
}
; This constant should not be split because it can be handled by one mov.
define i8 @test2(i32 %a) {
; CHECK-LABEL: test2:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov w8, #135 // =0x87
; CHECK-NEXT: and w8, w0, w8
; CHECK-NEXT: cmp w8, #1024
; CHECK-NEXT: cset w0, eq
; CHECK-NEXT: ret
entry:
%and = and i32 %a, 135
%cmp = icmp eq i32 %and, 1024
%conv = zext i1 %cmp to i8
ret i8 %conv
}
; This constant should not be split because the split immediate is not valid
; bitmask immediate.
define i8 @test3(i32 %a) {
; CHECK-LABEL: test3:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov w8, #1024 // =0x400
; CHECK-NEXT: movk w8, #33, lsl #16
; CHECK-NEXT: and w8, w0, w8
; CHECK-NEXT: cmp w8, #1024
; CHECK-NEXT: cset w0, eq
; CHECK-NEXT: ret
entry:
%and = and i32 %a, 2163712
%cmp = icmp eq i32 %and, 1024
%conv = zext i1 %cmp to i8
ret i8 %conv
}
define i8 @test4(i64 %a) {
; CHECK-LABEL: test4:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: and x8, x0, #0x3ffc00
; CHECK-NEXT: and x8, x8, #0xffffffffffe007ff
; CHECK-NEXT: cmp x8, #1024
; CHECK-NEXT: cset w0, eq
; CHECK-NEXT: ret
entry:
%and = and i64 %a, 2098176
%cmp = icmp eq i64 %and, 1024
%conv = zext i1 %cmp to i8
ret i8 %conv
}
define i8 @test5(i64 %a) {
; CHECK-LABEL: test5:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: and x8, x0, #0x3ffffc000
; CHECK-NEXT: and x8, x8, #0xfffffffe00007fff
; CHECK-NEXT: cmp x8, #1024
; CHECK-NEXT: cset w0, eq
; CHECK-NEXT: ret
entry:
%and = and i64 %a, 8589950976
%cmp = icmp eq i64 %and, 1024
%conv = zext i1 %cmp to i8
ret i8 %conv
}
; This constant should not be split because it can be handled by one mov.
define i8 @test6(i64 %a) {
; CHECK-LABEL: test6:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov w8, #135 // =0x87
; CHECK-NEXT: and x8, x0, x8
; CHECK-NEXT: cmp x8, #1024
; CHECK-NEXT: cset w0, eq
; CHECK-NEXT: ret
entry:
%and = and i64 %a, 135
%cmp = icmp eq i64 %and, 1024
%conv = zext i1 %cmp to i8
ret i8 %conv
}
; This constant should not be split because the split immediate is not valid
; bitmask immediate.
define i8 @test7(i64 %a) {
; CHECK-LABEL: test7:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov w8, #1024 // =0x400
; CHECK-NEXT: movk w8, #33, lsl #16
; CHECK-NEXT: and x8, x0, x8
; CHECK-NEXT: cmp x8, #1024
; CHECK-NEXT: cset w0, eq
; CHECK-NEXT: ret
entry:
%and = and i64 %a, 2163712
%cmp = icmp eq i64 %and, 1024
%conv = zext i1 %cmp to i8
ret i8 %conv
}
; The split bitmask immediates should be hoisted outside loop because they are
; loop invariant.
define void @test8(i64 %a, ptr noalias %src, ptr noalias %dst, i64 %n) {
; CHECK-LABEL: test8:
; CHECK: // %bb.0: // %loop.ph
; CHECK-NEXT: and x9, x0, #0x3ffc00
; CHECK-NEXT: mov x8, xzr
; CHECK-NEXT: and x9, x9, #0xffffffffffe007ff
; CHECK-NEXT: b .LBB7_2
; CHECK-NEXT: .LBB7_1: // %for.inc
; CHECK-NEXT: // in Loop: Header=BB7_2 Depth=1
; CHECK-NEXT: add x8, x8, #1
; CHECK-NEXT: cmp x8, x3
; CHECK-NEXT: b.gt .LBB7_4
; CHECK-NEXT: .LBB7_2: // %loop
; CHECK-NEXT: // =>This Inner Loop Header: Depth=1
; CHECK-NEXT: cmp x8, x9
; CHECK-NEXT: b.hs .LBB7_1
; CHECK-NEXT: // %bb.3: // %if.then
; CHECK-NEXT: // in Loop: Header=BB7_2 Depth=1
; CHECK-NEXT: ldr x10, [x1, x8, lsl #3]
; CHECK-NEXT: str x10, [x2, x8, lsl #3]
; CHECK-NEXT: b .LBB7_1
; CHECK-NEXT: .LBB7_4: // %exit
; CHECK-NEXT: ret
loop.ph:
br label %loop
loop:
%iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
%and = and i64 %a, 2098176
%cmp = icmp ult i64 %iv, %and
br i1 %cmp, label %if.then, label %if.else
if.then:
%src.arrayidx = getelementptr inbounds i64, ptr %src, i64 %iv
%val = load i64, ptr %src.arrayidx
%dst.arrayidx = getelementptr inbounds i64, ptr %dst, i64 %iv
store i64 %val, ptr %dst.arrayidx
br label %for.inc
if.else:
br label %for.inc
for.inc:
%inc = add nuw nsw i64 %iv, 1
%cond = icmp sgt i64 %inc, %n
br i1 %cond, label %exit, label %loop
exit:
ret void
}
; This constant should not be split because the `and` is not loop invariant.
define i32 @test9(ptr nocapture %x, ptr nocapture readonly %y, i32 %n) {
; CHECK-LABEL: test9:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: cmp w2, #1
; CHECK-NEXT: b.lt .LBB8_3
; CHECK-NEXT: // %bb.1: // %for.body.preheader
; CHECK-NEXT: mov w9, #1024 // =0x400
; CHECK-NEXT: mov w8, w2
; CHECK-NEXT: movk w9, #32, lsl #16
; CHECK-NEXT: .LBB8_2: // %for.body
; CHECK-NEXT: // =>This Inner Loop Header: Depth=1
; CHECK-NEXT: ldr w10, [x1], #4
; CHECK-NEXT: subs x8, x8, #1
; CHECK-NEXT: and w10, w10, w9
; CHECK-NEXT: str w10, [x0], #4
; CHECK-NEXT: b.ne .LBB8_2
; CHECK-NEXT: .LBB8_3: // %for.cond.cleanup
; CHECK-NEXT: mov w0, wzr
; CHECK-NEXT: ret
entry:
%cmp8 = icmp sgt i32 %n, 0
br i1 %cmp8, label %for.body.preheader, label %for.cond.cleanup
for.body.preheader: ; preds = %entry
%wide.trip.count = zext i32 %n to i64
br label %for.body
for.cond.cleanup: ; preds = %for.body, %entry
ret i32 0
for.body: ; preds = %for.body.preheader, %for.body
%indvars.iv = phi i64 [ 0, %for.body.preheader ], [ %indvars.iv.next, %for.body ]
%arrayidx = getelementptr inbounds i32, ptr %y, i64 %indvars.iv
%0 = load i32, ptr %arrayidx, align 4
%and = and i32 %0, 2098176
%arrayidx2 = getelementptr inbounds i32, ptr %x, i64 %indvars.iv
store i32 %and, ptr %arrayidx2, align 4
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
%exitcond.not = icmp eq i64 %indvars.iv.next, %wide.trip.count
br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
}
; After instruction selection end, we can see the `and` and `or` share the
; constant as below.
;
; %4:gpr32 = MOVi32imm 2098176
; %5:gpr32 = ANDWrr killed %3:gpr32, %4:gpr32
; STRWui killed %5:gpr32, %0:gpr64common, 0 :: (store (s32) into %ir.x, !tbaa !8)
; %6:gpr32 = LDRWui %1:gpr64common, 0 :: (load (s32) from %ir.y, !tbaa !8)
; %7:gpr32 = ORRWrr killed %6:gpr32, %4:gpr32
;
; In this case, the constant should not be split because it causes more
; instructions.
define void @test10(ptr nocapture %x, ptr nocapture readonly %y, ptr nocapture %z) {
; CHECK-LABEL: test10:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: ldr w8, [x1]
; CHECK-NEXT: mov w9, #1024 // =0x400
; CHECK-NEXT: movk w9, #32, lsl #16
; CHECK-NEXT: and w8, w8, w9
; CHECK-NEXT: str w8, [x0]
; CHECK-NEXT: ldr w8, [x1]
; CHECK-NEXT: orr w8, w8, w9
; CHECK-NEXT: str w8, [x2]
; CHECK-NEXT: ret
entry:
%0 = load i32, ptr %y, align 4
%and = and i32 %0, 2098176
store i32 %and, ptr %x, align 4
%1 = load i32, ptr %y, align 4
%or = or i32 %1, 2098176
store i32 %or, ptr %z, align 4
ret void
}
; This test genereates below MIs.
;
; MOVi32imm -1610612736
; SUBREG_TO_REG
;
; The constant should be zero-extended to 64 bit and it should not be split.
define i8 @test11(i64 %a) {
; CHECK-LABEL: test11:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov w8, #-1610612736 // =0xa0000000
; CHECK-NEXT: and x8, x0, x8
; CHECK-NEXT: cmp x8, #1024
; CHECK-NEXT: cset w0, eq
; CHECK-NEXT: ret
entry:
%and = and i64 %a, 2684354560
%cmp = icmp eq i64 %and, 1024
%conv = zext i1 %cmp to i8
ret i8 %conv
}
; Test ANDS.
define i32 @test1_ands(i32 %a) {
; CHECK-LABEL: test1_ands:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: and w8, w0, #0x3ffc00
; CHECK-NEXT: ands w8, w8, #0xffe007ff
; CHECK-NEXT: csel w0, w0, w8, eq
; CHECK-NEXT: ret
entry:
%ands = and i32 %a, 2098176
%c = icmp eq i32 %ands, 0
%r = select i1 %c, i32 %a, i32 %ands
ret i32 %r
}
; This constant should not be split because it can be handled by one mov.
define i32 @test2_ands(i32 %a) {
; CHECK-LABEL: test2_ands:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov w8, #135 // =0x87
; CHECK-NEXT: ands w8, w0, w8
; CHECK-NEXT: csel w0, w0, w8, eq
; CHECK-NEXT: ret
entry:
%ands = and i32 %a, 135
%c = icmp eq i32 %ands, 0
%r = select i1 %c, i32 %a, i32 %ands
ret i32 %r
}
; This constant should not be split because the split immediate is not valid
; bitmask immediate.
define i32 @test3_ands(i32 %a) {
; CHECK-LABEL: test3_ands:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov w8, #1024 // =0x400
; CHECK-NEXT: movk w8, #33, lsl #16
; CHECK-NEXT: ands w8, w0, w8
; CHECK-NEXT: csel w0, w0, w8, eq
; CHECK-NEXT: ret
entry:
%ands = and i32 %a, 2163712
%c = icmp eq i32 %ands, 0
%r = select i1 %c, i32 %a, i32 %ands
ret i32 %r
}
define i64 @test4_ands(i64 %a) {
; CHECK-LABEL: test4_ands:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: and x8, x0, #0x3ffc00
; CHECK-NEXT: ands x8, x8, #0xffffffffffe007ff
; CHECK-NEXT: csel x0, x0, x8, eq
; CHECK-NEXT: ret
entry:
%ands = and i64 %a, 2098176
%c = icmp eq i64 %ands, 0
%r = select i1 %c, i64 %a, i64 %ands
ret i64 %r
}
define i64 @test5_ands(i64 %a) {
; CHECK-LABEL: test5_ands:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: and x8, x0, #0x3ffffc000
; CHECK-NEXT: ands x8, x8, #0xfffffffe00007fff
; CHECK-NEXT: csel x0, x0, x8, eq
; CHECK-NEXT: ret
entry:
%ands = and i64 %a, 8589950976
%c = icmp eq i64 %ands, 0
%r = select i1 %c, i64 %a, i64 %ands
ret i64 %r
}
; This constant should not be split because it can be handled by one mov.
define i64 @test6_ands(i64 %a) {
; CHECK-LABEL: test6_ands:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov w8, #135 // =0x87
; CHECK-NEXT: ands x8, x0, x8
; CHECK-NEXT: csel x0, x0, x8, eq
; CHECK-NEXT: ret
entry:
%ands = and i64 %a, 135
%c = icmp eq i64 %ands, 0
%r = select i1 %c, i64 %a, i64 %ands
ret i64 %r
}
; This constant should not be split because the split immediate is not valid
; bitmask immediate.
define i64 @test7_ands(i64 %a) {
; CHECK-LABEL: test7_ands:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov w8, #1024 // =0x400
; CHECK-NEXT: movk w8, #33, lsl #16
; CHECK-NEXT: ands x8, x0, x8
; CHECK-NEXT: csel x0, x0, x8, eq
; CHECK-NEXT: ret
entry:
%ands = and i64 %a, 2163712
%c = icmp eq i64 %ands, 0
%r = select i1 %c, i64 %a, i64 %ands
ret i64 %r
}
; Test EOR.
define i32 @test1_eor(i32 %a) {
; CHECK-LABEL: test1_eor:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: eor w8, w0, #0x400
; CHECK-NEXT: eor w0, w8, #0x200000
; CHECK-NEXT: ret
entry:
%eor = xor i32 %a, 2098176
ret i32 %eor
}
; This constant should not be split because it can be handled by one mov.
define i32 @test2_eor(i32 %a) {
; CHECK-LABEL: test2_eor:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov w8, #135 // =0x87
; CHECK-NEXT: eor w0, w0, w8
; CHECK-NEXT: ret
entry:
%eor = xor i32 %a, 135
ret i32 %eor
}
; This constant should not be split because the split immediate is not valid
; bitmask immediate.
define i32 @test3_eor(i32 %a) {
; CHECK-LABEL: test3_eor:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov w8, #1024 // =0x400
; CHECK-NEXT: movk w8, #33, lsl #16
; CHECK-NEXT: eor w0, w0, w8
; CHECK-NEXT: ret
entry:
%eor = xor i32 %a, 2163712
ret i32 %eor
}
define i64 @test4_eor(i64 %a) {
; CHECK-LABEL: test4_eor:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: eor x8, x0, #0x400
; CHECK-NEXT: eor x0, x8, #0x200000
; CHECK-NEXT: ret
entry:
%eor = xor i64 %a, 2098176
ret i64 %eor
}
define i64 @test5_eor(i64 %a) {
; CHECK-LABEL: test5_eor:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: eor x8, x0, #0x4000
; CHECK-NEXT: eor x0, x8, #0x200000000
; CHECK-NEXT: ret
entry:
%eor = xor i64 %a, 8589950976
ret i64 %eor
}
; This constant should not be split because it can be handled by one mov.
define i64 @test6_eor(i64 %a) {
; CHECK-LABEL: test6_eor:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov w8, #135 // =0x87
; CHECK-NEXT: eor x0, x0, x8
; CHECK-NEXT: ret
entry:
%eor = xor i64 %a, 135
ret i64 %eor
}
; This constant should not be split because the split immediate is not valid
; bitmask immediate.
define i64 @test7_eor(i64 %a) {
; CHECK-LABEL: test7_eor:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov w8, #1024 // =0x400
; CHECK-NEXT: movk w8, #33, lsl #16
; CHECK-NEXT: eor x0, x0, x8
; CHECK-NEXT: ret
entry:
%eor = xor i64 %a, 2163712
ret i64 %eor
}
; Test ORR.
define i32 @test1_orr(i32 %a) {
; CHECK-LABEL: test1_orr:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: orr w8, w0, #0x400
; CHECK-NEXT: orr w0, w8, #0x200000
; CHECK-NEXT: ret
entry:
%orr = or i32 %a, 2098176
ret i32 %orr
}
; This constant should not be split because it can be handled by one mov.
define i32 @test2_orr(i32 %a) {
; CHECK-LABEL: test2_orr:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov w8, #135 // =0x87
; CHECK-NEXT: orr w0, w0, w8
; CHECK-NEXT: ret
entry:
%orr = or i32 %a, 135
ret i32 %orr
}
; This constant should not be split because the split immediate is not valid
; bitmask immediate.
define i32 @test3_orr(i32 %a) {
; CHECK-LABEL: test3_orr:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov w8, #1024 // =0x400
; CHECK-NEXT: movk w8, #33, lsl #16
; CHECK-NEXT: orr w0, w0, w8
; CHECK-NEXT: ret
entry:
%orr = or i32 %a, 2163712
ret i32 %orr
}
define i64 @test4_orr(i64 %a) {
; CHECK-LABEL: test4_orr:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: orr x8, x0, #0x400
; CHECK-NEXT: orr x0, x8, #0x200000
; CHECK-NEXT: ret
entry:
%orr = or i64 %a, 2098176
ret i64 %orr
}
define i64 @test5_orr(i64 %a) {
; CHECK-LABEL: test5_orr:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: orr x8, x0, #0x4000
; CHECK-NEXT: orr x0, x8, #0x200000000
; CHECK-NEXT: ret
entry:
%orr = or i64 %a, 8589950976
ret i64 %orr
}
; This constant should not be split because it can be handled by one mov.
define i64 @test6_orr(i64 %a) {
; CHECK-LABEL: test6_orr:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov w8, #135 // =0x87
; CHECK-NEXT: orr x0, x0, x8
; CHECK-NEXT: ret
entry:
%orr = or i64 %a, 135
ret i64 %orr
}
; This constant should not be split because the split immediate is not valid
; bitmask immediate.
define i64 @test7_orr(i64 %a) {
; CHECK-LABEL: test7_orr:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov w8, #1024 // =0x400
; CHECK-NEXT: movk w8, #33, lsl #16
; CHECK-NEXT: orr x0, x0, x8
; CHECK-NEXT: ret
entry:
%orr = or i64 %a, 2163712
ret i64 %orr
}