Compiler projects using llvm
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
#
# Check that we can fold (x & mask) -> x when (x & mask) is known to equal x.
#
# RUN: llc -mtriple aarch64 -run-pass=aarch64-postlegalizer-combiner -verify-machineinstrs %s -o - | FileCheck %s

---
name:            remove_and_with_one_bit
legalized:       true
tracksRegLiveness: true
body:             |
  bb.0:
    liveins: $w0, $w1
    ; G_ICMP produces a single bit. The mask is 1.
    ;
    ; cmp = 000...0?
    ; mask = 000...01
    ; cmp & mask = 000...0?
    ;
    ; Remove the G_AND.
    ;
    ; CHECK-LABEL: name: remove_and_with_one_bit
    ; CHECK: liveins: $w0, $w1
    ; CHECK: %x:_(s32) = COPY $w0
    ; CHECK: %y:_(s32) = COPY $w1
    ; CHECK: %cmp:_(s32) = G_ICMP intpred(eq), %x(s32), %y
    ; CHECK: $w0 = COPY %cmp(s32)
    ; CHECK: RET_ReallyLR implicit $w0
    %x:_(s32) = COPY $w0
    %y:_(s32) = COPY $w1
    %cmp:_(s32) = G_ICMP intpred(eq), %x(s32), %y
    %mask:_(s32) = G_CONSTANT i32 1
    %and:_(s32) = G_AND %cmp(s32), %mask
    $w0 = COPY %and(s32)
    RET_ReallyLR implicit $w0

...
---
name:            remove_and_all_ones_mask
legalized:       true
tracksRegLiveness: true
body:             |
  bb.0:
    liveins: $w0, $w1, $w2
    ; -1 is all ones. Therefore z & -1 = z. Remove the G_AND.
    ;
    ; CHECK-LABEL: name: remove_and_all_ones_mask
    ; CHECK: liveins: $w0, $w1, $w2
    ; CHECK: %z:_(s32) = COPY $w2
    ; CHECK: $w0 = COPY %z(s32)
    ; CHECK: RET_ReallyLR implicit $w0
    %x:_(s32) = COPY $w0
    %y:_(s32) = COPY $w1
    %z:_(s32) = COPY $w2
    %mask:_(s32) = G_CONSTANT i32 -1
    %and:_(s32) = G_AND %z(s32), %mask
    $w0 = COPY %and(s32)
    RET_ReallyLR implicit $w0

...
---
name:            remove_and_all_ones_zext
legalized:       true
tracksRegLiveness: true
body:             |
  bb.0:
    liveins: $w0, $w1, $w2
    ; %z is a s32, so it can be at most the all-ones value on 32 bits.
    ; In decimal this is 4294967295. Any zero-extension of %z is at most this
    ; value.
    ;
    ; Therefore, zext(z) & 4294967295 == z. Remove the G_AND.
    ;
    ; CHECK-LABEL: name: remove_and_all_ones_zext
    ; CHECK: liveins: $w0, $w1, $w2
    ; CHECK: %z:_(s32) = COPY $w2
    ; CHECK: %ext:_(s64) = G_ZEXT %z(s32)
    ; CHECK: $x0 = COPY %ext(s64)
    ; CHECK: RET_ReallyLR implicit $x0
    %x:_(s32) = COPY $w0
    %y:_(s32) = COPY $w1
    %z:_(s32) = COPY $w2
    %ext:_(s64) = G_ZEXT %z
    %mask:_(s64) = G_CONSTANT i64 4294967295
    %and:_(s64) = G_AND %ext(s64), %mask
    $x0 = COPY %and(s64)
    RET_ReallyLR implicit $x0

...
---
name:            remove_and_all_ones_anyext
legalized:       true
tracksRegLiveness: true
body:             |
  bb.0:
    liveins: $w0, $w1, $w2
    ; This is the same as the zext case.
    ;
    ; CHECK-LABEL: name: remove_and_all_ones_anyext
    ; CHECK: liveins: $w0, $w1, $w2
    ; CHECK: %z:_(s32) = COPY $w2
    ; CHECK: %ext:_(s64) = G_ZEXT %z(s32)
    ; CHECK: $x0 = COPY %ext(s64)
    ; CHECK: RET_ReallyLR implicit $x0
    %x:_(s32) = COPY $w0
    %y:_(s32) = COPY $w1
    %z:_(s32) = COPY $w2
    %ext:_(s64) = G_ZEXT %z
    %mask:_(s64) = G_CONSTANT i64 4294967295
    %and:_(s64) = G_AND %ext(s64), %mask
    $x0 = COPY %and(s64)
    RET_ReallyLR implicit $x0

...
---
name:            dont_remove_all_ones_sext
legalized:       true
tracksRegLiveness: true
body:             |
  bb.0:
    liveins: $w0, $w1, $w2
    ; We don't know if the sign bit is set on %z. So, the value in %ext may have
    ; higher bits set than 4294967295.
    ;
    ; CHECK-LABEL: name: dont_remove_all_ones_sext
    ; CHECK: liveins: $w0, $w1, $w2
    ; CHECK: %z:_(s32) = COPY $w2
    ; CHECK: %ext:_(s64) = G_SEXT %z(s32)
    ; CHECK: %mask:_(s64) = G_CONSTANT i64 4294967295
    ; CHECK: %and:_(s64) = G_AND %ext, %mask
    ; CHECK: $x0 = COPY %and(s64)
    ; CHECK: RET_ReallyLR implicit $x0
    %x:_(s32) = COPY $w0
    %y:_(s32) = COPY $w1
    %z:_(s32) = COPY $w2
    %ext:_(s64) = G_SEXT %z
    %mask:_(s64) = G_CONSTANT i64 4294967295
    %and:_(s64) = G_AND %ext(s64), %mask
    $x0 = COPY %and(s64)
    RET_ReallyLR implicit $x0

...
---
name:            remove_and_positive_constant_sext
legalized:       true
tracksRegLiveness: true
body:             |
  bb.0:
    liveins: $w0, $w1, $w2
    ; We know the sign bit is not set on %z. Therefore,
    ;
    ; z = ext = 42 = 000...0101010
    ; mask = 0000...0111111
    ;
    ; So z & mask == z
    ; CHECK-LABEL: name: remove_and_positive_constant_sext
    ; CHECK: liveins: $w0, $w1, $w2
    ; CHECK: %z:_(s32) = G_CONSTANT i32 42
    ; CHECK: %ext:_(s64) = G_SEXT %z(s32)
    ; CHECK: $x0 = COPY %ext(s64)
    ; CHECK: RET_ReallyLR implicit $x0
    %x:_(s32) = COPY $w0
    %y:_(s32) = COPY $w1
    %z:_(s32) = G_CONSTANT i32 42
    %ext:_(s64) = G_SEXT %z
    %mask:_(s64) = G_CONSTANT i64 63
    %and:_(s64) = G_AND %ext(s64), %mask
    $x0 = COPY %and(s64)
    RET_ReallyLR implicit $x0

...
---
name:            not_a_mask
legalized:       true
tracksRegLiveness: true
body:             |
  bb.0:
    liveins: $w0, $w1
    ; 6 is not a mask, so we should still have the G_AND.
    ;
    ; CHECK-LABEL: name: not_a_mask
    ; CHECK: liveins: $w0, $w1
    ; CHECK: %x:_(s32) = COPY $w0
    ; CHECK: %y:_(s32) = COPY $w1
    ; CHECK: %cmp:_(s32) = G_ICMP intpred(eq), %x(s32), %y
    ; CHECK: %mask:_(s32) = G_CONSTANT i32 6
    ; CHECK: %and:_(s32) = G_AND %cmp, %mask
    ; CHECK: $w0 = COPY %and(s32)
    ; CHECK: RET_ReallyLR implicit $w0
    %x:_(s32) = COPY $w0
    %y:_(s32) = COPY $w1
    %cmp:_(s32) = G_ICMP intpred(eq), %x(s32), %y
    %mask:_(s32) = G_CONSTANT i32 6
    %and:_(s32) = G_AND %cmp(s32), %mask
    $w0 = COPY %and(s32)
    RET_ReallyLR implicit $w0

...
---
name:            unknown_val
legalized:       true
tracksRegLiveness: true
body:             |
  bb.0:
    liveins: $w0, $w1, $w2
    ; We don't know what's in $w2, so we can't remove the G_AND without a mask
    ; that fills every bit in the type.
    ;
    ; CHECK-LABEL: name: unknown_val
    ; CHECK: liveins: $w0, $w1, $w2
    ; CHECK: %z:_(s32) = COPY $w2
    ; CHECK: %one:_(s32) = G_CONSTANT i32 32
    ; CHECK: %and:_(s32) = G_AND %z, %one
    ; CHECK: $w0 = COPY %and(s32)
    ; CHECK: RET_ReallyLR implicit $w0
    %x:_(s32) = COPY $w0
    %y:_(s32) = COPY $w1
    %z:_(s32) = COPY $w2
    %one:_(s32) = G_CONSTANT i32 32
    %and:_(s32) = G_AND %z(s32), %one
    $w0 = COPY %and(s32)
    RET_ReallyLR implicit $w0
...
---
name:            remove_and_assert_zext
legalized:       true
tracksRegLiveness: true
body:             |
  bb.0:
    liveins: $w0
    ; G_ASSERT_ZEXT communicates that only the bottom 8 bits of %x can be set.
    ; So, the G_AND can be removed.

    ; CHECK-LABEL: name: remove_and_assert_zext
    ; CHECK: liveins: $w0
    ; CHECK: %x:_(s32) = COPY $w0
    ; CHECK: %assert_zext:_(s32) = G_ASSERT_ZEXT %x, 8
    ; CHECK: $w0 = COPY %assert_zext(s32)
    ; CHECK: RET_ReallyLR implicit $w0
    %x:_(s32) = COPY $w0
    %assert_zext:_(s32) = G_ASSERT_ZEXT %x(s32), 8
    %mask:_(s32) = G_CONSTANT i32 255
    %and:_(s32) = G_AND %assert_zext(s32), %mask
    $w0 = COPY %and(s32)
    RET_ReallyLR implicit $w0
...
---
name:            dont_remove_and_assert_zext_wrong_mask
legalized:       true
tracksRegLiveness: true
body:             |
  bb.0:
    liveins: $w0
    ; The mask here is for 8 bits, not 16.

    ; CHECK-LABEL: name: dont_remove_and_assert_zext
    ; CHECK: liveins: $w0
    ; CHECK: %x:_(s32) = COPY $w0
    ; CHECK: %assert_zext:_(s32) = G_ASSERT_ZEXT %x, 16
    ; CHECK: %mask:_(s32) = G_CONSTANT i32 255
    ; CHECK: %and:_(s32) = G_AND %assert_zext, %mask
    ; CHECK: $w0 = COPY %and(s32)
    ; CHECK: RET_ReallyLR implicit $w0
    %x:_(s32) = COPY $w0
    %assert_zext:_(s32) = G_ASSERT_ZEXT %x(s32), 16
    %mask:_(s32) = G_CONSTANT i32 255
    %and:_(s32) = G_AND %assert_zext(s32), %mask
    $w0 = COPY %and(s32)
    RET_ReallyLR implicit $w0