| ; 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 |
| } |