# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py # RUN: llc -mtriple aarch64 -run-pass=aarch64-postlegalizer-combiner --aarch64postlegalizercombiner-only-enable-rule="bitfield_extract_from_and" -verify-machineinstrs %s -o - | FileCheck %s # REQUIRES: asserts # Check that we can combine # # and (lshr x, cst), mask -> ubfx x, cst, width # LSB = 5 # Width = LSB + trailing_ones(255) - 1 = # 5 + 8 - 1 = 12 ... --- name: ubfx_s32 tracksRegLiveness: true legalized: true body: | bb.0: liveins: $w0 ; CHECK-LABEL: name: ubfx_s32 ; CHECK: liveins: $w0 ; CHECK-NEXT: {{ $}} ; CHECK-NEXT: %x:_(s32) = COPY $w0 ; CHECK-NEXT: %lsb:_(s32) = G_CONSTANT i32 5 ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 8 ; CHECK-NEXT: %and:_(s32) = G_UBFX %x, %lsb(s32), [[C]] ; CHECK-NEXT: $w0 = COPY %and(s32) ; CHECK-NEXT: RET_ReallyLR implicit $w0 %x:_(s32) = COPY $w0 %lsb:_(s32) = G_CONSTANT i32 5 %mask:_(s32) = G_CONSTANT i32 255 %shift:_(s32) = G_LSHR %x, %lsb %and:_(s32) = G_AND %shift, %mask $w0 = COPY %and RET_ReallyLR implicit $w0 # LSB = 5 # Width = LSB + trailing_ones(1) - 1 = # 5 + 1 - 1 = 5 ... --- name: ubfx_s64 tracksRegLiveness: true legalized: true body: | bb.0: liveins: $x0 ; CHECK-LABEL: name: ubfx_s64 ; CHECK: liveins: $x0 ; CHECK-NEXT: {{ $}} ; CHECK-NEXT: %x:_(s64) = COPY $x0 ; CHECK-NEXT: %lsb:_(s64) = G_CONSTANT i64 5 ; CHECK-NEXT: %mask:_(s64) = G_CONSTANT i64 1 ; CHECK-NEXT: %and:_(s64) = G_UBFX %x, %lsb(s64), %mask ; CHECK-NEXT: $x0 = COPY %and(s64) ; CHECK-NEXT: RET_ReallyLR implicit $x0 %x:_(s64) = COPY $x0 %lsb:_(s64) = G_CONSTANT i64 5 %mask:_(s64) = G_CONSTANT i64 1 %shift:_(s64) = G_LSHR %x, %lsb %and:_(s64) = G_AND %shift, %mask $x0 = COPY %and RET_ReallyLR implicit $x0 # UBFX needs to be selected to UBFMWri/UBFMXri, so we need constants. ... --- name: dont_combine_no_and_cst tracksRegLiveness: true legalized: true body: | bb.0: liveins: $w0, $w1 ; CHECK-LABEL: name: dont_combine_no_and_cst ; CHECK: liveins: $w0, $w1 ; CHECK-NEXT: {{ $}} ; CHECK-NEXT: %x:_(s32) = COPY $w0 ; CHECK-NEXT: %y:_(s32) = COPY $w1 ; CHECK-NEXT: %lsb:_(s32) = G_CONSTANT i32 5 ; CHECK-NEXT: %shift:_(s32) = G_LSHR %x, %lsb(s32) ; CHECK-NEXT: %and:_(s32) = G_AND %shift, %y ; CHECK-NEXT: $w0 = COPY %and(s32) ; CHECK-NEXT: RET_ReallyLR implicit $w0 %x:_(s32) = COPY $w0 %y:_(s32) = COPY $w1 %lsb:_(s32) = G_CONSTANT i32 5 %shift:_(s32) = G_LSHR %x, %lsb %and:_(s32) = G_AND %shift, %y $w0 = COPY %and RET_ReallyLR implicit $w0 ... --- name: dont_combine_and_cst_not_mask tracksRegLiveness: true legalized: true body: | bb.0: liveins: $w0 ; CHECK-LABEL: name: dont_combine_and_cst_not_mask ; CHECK: liveins: $w0 ; CHECK-NEXT: {{ $}} ; CHECK-NEXT: %x:_(s32) = COPY $w0 ; CHECK-NEXT: %lsb:_(s32) = G_CONSTANT i32 5 ; CHECK-NEXT: %not_a_mask:_(s32) = G_CONSTANT i32 2 ; CHECK-NEXT: %shift:_(s32) = G_LSHR %x, %lsb(s32) ; CHECK-NEXT: %and:_(s32) = G_AND %shift, %not_a_mask ; CHECK-NEXT: $w0 = COPY %and(s32) ; CHECK-NEXT: RET_ReallyLR implicit $w0 %x:_(s32) = COPY $w0 %lsb:_(s32) = G_CONSTANT i32 5 %not_a_mask:_(s32) = G_CONSTANT i32 2 %shift:_(s32) = G_LSHR %x, %lsb %and:_(s32) = G_AND %shift, %not_a_mask $w0 = COPY %and RET_ReallyLR implicit $w0 ... --- name: dont_combine_shift_more_than_one_use tracksRegLiveness: true legalized: true body: | bb.0: liveins: $x0 ; CHECK-LABEL: name: dont_combine_shift_more_than_one_use ; CHECK: liveins: $x0 ; CHECK-NEXT: {{ $}} ; CHECK-NEXT: %x:_(s64) = COPY $x0 ; CHECK-NEXT: %lsb:_(s64) = G_CONSTANT i64 5 ; CHECK-NEXT: %mask:_(s64) = G_CONSTANT i64 1 ; CHECK-NEXT: %shift:_(s64) = G_LSHR %x, %lsb(s64) ; CHECK-NEXT: %and:_(s64) = G_AND %shift, %mask ; CHECK-NEXT: %sub:_(s64) = G_SUB %and, %shift ; CHECK-NEXT: $x0 = COPY %sub(s64) ; CHECK-NEXT: RET_ReallyLR implicit $x0 %x:_(s64) = COPY $x0 %lsb:_(s64) = G_CONSTANT i64 5 %mask:_(s64) = G_CONSTANT i64 1 %shift:_(s64) = G_LSHR %x, %lsb %and:_(s64) = G_AND %shift, %mask %sub:_(s64) = G_SUB %and, %shift $x0 = COPY %sub RET_ReallyLR implicit $x0 # LSB must be in [0, reg_size) ... --- name: dont_combine_negative_lsb tracksRegLiveness: true legalized: true body: | bb.0: liveins: $w0 ; CHECK-LABEL: name: dont_combine_negative_lsb ; CHECK: liveins: $w0 ; CHECK-NEXT: {{ $}} ; CHECK-NEXT: %x:_(s32) = COPY $w0 ; CHECK-NEXT: %negative:_(s32) = G_CONSTANT i32 -1 ; CHECK-NEXT: %mask:_(s32) = G_CONSTANT i32 255 ; CHECK-NEXT: %shift:_(s32) = G_LSHR %x, %negative(s32) ; CHECK-NEXT: %and:_(s32) = G_AND %shift, %mask ; CHECK-NEXT: $w0 = COPY %and(s32) ; CHECK-NEXT: RET_ReallyLR implicit $w0 %x:_(s32) = COPY $w0 %negative:_(s32) = G_CONSTANT i32 -1 %mask:_(s32) = G_CONSTANT i32 255 %shift:_(s32) = G_LSHR %x, %negative %and:_(s32) = G_AND %shift, %mask $w0 = COPY %and RET_ReallyLR implicit $w0 # LSB must be in [0, reg_size) ... --- name: dont_combine_lsb_too_large tracksRegLiveness: true legalized: true body: | bb.0: liveins: $w0 ; CHECK-LABEL: name: dont_combine_lsb_too_large ; CHECK: liveins: $w0 ; CHECK-NEXT: {{ $}} ; CHECK-NEXT: %x:_(s32) = COPY $w0 ; CHECK-NEXT: %too_large:_(s32) = G_CONSTANT i32 32 ; CHECK-NEXT: %mask:_(s32) = G_CONSTANT i32 255 ; CHECK-NEXT: %shift:_(s32) = G_LSHR %x, %too_large(s32) ; CHECK-NEXT: %and:_(s32) = G_AND %shift, %mask ; CHECK-NEXT: $w0 = COPY %and(s32) ; CHECK-NEXT: RET_ReallyLR implicit $w0 %x:_(s32) = COPY $w0 %too_large:_(s32) = G_CONSTANT i32 32 %mask:_(s32) = G_CONSTANT i32 255 %shift:_(s32) = G_LSHR %x, %too_large %and:_(s32) = G_AND %shift, %mask $w0 = COPY %and RET_ReallyLR implicit $w0 ... --- name: dont_combine_vector tracksRegLiveness: true legalized: true body: | bb.0: liveins: $d0 ; CHECK-LABEL: name: dont_combine_vector ; CHECK: liveins: $d0 ; CHECK-NEXT: {{ $}} ; CHECK-NEXT: %x:_(<2 x s32>) = COPY $d0 ; CHECK-NEXT: %lsb_cst:_(s32) = G_CONSTANT i32 5 ; CHECK-NEXT: %lsb:_(<2 x s32>) = G_BUILD_VECTOR %lsb_cst(s32), %lsb_cst(s32) ; CHECK-NEXT: %mask_cst:_(s32) = G_CONSTANT i32 255 ; CHECK-NEXT: %mask:_(<2 x s32>) = G_BUILD_VECTOR %mask_cst(s32), %mask_cst(s32) ; CHECK-NEXT: %shift:_(<2 x s32>) = G_LSHR %x, %lsb(<2 x s32>) ; CHECK-NEXT: %and:_(<2 x s32>) = G_AND %shift, %mask ; CHECK-NEXT: $d0 = COPY %and(<2 x s32>) ; CHECK-NEXT: RET_ReallyLR implicit $d0 %x:_(<2 x s32>) = COPY $d0 %lsb_cst:_(s32) = G_CONSTANT i32 5 %lsb:_(<2 x s32>) = G_BUILD_VECTOR %lsb_cst, %lsb_cst %mask_cst:_(s32) = G_CONSTANT i32 255 %mask:_(<2 x s32>) = G_BUILD_VECTOR %mask_cst, %mask_cst %shift:_(<2 x s32>) = G_LSHR %x, %lsb %and:_(<2 x s32>) = G_AND %shift, %mask $d0 = COPY %and RET_ReallyLR implicit $d0 # mask = 0111 1111 1111 ... 1111 # mask + 1 = 1000 0000 0000 ... 0000 ... --- name: max_signed_int_mask tracksRegLiveness: true legalized: true body: | bb.0: liveins: $x0 ; CHECK-LABEL: name: max_signed_int_mask ; CHECK: liveins: $x0 ; CHECK-NEXT: {{ $}} ; CHECK-NEXT: %x:_(s64) = COPY $x0 ; CHECK-NEXT: %lsb:_(s64) = G_CONSTANT i64 0 ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 63 ; CHECK-NEXT: %and:_(s64) = G_UBFX %x, %lsb(s64), [[C]] ; CHECK-NEXT: $x0 = COPY %and(s64) ; CHECK-NEXT: RET_ReallyLR implicit $x0 %x:_(s64) = COPY $x0 %lsb:_(s64) = G_CONSTANT i64 0 %mask:_(s64) = G_CONSTANT i64 9223372036854775807 %shift:_(s64) = G_LSHR %x, %lsb %and:_(s64) = G_AND %shift, %mask $x0 = COPY %and RET_ReallyLR implicit $x0 # mask = 1111 1111 1111 ... 1111 # mask + 1 = 0000 0000 0000 ... 000 ... --- name: max_unsigned_int_mask tracksRegLiveness: true legalized: true body: | bb.0: liveins: $x0 ; CHECK-LABEL: name: max_unsigned_int_mask ; CHECK: liveins: $x0 ; CHECK-NEXT: {{ $}} ; CHECK-NEXT: %x:_(s64) = COPY $x0 ; CHECK-NEXT: %lsb:_(s64) = G_CONSTANT i64 5 ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 64 ; CHECK-NEXT: %and:_(s64) = G_UBFX %x, %lsb(s64), [[C]] ; CHECK-NEXT: $x0 = COPY %and(s64) ; CHECK-NEXT: RET_ReallyLR implicit $x0 %x:_(s64) = COPY $x0 %lsb:_(s64) = G_CONSTANT i64 5 %mask:_(s64) = G_CONSTANT i64 18446744073709551615 %shift:_(s64) = G_LSHR %x, %lsb %and:_(s64) = G_AND %shift, %mask $x0 = COPY %and RET_ReallyLR implicit $x0