Files
clang-p2996/llvm/test/Transforms/InstCombine/and.ll
Nikita Popov a105877646 [InstCombine] Remove some of the complexity-based canonicalization (#91185)
The idea behind this canonicalization is that it allows us to handle less
patterns, because we know that some will be canonicalized away. This is
indeed very useful to e.g. know that constants are always on the right.

However, this is only useful if the canonicalization is actually
reliable. This is the case for constants, but not for arguments: Moving
these to the right makes it look like the "more complex" expression is
guaranteed to be on the left, but this is not actually the case in
practice. It fails as soon as you replace the argument with another
instruction.

The end result is that it looks like things correctly work in tests,
while they actually don't. We use the "thwart complexity-based
canonicalization" trick to handle this in tests, but it's often a
challenge for new contributors to get this right, and based on the
regressions this PR originally exposed, we clearly don't get this right
in many cases.

For this reason, I think that it's better to remove this complexity
canonicalization. It will make it much easier to write tests for
commuted cases and make sure that they are handled.
2024-08-21 12:02:54 +02:00

2872 lines
84 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
declare void @use8(i8)
declare void @use16(i16)
declare void @use32(i32)
; There should be no 'and' instructions left in any test.
define i32 @test_with_1(i32 %x) {
; CHECK-LABEL: @test_with_1(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[X:%.*]], 0
; CHECK-NEXT: [[AND:%.*]] = zext i1 [[TMP1]] to i32
; CHECK-NEXT: ret i32 [[AND]]
;
%shl = shl i32 1, %x
%and = and i32 %shl, 1
ret i32 %and
}
define i32 @test_with_3(i32 %x) {
; CHECK-LABEL: @test_with_3(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[X:%.*]], 0
; CHECK-NEXT: [[AND:%.*]] = zext i1 [[TMP1]] to i32
; CHECK-NEXT: ret i32 [[AND]]
;
%shl = shl i32 3, %x
%and = and i32 %shl, 1
ret i32 %and
}
define i32 @test_with_5(i32 %x) {
; CHECK-LABEL: @test_with_5(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[X:%.*]], 0
; CHECK-NEXT: [[AND:%.*]] = zext i1 [[TMP1]] to i32
; CHECK-NEXT: ret i32 [[AND]]
;
%shl = shl i32 5, %x
%and = and i32 %shl, 1
ret i32 %and
}
define i32 @test_with_neg_5(i32 %x) {
; CHECK-LABEL: @test_with_neg_5(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[X:%.*]], 0
; CHECK-NEXT: [[AND:%.*]] = zext i1 [[TMP1]] to i32
; CHECK-NEXT: ret i32 [[AND]]
;
%shl = shl i32 -5, %x
%and = and i32 %shl, 1
ret i32 %and
}
define i32 @test_with_even(i32 %x) {
; CHECK-LABEL: @test_with_even(
; CHECK-NEXT: ret i32 0
;
%shl = shl i32 4, %x
%and = and i32 %shl, 1
ret i32 %and
}
define <2 x i32> @test_vec(<2 x i32> %x) {
; CHECK-LABEL: @test_vec(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <2 x i32> [[X:%.*]], zeroinitializer
; CHECK-NEXT: [[AND:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i32>
; CHECK-NEXT: ret <2 x i32> [[AND]]
;
%shl = shl <2 x i32> <i32 5, i32 5>, %x
%and = and <2 x i32> %shl, <i32 1, i32 1>
ret <2 x i32> %and
}
define i32 @test_with_neg_even(i32 %x) {
; CHECK-LABEL: @test_with_neg_even(
; CHECK-NEXT: ret i32 0
;
%shl = shl i32 -4, %x
%and = and i32 %shl, 1
ret i32 %and
}
define i32 @test_with_more_one_use(i32 %x) {
; CHECK-LABEL: @test_with_more_one_use(
; CHECK-NEXT: [[SHL:%.*]] = shl i32 7, [[X:%.*]]
; CHECK-NEXT: [[AND:%.*]] = and i32 [[SHL]], 1
; CHECK-NEXT: call void @use32(i32 [[SHL]])
; CHECK-NEXT: ret i32 [[AND]]
;
%shl = shl i32 7, %x
%and = and i32 %shl, 1
call void @use32(i32 %shl)
ret i32 %and
}
define i32 @test1(i32 %A) {
; CHECK-LABEL: @test1(
; CHECK-NEXT: ret i32 0
;
%B = and i32 %A, 0
ret i32 %B
}
define i32 @test2(i32 %A) {
; CHECK-LABEL: @test2(
; CHECK-NEXT: ret i32 [[A:%.*]]
;
%B = and i32 %A, -1
ret i32 %B
}
define i1 @test3(i1 %A) {
; CHECK-LABEL: @test3(
; CHECK-NEXT: ret i1 false
;
%B = and i1 %A, false
ret i1 %B
}
define i1 @test3_logical(i1 %A) {
; CHECK-LABEL: @test3_logical(
; CHECK-NEXT: ret i1 false
;
%B = select i1 %A, i1 false, i1 false
ret i1 %B
}
define i1 @test4(i1 %A) {
; CHECK-LABEL: @test4(
; CHECK-NEXT: ret i1 [[A:%.*]]
;
%B = and i1 %A, true
ret i1 %B
}
define i1 @test4_logical(i1 %A) {
; CHECK-LABEL: @test4_logical(
; CHECK-NEXT: ret i1 [[A:%.*]]
;
%B = select i1 %A, i1 true, i1 false
ret i1 %B
}
define i32 @test5(i32 %A) {
; CHECK-LABEL: @test5(
; CHECK-NEXT: ret i32 [[A:%.*]]
;
%B = and i32 %A, %A
ret i32 %B
}
define i1 @test6(i1 %A) {
; CHECK-LABEL: @test6(
; CHECK-NEXT: ret i1 [[A:%.*]]
;
%B = and i1 %A, %A
ret i1 %B
}
define i1 @test6_logical(i1 %A) {
; CHECK-LABEL: @test6_logical(
; CHECK-NEXT: ret i1 [[A:%.*]]
;
%B = select i1 %A, i1 %A, i1 false
ret i1 %B
}
; A & ~A == 0
define i32 @test7(i32 %A) {
; CHECK-LABEL: @test7(
; CHECK-NEXT: ret i32 0
;
%NotA = xor i32 %A, -1
%B = and i32 %A, %NotA
ret i32 %B
}
; AND associates
define i8 @test8(i8 %A) {
; CHECK-LABEL: @test8(
; CHECK-NEXT: ret i8 0
;
%B = and i8 %A, 3
%C = and i8 %B, 4
ret i8 %C
}
; Test of sign bit, convert to setle %A, 0
define i1 @test9(i32 %A) {
; CHECK-LABEL: @test9(
; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[A:%.*]], 0
; CHECK-NEXT: ret i1 [[C]]
;
%B = and i32 %A, -2147483648
%C = icmp ne i32 %B, 0
ret i1 %C
}
; Test of sign bit, convert to setle %A, 0
define i1 @test9a(i32 %A) {
; CHECK-LABEL: @test9a(
; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[A:%.*]], 0
; CHECK-NEXT: ret i1 [[C]]
;
%B = and i32 %A, -2147483648
%C = icmp ne i32 %B, 0
ret i1 %C
}
define i32 @test10(i32 %A) {
; CHECK-LABEL: @test10(
; CHECK-NEXT: ret i32 1
;
%B = and i32 %A, 12
%C = xor i32 %B, 15
; (X ^ C1) & C2 --> (X & C2) ^ (C1&C2)
%D = and i32 %C, 1
ret i32 %D
}
define i32 @test11(i32 %A, ptr %P) {
; CHECK-LABEL: @test11(
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A:%.*]], -4
; CHECK-NEXT: [[C:%.*]] = xor i32 [[TMP1]], 15
; CHECK-NEXT: store i32 [[C]], ptr [[P:%.*]], align 4
; CHECK-NEXT: ret i32 3
;
%B = or i32 %A, 3
%C = xor i32 %B, 12
; additional use of C
store i32 %C, ptr %P
; %C = and uint %B, 3 --> 3
%D = and i32 %C, 3
ret i32 %D
}
define i1 @test12(i32 %A, i32 %B) {
; CHECK-LABEL: @test12(
; CHECK-NEXT: [[C1:%.*]] = icmp ult i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: ret i1 [[C1]]
;
%C1 = icmp ult i32 %A, %B
%C2 = icmp ule i32 %A, %B
; (A < B) & (A <= B) === (A < B)
%D = and i1 %C1, %C2
ret i1 %D
}
define i1 @test12_logical(i32 %A, i32 %B) {
; CHECK-LABEL: @test12_logical(
; CHECK-NEXT: [[C1:%.*]] = icmp ult i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: ret i1 [[C1]]
;
%C1 = icmp ult i32 %A, %B
%C2 = icmp ule i32 %A, %B
; (A < B) & (A <= B) === (A < B)
%D = select i1 %C1, i1 %C2, i1 false
ret i1 %D
}
define i1 @test13(i32 %A, i32 %B) {
; CHECK-LABEL: @test13(
; CHECK-NEXT: ret i1 false
;
%C1 = icmp ult i32 %A, %B
%C2 = icmp ugt i32 %A, %B
; (A < B) & (A > B) === false
%D = and i1 %C1, %C2
ret i1 %D
}
define i1 @test13_logical(i32 %A, i32 %B) {
; CHECK-LABEL: @test13_logical(
; CHECK-NEXT: ret i1 false
;
%C1 = icmp ult i32 %A, %B
%C2 = icmp ugt i32 %A, %B
; (A < B) & (A > B) === false
%D = select i1 %C1, i1 %C2, i1 false
ret i1 %D
}
define i1 @test14(i8 %A) {
; CHECK-LABEL: @test14(
; CHECK-NEXT: [[C:%.*]] = icmp slt i8 [[A:%.*]], 0
; CHECK-NEXT: ret i1 [[C]]
;
%B = and i8 %A, -128
%C = icmp ne i8 %B, 0
ret i1 %C
}
define i8 @test15(i8 %A) {
; CHECK-LABEL: @test15(
; CHECK-NEXT: ret i8 0
;
%B = lshr i8 %A, 7
; Always equals zero
%C = and i8 %B, 2
ret i8 %C
}
define i8 @test16(i8 %A) {
; CHECK-LABEL: @test16(
; CHECK-NEXT: ret i8 0
;
%B = shl i8 %A, 2
%C = and i8 %B, 3
ret i8 %C
}
define i1 @test18(i32 %A) {
; CHECK-LABEL: @test18(
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[A:%.*]], 127
; CHECK-NEXT: ret i1 [[C]]
;
%B = and i32 %A, -128
;; C >= 128
%C = icmp ne i32 %B, 0
ret i1 %C
}
define <2 x i1> @test18_vec(<2 x i32> %A) {
; CHECK-LABEL: @test18_vec(
; CHECK-NEXT: [[C:%.*]] = icmp ugt <2 x i32> [[A:%.*]], <i32 127, i32 127>
; CHECK-NEXT: ret <2 x i1> [[C]]
;
%B = and <2 x i32> %A, <i32 -128, i32 -128>
%C = icmp ne <2 x i32> %B, zeroinitializer
ret <2 x i1> %C
}
define i1 @test18a(i8 %A) {
; CHECK-LABEL: @test18a(
; CHECK-NEXT: [[C:%.*]] = icmp ult i8 [[A:%.*]], 2
; CHECK-NEXT: ret i1 [[C]]
;
%B = and i8 %A, -2
%C = icmp eq i8 %B, 0
ret i1 %C
}
define <2 x i1> @test18a_vec(<2 x i8> %A) {
; CHECK-LABEL: @test18a_vec(
; CHECK-NEXT: [[C:%.*]] = icmp ult <2 x i8> [[A:%.*]], <i8 2, i8 2>
; CHECK-NEXT: ret <2 x i1> [[C]]
;
%B = and <2 x i8> %A, <i8 -2, i8 -2>
%C = icmp eq <2 x i8> %B, zeroinitializer
ret <2 x i1> %C
}
define i32 @test19(i32 %A) {
; CHECK-LABEL: @test19(
; CHECK-NEXT: [[B:%.*]] = shl i32 [[A:%.*]], 3
; CHECK-NEXT: ret i32 [[B]]
;
%B = shl i32 %A, 3
;; Clearing a zero bit
%C = and i32 %B, -2
ret i32 %C
}
define i8 @test20(i8 %A) {
; CHECK-LABEL: @test20(
; CHECK-NEXT: [[C:%.*]] = lshr i8 [[A:%.*]], 7
; CHECK-NEXT: ret i8 [[C]]
;
%C = lshr i8 %A, 7
;; Unneeded
%D = and i8 %C, 1
ret i8 %D
}
define i1 @test23(i32 %A) {
; CHECK-LABEL: @test23(
; CHECK-NEXT: [[D:%.*]] = icmp eq i32 [[A:%.*]], 2
; CHECK-NEXT: ret i1 [[D]]
;
%B = icmp sgt i32 %A, 1
%C = icmp sle i32 %A, 2
%D = and i1 %B, %C
ret i1 %D
}
define i1 @test23_logical(i32 %A) {
; CHECK-LABEL: @test23_logical(
; CHECK-NEXT: [[D:%.*]] = icmp eq i32 [[A:%.*]], 2
; CHECK-NEXT: ret i1 [[D]]
;
%B = icmp sgt i32 %A, 1
%C = icmp sle i32 %A, 2
%D = select i1 %B, i1 %C, i1 false
ret i1 %D
}
define <2 x i1> @test23vec(<2 x i32> %A) {
; CHECK-LABEL: @test23vec(
; CHECK-NEXT: [[D:%.*]] = icmp eq <2 x i32> [[A:%.*]], <i32 2, i32 2>
; CHECK-NEXT: ret <2 x i1> [[D]]
;
%B = icmp sgt <2 x i32> %A, <i32 1, i32 1>
%C = icmp sle <2 x i32> %A, <i32 2, i32 2>
%D = and <2 x i1> %B, %C
ret <2 x i1> %D
}
define i1 @test24(i32 %A) {
; CHECK-LABEL: @test24(
; CHECK-NEXT: [[D:%.*]] = icmp sgt i32 [[A:%.*]], 2
; CHECK-NEXT: ret i1 [[D]]
;
%B = icmp sgt i32 %A, 1
%C = icmp ne i32 %A, 2
;; A > 2
%D = and i1 %B, %C
ret i1 %D
}
define i1 @test24_logical(i32 %A) {
; CHECK-LABEL: @test24_logical(
; CHECK-NEXT: [[D:%.*]] = icmp sgt i32 [[A:%.*]], 2
; CHECK-NEXT: ret i1 [[D]]
;
%B = icmp sgt i32 %A, 1
%C = icmp ne i32 %A, 2
;; A > 2
%D = select i1 %B, i1 %C, i1 false
ret i1 %D
}
define i1 @test25(i32 %A) {
; CHECK-LABEL: @test25(
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[A:%.*]], -50
; CHECK-NEXT: [[D:%.*]] = icmp ult i32 [[TMP1]], 50
; CHECK-NEXT: ret i1 [[D]]
;
%B = icmp sge i32 %A, 50
%C = icmp slt i32 %A, 100
%D = and i1 %B, %C
ret i1 %D
}
define i1 @test25_logical(i32 %A) {
; CHECK-LABEL: @test25_logical(
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[A:%.*]], -50
; CHECK-NEXT: [[D:%.*]] = icmp ult i32 [[TMP1]], 50
; CHECK-NEXT: ret i1 [[D]]
;
%B = icmp sge i32 %A, 50
%C = icmp slt i32 %A, 100
%D = select i1 %B, i1 %C, i1 false
ret i1 %D
}
define <2 x i1> @test25vec(<2 x i32> %A) {
; CHECK-LABEL: @test25vec(
; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i32> [[A:%.*]], <i32 -50, i32 -50>
; CHECK-NEXT: [[D:%.*]] = icmp ult <2 x i32> [[TMP1]], <i32 50, i32 50>
; CHECK-NEXT: ret <2 x i1> [[D]]
;
%B = icmp sge <2 x i32> %A, <i32 50, i32 50>
%C = icmp slt <2 x i32> %A, <i32 100, i32 100>
%D = and <2 x i1> %B, %C
ret <2 x i1> %D
}
define i8 @test27(i8 %A) {
; CHECK-LABEL: @test27(
; CHECK-NEXT: ret i8 0
;
%B = and i8 %A, 4
%C = sub i8 %B, 16
;; 0xF0
%D = and i8 %C, -16
%E = add i8 %D, 16
ret i8 %E
}
;; No demand for extra sign bits.
define i32 @ashr_lowmask(i32 %x) {
; CHECK-LABEL: @ashr_lowmask(
; CHECK-NEXT: [[A:%.*]] = lshr i32 [[X:%.*]], 24
; CHECK-NEXT: ret i32 [[A]]
;
%a = ashr i32 %x, 24
%r = and i32 %a, 255
ret i32 %r
}
define i32 @ashr_lowmask_use(i32 %x) {
; CHECK-LABEL: @ashr_lowmask_use(
; CHECK-NEXT: [[A:%.*]] = ashr i32 [[X:%.*]], 1
; CHECK-NEXT: call void @use32(i32 [[A]])
; CHECK-NEXT: [[R:%.*]] = lshr i32 [[X]], 1
; CHECK-NEXT: ret i32 [[R]]
;
%a = ashr i32 %x, 1
call void @use32(i32 %a)
%r = and i32 %a, 2147483647
ret i32 %r
}
define <2 x i8> @ashr_lowmask_use_splat(<2 x i8> %x, ptr %p) {
; CHECK-LABEL: @ashr_lowmask_use_splat(
; CHECK-NEXT: [[A:%.*]] = ashr <2 x i8> [[X:%.*]], <i8 7, i8 7>
; CHECK-NEXT: store <2 x i8> [[A]], ptr [[P:%.*]], align 2
; CHECK-NEXT: [[R:%.*]] = lshr <2 x i8> [[X]], <i8 7, i8 7>
; CHECK-NEXT: ret <2 x i8> [[R]]
;
%a = ashr <2 x i8> %x, <i8 7, i8 7>
store <2 x i8> %a, ptr %p
%r = and <2 x i8> %a, <i8 1, i8 1>
ret <2 x i8> %r
}
; negative test - must keep all low bits
define i32 @ashr_not_lowmask1_use(i32 %x) {
; CHECK-LABEL: @ashr_not_lowmask1_use(
; CHECK-NEXT: [[A:%.*]] = ashr i32 [[X:%.*]], 24
; CHECK-NEXT: call void @use32(i32 [[A]])
; CHECK-NEXT: [[R:%.*]] = and i32 [[A]], 254
; CHECK-NEXT: ret i32 [[R]]
;
%a = ashr i32 %x, 24
call void @use32(i32 %a)
%r = and i32 %a, 254
ret i32 %r
}
; negative test - must keep all low bits
define i32 @ashr_not_lowmask2_use(i32 %x) {
; CHECK-LABEL: @ashr_not_lowmask2_use(
; CHECK-NEXT: [[A:%.*]] = ashr i32 [[X:%.*]], 24
; CHECK-NEXT: call void @use32(i32 [[A]])
; CHECK-NEXT: [[R:%.*]] = and i32 [[A]], 127
; CHECK-NEXT: ret i32 [[R]]
;
%a = ashr i32 %x, 24
call void @use32(i32 %a)
%r = and i32 %a, 127
ret i32 %r
}
; negative test - must keep only low bits
define i32 @ashr_not_lowmask3_use(i32 %x) {
; CHECK-LABEL: @ashr_not_lowmask3_use(
; CHECK-NEXT: [[A:%.*]] = ashr i32 [[X:%.*]], 24
; CHECK-NEXT: call void @use32(i32 [[A]])
; CHECK-NEXT: [[R:%.*]] = and i32 [[A]], 511
; CHECK-NEXT: ret i32 [[R]]
;
%a = ashr i32 %x, 24
call void @use32(i32 %a)
%r = and i32 %a, 511
ret i32 %r
}
define i32 @test29(i8 %X) {
; CHECK-LABEL: @test29(
; CHECK-NEXT: [[Y:%.*]] = zext i8 [[X:%.*]] to i32
; CHECK-NEXT: ret i32 [[Y]]
;
%Y = zext i8 %X to i32
;; Zero extend makes this unneeded.
%Z = and i32 %Y, 255
ret i32 %Z
}
define i32 @test30(i1 %X) {
; CHECK-LABEL: @test30(
; CHECK-NEXT: [[Y:%.*]] = zext i1 [[X:%.*]] to i32
; CHECK-NEXT: ret i32 [[Y]]
;
%Y = zext i1 %X to i32
%Z = and i32 %Y, 1
ret i32 %Z
}
define i32 @test31(i1 %X) {
; CHECK-LABEL: @test31(
; CHECK-NEXT: [[Z:%.*]] = select i1 [[X:%.*]], i32 16, i32 0
; CHECK-NEXT: ret i32 [[Z]]
;
%Y = zext i1 %X to i32
%Z = shl i32 %Y, 4
%A = and i32 %Z, 16
ret i32 %A
}
; Demanded bit analysis allows us to eliminate the add.
define <2 x i32> @and_demanded_bits_splat_vec(<2 x i32> %x) {
; CHECK-LABEL: @and_demanded_bits_splat_vec(
; CHECK-NEXT: [[Z:%.*]] = and <2 x i32> [[X:%.*]], <i32 7, i32 7>
; CHECK-NEXT: ret <2 x i32> [[Z]]
;
%y = add <2 x i32> %x, <i32 8, i32 8>
%z = and <2 x i32> %y, <i32 7, i32 7>
ret <2 x i32> %z
}
; zext (x >> 8) has all zeros in the high 24-bits: 0x000000xx
; (y | 255) has all ones in the low 8-bits: 0xyyyyyyff
; 'and' of those is all known bits - it's just 'z'.
define i32 @and_zext_demanded(i16 %x, i32 %y) {
; CHECK-LABEL: @and_zext_demanded(
; CHECK-NEXT: [[S:%.*]] = lshr i16 [[X:%.*]], 8
; CHECK-NEXT: [[Z:%.*]] = zext nneg i16 [[S]] to i32
; CHECK-NEXT: ret i32 [[Z]]
;
%s = lshr i16 %x, 8
%z = zext i16 %s to i32
%o = or i32 %y, 255
%a = and i32 %o, %z
ret i32 %a
}
define i32 @test32(i32 %In) {
; CHECK-LABEL: @test32(
; CHECK-NEXT: ret i32 0
;
%Y = and i32 %In, 16
%Z = lshr i32 %Y, 2
%A = and i32 %Z, 1
ret i32 %A
}
;; Code corresponding to one-bit bitfield ^1.
define i32 @test33(i32 %b) {
; CHECK-LABEL: @test33(
; CHECK-NEXT: [[T13:%.*]] = xor i32 [[B:%.*]], 1
; CHECK-NEXT: ret i32 [[T13]]
;
%t4.mask = and i32 %b, 1
%t10 = xor i32 %t4.mask, 1
%t12 = and i32 %b, -2
%t13 = or i32 %t12, %t10
ret i32 %t13
}
define i32 @test33b(i32 %b) {
; CHECK-LABEL: @test33b(
; CHECK-NEXT: [[T13:%.*]] = xor i32 [[B:%.*]], 1
; CHECK-NEXT: ret i32 [[T13]]
;
%t4.mask = and i32 %b, 1
%t10 = xor i32 %t4.mask, 1
%t12 = and i32 %b, -2
%t13 = or i32 %t10, %t12
ret i32 %t13
}
define <2 x i32> @test33vec(<2 x i32> %b) {
; CHECK-LABEL: @test33vec(
; CHECK-NEXT: [[T13:%.*]] = xor <2 x i32> [[B:%.*]], <i32 1, i32 1>
; CHECK-NEXT: ret <2 x i32> [[T13]]
;
%t4.mask = and <2 x i32> %b, <i32 1, i32 1>
%t10 = xor <2 x i32> %t4.mask, <i32 1, i32 1>
%t12 = and <2 x i32> %b, <i32 -2, i32 -2>
%t13 = or <2 x i32> %t12, %t10
ret <2 x i32> %t13
}
define <2 x i32> @test33vecb(<2 x i32> %b) {
; CHECK-LABEL: @test33vecb(
; CHECK-NEXT: [[T13:%.*]] = xor <2 x i32> [[B:%.*]], <i32 1, i32 1>
; CHECK-NEXT: ret <2 x i32> [[T13]]
;
%t4.mask = and <2 x i32> %b, <i32 1, i32 1>
%t10 = xor <2 x i32> %t4.mask, <i32 1, i32 1>
%t12 = and <2 x i32> %b, <i32 -2, i32 -2>
%t13 = or <2 x i32> %t10, %t12
ret <2 x i32> %t13
}
define i32 @test34(i32 %A, i32 %B) {
; CHECK-LABEL: @test34(
; CHECK-NEXT: ret i32 [[B:%.*]]
;
%t2 = or i32 %B, %A
%t4 = and i32 %t2, %B
ret i32 %t4
}
; FIXME: This test should only need -passes=instsimplify (ValueTracking / computeKnownBits), not -passes=instcombine.
define <2 x i32> @PR24942(<2 x i32> %x) {
; CHECK-LABEL: @PR24942(
; CHECK-NEXT: ret <2 x i32> zeroinitializer
;
%lshr = lshr <2 x i32> %x, <i32 31, i32 31>
%and = and <2 x i32> %lshr, <i32 2, i32 2>
ret <2 x i32> %and
}
define i64 @test35(i32 %X) {
; CHECK-LABEL: @test35(
; CHECK-NEXT: [[TMP1:%.*]] = sub i32 0, [[X:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 240
; CHECK-NEXT: [[RES:%.*]] = zext nneg i32 [[TMP2]] to i64
; CHECK-NEXT: ret i64 [[RES]]
;
%zext = zext i32 %X to i64
%zsub = sub i64 0, %zext
%res = and i64 %zsub, 240
ret i64 %res
}
define <2 x i64> @test35_uniform(<2 x i32> %X) {
; CHECK-LABEL: @test35_uniform(
; CHECK-NEXT: [[TMP1:%.*]] = sub <2 x i32> zeroinitializer, [[X:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = and <2 x i32> [[TMP1]], <i32 240, i32 240>
; CHECK-NEXT: [[RES:%.*]] = zext nneg <2 x i32> [[TMP2]] to <2 x i64>
; CHECK-NEXT: ret <2 x i64> [[RES]]
;
%zext = zext <2 x i32> %X to <2 x i64>
%zsub = sub <2 x i64> zeroinitializer, %zext
%res = and <2 x i64> %zsub, <i64 240, i64 240>
ret <2 x i64> %res
}
define i64 @test36(i32 %X) {
; CHECK-LABEL: @test36(
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], 7
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 240
; CHECK-NEXT: [[RES:%.*]] = zext nneg i32 [[TMP2]] to i64
; CHECK-NEXT: ret i64 [[RES]]
;
%zext = zext i32 %X to i64
%zsub = add i64 %zext, 7
%res = and i64 %zsub, 240
ret i64 %res
}
define <2 x i64> @test36_uniform(<2 x i32> %X) {
; CHECK-LABEL: @test36_uniform(
; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i32> [[X:%.*]], <i32 7, i32 7>
; CHECK-NEXT: [[TMP2:%.*]] = and <2 x i32> [[TMP1]], <i32 240, i32 240>
; CHECK-NEXT: [[RES:%.*]] = zext nneg <2 x i32> [[TMP2]] to <2 x i64>
; CHECK-NEXT: ret <2 x i64> [[RES]]
;
%zext = zext <2 x i32> %X to <2 x i64>
%zsub = add <2 x i64> %zext, <i64 7, i64 7>
%res = and <2 x i64> %zsub, <i64 240, i64 240>
ret <2 x i64> %res
}
define <2 x i64> @test36_poison(<2 x i32> %X) {
; CHECK-LABEL: @test36_poison(
; CHECK-NEXT: [[ZEXT:%.*]] = zext <2 x i32> [[X:%.*]] to <2 x i64>
; CHECK-NEXT: [[ZSUB:%.*]] = add nuw nsw <2 x i64> [[ZEXT]], <i64 7, i64 poison>
; CHECK-NEXT: [[RES:%.*]] = and <2 x i64> [[ZSUB]], <i64 240, i64 poison>
; CHECK-NEXT: ret <2 x i64> [[RES]]
;
%zext = zext <2 x i32> %X to <2 x i64>
%zsub = add <2 x i64> %zext, <i64 7, i64 poison>
%res = and <2 x i64> %zsub, <i64 240, i64 poison>
ret <2 x i64> %res
}
define i64 @test37(i32 %X) {
; CHECK-LABEL: @test37(
; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[X:%.*]], 7
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 240
; CHECK-NEXT: [[RES:%.*]] = zext nneg i32 [[TMP2]] to i64
; CHECK-NEXT: ret i64 [[RES]]
;
%zext = zext i32 %X to i64
%zsub = mul i64 %zext, 7
%res = and i64 %zsub, 240
ret i64 %res
}
define <2 x i64> @test37_uniform(<2 x i32> %X) {
; CHECK-LABEL: @test37_uniform(
; CHECK-NEXT: [[TMP1:%.*]] = mul <2 x i32> [[X:%.*]], <i32 7, i32 7>
; CHECK-NEXT: [[TMP2:%.*]] = and <2 x i32> [[TMP1]], <i32 240, i32 240>
; CHECK-NEXT: [[RES:%.*]] = zext nneg <2 x i32> [[TMP2]] to <2 x i64>
; CHECK-NEXT: ret <2 x i64> [[RES]]
;
%zext = zext <2 x i32> %X to <2 x i64>
%zsub = mul <2 x i64> %zext, <i64 7, i64 7>
%res = and <2 x i64> %zsub, <i64 240, i64 240>
ret <2 x i64> %res
}
define <2 x i64> @test37_nonuniform(<2 x i32> %X) {
; CHECK-LABEL: @test37_nonuniform(
; CHECK-NEXT: [[ZEXT:%.*]] = zext <2 x i32> [[X:%.*]] to <2 x i64>
; CHECK-NEXT: [[ZSUB:%.*]] = mul nuw nsw <2 x i64> [[ZEXT]], <i64 7, i64 9>
; CHECK-NEXT: [[RES:%.*]] = and <2 x i64> [[ZSUB]], <i64 240, i64 110>
; CHECK-NEXT: ret <2 x i64> [[RES]]
;
%zext = zext <2 x i32> %X to <2 x i64>
%zsub = mul <2 x i64> %zext, <i64 7, i64 9>
%res = and <2 x i64> %zsub, <i64 240, i64 110>
ret <2 x i64> %res
}
define i64 @test38(i32 %X) {
; CHECK-LABEL: @test38(
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 240
; CHECK-NEXT: [[RES:%.*]] = zext nneg i32 [[TMP1]] to i64
; CHECK-NEXT: ret i64 [[RES]]
;
%zext = zext i32 %X to i64
%zsub = xor i64 %zext, 7
%res = and i64 %zsub, 240
ret i64 %res
}
define i64 @test39(i32 %X) {
; CHECK-LABEL: @test39(
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 240
; CHECK-NEXT: [[RES:%.*]] = zext nneg i32 [[TMP1]] to i64
; CHECK-NEXT: ret i64 [[RES]]
;
%zext = zext i32 %X to i64
%zsub = or i64 %zext, 7
%res = and i64 %zsub, 240
ret i64 %res
}
define i32 @lowmask_add_zext(i8 %x, i32 %y) {
; CHECK-LABEL: @lowmask_add_zext(
; CHECK-NEXT: [[Y_TR:%.*]] = trunc i32 [[Y:%.*]] to i8
; CHECK-NEXT: [[BO_NARROW:%.*]] = add i8 [[X:%.*]], [[Y_TR]]
; CHECK-NEXT: [[R:%.*]] = zext i8 [[BO_NARROW]] to i32
; CHECK-NEXT: ret i32 [[R]]
;
%zx = zext i8 %x to i32
%bo = add i32 %zx, %y
%r = and i32 %bo, 255
ret i32 %r
}
define i32 @lowmask_add_zext_commute(i16 %x, i32 %p) {
; CHECK-LABEL: @lowmask_add_zext_commute(
; CHECK-NEXT: [[Y:%.*]] = mul i32 [[P:%.*]], [[P]]
; CHECK-NEXT: [[Y_TR:%.*]] = trunc i32 [[Y]] to i16
; CHECK-NEXT: [[BO_NARROW:%.*]] = add i16 [[X:%.*]], [[Y_TR]]
; CHECK-NEXT: [[R:%.*]] = zext i16 [[BO_NARROW]] to i32
; CHECK-NEXT: ret i32 [[R]]
;
%y = mul i32 %p, %p ; thwart complexity-based canonicalization
%zx = zext i16 %x to i32
%bo = add i32 %y, %zx
%r = and i32 %bo, 65535
ret i32 %r
}
; negative test - the mask constant must match the zext source type
define i32 @lowmask_add_zext_wrong_mask(i8 %x, i32 %y) {
; CHECK-LABEL: @lowmask_add_zext_wrong_mask(
; CHECK-NEXT: [[ZX:%.*]] = zext i8 [[X:%.*]] to i32
; CHECK-NEXT: [[BO:%.*]] = add i32 [[Y:%.*]], [[ZX]]
; CHECK-NEXT: [[R:%.*]] = and i32 [[BO]], 511
; CHECK-NEXT: ret i32 [[R]]
;
%zx = zext i8 %x to i32
%bo = add i32 %zx, %y
%r = and i32 %bo, 511
ret i32 %r
}
; negative test - extra use
define i32 @lowmask_add_zext_use1(i8 %x, i32 %y) {
; CHECK-LABEL: @lowmask_add_zext_use1(
; CHECK-NEXT: [[ZX:%.*]] = zext i8 [[X:%.*]] to i32
; CHECK-NEXT: call void @use32(i32 [[ZX]])
; CHECK-NEXT: [[BO:%.*]] = add i32 [[Y:%.*]], [[ZX]]
; CHECK-NEXT: [[R:%.*]] = and i32 [[BO]], 255
; CHECK-NEXT: ret i32 [[R]]
;
%zx = zext i8 %x to i32
call void @use32(i32 %zx)
%bo = add i32 %zx, %y
%r = and i32 %bo, 255
ret i32 %r
}
; negative test - extra use
define i32 @lowmask_add_zext_use2(i8 %x, i32 %y) {
; CHECK-LABEL: @lowmask_add_zext_use2(
; CHECK-NEXT: [[ZX:%.*]] = zext i8 [[X:%.*]] to i32
; CHECK-NEXT: [[BO:%.*]] = add i32 [[Y:%.*]], [[ZX]]
; CHECK-NEXT: call void @use32(i32 [[BO]])
; CHECK-NEXT: [[R:%.*]] = and i32 [[BO]], 255
; CHECK-NEXT: ret i32 [[R]]
;
%zx = zext i8 %x to i32
%bo = add i32 %zx, %y
call void @use32(i32 %bo)
%r = and i32 %bo, 255
ret i32 %r
}
; vector splats work too
define <2 x i32> @lowmask_sub_zext(<2 x i4> %x, <2 x i32> %y) {
; CHECK-LABEL: @lowmask_sub_zext(
; CHECK-NEXT: [[Y_TR:%.*]] = trunc <2 x i32> [[Y:%.*]] to <2 x i4>
; CHECK-NEXT: [[BO_NARROW:%.*]] = sub <2 x i4> [[X:%.*]], [[Y_TR]]
; CHECK-NEXT: [[R:%.*]] = zext <2 x i4> [[BO_NARROW]] to <2 x i32>
; CHECK-NEXT: ret <2 x i32> [[R]]
;
%zx = zext <2 x i4> %x to <2 x i32>
%bo = sub <2 x i32> %zx, %y
%r = and <2 x i32> %bo, <i32 15, i32 15>
ret <2 x i32> %r
}
; weird types are allowed
define i17 @lowmask_sub_zext_commute(i5 %x, i17 %y) {
; CHECK-LABEL: @lowmask_sub_zext_commute(
; CHECK-NEXT: [[Y_TR:%.*]] = trunc i17 [[Y:%.*]] to i5
; CHECK-NEXT: [[BO_NARROW:%.*]] = sub i5 [[Y_TR]], [[X:%.*]]
; CHECK-NEXT: [[R:%.*]] = zext i5 [[BO_NARROW]] to i17
; CHECK-NEXT: ret i17 [[R]]
;
%zx = zext i5 %x to i17
%bo = sub i17 %y, %zx
%r = and i17 %bo, 31
ret i17 %r
}
define i32 @lowmask_mul_zext(i8 %x, i32 %y) {
; CHECK-LABEL: @lowmask_mul_zext(
; CHECK-NEXT: [[Y_TR:%.*]] = trunc i32 [[Y:%.*]] to i8
; CHECK-NEXT: [[BO_NARROW:%.*]] = mul i8 [[X:%.*]], [[Y_TR]]
; CHECK-NEXT: [[R:%.*]] = zext i8 [[BO_NARROW]] to i32
; CHECK-NEXT: ret i32 [[R]]
;
%zx = zext i8 %x to i32
%bo = mul i32 %zx, %y
%r = and i32 %bo, 255
ret i32 %r
}
define i32 @lowmask_xor_zext_commute(i8 %x, i32 %p) {
; CHECK-LABEL: @lowmask_xor_zext_commute(
; CHECK-NEXT: [[Y:%.*]] = mul i32 [[P:%.*]], [[P]]
; CHECK-NEXT: [[Y_TR:%.*]] = trunc i32 [[Y]] to i8
; CHECK-NEXT: [[BO_NARROW:%.*]] = xor i8 [[X:%.*]], [[Y_TR]]
; CHECK-NEXT: [[R:%.*]] = zext i8 [[BO_NARROW]] to i32
; CHECK-NEXT: ret i32 [[R]]
;
%y = mul i32 %p, %p ; thwart complexity-based canonicalization
%zx = zext i8 %x to i32
%bo = xor i32 %y, %zx
%r = and i32 %bo, 255
ret i32 %r
}
define i24 @lowmask_or_zext_commute(i16 %x, i24 %y) {
; CHECK-LABEL: @lowmask_or_zext_commute(
; CHECK-NEXT: [[Y_TR:%.*]] = trunc i24 [[Y:%.*]] to i16
; CHECK-NEXT: [[BO_NARROW:%.*]] = or i16 [[X:%.*]], [[Y_TR]]
; CHECK-NEXT: [[R:%.*]] = zext i16 [[BO_NARROW]] to i24
; CHECK-NEXT: ret i24 [[R]]
;
%zx = zext i16 %x to i24
%bo = or i24 %y, %zx
%r = and i24 %bo, 65535
ret i24 %r
}
define i32 @test40(i1 %C) {
; CHECK-LABEL: @test40(
; CHECK-NEXT: [[A:%.*]] = select i1 [[C:%.*]], i32 104, i32 10
; CHECK-NEXT: ret i32 [[A]]
;
%A = select i1 %C, i32 1000, i32 10
%V = and i32 %A, 123
ret i32 %V
}
define <2 x i32> @test40vec(i1 %C) {
; CHECK-LABEL: @test40vec(
; CHECK-NEXT: [[A:%.*]] = select i1 [[C:%.*]], <2 x i32> <i32 104, i32 104>, <2 x i32> <i32 10, i32 10>
; CHECK-NEXT: ret <2 x i32> [[A]]
;
%A = select i1 %C, <2 x i32> <i32 1000, i32 1000>, <2 x i32> <i32 10, i32 10>
%V = and <2 x i32> %A, <i32 123, i32 123>
ret <2 x i32> %V
}
define <2 x i32> @test40vec2(i1 %C) {
; CHECK-LABEL: @test40vec2(
; CHECK-NEXT: [[V:%.*]] = select i1 [[C:%.*]], <2 x i32> <i32 104, i32 324>, <2 x i32> <i32 10, i32 12>
; CHECK-NEXT: ret <2 x i32> [[V]]
;
%A = select i1 %C, <2 x i32> <i32 1000, i32 2500>, <2 x i32> <i32 10, i32 30>
%V = and <2 x i32> %A, <i32 123, i32 333>
ret <2 x i32> %V
}
define i32 @test41(i1 %which) {
; CHECK-LABEL: @test41(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[WHICH:%.*]], label [[FINAL:%.*]], label [[DELAY:%.*]]
; CHECK: delay:
; CHECK-NEXT: br label [[FINAL]]
; CHECK: final:
; CHECK-NEXT: [[A:%.*]] = phi i32 [ 104, [[ENTRY:%.*]] ], [ 10, [[DELAY]] ]
; CHECK-NEXT: ret i32 [[A]]
;
entry:
br i1 %which, label %final, label %delay
delay:
br label %final
final:
%A = phi i32 [ 1000, %entry ], [ 10, %delay ]
%value = and i32 %A, 123
ret i32 %value
}
define <2 x i32> @test41vec(i1 %which) {
; CHECK-LABEL: @test41vec(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[WHICH:%.*]], label [[FINAL:%.*]], label [[DELAY:%.*]]
; CHECK: delay:
; CHECK-NEXT: br label [[FINAL]]
; CHECK: final:
; CHECK-NEXT: [[A:%.*]] = phi <2 x i32> [ <i32 104, i32 104>, [[ENTRY:%.*]] ], [ <i32 10, i32 10>, [[DELAY]] ]
; CHECK-NEXT: ret <2 x i32> [[A]]
;
entry:
br i1 %which, label %final, label %delay
delay:
br label %final
final:
%A = phi <2 x i32> [ <i32 1000, i32 1000>, %entry ], [ <i32 10, i32 10>, %delay ]
%value = and <2 x i32> %A, <i32 123, i32 123>
ret <2 x i32> %value
}
define <2 x i32> @test41vec2(i1 %which) {
; CHECK-LABEL: @test41vec2(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[WHICH:%.*]], label [[FINAL:%.*]], label [[DELAY:%.*]]
; CHECK: delay:
; CHECK-NEXT: br label [[FINAL]]
; CHECK: final:
; CHECK-NEXT: [[A:%.*]] = phi <2 x i32> [ <i32 104, i32 324>, [[ENTRY:%.*]] ], [ <i32 10, i32 12>, [[DELAY]] ]
; CHECK-NEXT: ret <2 x i32> [[A]]
;
entry:
br i1 %which, label %final, label %delay
delay:
br label %final
final:
%A = phi <2 x i32> [ <i32 1000, i32 2500>, %entry ], [ <i32 10, i32 30>, %delay ]
%value = and <2 x i32> %A, <i32 123, i32 333>
ret <2 x i32> %value
}
define i32 @test42(i32 %a, i32 %c, i32 %d) {
; CHECK-LABEL: @test42(
; CHECK-NEXT: [[FORCE:%.*]] = mul i32 [[C:%.*]], [[D:%.*]]
; CHECK-NEXT: [[AND:%.*]] = and i32 [[FORCE]], [[A:%.*]]
; CHECK-NEXT: ret i32 [[AND]]
;
%force = mul i32 %c, %d ; forces the complexity sorting
%or = or i32 %a, %force
%nota = xor i32 %a, -1
%xor = xor i32 %nota, %force
%and = and i32 %xor, %or
ret i32 %and
}
define i32 @test43(i32 %a, i32 %c, i32 %d) {
; CHECK-LABEL: @test43(
; CHECK-NEXT: [[FORCE:%.*]] = mul i32 [[C:%.*]], [[D:%.*]]
; CHECK-NEXT: [[AND:%.*]] = and i32 [[FORCE]], [[A:%.*]]
; CHECK-NEXT: ret i32 [[AND]]
;
%force = mul i32 %c, %d ; forces the complexity sorting
%or = or i32 %a, %force
%nota = xor i32 %a, -1
%xor = xor i32 %nota, %force
%and = and i32 %or, %xor
ret i32 %and
}
; (~y | x) & y -> x & y
define i32 @test44(i32 %x, i32 %y) nounwind {
; CHECK-LABEL: @test44(
; CHECK-NEXT: [[A:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i32 [[A]]
;
%n = xor i32 %y, -1
%o = or i32 %n, %x
%a = and i32 %o, %y
ret i32 %a
}
; (x | ~y) & y -> x & y
define i32 @test45(i32 %x, i32 %y) nounwind {
; CHECK-LABEL: @test45(
; CHECK-NEXT: [[A:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i32 [[A]]
;
%n = xor i32 %y, -1
%o = or i32 %x, %n
%a = and i32 %o, %y
ret i32 %a
}
; y & (~y | x) -> y | x
define i32 @test46(i32 %x, i32 %y) nounwind {
; CHECK-LABEL: @test46(
; CHECK-NEXT: [[A:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: ret i32 [[A]]
;
%n = xor i32 %y, -1
%o = or i32 %n, %x
%a = and i32 %y, %o
ret i32 %a
}
; y & (x | ~y) -> y | x
define i32 @test47(i32 %x, i32 %y) nounwind {
; CHECK-LABEL: @test47(
; CHECK-NEXT: [[A:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: ret i32 [[A]]
;
%n = xor i32 %y, -1
%o = or i32 %x, %n
%a = and i32 %y, %o
ret i32 %a
}
; In the next 4 tests, vary the types and predicates for extra coverage.
; (X & (Y | ~X)) -> (X & Y), where 'not' is an inverted cmp
define i1 @and_orn_cmp_1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_orn_cmp_1(
; CHECK-NEXT: [[X:%.*]] = icmp sgt i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[Y:%.*]] = icmp ugt i32 [[C:%.*]], 42
; CHECK-NEXT: [[AND:%.*]] = and i1 [[X]], [[Y]]
; CHECK-NEXT: ret i1 [[AND]]
;
%x = icmp sgt i32 %a, %b
%x_inv = icmp sle i32 %a, %b
%y = icmp ugt i32 %c, 42 ; thwart complexity-based ordering
%or = or i1 %y, %x_inv
%and = and i1 %x, %or
ret i1 %and
}
define i1 @and_orn_cmp_1_logical(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_orn_cmp_1_logical(
; CHECK-NEXT: [[X:%.*]] = icmp sgt i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[Y:%.*]] = icmp ugt i32 [[C:%.*]], 42
; CHECK-NEXT: [[AND:%.*]] = select i1 [[X]], i1 [[Y]], i1 false
; CHECK-NEXT: ret i1 [[AND]]
;
%x = icmp sgt i32 %a, %b
%x_inv = icmp sle i32 %a, %b
%y = icmp ugt i32 %c, 42 ; thwart complexity-based ordering
%or = select i1 %y, i1 true, i1 %x_inv
%and = select i1 %x, i1 %or, i1 false
ret i1 %and
}
; Commute the 'and':
; ((Y | ~X) & X) -> (X & Y), where 'not' is an inverted cmp
define <2 x i1> @and_orn_cmp_2(<2 x i32> %a, <2 x i32> %b, <2 x i32> %c) {
; CHECK-LABEL: @and_orn_cmp_2(
; CHECK-NEXT: [[X:%.*]] = icmp sge <2 x i32> [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[Y:%.*]] = icmp ugt <2 x i32> [[C:%.*]], <i32 42, i32 47>
; CHECK-NEXT: [[AND:%.*]] = and <2 x i1> [[Y]], [[X]]
; CHECK-NEXT: ret <2 x i1> [[AND]]
;
%x = icmp sge <2 x i32> %a, %b
%x_inv = icmp slt <2 x i32> %a, %b
%y = icmp ugt <2 x i32> %c, <i32 42, i32 47> ; thwart complexity-based ordering
%or = or <2 x i1> %y, %x_inv
%and = and <2 x i1> %or, %x
ret <2 x i1> %and
}
; Commute the 'or':
; (X & (~X | Y)) -> (X & Y), where 'not' is an inverted cmp
define i1 @and_orn_cmp_3(i72 %a, i72 %b, i72 %c) {
; CHECK-LABEL: @and_orn_cmp_3(
; CHECK-NEXT: [[X:%.*]] = icmp ugt i72 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[Y:%.*]] = icmp ugt i72 [[C:%.*]], 42
; CHECK-NEXT: [[AND:%.*]] = and i1 [[X]], [[Y]]
; CHECK-NEXT: ret i1 [[AND]]
;
%x = icmp ugt i72 %a, %b
%x_inv = icmp ule i72 %a, %b
%y = icmp ugt i72 %c, 42 ; thwart complexity-based ordering
%or = or i1 %x_inv, %y
%and = and i1 %x, %or
ret i1 %and
}
define i1 @and_orn_cmp_3_logical(i72 %a, i72 %b, i72 %c) {
; CHECK-LABEL: @and_orn_cmp_3_logical(
; CHECK-NEXT: [[X:%.*]] = icmp ugt i72 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[Y:%.*]] = icmp ugt i72 [[C:%.*]], 42
; CHECK-NEXT: [[AND:%.*]] = select i1 [[X]], i1 [[Y]], i1 false
; CHECK-NEXT: ret i1 [[AND]]
;
%x = icmp ugt i72 %a, %b
%x_inv = icmp ule i72 %a, %b
%y = icmp ugt i72 %c, 42 ; thwart complexity-based ordering
%or = select i1 %x_inv, i1 true, i1 %y
%and = select i1 %x, i1 %or, i1 false
ret i1 %and
}
; Commute the 'and':
; ((~X | Y) & X) -> (X & Y), where 'not' is an inverted cmp
define <3 x i1> @or_andn_cmp_4(<3 x i32> %a, <3 x i32> %b, <3 x i32> %c) {
; CHECK-LABEL: @or_andn_cmp_4(
; CHECK-NEXT: [[X:%.*]] = icmp eq <3 x i32> [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[Y:%.*]] = icmp ugt <3 x i32> [[C:%.*]], <i32 42, i32 43, i32 -1>
; CHECK-NEXT: [[AND:%.*]] = and <3 x i1> [[Y]], [[X]]
; CHECK-NEXT: ret <3 x i1> [[AND]]
;
%x = icmp eq <3 x i32> %a, %b
%x_inv = icmp ne <3 x i32> %a, %b
%y = icmp ugt <3 x i32> %c, <i32 42, i32 43, i32 -1> ; thwart complexity-based ordering
%or = or <3 x i1> %x_inv, %y
%and = and <3 x i1> %or, %x
ret <3 x i1> %and
}
; In the next 4 tests, vary the types and predicates for extra coverage.
; (~X & (Y | X)) -> (~X & Y), where 'not' is an inverted cmp
define i1 @andn_or_cmp_1(i37 %a, i37 %b, i37 %c) {
; CHECK-LABEL: @andn_or_cmp_1(
; CHECK-NEXT: [[X_INV:%.*]] = icmp sle i37 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[Y:%.*]] = icmp ugt i37 [[C:%.*]], 42
; CHECK-NEXT: [[AND:%.*]] = and i1 [[X_INV]], [[Y]]
; CHECK-NEXT: ret i1 [[AND]]
;
%x = icmp sgt i37 %a, %b
%x_inv = icmp sle i37 %a, %b
%y = icmp ugt i37 %c, 42 ; thwart complexity-based ordering
%or = or i1 %y, %x
%and = and i1 %x_inv, %or
ret i1 %and
}
define i1 @andn_or_cmp_1_logical(i37 %a, i37 %b, i37 %c) {
; CHECK-LABEL: @andn_or_cmp_1_logical(
; CHECK-NEXT: [[X_INV:%.*]] = icmp sle i37 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[Y:%.*]] = icmp ugt i37 [[C:%.*]], 42
; CHECK-NEXT: [[AND:%.*]] = select i1 [[X_INV]], i1 [[Y]], i1 false
; CHECK-NEXT: ret i1 [[AND]]
;
%x = icmp sgt i37 %a, %b
%x_inv = icmp sle i37 %a, %b
%y = icmp ugt i37 %c, 42 ; thwart complexity-based ordering
%or = select i1 %y, i1 true, i1 %x
%and = select i1 %x_inv, i1 %or, i1 false
ret i1 %and
}
; Commute the 'and':
; ((Y | X) & ~X) -> (~X & Y), where 'not' is an inverted cmp
define i1 @andn_or_cmp_2(i16 %a, i16 %b, i16 %c) {
; CHECK-LABEL: @andn_or_cmp_2(
; CHECK-NEXT: [[X_INV:%.*]] = icmp slt i16 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[Y:%.*]] = icmp ugt i16 [[C:%.*]], 42
; CHECK-NEXT: [[AND:%.*]] = and i1 [[Y]], [[X_INV]]
; CHECK-NEXT: ret i1 [[AND]]
;
%x = icmp sge i16 %a, %b
%x_inv = icmp slt i16 %a, %b
%y = icmp ugt i16 %c, 42 ; thwart complexity-based ordering
%or = or i1 %y, %x
%and = and i1 %or, %x_inv
ret i1 %and
}
define i1 @andn_or_cmp_2_logical(i16 %a, i16 %b, i16 %c) {
; CHECK-LABEL: @andn_or_cmp_2_logical(
; CHECK-NEXT: [[X_INV:%.*]] = icmp slt i16 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[Y:%.*]] = icmp ugt i16 [[C:%.*]], 42
; CHECK-NEXT: [[AND:%.*]] = select i1 [[Y]], i1 [[X_INV]], i1 false
; CHECK-NEXT: ret i1 [[AND]]
;
%x = icmp sge i16 %a, %b
%x_inv = icmp slt i16 %a, %b
%y = icmp ugt i16 %c, 42 ; thwart complexity-based ordering
%or = select i1 %y, i1 true, i1 %x
%and = select i1 %or, i1 %x_inv, i1 false
ret i1 %and
}
; Commute the 'or':
; (~X & (X | Y)) -> (~X & Y), where 'not' is an inverted cmp
define <4 x i1> @andn_or_cmp_3(<4 x i32> %a, <4 x i32> %b, <4 x i32> %c) {
; CHECK-LABEL: @andn_or_cmp_3(
; CHECK-NEXT: [[X_INV:%.*]] = icmp ule <4 x i32> [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[Y:%.*]] = icmp ugt <4 x i32> [[C:%.*]], <i32 42, i32 0, i32 1, i32 -1>
; CHECK-NEXT: [[AND:%.*]] = and <4 x i1> [[X_INV]], [[Y]]
; CHECK-NEXT: ret <4 x i1> [[AND]]
;
%x = icmp ugt <4 x i32> %a, %b
%x_inv = icmp ule <4 x i32> %a, %b
%y = icmp ugt <4 x i32> %c, <i32 42, i32 0, i32 1, i32 -1> ; thwart complexity-based ordering
%or = or <4 x i1> %x, %y
%and = and <4 x i1> %x_inv, %or
ret <4 x i1> %and
}
; Commute the 'and':
; ((X | Y) & ~X) -> (~X & Y), where 'not' is an inverted cmp
define i1 @andn_or_cmp_4(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @andn_or_cmp_4(
; CHECK-NEXT: [[X_INV:%.*]] = icmp ne i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[Y:%.*]] = icmp ugt i32 [[C:%.*]], 42
; CHECK-NEXT: [[AND:%.*]] = and i1 [[Y]], [[X_INV]]
; CHECK-NEXT: ret i1 [[AND]]
;
%x = icmp eq i32 %a, %b
%x_inv = icmp ne i32 %a, %b
%y = icmp ugt i32 %c, 42 ; thwart complexity-based ordering
%or = or i1 %x, %y
%and = and i1 %or, %x_inv
ret i1 %and
}
define i1 @andn_or_cmp_4_logical(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @andn_or_cmp_4_logical(
; CHECK-NEXT: [[X_INV:%.*]] = icmp ne i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[Y:%.*]] = icmp ugt i32 [[C:%.*]], 42
; CHECK-NEXT: [[AND:%.*]] = select i1 [[X_INV]], i1 [[Y]], i1 false
; CHECK-NEXT: ret i1 [[AND]]
;
%x = icmp eq i32 %a, %b
%x_inv = icmp ne i32 %a, %b
%y = icmp ugt i32 %c, 42 ; thwart complexity-based ordering
%or = select i1 %x, i1 true, i1 %y
%and = select i1 %or, i1 %x_inv, i1 false
ret i1 %and
}
define i32 @lowbitmask_casted_shift(i8 %x) {
; CHECK-LABEL: @lowbitmask_casted_shift(
; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X:%.*]] to i32
; CHECK-NEXT: [[R:%.*]] = lshr i32 [[TMP1]], 1
; CHECK-NEXT: ret i32 [[R]]
;
%a = ashr i8 %x, 1
%s = sext i8 %a to i32
%r = and i32 %s, 2147483647
ret i32 %r
}
; Negative test - mask constant is too big.
define i32 @lowbitmask_casted_shift_wrong_mask1(i8 %x) {
; CHECK-LABEL: @lowbitmask_casted_shift_wrong_mask1(
; CHECK-NEXT: [[A:%.*]] = ashr i8 [[X:%.*]], 2
; CHECK-NEXT: [[S:%.*]] = sext i8 [[A]] to i32
; CHECK-NEXT: [[R:%.*]] = and i32 [[S]], 2147483647
; CHECK-NEXT: ret i32 [[R]]
;
%a = ashr i8 %x, 2
%s = sext i8 %a to i32
%r = and i32 %s, 2147483647 ; 0x7fffffff
ret i32 %r
}
; Negative test - mask constant is too small.
define i32 @lowbitmask_casted_shift_wrong_mask2(i8 %x) {
; CHECK-LABEL: @lowbitmask_casted_shift_wrong_mask2(
; CHECK-NEXT: [[A:%.*]] = ashr i8 [[X:%.*]], 2
; CHECK-NEXT: [[S:%.*]] = sext i8 [[A]] to i32
; CHECK-NEXT: [[R:%.*]] = and i32 [[S]], 536870911
; CHECK-NEXT: ret i32 [[R]]
;
%a = ashr i8 %x, 2
%s = sext i8 %a to i32
%r = and i32 %s, 536870911 ; 0x1fffffff
ret i32 %r
}
; Extra use of shift is ok.
define i32 @lowbitmask_casted_shift_use1(i8 %x) {
; CHECK-LABEL: @lowbitmask_casted_shift_use1(
; CHECK-NEXT: [[A:%.*]] = ashr i8 [[X:%.*]], 3
; CHECK-NEXT: call void @use8(i8 [[A]])
; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32
; CHECK-NEXT: [[R:%.*]] = lshr i32 [[TMP1]], 3
; CHECK-NEXT: ret i32 [[R]]
;
%a = ashr i8 %x, 3
call void @use8(i8 %a)
%s = sext i8 %a to i32
%r = and i32 %s, 536870911
ret i32 %r
}
; Negative test - extra use of sext requires more instructions.
define i32 @lowbitmask_casted_shift_use2(i8 %x) {
; CHECK-LABEL: @lowbitmask_casted_shift_use2(
; CHECK-NEXT: [[A:%.*]] = ashr i8 [[X:%.*]], 3
; CHECK-NEXT: [[S:%.*]] = sext i8 [[A]] to i32
; CHECK-NEXT: call void @use32(i32 [[S]])
; CHECK-NEXT: [[R:%.*]] = and i32 [[S]], 536870911
; CHECK-NEXT: ret i32 [[R]]
;
%a = ashr i8 %x, 3
%s = sext i8 %a to i32
call void @use32(i32 %s)
%r = and i32 %s, 536870911
ret i32 %r
}
; Vectors/weird types are ok.
define <2 x i59> @lowbitmask_casted_shift_vec_splat(<2 x i47> %x) {
; CHECK-LABEL: @lowbitmask_casted_shift_vec_splat(
; CHECK-NEXT: [[TMP1:%.*]] = sext <2 x i47> [[X:%.*]] to <2 x i59>
; CHECK-NEXT: [[R:%.*]] = lshr <2 x i59> [[TMP1]], <i59 5, i59 5>
; CHECK-NEXT: ret <2 x i59> [[R]]
;
%a = ashr <2 x i47> %x, <i47 5, i47 5>
%s = sext <2 x i47> %a to <2 x i59>
%r = and <2 x i59> %s, <i59 18014398509481983, i59 18014398509481983> ; -1 u>> 5 == 0x3f_ffff_ffff_ffff
ret <2 x i59> %r
}
define i32 @lowmask_sext_in_reg(i32 %x) {
; CHECK-LABEL: @lowmask_sext_in_reg(
; CHECK-NEXT: [[L:%.*]] = shl i32 [[X:%.*]], 20
; CHECK-NEXT: [[R:%.*]] = ashr exact i32 [[L]], 20
; CHECK-NEXT: call void @use32(i32 [[R]])
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], 4095
; CHECK-NEXT: ret i32 [[AND]]
;
%l = shl i32 %x, 20
%r = ashr i32 %l, 20
call void @use32(i32 %r)
%and = and i32 %r, 4095
ret i32 %and
}
; Mismatched shift amounts, but the mask op can be replaced by a shift.
define i32 @lowmask_not_sext_in_reg(i32 %x) {
; CHECK-LABEL: @lowmask_not_sext_in_reg(
; CHECK-NEXT: [[L:%.*]] = shl i32 [[X:%.*]], 19
; CHECK-NEXT: [[R:%.*]] = ashr i32 [[L]], 20
; CHECK-NEXT: call void @use32(i32 [[R]])
; CHECK-NEXT: [[AND:%.*]] = lshr i32 [[L]], 20
; CHECK-NEXT: ret i32 [[AND]]
;
%l = shl i32 %x, 19
%r = ashr i32 %l, 20
call void @use32(i32 %r)
%and = and i32 %r, 4095
ret i32 %and
}
; Negative test - too much shift for mask
define i32 @not_lowmask_sext_in_reg(i32 %x) {
; CHECK-LABEL: @not_lowmask_sext_in_reg(
; CHECK-NEXT: [[L:%.*]] = shl i32 [[X:%.*]], 20
; CHECK-NEXT: [[R:%.*]] = ashr exact i32 [[L]], 20
; CHECK-NEXT: call void @use32(i32 [[R]])
; CHECK-NEXT: [[AND:%.*]] = and i32 [[R]], 4096
; CHECK-NEXT: ret i32 [[AND]]
;
%l = shl i32 %x, 20
%r = ashr i32 %l, 20
call void @use32(i32 %r)
%and = and i32 %r, 4096
ret i32 %and
}
; Negative test - too much shift for mask
define i32 @not_lowmask_sext_in_reg2(i32 %x) {
; CHECK-LABEL: @not_lowmask_sext_in_reg2(
; CHECK-NEXT: [[L:%.*]] = shl i32 [[X:%.*]], 21
; CHECK-NEXT: [[R:%.*]] = ashr exact i32 [[L]], 21
; CHECK-NEXT: call void @use32(i32 [[R]])
; CHECK-NEXT: [[AND:%.*]] = and i32 [[R]], 4095
; CHECK-NEXT: ret i32 [[AND]]
;
%l = shl i32 %x, 21
%r = ashr i32 %l, 21
call void @use32(i32 %r)
%and = and i32 %r, 4095
ret i32 %and
}
define <2 x i32> @lowmask_sext_in_reg_splat(<2 x i32> %x, ptr %p) {
; CHECK-LABEL: @lowmask_sext_in_reg_splat(
; CHECK-NEXT: [[L:%.*]] = shl <2 x i32> [[X:%.*]], <i32 20, i32 20>
; CHECK-NEXT: [[R:%.*]] = ashr exact <2 x i32> [[L]], <i32 20, i32 20>
; CHECK-NEXT: store <2 x i32> [[R]], ptr [[P:%.*]], align 8
; CHECK-NEXT: [[AND:%.*]] = and <2 x i32> [[X]], <i32 4095, i32 4095>
; CHECK-NEXT: ret <2 x i32> [[AND]]
;
%l = shl <2 x i32> %x, <i32 20, i32 20>
%r = ashr <2 x i32> %l, <i32 20, i32 20>
store <2 x i32> %r, ptr %p
%and = and <2 x i32> %r, <i32 4095, i32 4095>
ret <2 x i32> %and
}
define i8 @lowmask_add(i8 %x) {
; CHECK-LABEL: @lowmask_add(
; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], -64
; CHECK-NEXT: call void @use8(i8 [[A]])
; CHECK-NEXT: [[R:%.*]] = and i8 [[X]], 32
; CHECK-NEXT: ret i8 [[R]]
;
%a = add i8 %x, -64 ; 0xc0
call void @use8(i8 %a)
%r = and i8 %a, 32 ; 0x20
ret i8 %r
}
define i8 @lowmask_add_2(i8 %x) {
; CHECK-LABEL: @lowmask_add_2(
; CHECK-NEXT: [[R:%.*]] = and i8 [[X:%.*]], 63
; CHECK-NEXT: ret i8 [[R]]
;
%a = add i8 %x, -64 ; 0xc0
%r = and i8 %a, 63 ; 0x3f
ret i8 %r
}
define i8 @lowmask_add_2_uses(i8 %x) {
; CHECK-LABEL: @lowmask_add_2_uses(
; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], -64
; CHECK-NEXT: call void @use8(i8 [[A]])
; CHECK-NEXT: [[R:%.*]] = and i8 [[X]], 63
; CHECK-NEXT: ret i8 [[R]]
;
%a = add i8 %x, -64 ; 0xc0
call void @use8(i8 %a)
%r = and i8 %a, 63 ; 0x3f
ret i8 %r
}
define <2 x i8> @lowmask_add_2_splat(<2 x i8> %x, ptr %p) {
; CHECK-LABEL: @lowmask_add_2_splat(
; CHECK-NEXT: [[A:%.*]] = add <2 x i8> [[X:%.*]], <i8 -64, i8 -64>
; CHECK-NEXT: store <2 x i8> [[A]], ptr [[P:%.*]], align 2
; CHECK-NEXT: [[R:%.*]] = and <2 x i8> [[X]], <i8 63, i8 63>
; CHECK-NEXT: ret <2 x i8> [[R]]
;
%a = add <2 x i8> %x, <i8 -64, i8 -64> ; 0xc0
store <2 x i8> %a, ptr %p
%r = and <2 x i8> %a, <i8 63, i8 63> ; 0x3f
ret <2 x i8> %r
}
; Negative test - mask overlaps low bit of add
define i8 @not_lowmask_add(i8 %x) {
; CHECK-LABEL: @not_lowmask_add(
; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], -64
; CHECK-NEXT: call void @use8(i8 [[A]])
; CHECK-NEXT: [[R:%.*]] = and i8 [[A]], 64
; CHECK-NEXT: ret i8 [[R]]
;
%a = add i8 %x, -64 ; 0xc0
call void @use8(i8 %a)
%r = and i8 %a, 64 ; 0x40
ret i8 %r
}
; Negative test - mask overlaps low bit of add
define i8 @not_lowmask_add2(i8 %x) {
; CHECK-LABEL: @not_lowmask_add2(
; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], -96
; CHECK-NEXT: call void @use8(i8 [[A]])
; CHECK-NEXT: [[R:%.*]] = and i8 [[A]], 63
; CHECK-NEXT: ret i8 [[R]]
;
%a = add i8 %x, -96 ; 0xe0
call void @use8(i8 %a)
%r = and i8 %a, 63 ; 0x3f
ret i8 %r
}
define <2 x i8> @lowmask_add_splat(<2 x i8> %x, ptr %p) {
; CHECK-LABEL: @lowmask_add_splat(
; CHECK-NEXT: [[A:%.*]] = add <2 x i8> [[X:%.*]], <i8 -64, i8 -64>
; CHECK-NEXT: store <2 x i8> [[A]], ptr [[P:%.*]], align 2
; CHECK-NEXT: [[R:%.*]] = and <2 x i8> [[X]], <i8 32, i8 32>
; CHECK-NEXT: ret <2 x i8> [[R]]
;
%a = add <2 x i8> %x, <i8 -64, i8 -64> ; 0xc0
store <2 x i8> %a, ptr %p
%r = and <2 x i8> %a, <i8 32, i8 32> ; 0x20
ret <2 x i8> %r
}
define <2 x i8> @lowmask_add_splat_poison(<2 x i8> %x, ptr %p) {
; CHECK-LABEL: @lowmask_add_splat_poison(
; CHECK-NEXT: [[A:%.*]] = add <2 x i8> [[X:%.*]], <i8 -64, i8 poison>
; CHECK-NEXT: store <2 x i8> [[A]], ptr [[P:%.*]], align 2
; CHECK-NEXT: [[R:%.*]] = and <2 x i8> [[X]], <i8 poison, i8 32>
; CHECK-NEXT: ret <2 x i8> [[R]]
;
%a = add <2 x i8> %x, <i8 -64, i8 poison> ; 0xc0
store <2 x i8> %a, ptr %p
%r = and <2 x i8> %a, <i8 poison, i8 32> ; 0x20
ret <2 x i8> %r
}
define <2 x i8> @lowmask_add_vec(<2 x i8> %x, ptr %p) {
; CHECK-LABEL: @lowmask_add_vec(
; CHECK-NEXT: [[A:%.*]] = add <2 x i8> [[X:%.*]], <i8 -96, i8 -64>
; CHECK-NEXT: store <2 x i8> [[A]], ptr [[P:%.*]], align 2
; CHECK-NEXT: [[R:%.*]] = and <2 x i8> [[A]], <i8 16, i8 32>
; CHECK-NEXT: ret <2 x i8> [[R]]
;
%a = add <2 x i8> %x, <i8 -96, i8 -64> ; 0xe0, 0xc0
store <2 x i8> %a, ptr %p
%r = and <2 x i8> %a, <i8 16, i8 32> ; 0x10, 0x20
ret <2 x i8> %r
}
; Only one bit set
define i8 @flip_masked_bit(i8 %A) {
; CHECK-LABEL: @flip_masked_bit(
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[A:%.*]], 16
; CHECK-NEXT: [[C:%.*]] = xor i8 [[TMP1]], 16
; CHECK-NEXT: ret i8 [[C]]
;
%B = add i8 %A, 16
%C = and i8 %B, 16
ret i8 %C
}
define <2 x i8> @flip_masked_bit_uniform(<2 x i8> %A) {
; CHECK-LABEL: @flip_masked_bit_uniform(
; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[A:%.*]], <i8 16, i8 16>
; CHECK-NEXT: [[C:%.*]] = xor <2 x i8> [[TMP1]], <i8 16, i8 16>
; CHECK-NEXT: ret <2 x i8> [[C]]
;
%B = add <2 x i8> %A, <i8 16, i8 16>
%C = and <2 x i8> %B, <i8 16, i8 16>
ret <2 x i8> %C
}
define <2 x i8> @flip_masked_bit_poison(<2 x i8> %A) {
; CHECK-LABEL: @flip_masked_bit_poison(
; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i8> [[A:%.*]], <i8 -1, i8 -1>
; CHECK-NEXT: [[C:%.*]] = and <2 x i8> [[TMP1]], <i8 16, i8 poison>
; CHECK-NEXT: ret <2 x i8> [[C]]
;
%B = add <2 x i8> %A, <i8 16, i8 poison>
%C = and <2 x i8> %B, <i8 16, i8 poison>
ret <2 x i8> %C
}
define <2 x i8> @flip_masked_bit_nonuniform(<2 x i8> %A) {
; CHECK-LABEL: @flip_masked_bit_nonuniform(
; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i8> [[A:%.*]], <i8 -1, i8 -1>
; CHECK-NEXT: [[C:%.*]] = and <2 x i8> [[TMP1]], <i8 16, i8 4>
; CHECK-NEXT: ret <2 x i8> [[C]]
;
%B = add <2 x i8> %A, <i8 16, i8 4>
%C = and <2 x i8> %B, <i8 16, i8 4>
ret <2 x i8> %C
}
define i8 @ashr_bitwidth_mask(i8 %x, i8 %y) {
; CHECK-LABEL: @ashr_bitwidth_mask(
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i8 [[X:%.*]], 0
; CHECK-NEXT: [[NEG_OR_ZERO:%.*]] = select i1 [[ISNEG]], i8 [[Y:%.*]], i8 0
; CHECK-NEXT: ret i8 [[NEG_OR_ZERO]]
;
%sign = ashr i8 %x, 7
%neg_or_zero = and i8 %sign, %y
ret i8 %neg_or_zero
}
define <2 x i8> @ashr_bitwidth_mask_vec_commute(<2 x i8> %x, <2 x i8> %py) {
; CHECK-LABEL: @ashr_bitwidth_mask_vec_commute(
; CHECK-NEXT: [[Y:%.*]] = mul <2 x i8> [[PY:%.*]], <i8 42, i8 2>
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt <2 x i8> [[X:%.*]], zeroinitializer
; CHECK-NEXT: [[NEG_OR_ZERO:%.*]] = select <2 x i1> [[ISNEG]], <2 x i8> [[Y]], <2 x i8> zeroinitializer
; CHECK-NEXT: ret <2 x i8> [[NEG_OR_ZERO]]
;
%y = mul <2 x i8> %py, <i8 42, i8 2> ; thwart complexity-based ordering
%sign = ashr <2 x i8> %x, <i8 7, i8 7>
%neg_or_zero = and <2 x i8> %y, %sign
ret <2 x i8> %neg_or_zero
}
; negative test - extra use
define i8 @ashr_bitwidth_mask_use(i8 %x, i8 %y) {
; CHECK-LABEL: @ashr_bitwidth_mask_use(
; CHECK-NEXT: [[SIGN:%.*]] = ashr i8 [[X:%.*]], 7
; CHECK-NEXT: call void @use8(i8 [[SIGN]])
; CHECK-NEXT: [[R:%.*]] = and i8 [[SIGN]], [[Y:%.*]]
; CHECK-NEXT: ret i8 [[R]]
;
%sign = ashr i8 %x, 7
call void @use8(i8 %sign)
%r = and i8 %sign, %y
ret i8 %r
}
; negative test - wrong shift amount
define i8 @ashr_not_bitwidth_mask(i8 %x, i8 %y) {
; CHECK-LABEL: @ashr_not_bitwidth_mask(
; CHECK-NEXT: [[SIGN:%.*]] = ashr i8 [[X:%.*]], 6
; CHECK-NEXT: [[R:%.*]] = and i8 [[SIGN]], [[Y:%.*]]
; CHECK-NEXT: ret i8 [[R]]
;
%sign = ashr i8 %x, 6
%r = and i8 %sign, %y
ret i8 %r
}
; negative test - wrong shift opcode
define i8 @lshr_bitwidth_mask(i8 %x, i8 %y) {
; CHECK-LABEL: @lshr_bitwidth_mask(
; CHECK-NEXT: [[SIGN:%.*]] = lshr i8 [[X:%.*]], 7
; CHECK-NEXT: [[R:%.*]] = and i8 [[SIGN]], [[Y:%.*]]
; CHECK-NEXT: ret i8 [[R]]
;
%sign = lshr i8 %x, 7
%r = and i8 %sign, %y
ret i8 %r
}
define i16 @signbit_splat_mask(i8 %x, i16 %y) {
; CHECK-LABEL: @signbit_splat_mask(
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i8 [[X:%.*]], 0
; CHECK-NEXT: [[R:%.*]] = select i1 [[ISNEG]], i16 [[Y:%.*]], i16 0
; CHECK-NEXT: ret i16 [[R]]
;
%a = ashr i8 %x, 7
%s = sext i8 %a to i16
%r = and i16 %s, %y
ret i16 %r
}
define <2 x i16> @signbit_splat_mask_commute(<2 x i5> %x, <2 x i16> %p) {
; CHECK-LABEL: @signbit_splat_mask_commute(
; CHECK-NEXT: [[Y:%.*]] = mul <2 x i16> [[P:%.*]], [[P]]
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt <2 x i5> [[X:%.*]], zeroinitializer
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[ISNEG]], <2 x i16> [[Y]], <2 x i16> zeroinitializer
; CHECK-NEXT: ret <2 x i16> [[R]]
;
%y = mul <2 x i16> %p, %p ; thwart complexity-based canonicalization
%a = ashr <2 x i5> %x, <i5 4, i5 poison>
%s = sext <2 x i5> %a to <2 x i16>
%r = and <2 x i16> %y, %s
ret <2 x i16> %r
}
define i16 @signbit_splat_mask_use1(i8 %x, i16 %y) {
; CHECK-LABEL: @signbit_splat_mask_use1(
; CHECK-NEXT: [[A:%.*]] = ashr i8 [[X:%.*]], 7
; CHECK-NEXT: call void @use8(i8 [[A]])
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i8 [[X]], 0
; CHECK-NEXT: [[R:%.*]] = select i1 [[ISNEG]], i16 [[Y:%.*]], i16 0
; CHECK-NEXT: ret i16 [[R]]
;
%a = ashr i8 %x, 7
call void @use8(i8 %a)
%s = sext i8 %a to i16
%r = and i16 %s, %y
ret i16 %r
}
; negative test - extra use
define i16 @signbit_splat_mask_use2(i8 %x, i16 %y) {
; CHECK-LABEL: @signbit_splat_mask_use2(
; CHECK-NEXT: [[A:%.*]] = ashr i8 [[X:%.*]], 7
; CHECK-NEXT: [[S:%.*]] = sext i8 [[A]] to i16
; CHECK-NEXT: call void @use16(i16 [[S]])
; CHECK-NEXT: [[R:%.*]] = and i16 [[Y:%.*]], [[S]]
; CHECK-NEXT: ret i16 [[R]]
;
%a = ashr i8 %x, 7
%s = sext i8 %a to i16
call void @use16(i16 %s)
%r = and i16 %s, %y
ret i16 %r
}
; negative test - wrong extend
define i16 @not_signbit_splat_mask1(i8 %x, i16 %y) {
; CHECK-LABEL: @not_signbit_splat_mask1(
; CHECK-NEXT: [[A:%.*]] = ashr i8 [[X:%.*]], 7
; CHECK-NEXT: [[Z:%.*]] = zext i8 [[A]] to i16
; CHECK-NEXT: [[R:%.*]] = and i16 [[Y:%.*]], [[Z]]
; CHECK-NEXT: ret i16 [[R]]
;
%a = ashr i8 %x, 7
%z = zext i8 %a to i16
%r = and i16 %z, %y
ret i16 %r
}
; negative test - wrong shift amount
define i16 @not_signbit_splat_mask2(i8 %x, i16 %y) {
; CHECK-LABEL: @not_signbit_splat_mask2(
; CHECK-NEXT: [[A:%.*]] = ashr i8 [[X:%.*]], 6
; CHECK-NEXT: [[S:%.*]] = sext i8 [[A]] to i16
; CHECK-NEXT: [[R:%.*]] = and i16 [[Y:%.*]], [[S]]
; CHECK-NEXT: ret i16 [[R]]
;
%a = ashr i8 %x, 6
%s = sext i8 %a to i16
%r = and i16 %s, %y
ret i16 %r
}
define i8 @not_ashr_bitwidth_mask(i8 %x, i8 %y) {
; CHECK-LABEL: @not_ashr_bitwidth_mask(
; CHECK-NEXT: [[ISNOTNEG_INV:%.*]] = icmp slt i8 [[X:%.*]], 0
; CHECK-NEXT: [[POS_OR_ZERO:%.*]] = select i1 [[ISNOTNEG_INV]], i8 0, i8 [[Y:%.*]]
; CHECK-NEXT: ret i8 [[POS_OR_ZERO]]
;
%sign = ashr i8 %x, 7
%not = xor i8 %sign, -1
%pos_or_zero = and i8 %not, %y
ret i8 %pos_or_zero
}
define <2 x i8> @not_ashr_bitwidth_mask_vec_commute(<2 x i8> %x, <2 x i8> %py) {
; CHECK-LABEL: @not_ashr_bitwidth_mask_vec_commute(
; CHECK-NEXT: [[Y:%.*]] = mul <2 x i8> [[PY:%.*]], <i8 42, i8 2>
; CHECK-NEXT: [[ISNOTNEG_INV:%.*]] = icmp slt <2 x i8> [[X:%.*]], zeroinitializer
; CHECK-NEXT: [[POS_OR_ZERO:%.*]] = select <2 x i1> [[ISNOTNEG_INV]], <2 x i8> zeroinitializer, <2 x i8> [[Y]]
; CHECK-NEXT: ret <2 x i8> [[POS_OR_ZERO]]
;
%y = mul <2 x i8> %py, <i8 42, i8 2> ; thwart complexity-based ordering
%sign = ashr <2 x i8> %x, <i8 7, i8 7>
%not = xor <2 x i8> %sign, <i8 -1, i8 -1>
%pos_or_zero = and <2 x i8> %y, %not
ret <2 x i8> %pos_or_zero
}
; extra use of shift is ok
define i8 @not_ashr_bitwidth_mask_use1(i8 %x, i8 %y) {
; CHECK-LABEL: @not_ashr_bitwidth_mask_use1(
; CHECK-NEXT: [[SIGN:%.*]] = ashr i8 [[X:%.*]], 7
; CHECK-NEXT: call void @use8(i8 [[SIGN]])
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i8 [[X]], 0
; CHECK-NEXT: [[R:%.*]] = select i1 [[ISNEG]], i8 0, i8 [[Y:%.*]]
; CHECK-NEXT: ret i8 [[R]]
;
%sign = ashr i8 %x, 7
call void @use8(i8 %sign)
%not = xor i8 %sign, -1
%r = and i8 %not, %y
ret i8 %r
}
; extra use of xor is ok
define i8 @not_ashr_bitwidth_mask_use2(i8 %x, i8 %y) {
; CHECK-LABEL: @not_ashr_bitwidth_mask_use2(
; CHECK-NEXT: [[ISNOTNEG:%.*]] = icmp sgt i8 [[X:%.*]], -1
; CHECK-NEXT: [[NOT:%.*]] = sext i1 [[ISNOTNEG]] to i8
; CHECK-NEXT: call void @use8(i8 [[NOT]])
; CHECK-NEXT: [[R:%.*]] = select i1 [[ISNOTNEG]], i8 [[Y:%.*]], i8 0
; CHECK-NEXT: ret i8 [[R]]
;
%sign = ashr i8 %x, 7
%not = xor i8 %sign, -1
call void @use8(i8 %not)
%r = and i8 %not, %y
ret i8 %r
}
; negative test - wrong shift amount
define i8 @not_ashr_not_bitwidth_mask(i8 %x, i8 %y) {
; CHECK-LABEL: @not_ashr_not_bitwidth_mask(
; CHECK-NEXT: [[SIGN:%.*]] = ashr i8 [[X:%.*]], 6
; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[SIGN]], -1
; CHECK-NEXT: [[R:%.*]] = and i8 [[Y:%.*]], [[NOT]]
; CHECK-NEXT: ret i8 [[R]]
;
%sign = ashr i8 %x, 6
%not = xor i8 %sign, -1
%r = and i8 %not, %y
ret i8 %r
}
; negative test - wrong shift opcode
define i8 @not_lshr_bitwidth_mask(i8 %x, i8 %y) {
; CHECK-LABEL: @not_lshr_bitwidth_mask(
; CHECK-NEXT: [[SIGN:%.*]] = lshr i8 [[X:%.*]], 7
; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[SIGN]], -1
; CHECK-NEXT: [[R:%.*]] = and i8 [[Y:%.*]], [[NOT]]
; CHECK-NEXT: ret i8 [[R]]
;
%sign = lshr i8 %x, 7
%not = xor i8 %sign, -1
%r = and i8 %not, %y
ret i8 %r
}
define i16 @invert_signbit_splat_mask(i8 %x, i16 %y) {
; CHECK-LABEL: @invert_signbit_splat_mask(
; CHECK-NEXT: [[ISNOTNEG:%.*]] = icmp sgt i8 [[X:%.*]], -1
; CHECK-NEXT: [[R:%.*]] = select i1 [[ISNOTNEG]], i16 [[Y:%.*]], i16 0
; CHECK-NEXT: ret i16 [[R]]
;
%a = ashr i8 %x, 7
%n = xor i8 %a, -1
%s = sext i8 %n to i16
%r = and i16 %s, %y
ret i16 %r
}
define <2 x i16> @invert_signbit_splat_mask_commute(<2 x i5> %x, <2 x i16> %p) {
; CHECK-LABEL: @invert_signbit_splat_mask_commute(
; CHECK-NEXT: [[Y:%.*]] = mul <2 x i16> [[P:%.*]], [[P]]
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt <2 x i5> [[X:%.*]], zeroinitializer
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[ISNEG]], <2 x i16> zeroinitializer, <2 x i16> [[Y]]
; CHECK-NEXT: ret <2 x i16> [[R]]
;
%y = mul <2 x i16> %p, %p ; thwart complexity-based canonicalization
%a = ashr <2 x i5> %x, <i5 4, i5 poison>
%n = xor <2 x i5> %a, <i5 -1, i5 -1>
%s = sext <2 x i5> %n to <2 x i16>
%r = and <2 x i16> %y, %s
ret <2 x i16> %r
}
define i16 @invert_signbit_splat_mask_use1(i8 %x, i16 %y) {
; CHECK-LABEL: @invert_signbit_splat_mask_use1(
; CHECK-NEXT: [[A:%.*]] = ashr i8 [[X:%.*]], 7
; CHECK-NEXT: call void @use8(i8 [[A]])
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i8 [[X]], 0
; CHECK-NEXT: [[R:%.*]] = select i1 [[ISNEG]], i16 0, i16 [[Y:%.*]]
; CHECK-NEXT: ret i16 [[R]]
;
%a = ashr i8 %x, 7
call void @use8(i8 %a)
%n = xor i8 %a, -1
%s = sext i8 %n to i16
%r = and i16 %s, %y
ret i16 %r
}
define i16 @invert_signbit_splat_mask_use2(i8 %x, i16 %y) {
; CHECK-LABEL: @invert_signbit_splat_mask_use2(
; CHECK-NEXT: [[ISNOTNEG:%.*]] = icmp sgt i8 [[X:%.*]], -1
; CHECK-NEXT: [[N:%.*]] = sext i1 [[ISNOTNEG]] to i8
; CHECK-NEXT: call void @use8(i8 [[N]])
; CHECK-NEXT: [[R:%.*]] = select i1 [[ISNOTNEG]], i16 [[Y:%.*]], i16 0
; CHECK-NEXT: ret i16 [[R]]
;
%a = ashr i8 %x, 7
%n = xor i8 %a, -1
call void @use8(i8 %n)
%s = sext i8 %n to i16
%r = and i16 %s, %y
ret i16 %r
}
; extra use of sext is ok
define i16 @invert_signbit_splat_mask_use3(i8 %x, i16 %y) {
; CHECK-LABEL: @invert_signbit_splat_mask_use3(
; CHECK-NEXT: [[ISNOTNEG:%.*]] = icmp sgt i8 [[X:%.*]], -1
; CHECK-NEXT: [[S:%.*]] = sext i1 [[ISNOTNEG]] to i16
; CHECK-NEXT: call void @use16(i16 [[S]])
; CHECK-NEXT: [[R:%.*]] = select i1 [[ISNOTNEG]], i16 [[Y:%.*]], i16 0
; CHECK-NEXT: ret i16 [[R]]
;
%a = ashr i8 %x, 7
%n = xor i8 %a, -1
%s = sext i8 %n to i16
call void @use16(i16 %s)
%r = and i16 %s, %y
ret i16 %r
}
; negative test - wrong extend
define i16 @not_invert_signbit_splat_mask1(i8 %x, i16 %y) {
; CHECK-LABEL: @not_invert_signbit_splat_mask1(
; CHECK-NEXT: [[ISNOTNEG:%.*]] = icmp sgt i8 [[X:%.*]], -1
; CHECK-NEXT: [[N:%.*]] = sext i1 [[ISNOTNEG]] to i8
; CHECK-NEXT: [[Z:%.*]] = zext i8 [[N]] to i16
; CHECK-NEXT: [[R:%.*]] = and i16 [[Y:%.*]], [[Z]]
; CHECK-NEXT: ret i16 [[R]]
;
%a = ashr i8 %x, 7
%n = xor i8 %a, -1
%z = zext i8 %n to i16
%r = and i16 %z, %y
ret i16 %r
}
; negative test - wrong shift amount
define i16 @not_invert_signbit_splat_mask2(i8 %x, i16 %y) {
; CHECK-LABEL: @not_invert_signbit_splat_mask2(
; CHECK-NEXT: [[A:%.*]] = ashr i8 [[X:%.*]], 6
; CHECK-NEXT: [[N:%.*]] = xor i8 [[A]], -1
; CHECK-NEXT: [[S:%.*]] = sext i8 [[N]] to i16
; CHECK-NEXT: [[R:%.*]] = and i16 [[Y:%.*]], [[S]]
; CHECK-NEXT: ret i16 [[R]]
;
%a = ashr i8 %x, 6
%n = xor i8 %a, -1
%s = sext i8 %n to i16
%r = and i16 %s, %y
ret i16 %r
}
; CTTZ(ShlC) < LShrC
define i16 @shl_lshr_pow2_const_case1(i16 %x) {
; CHECK-LABEL: @shl_lshr_pow2_const_case1(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i16 [[X:%.*]], 7
; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i16 8, i16 0
; CHECK-NEXT: ret i16 [[R]]
;
%shl = shl i16 4, %x
%lshr = lshr i16 %shl, 6
%r = and i16 %lshr, 8
ret i16 %r
}
define i16 @shl_ashr_pow2_const_case1(i16 %x) {
; CHECK-LABEL: @shl_ashr_pow2_const_case1(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i16 [[X:%.*]], 7
; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i16 8, i16 0
; CHECK-NEXT: ret i16 [[R]]
;
%shl = shl i16 4, %x
%lshr = ashr i16 %shl, 6
%r = and i16 %lshr, 8
ret i16 %r
}
define <3 x i16> @shl_lshr_pow2_const_case1_uniform_vec(<3 x i16> %x) {
; CHECK-LABEL: @shl_lshr_pow2_const_case1_uniform_vec(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <3 x i16> [[X:%.*]], <i16 7, i16 7, i16 7>
; CHECK-NEXT: [[R:%.*]] = select <3 x i1> [[TMP1]], <3 x i16> <i16 8, i16 8, i16 8>, <3 x i16> zeroinitializer
; CHECK-NEXT: ret <3 x i16> [[R]]
;
%shl = shl <3 x i16> <i16 4, i16 4, i16 4>, %x
%lshr = lshr <3 x i16> %shl, <i16 6, i16 6, i16 6>
%r = and <3 x i16> %lshr, <i16 8, i16 8, i16 8>
ret <3 x i16> %r
}
define <3 x i16> @shl_lshr_pow2_const_case1_non_uniform_vec(<3 x i16> %x) {
; CHECK-LABEL: @shl_lshr_pow2_const_case1_non_uniform_vec(
; CHECK-NEXT: [[SHL:%.*]] = shl <3 x i16> <i16 2, i16 8, i16 32>, [[X:%.*]]
; CHECK-NEXT: [[LSHR:%.*]] = lshr <3 x i16> [[SHL]], <i16 5, i16 6, i16 3>
; CHECK-NEXT: [[R:%.*]] = and <3 x i16> [[LSHR]], <i16 8, i16 4, i16 8>
; CHECK-NEXT: ret <3 x i16> [[R]]
;
%shl = shl <3 x i16> <i16 2, i16 8, i16 32>, %x
%lshr = lshr <3 x i16> %shl, <i16 5, i16 6, i16 3>
%r = and <3 x i16> %lshr, <i16 8, i16 4, i16 8>
ret <3 x i16> %r
}
define <3 x i16> @shl_lshr_pow2_const_case1_non_uniform_vec_negative(<3 x i16> %x) {
; CHECK-LABEL: @shl_lshr_pow2_const_case1_non_uniform_vec_negative(
; CHECK-NEXT: [[SHL:%.*]] = shl <3 x i16> <i16 2, i16 8, i16 32>, [[X:%.*]]
; CHECK-NEXT: [[LSHR:%.*]] = lshr <3 x i16> [[SHL]], <i16 5, i16 6, i16 3>
; CHECK-NEXT: [[R:%.*]] = and <3 x i16> [[LSHR]], <i16 8, i16 4, i16 16384>
; CHECK-NEXT: ret <3 x i16> [[R]]
;
%shl = shl <3 x i16> <i16 2, i16 8, i16 32>, %x
%lshr = lshr <3 x i16> %shl, <i16 5, i16 6, i16 3>
%r = and <3 x i16> %lshr, <i16 8, i16 4, i16 16384>
ret <3 x i16> %r
}
define <3 x i16> @shl_lshr_pow2_const_case1_poison1_vec(<3 x i16> %x) {
; CHECK-LABEL: @shl_lshr_pow2_const_case1_poison1_vec(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <3 x i16> [[X:%.*]], <i16 8, i16 4, i16 4>
; CHECK-NEXT: [[R:%.*]] = select <3 x i1> [[TMP1]], <3 x i16> <i16 8, i16 8, i16 8>, <3 x i16> zeroinitializer
; CHECK-NEXT: ret <3 x i16> [[R]]
;
%shl = shl <3 x i16> <i16 poison, i16 16, i16 16>, %x
%lshr = lshr <3 x i16> %shl, <i16 5, i16 5, i16 5>
%r = and <3 x i16> %lshr, <i16 8, i16 8, i16 8>
ret <3 x i16> %r
}
define <3 x i16> @shl_lshr_pow2_const_case1_poison2_vec(<3 x i16> %x) {
; CHECK-LABEL: @shl_lshr_pow2_const_case1_poison2_vec(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <3 x i16> [[X:%.*]], <i16 poison, i16 4, i16 4>
; CHECK-NEXT: [[R:%.*]] = select <3 x i1> [[TMP1]], <3 x i16> <i16 8, i16 8, i16 8>, <3 x i16> zeroinitializer
; CHECK-NEXT: ret <3 x i16> [[R]]
;
%shl = shl <3 x i16> <i16 16, i16 16, i16 16>, %x
%lshr = lshr <3 x i16> %shl, <i16 poison, i16 5, i16 5>
%r = and <3 x i16> %lshr, <i16 8, i16 8, i16 8>
ret <3 x i16> %r
}
define <3 x i16> @shl_lshr_pow2_const_case1_poison3_vec(<3 x i16> %x) {
; CHECK-LABEL: @shl_lshr_pow2_const_case1_poison3_vec(
; CHECK-NEXT: [[SHL:%.*]] = shl <3 x i16> <i16 16, i16 16, i16 16>, [[X:%.*]]
; CHECK-NEXT: [[LSHR:%.*]] = lshr <3 x i16> [[SHL]], <i16 5, i16 5, i16 5>
; CHECK-NEXT: [[R:%.*]] = and <3 x i16> [[LSHR]], <i16 poison, i16 8, i16 8>
; CHECK-NEXT: ret <3 x i16> [[R]]
;
%shl = shl <3 x i16> <i16 16, i16 16, i16 16>, %x
%lshr = lshr <3 x i16> %shl, <i16 5, i16 5, i16 5>
%r = and <3 x i16> %lshr, <i16 poison, i16 8, i16 8>
ret <3 x i16> %r
}
; LShrC < CTTZ(ShlC) < LShrC + CTTZ(AndC)
define i16 @shl_lshr_pow2_const_case2(i16 %x) {
; CHECK-LABEL: @shl_lshr_pow2_const_case2(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i16 [[X:%.*]], 2
; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i16 8, i16 0
; CHECK-NEXT: ret i16 [[R]]
;
%shl = shl i16 16, %x
%lshr = lshr i16 %shl, 3
%r = and i16 %lshr, 8
ret i16 %r
}
define i16 @shl_lshr_pow2_not_const_case2(i16 %x) {
; CHECK-LABEL: @shl_lshr_pow2_not_const_case2(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i16 [[X:%.*]], 2
; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i16 0, i16 8
; CHECK-NEXT: ret i16 [[R]]
;
%shl = shl i16 16, %x
%lshr = lshr i16 %shl, 3
%and = and i16 %lshr, 8
%r = xor i16 %and, 8
ret i16 %r
}
; CTTZ(ShlC) > LShrC + CTTZ(AndC)
define i16 @shl_lshr_pow2_const_negative_overflow1(i16 %x) {
; CHECK-LABEL: @shl_lshr_pow2_const_negative_overflow1(
; CHECK-NEXT: ret i16 0
;
%shl = shl i16 4096, %x
%lshr = lshr i16 %shl, 6
%r = and i16 %lshr, 8
ret i16 %r
}
; LShrC + CTTZ(AndC) > BitWidth
define i16 @shl_lshr_pow2_const_negative_overflow2(i16 %x) {
; CHECK-LABEL: @shl_lshr_pow2_const_negative_overflow2(
; CHECK-NEXT: ret i16 0
;
%shl = shl i16 8, %x
%lshr = lshr i16 %shl, 6
%r = and i16 %lshr, 32768
ret i16 %r
}
define i16 @shl_lshr_pow2_const_negative_oneuse(i16 %x) {
; CHECK-LABEL: @shl_lshr_pow2_const_negative_oneuse(
; CHECK-NEXT: [[SHL:%.*]] = shl i16 4, [[X:%.*]]
; CHECK-NEXT: [[LSHR:%.*]] = lshr i16 [[SHL]], 6
; CHECK-NEXT: call void @use16(i16 [[LSHR]])
; CHECK-NEXT: [[R:%.*]] = and i16 [[LSHR]], 8
; CHECK-NEXT: ret i16 [[R]]
;
%shl = shl i16 4, %x
%lshr = lshr i16 %shl, 6
call void @use16(i16 %lshr)
%r = and i16 %lshr, 8
ret i16 %r
}
define i16 @shl_lshr_pow2_const_negative_nopow2_1(i16 %x) {
; CHECK-LABEL: @shl_lshr_pow2_const_negative_nopow2_1(
; CHECK-NEXT: [[SHL:%.*]] = shl i16 3, [[X:%.*]]
; CHECK-NEXT: [[LSHR:%.*]] = lshr i16 [[SHL]], 6
; CHECK-NEXT: [[R:%.*]] = and i16 [[LSHR]], 8
; CHECK-NEXT: ret i16 [[R]]
;
%shl = shl i16 3, %x
%lshr = lshr i16 %shl, 6
%r = and i16 %lshr, 8
ret i16 %r
}
define i16 @shl_lshr_pow2_const_negative_nopow2_2(i16 %x) {
; CHECK-LABEL: @shl_lshr_pow2_const_negative_nopow2_2(
; CHECK-NEXT: [[SHL:%.*]] = shl i16 3, [[X:%.*]]
; CHECK-NEXT: [[LSHR:%.*]] = lshr i16 [[SHL]], 6
; CHECK-NEXT: [[R:%.*]] = and i16 [[LSHR]], 7
; CHECK-NEXT: ret i16 [[R]]
;
%shl = shl i16 3, %x
%lshr = lshr i16 %shl, 6
%r = and i16 %lshr, 7
ret i16 %r
}
define i16 @lshr_lshr_pow2_const(i16 %x) {
; CHECK-LABEL: @lshr_lshr_pow2_const(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i16 [[X:%.*]], 3
; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i16 4, i16 0
; CHECK-NEXT: ret i16 [[R]]
;
%lshr1 = lshr i16 2048, %x
%lshr2 = lshr i16 %lshr1, 6
%r = and i16 %lshr2, 4
ret i16 %r
}
define i16 @lshr_lshr_pow2_const_negative_oneuse(i16 %x) {
; CHECK-LABEL: @lshr_lshr_pow2_const_negative_oneuse(
; CHECK-NEXT: [[LSHR2:%.*]] = lshr i16 32, [[X:%.*]]
; CHECK-NEXT: call void @use16(i16 [[LSHR2]])
; CHECK-NEXT: [[R:%.*]] = and i16 [[LSHR2]], 4
; CHECK-NEXT: ret i16 [[R]]
;
%lshr1 = lshr i16 2048, %x
%lshr2 = lshr i16 %lshr1, 6
call void @use16(i16 %lshr2)
%r = and i16 %lshr2, 4
ret i16 %r
}
define i16 @lshr_lshr_pow2_const_negative_nopow2_1(i16 %x) {
; CHECK-LABEL: @lshr_lshr_pow2_const_negative_nopow2_1(
; CHECK-NEXT: [[LSHR2:%.*]] = lshr i16 31, [[X:%.*]]
; CHECK-NEXT: [[R:%.*]] = and i16 [[LSHR2]], 4
; CHECK-NEXT: ret i16 [[R]]
;
%lshr1 = lshr i16 2047, %x
%lshr2 = lshr i16 %lshr1, 6
%r = and i16 %lshr2, 4
ret i16 %r
}
define i16 @lshr_lshr_pow2_const_negative_nopow2_2(i16 %x) {
; CHECK-LABEL: @lshr_lshr_pow2_const_negative_nopow2_2(
; CHECK-NEXT: [[LSHR2:%.*]] = lshr i16 128, [[X:%.*]]
; CHECK-NEXT: [[R:%.*]] = and i16 [[LSHR2]], 3
; CHECK-NEXT: ret i16 [[R]]
;
%lshr1 = lshr i16 8192, %x
%lshr2 = lshr i16 %lshr1, 6
%r = and i16 %lshr2, 3
ret i16 %r
}
define i16 @lshr_lshr_pow2_const_negative_overflow(i16 %x) {
; CHECK-LABEL: @lshr_lshr_pow2_const_negative_overflow(
; CHECK-NEXT: ret i16 0
;
%lshr1 = lshr i16 32768, %x
%lshr2 = lshr i16 %lshr1, 15
%r = and i16 %lshr2, 4
ret i16 %r
}
; demanded bits path for lshr+shl+and
; Log2(LshrC) + ShlC < BitWidth
define i16 @lshr_shl_pow2_const_case1(i16 %x) {
; CHECK-LABEL: @lshr_shl_pow2_const_case1(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i16 [[X:%.*]], 7
; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i16 8, i16 0
; CHECK-NEXT: ret i16 [[R]]
;
%lshr1 = lshr i16 256, %x
%shl = shl i16 %lshr1, 2
%r = and i16 %shl, 8
ret i16 %r
}
define i16 @lshr_shl_pow2_const_xor(i16 %x) {
; CHECK-LABEL: @lshr_shl_pow2_const_xor(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i16 [[X:%.*]], 7
; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i16 0, i16 8
; CHECK-NEXT: ret i16 [[R]]
;
%lshr1 = lshr i16 256, %x
%shl = shl i16 %lshr1, 2
%and = and i16 %shl, 8
%r = xor i16 %and, 8
ret i16 %r
}
; Log2(LshrC) + ShlC >= BitWidth
define i16 @lshr_shl_pow2_const_case2(i16 %x) {
; CHECK-LABEL: @lshr_shl_pow2_const_case2(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i16 [[X:%.*]], 12
; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i16 32, i16 0
; CHECK-NEXT: ret i16 [[R]]
;
%lshr1 = lshr i16 8192, %x
%shl = shl i16 %lshr1, 4
%r = and i16 %shl, 32
ret i16 %r
}
; ShlC > Log2(AndC)
define i16 @lshr_shl_pow2_const_overflow(i16 %x) {
; CHECK-LABEL: @lshr_shl_pow2_const_overflow(
; CHECK-NEXT: ret i16 0
;
%lshr1 = lshr i16 8192, %x
%shl = shl i16 %lshr1, 6
%r = and i16 %shl, 32
ret i16 %r
}
define i16 @lshr_shl_pow2_const_negative_oneuse(i16 %x) {
; CHECK-LABEL: @lshr_shl_pow2_const_negative_oneuse(
; CHECK-NEXT: [[LSHR1:%.*]] = lshr i16 8192, [[X:%.*]]
; CHECK-NEXT: [[SHL:%.*]] = shl i16 [[LSHR1]], 4
; CHECK-NEXT: call void @use16(i16 [[SHL]])
; CHECK-NEXT: [[R:%.*]] = and i16 [[SHL]], 32
; CHECK-NEXT: ret i16 [[R]]
;
%lshr1 = lshr i16 8192, %x
%shl = shl i16 %lshr1, 4
call void @use16(i16 %shl)
%r = and i16 %shl, 32
ret i16 %r
}
define <3 x i16> @lshr_shl_pow2_const_case1_uniform_vec(<3 x i16> %x) {
; CHECK-LABEL: @lshr_shl_pow2_const_case1_uniform_vec(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <3 x i16> [[X:%.*]], <i16 12, i16 12, i16 12>
; CHECK-NEXT: [[R:%.*]] = select <3 x i1> [[TMP1]], <3 x i16> <i16 128, i16 128, i16 128>, <3 x i16> zeroinitializer
; CHECK-NEXT: ret <3 x i16> [[R]]
;
%lshr = lshr <3 x i16> <i16 8192, i16 8192, i16 8192>, %x
%shl = shl <3 x i16> %lshr, <i16 6, i16 6, i16 6>
%r = and <3 x i16> %shl, <i16 128, i16 128, i16 128>
ret <3 x i16> %r
}
define <3 x i16> @lshr_shl_pow2_const_case1_non_uniform_vec(<3 x i16> %x) {
; CHECK-LABEL: @lshr_shl_pow2_const_case1_non_uniform_vec(
; CHECK-NEXT: [[LSHR:%.*]] = lshr <3 x i16> <i16 8192, i16 16384, i16 -32768>, [[X:%.*]]
; CHECK-NEXT: [[SHL:%.*]] = shl <3 x i16> [[LSHR]], <i16 7, i16 5, i16 3>
; CHECK-NEXT: [[R:%.*]] = and <3 x i16> [[SHL]], <i16 128, i16 256, i16 512>
; CHECK-NEXT: ret <3 x i16> [[R]]
;
%lshr = lshr <3 x i16> <i16 8192, i16 16384, i16 32768>, %x
%shl = shl <3 x i16> %lshr, <i16 7, i16 5, i16 3>
%r = and <3 x i16> %shl, <i16 128, i16 256, i16 512>
ret <3 x i16> %r
}
define <3 x i16> @lshr_shl_pow2_const_case1_non_uniform_vec_negative(<3 x i16> %x) {
; CHECK-LABEL: @lshr_shl_pow2_const_case1_non_uniform_vec_negative(
; CHECK-NEXT: [[LSHR:%.*]] = lshr <3 x i16> <i16 8192, i16 16384, i16 -32768>, [[X:%.*]]
; CHECK-NEXT: [[SHL:%.*]] = shl <3 x i16> [[LSHR]], <i16 8, i16 5, i16 3>
; CHECK-NEXT: [[R:%.*]] = and <3 x i16> [[SHL]], <i16 128, i16 256, i16 512>
; CHECK-NEXT: ret <3 x i16> [[R]]
;
%lshr = lshr <3 x i16> <i16 8192, i16 16384, i16 32768>, %x
%shl = shl <3 x i16> %lshr, <i16 8, i16 5, i16 3>
%r = and <3 x i16> %shl, <i16 128, i16 256, i16 512>
ret <3 x i16> %r
}
define <3 x i16> @lshr_shl_pow2_const_case1_poison1_vec(<3 x i16> %x) {
; CHECK-LABEL: @lshr_shl_pow2_const_case1_poison1_vec(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <3 x i16> [[X:%.*]], <i16 -1, i16 12, i16 12>
; CHECK-NEXT: [[R:%.*]] = select <3 x i1> [[TMP1]], <3 x i16> <i16 128, i16 128, i16 128>, <3 x i16> zeroinitializer
; CHECK-NEXT: ret <3 x i16> [[R]]
;
%lshr = lshr <3 x i16> <i16 poison, i16 8192, i16 8192>, %x
%shl = shl <3 x i16> %lshr, <i16 6, i16 6, i16 6>
%r = and <3 x i16> %shl, <i16 128, i16 128, i16 128>
ret <3 x i16> %r
}
define <3 x i16> @lshr_shl_pow2_const_case1_poison2_vec(<3 x i16> %x) {
; CHECK-LABEL: @lshr_shl_pow2_const_case1_poison2_vec(
; CHECK-NEXT: [[LSHR:%.*]] = lshr <3 x i16> <i16 8192, i16 8192, i16 8192>, [[X:%.*]]
; CHECK-NEXT: [[SHL:%.*]] = shl <3 x i16> [[LSHR]], <i16 poison, i16 6, i16 6>
; CHECK-NEXT: [[R:%.*]] = and <3 x i16> [[SHL]], <i16 128, i16 128, i16 128>
; CHECK-NEXT: ret <3 x i16> [[R]]
;
%lshr = lshr <3 x i16> <i16 8192, i16 8192, i16 8192>, %x
%shl = shl <3 x i16> %lshr, <i16 poison, i16 6, i16 6>
%r = and <3 x i16> %shl, <i16 128, i16 128, i16 128>
ret <3 x i16> %r
}
define <3 x i16> @lshr_shl_pow2_const_case1_poison3_vec(<3 x i16> %x) {
; CHECK-LABEL: @lshr_shl_pow2_const_case1_poison3_vec(
; CHECK-NEXT: [[LSHR:%.*]] = lshr <3 x i16> <i16 8192, i16 8192, i16 8192>, [[X:%.*]]
; CHECK-NEXT: [[SHL:%.*]] = shl <3 x i16> [[LSHR]], <i16 6, i16 6, i16 6>
; CHECK-NEXT: [[R:%.*]] = and <3 x i16> [[SHL]], <i16 poison, i16 128, i16 128>
; CHECK-NEXT: ret <3 x i16> [[R]]
;
%lshr = lshr <3 x i16> <i16 8192, i16 8192, i16 8192>, %x
%shl = shl <3 x i16> %lshr, <i16 6, i16 6, i16 6>
%r = and <3 x i16> %shl, <i16 poison, i16 128, i16 128>
ret <3 x i16> %r
}
define i8 @negate_lowbitmask(i8 %x, i8 %y) {
; CHECK-LABEL: @negate_lowbitmask(
; CHECK-NEXT: [[A:%.*]] = and i8 [[X:%.*]], 1
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[A]], 0
; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i8 0, i8 [[Y:%.*]]
; CHECK-NEXT: ret i8 [[R]]
;
%a = and i8 %x, 1
%n = sub i8 0, %a
%r = and i8 %n, %y
ret i8 %r
}
define <2 x i5> @negate_lowbitmask_commute(<2 x i5> %x, <2 x i5> %p) {
; CHECK-LABEL: @negate_lowbitmask_commute(
; CHECK-NEXT: [[Y:%.*]] = mul <2 x i5> [[P:%.*]], [[P]]
; CHECK-NEXT: [[A:%.*]] = and <2 x i5> [[X:%.*]], <i5 1, i5 poison>
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <2 x i5> [[A]], <i5 poison, i5 0>
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[TMP1]], <2 x i5> zeroinitializer, <2 x i5> [[Y]]
; CHECK-NEXT: ret <2 x i5> [[R]]
;
%y = mul <2 x i5> %p, %p ; thwart complexity-based canonicalization
%a = and <2 x i5> %x, <i5 1, i5 poison>
%n = sub <2 x i5> <i5 poison, i5 0>, %a
%r = and <2 x i5> %y, %n
ret <2 x i5> %r
}
define i8 @negate_lowbitmask_use1(i8 %x, i8 %y) {
; CHECK-LABEL: @negate_lowbitmask_use1(
; CHECK-NEXT: [[A:%.*]] = and i8 [[X:%.*]], 1
; CHECK-NEXT: call void @use8(i8 [[A]])
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[A]], 0
; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i8 0, i8 [[Y:%.*]]
; CHECK-NEXT: ret i8 [[R]]
;
%a = and i8 %x, 1
call void @use8(i8 %a)
%n = sub i8 0, %a
%r = and i8 %n, %y
ret i8 %r
}
; negative test
define i8 @negate_lowbitmask_use2(i8 %x, i8 %y) {
; CHECK-LABEL: @negate_lowbitmask_use2(
; CHECK-NEXT: [[A:%.*]] = and i8 [[X:%.*]], 1
; CHECK-NEXT: [[N:%.*]] = sub nsw i8 0, [[A]]
; CHECK-NEXT: call void @use8(i8 [[N]])
; CHECK-NEXT: [[R:%.*]] = and i8 [[Y:%.*]], [[N]]
; CHECK-NEXT: ret i8 [[R]]
;
%a = and i8 %x, 1
%n = sub i8 0, %a
call void @use8(i8 %n)
%r = and i8 %n, %y
ret i8 %r
}
@g = external global i64
define i64 @test_and_or_constexpr_infloop() {
; CHECK-LABEL: @test_and_or_constexpr_infloop(
; CHECK-NEXT: [[AND:%.*]] = and i64 ptrtoint (ptr @g to i64), -8
; CHECK-NEXT: [[OR:%.*]] = or disjoint i64 [[AND]], 1
; CHECK-NEXT: ret i64 [[OR]]
;
%and = and i64 ptrtoint (ptr @g to i64), -8
%or = or i64 %and, 1
ret i64 %or
}
define i32 @and_zext(i32 %a, i1 %b) {
; CHECK-LABEL: @and_zext(
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A:%.*]], 1
; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], i32 [[TMP1]], i32 0
; CHECK-NEXT: ret i32 [[R]]
;
%mask = zext i1 %b to i32
%r = and i32 %a, %mask
ret i32 %r
}
define i32 @and_zext_commuted(i32 %a, i1 %b) {
; CHECK-LABEL: @and_zext_commuted(
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A:%.*]], 1
; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], i32 [[TMP1]], i32 0
; CHECK-NEXT: ret i32 [[R]]
;
%mask = zext i1 %b to i32
%r = and i32 %mask, %a
ret i32 %r
}
define i32 @and_zext_multiuse(i32 %a, i1 %b) {
; CHECK-LABEL: @and_zext_multiuse(
; CHECK-NEXT: [[MASK:%.*]] = zext i1 [[B:%.*]] to i32
; CHECK-NEXT: call void @use32(i32 [[MASK]])
; CHECK-NEXT: [[R:%.*]] = and i32 [[A:%.*]], [[MASK]]
; CHECK-NEXT: ret i32 [[R]]
;
%mask = zext i1 %b to i32
call void @use32(i32 %mask)
%r = and i32 %a, %mask
ret i32 %r
}
define <2 x i32> @and_zext_vec(<2 x i32> %a, <2 x i1> %b) {
; CHECK-LABEL: @and_zext_vec(
; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[A:%.*]], <i32 1, i32 1>
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[B:%.*]], <2 x i32> [[TMP1]], <2 x i32> zeroinitializer
; CHECK-NEXT: ret <2 x i32> [[R]]
;
%mask = zext <2 x i1> %b to <2 x i32>
%r = and <2 x i32> %a, %mask
ret <2 x i32> %r
}
; tests from PR66606
define i32 @and_zext_eq_even(i32 %a) {
; CHECK-LABEL: @and_zext_eq_even(
; CHECK-NEXT: ret i32 0
;
%cond = icmp eq i32 %a, 2
%not = zext i1 %cond to i32
%r = and i32 %a, %not
ret i32 %r
}
define i32 @and_zext_eq_even_commuted(i32 %a) {
; CHECK-LABEL: @and_zext_eq_even_commuted(
; CHECK-NEXT: ret i32 0
;
%cond = icmp eq i32 %a, 2
%not = zext i1 %cond to i32
%r = and i32 %not, %a
ret i32 %r
}
define i32 @and_zext_eq_odd(i32 %a) {
; CHECK-LABEL: @and_zext_eq_odd(
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[A:%.*]], 3
; CHECK-NEXT: [[R:%.*]] = zext i1 [[COND]] to i32
; CHECK-NEXT: ret i32 [[R]]
;
%cond = icmp eq i32 %a, 3
%not = zext i1 %cond to i32
%r = and i32 %a, %not
ret i32 %r
}
define i32 @and_zext_eq_odd_commuted(i32 %a) {
; CHECK-LABEL: @and_zext_eq_odd_commuted(
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[A:%.*]], 3
; CHECK-NEXT: [[R:%.*]] = zext i1 [[COND]] to i32
; CHECK-NEXT: ret i32 [[R]]
;
%cond = icmp eq i32 %a, 3
%not = zext i1 %cond to i32
%r = and i32 %not, %a
ret i32 %r
}
; Tests from PR66733
define i32 @and_zext_eq_zero(i32 %A, i32 %C) {
; CHECK-LABEL: @and_zext_eq_zero(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[A:%.*]], 0
; CHECK-NEXT: [[TMP2:%.*]] = zext i1 [[TMP1]] to i32
; CHECK-NEXT: ret i32 [[TMP2]]
;
%1 = icmp eq i32 %A, 0
%2 = zext i1 %1 to i32
%3 = lshr i32 %A, %C
%4 = xor i32 %3, -1
%5 = and i32 %2, %4
ret i32 %5
}
define i32 @canonicalize_and_add_power2_or_zero(i32 %x, i32 %y) {
; CHECK-LABEL: @canonicalize_and_add_power2_or_zero(
; CHECK-NEXT: [[NY:%.*]] = sub i32 0, [[Y:%.*]]
; CHECK-NEXT: [[P2:%.*]] = and i32 [[Y]], [[NY]]
; CHECK-NEXT: call void @use32(i32 [[P2]])
; CHECK-NEXT: [[X2:%.*]] = mul i32 [[X:%.*]], [[X]]
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X2]], -1
; CHECK-NEXT: [[AND:%.*]] = and i32 [[P2]], [[TMP1]]
; CHECK-NEXT: ret i32 [[AND]]
;
%ny = sub i32 0, %y
%p2 = and i32 %ny, %y
call void @use32(i32 %p2) ; keep p2
%x2 = mul i32 %x, %x ; thwart complexity-based canonicalization
%val = add i32 %x2, %p2
%and = and i32 %val, %p2
ret i32 %and
}
define i32 @canonicalize_and_sub_power2_or_zero(i32 %x, i32 %y) {
; CHECK-LABEL: @canonicalize_and_sub_power2_or_zero(
; CHECK-NEXT: [[NY:%.*]] = sub i32 0, [[Y:%.*]]
; CHECK-NEXT: [[P2:%.*]] = and i32 [[Y]], [[NY]]
; CHECK-NEXT: call void @use32(i32 [[P2]])
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], -1
; CHECK-NEXT: [[AND:%.*]] = and i32 [[P2]], [[TMP1]]
; CHECK-NEXT: ret i32 [[AND]]
;
%ny = sub i32 0, %y
%p2 = and i32 %ny, %y
call void @use32(i32 %p2) ; keep p2
%val = sub i32 %x, %p2
%and = and i32 %val, %p2
ret i32 %and
}
define i32 @canonicalize_and_add_power2_or_zero_commuted1(i32 %x, i32 %y) {
; CHECK-LABEL: @canonicalize_and_add_power2_or_zero_commuted1(
; CHECK-NEXT: [[NY:%.*]] = sub i32 0, [[Y:%.*]]
; CHECK-NEXT: [[P2:%.*]] = and i32 [[Y]], [[NY]]
; CHECK-NEXT: call void @use32(i32 [[P2]])
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], -1
; CHECK-NEXT: [[AND:%.*]] = and i32 [[P2]], [[TMP1]]
; CHECK-NEXT: ret i32 [[AND]]
;
%ny = sub i32 0, %y
%p2 = and i32 %ny, %y
call void @use32(i32 %p2) ; keep p2
%val = add i32 %p2, %x
%and = and i32 %val, %p2
ret i32 %and
}
define i32 @canonicalize_and_add_power2_or_zero_commuted2(i32 %x, i32 %y) {
; CHECK-LABEL: @canonicalize_and_add_power2_or_zero_commuted2(
; CHECK-NEXT: [[NY:%.*]] = sub i32 0, [[Y:%.*]]
; CHECK-NEXT: [[P2:%.*]] = and i32 [[Y]], [[NY]]
; CHECK-NEXT: call void @use32(i32 [[P2]])
; CHECK-NEXT: [[X2:%.*]] = mul i32 [[X:%.*]], [[X]]
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X2]], -1
; CHECK-NEXT: [[AND:%.*]] = and i32 [[P2]], [[TMP1]]
; CHECK-NEXT: ret i32 [[AND]]
;
%ny = sub i32 0, %y
%p2 = and i32 %ny, %y
call void @use32(i32 %p2) ; keep p2
%x2 = mul i32 %x, %x ; thwart complexity-based canonicalization
%val = add i32 %x2, %p2
%and = and i32 %p2, %val
ret i32 %and
}
define i32 @canonicalize_and_add_power2_or_zero_commuted3(i32 %x, i32 %y) {
; CHECK-LABEL: @canonicalize_and_add_power2_or_zero_commuted3(
; CHECK-NEXT: [[NY:%.*]] = sub i32 0, [[Y:%.*]]
; CHECK-NEXT: [[P2:%.*]] = and i32 [[Y]], [[NY]]
; CHECK-NEXT: call void @use32(i32 [[P2]])
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], -1
; CHECK-NEXT: [[AND:%.*]] = and i32 [[P2]], [[TMP1]]
; CHECK-NEXT: ret i32 [[AND]]
;
%ny = sub i32 0, %y
%p2 = and i32 %ny, %y
call void @use32(i32 %p2) ; keep p2
%val = add i32 %p2, %x
%and = and i32 %p2, %val
ret i32 %and
}
define i32 @canonicalize_and_sub_power2_or_zero_commuted_nofold(i32 %x, i32 %y) {
; CHECK-LABEL: @canonicalize_and_sub_power2_or_zero_commuted_nofold(
; CHECK-NEXT: [[NY:%.*]] = sub i32 0, [[Y:%.*]]
; CHECK-NEXT: [[P2:%.*]] = and i32 [[Y]], [[NY]]
; CHECK-NEXT: call void @use32(i32 [[P2]])
; CHECK-NEXT: [[VAL:%.*]] = sub i32 [[P2]], [[X:%.*]]
; CHECK-NEXT: [[AND:%.*]] = and i32 [[VAL]], [[P2]]
; CHECK-NEXT: ret i32 [[AND]]
;
%ny = sub i32 0, %y
%p2 = and i32 %ny, %y
call void @use32(i32 %p2) ; keep p2
%val = sub i32 %p2, %x
%and = and i32 %val, %p2
ret i32 %and
}
define i32 @canonicalize_and_add_non_power2_or_zero_nofold(i32 %x, i32 %y) {
; CHECK-LABEL: @canonicalize_and_add_non_power2_or_zero_nofold(
; CHECK-NEXT: [[VAL:%.*]] = add i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[AND:%.*]] = and i32 [[VAL]], [[Y]]
; CHECK-NEXT: ret i32 [[AND]]
;
%val = add i32 %x, %y
%and = and i32 %val, %y
ret i32 %and
}
define i32 @canonicalize_and_add_power2_or_zero_multiuse_nofold(i32 %x, i32 %y) {
; CHECK-LABEL: @canonicalize_and_add_power2_or_zero_multiuse_nofold(
; CHECK-NEXT: [[NY:%.*]] = sub i32 0, [[Y:%.*]]
; CHECK-NEXT: [[P2:%.*]] = and i32 [[Y]], [[NY]]
; CHECK-NEXT: call void @use32(i32 [[P2]])
; CHECK-NEXT: [[X2:%.*]] = mul i32 [[X:%.*]], [[X]]
; CHECK-NEXT: [[VAL:%.*]] = add i32 [[X2]], [[P2]]
; CHECK-NEXT: call void @use32(i32 [[VAL]])
; CHECK-NEXT: [[AND:%.*]] = and i32 [[VAL]], [[P2]]
; CHECK-NEXT: ret i32 [[AND]]
;
%ny = sub i32 0, %y
%p2 = and i32 %ny, %y
call void @use32(i32 %p2) ; keep p2
%x2 = mul i32 %x, %x ; thwart complexity-based canonicalization
%val = add i32 %x2, %p2
call void @use32(i32 %val)
%and = and i32 %val, %p2
ret i32 %and
}
define i32 @canonicalize_and_sub_power2_or_zero_multiuse_nofold(i32 %x, i32 %y) {
; CHECK-LABEL: @canonicalize_and_sub_power2_or_zero_multiuse_nofold(
; CHECK-NEXT: [[NY:%.*]] = sub i32 0, [[Y:%.*]]
; CHECK-NEXT: [[P2:%.*]] = and i32 [[Y]], [[NY]]
; CHECK-NEXT: call void @use32(i32 [[P2]])
; CHECK-NEXT: [[VAL:%.*]] = sub i32 [[X:%.*]], [[P2]]
; CHECK-NEXT: call void @use32(i32 [[VAL]])
; CHECK-NEXT: [[AND:%.*]] = and i32 [[VAL]], [[P2]]
; CHECK-NEXT: ret i32 [[AND]]
;
%ny = sub i32 0, %y
%p2 = and i32 %ny, %y
call void @use32(i32 %p2) ; keep p2
%val = sub i32 %x, %p2
call void @use32(i32 %val)
%and = and i32 %val, %p2
ret i32 %and
}
define i32 @add_constant_equal_with_the_top_bit_of_demandedbits_pass(i32 %x) {
; CHECK-LABEL: @add_constant_equal_with_the_top_bit_of_demandedbits_pass(
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 24
; CHECK-NEXT: [[AND:%.*]] = xor i32 [[TMP1]], 16
; CHECK-NEXT: ret i32 [[AND]]
;
%add = add i32 %x, 16
%and = and i32 %add, 24
ret i32 %and
}
define <2 x i16> @add_constant_equal_with_the_top_bit_of_demandedbits_pass_vector(<2 x i16> %x) {
; CHECK-LABEL: @add_constant_equal_with_the_top_bit_of_demandedbits_pass_vector(
; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i16> [[X:%.*]], <i16 24, i16 24>
; CHECK-NEXT: [[AND:%.*]] = xor <2 x i16> [[TMP1]], <i16 16, i16 16>
; CHECK-NEXT: ret <2 x i16> [[AND]]
;
%add = add <2 x i16> %x, <i16 16, i16 16>
%and = and <2 x i16> %add, <i16 24, i16 24>
ret <2 x i16> %and
}
define i32 @add_constant_equal_with_the_top_bit_of_demandedbits_fail1(i32 %x) {
; CHECK-LABEL: @add_constant_equal_with_the_top_bit_of_demandedbits_fail1(
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X:%.*]], 8
; CHECK-NEXT: [[AND:%.*]] = and i32 [[ADD]], 24
; CHECK-NEXT: ret i32 [[AND]]
;
%add = add i32 %x, 8
%and = and i32 %add, 24
ret i32 %and
}
define i32 @add_constant_equal_with_the_top_bit_of_demandedbits_fail2(i32 %x) {
; CHECK-LABEL: @add_constant_equal_with_the_top_bit_of_demandedbits_fail2(
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X:%.*]], 24
; CHECK-NEXT: [[AND:%.*]] = and i32 [[ADD]], 24
; CHECK-NEXT: ret i32 [[AND]]
;
%add = add i32 %x, 24
%and = and i32 %add, 24
ret i32 %and
}
define i32 @add_constant_equal_with_the_top_bit_of_demandedbits_insertpt(i32 %x, i32 %y) {
; CHECK-LABEL: @add_constant_equal_with_the_top_bit_of_demandedbits_insertpt(
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], 16
; CHECK-NEXT: [[OR:%.*]] = or i32 [[TMP1]], [[Y:%.*]]
; CHECK-NEXT: [[AND:%.*]] = and i32 [[OR]], 24
; CHECK-NEXT: ret i32 [[AND]]
;
%add = add i32 %x, 16
%or = or i32 %add, %y
%and = and i32 %or, 24
ret i32 %and
}
define i32 @and_sext_multiuse(i32 %x, i32 %y, i32 %a, i32 %b) {
; CHECK-LABEL: @and_sext_multiuse(
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[ADD:%.*]] = select i1 [[CMP]], i32 [[TMP1]], i32 0
; CHECK-NEXT: ret i32 [[ADD]]
;
%cmp = icmp sgt i32 %x, %y
%sext = sext i1 %cmp to i32
%and1 = and i32 %sext, %a
%and2 = and i32 %sext, %b
%add = add i32 %and1, %and2
ret i32 %add
}