; 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 ; 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 ; 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 ; 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 ; 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, i64* noalias %src, i64* 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: lsl x10, x8, #3 ; CHECK-NEXT: ldr x11, [x1, x10] ; CHECK-NEXT: str x11, [x2, x10] ; 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, i64* %src, i64 %iv %val = load i64, i64* %src.arrayidx %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv store i64 %val, i64* %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(i32* nocapture %x, i32* 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 ; 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, i32* %y, i64 %indvars.iv %0 = load i32, i32* %arrayidx, align 4 %and = and i32 %0, 2098176 %arrayidx2 = getelementptr inbounds i32, i32* %x, i64 %indvars.iv store i32 %and, i32* %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(i32* nocapture %x, i32* nocapture readonly %y, i32* nocapture %z) { ; CHECK-LABEL: test10: ; CHECK: // %bb.0: // %entry ; CHECK-NEXT: ldr w8, [x1] ; CHECK-NEXT: mov w9, #1024 ; 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, i32* %y, align 4 %and = and i32 %0, 2098176 store i32 %and, i32* %x, align 4 %1 = load i32, i32* %y, align 4 %or = or i32 %1, 2098176 store i32 %or, i32* %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 ; 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 }