Files
clang-p2996/llvm/test/Transforms/InstSimplify/AndOrXor.ll
Nikita Popov d9a5aa8e2d [PatternMatch] Do not accept undef elements in m_AllOnes() and friends (#88217)
Change all the cstval_pred_ty based PatternMatch helpers (things like
m_AllOnes and m_Zero) to only allow poison elements inside vector
splats, not undef elements.

Historically, we used to represent non-demanded elements in vectors
using undef. Nowadays, we use poison instead. As such, I believe that
support for undef in vector splats is no longer useful.

At the same time, while poison splat elements are pretty much always
safe to ignore, this is not generally the case for undef elements. We
have existing miscompiles in our tests due to this (see the
masked-merge-*.ll tests changed here) and it's easy to miss such cases
in the future, now that we write tests using poison instead of undef
elements.

I think overall, keeping support for undef elements no longer makes
sense, and we should drop it. Once this is done consistently, I think we
may also consider allowing poison in m_APInt by default, as doing that
change is much less risky than doing the same with undef.

This change involves a substantial amount of test changes. For most
tests, I've just replaced undef with poison, as I don't think there is
value in retaining both. For some tests (where the distinction between
undef and poison is important), I've duplicated tests.
2024-04-17 18:22:05 +09:00

1175 lines
31 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
declare i32 @llvm.smax.i32(i32, i32)
declare <2 x i32> @llvm.umin.v2i32(<2 x i32>, <2 x i32>)
define i8 @and0(i8 %x) {
; CHECK-LABEL: @and0(
; CHECK-NEXT: ret i8 0
;
%r = and i8 %x, 0
ret i8 %r
}
define <2 x i8> @and0_vec_poison_elt(<2 x i8> %x) {
; CHECK-LABEL: @and0_vec_poison_elt(
; CHECK-NEXT: ret <2 x i8> zeroinitializer
;
%r = and <2 x i8> %x, <i8 poison, i8 0>
ret <2 x i8> %r
}
; add nsw (xor X, signbit), signbit --> X
define <2 x i32> @add_nsw_signbit(<2 x i32> %x) {
; CHECK-LABEL: @add_nsw_signbit(
; CHECK-NEXT: ret <2 x i32> [[X:%.*]]
;
%y = xor <2 x i32> %x, <i32 -2147483648, i32 -2147483648>
%z = add nsw <2 x i32> %y, <i32 -2147483648, i32 -2147483648>
ret <2 x i32> %z
}
; Poison elements in either constant vector are ok.
define <2 x i32> @add_nsw_signbit_poison(<2 x i32> %x) {
; CHECK-LABEL: @add_nsw_signbit_poison(
; CHECK-NEXT: ret <2 x i32> [[X:%.*]]
;
%y = xor <2 x i32> %x, <i32 poison, i32 -2147483648>
%z = add nsw <2 x i32> %y, <i32 -2147483648, i32 poison>
ret <2 x i32> %z
}
; add nuw (xor X, signbit), signbit --> X
define <2 x i5> @add_nuw_signbit(<2 x i5> %x) {
; CHECK-LABEL: @add_nuw_signbit(
; CHECK-NEXT: ret <2 x i5> [[X:%.*]]
;
%y = xor <2 x i5> %x, <i5 -16, i5 -16>
%z = add nuw <2 x i5> %y, <i5 -16, i5 -16>
ret <2 x i5> %z
}
; Poison elements in either constant vector are ok.
define <2 x i5> @add_nuw_signbit_poison(<2 x i5> %x) {
; CHECK-LABEL: @add_nuw_signbit_poison(
; CHECK-NEXT: ret <2 x i5> [[X:%.*]]
;
%y = xor <2 x i5> %x, <i5 -16, i5 poison>
%z = add nuw <2 x i5> %y, <i5 poison, i5 -16>
ret <2 x i5> %z
}
define i64 @pow2(i32 %x) {
; CHECK-LABEL: @pow2(
; CHECK-NEXT: [[NEGX:%.*]] = sub i32 0, [[X:%.*]]
; CHECK-NEXT: [[X2:%.*]] = and i32 [[X]], [[NEGX]]
; CHECK-NEXT: [[E:%.*]] = zext i32 [[X2]] to i64
; CHECK-NEXT: ret i64 [[E]]
;
%negx = sub i32 0, %x
%x2 = and i32 %x, %negx
%e = zext i32 %x2 to i64
%nege = sub i64 0, %e
%e2 = and i64 %e, %nege
ret i64 %e2
}
define i64 @pow2b(i32 %x) {
; CHECK-LABEL: @pow2b(
; CHECK-NEXT: [[SH:%.*]] = shl i32 2, [[X:%.*]]
; CHECK-NEXT: [[E:%.*]] = zext i32 [[SH]] to i64
; CHECK-NEXT: ret i64 [[E]]
;
%sh = shl i32 2, %x
%e = zext i32 %sh to i64
%nege = sub i64 0, %e
%e2 = and i64 %e, %nege
ret i64 %e2
}
define i32 @pow2b_max(i32 %x, i32 %y) {
; CHECK-LABEL: @pow2b_max(
; CHECK-NEXT: [[SHX:%.*]] = shl i32 2, [[X:%.*]]
; CHECK-NEXT: [[SHY:%.*]] = shl i32 32, [[Y:%.*]]
; CHECK-NEXT: [[M:%.*]] = call i32 @llvm.smax.i32(i32 [[SHX]], i32 [[SHY]])
; CHECK-NEXT: ret i32 [[M]]
;
%shx = shl i32 2, %x
%shy = shl i32 32, %y
%m = call i32 @llvm.smax.i32(i32 %shx, i32 %shy)
%neg = sub i32 0, %m
%r = and i32 %m, %neg
ret i32 %r
}
; Power-of-2-or-zero value has no bits in common with its decrement.
define i32 @pow2_decrement(i32 %p) {
; CHECK-LABEL: @pow2_decrement(
; CHECK-NEXT: ret i32 0
;
%x = shl i32 1, %p
%a = add i32 %x, -1
%r = and i32 %a, %x
ret i32 %r
}
define <2 x i32> @pow2_decrement_commute_vec(<2 x i32> %p) {
; CHECK-LABEL: @pow2_decrement_commute_vec(
; CHECK-NEXT: ret <2 x i32> zeroinitializer
;
%x = and <2 x i32> %p, <i32 2048, i32 2048>
%a = add <2 x i32> %x, <i32 -1, i32 -1>
%r = and <2 x i32> %x, %a
ret <2 x i32> %r
}
define <2 x i32> @pow2_decrement_min_vec(<2 x i32> %x, <2 x i32> %y) {
; CHECK-LABEL: @pow2_decrement_min_vec(
; CHECK-NEXT: ret <2 x i32> zeroinitializer
;
%p1 = and <2 x i32> %x, <i32 2048, i32 2048>
%p2 = shl <2 x i32> <i32 1, i32 1>, %y
%m = call <2 x i32> @llvm.umin.v2i32(<2 x i32> %p1, <2 x i32> %p2)
%a = add <2 x i32> %m, <i32 -1, i32 -1>
%r = and <2 x i32> %m, %a
ret <2 x i32> %r
}
define i1 @and_of_icmps0(i32 %b) {
; CHECK-LABEL: @and_of_icmps0(
; CHECK-NEXT: ret i1 false
;
%1 = add i32 %b, 2
%2 = icmp ult i32 %1, 4
%cmp3 = icmp sgt i32 %b, 2
%cmp = and i1 %2, %cmp3
ret i1 %cmp
}
define <2 x i1> @and_of_icmps0_vec(<2 x i32> %b) {
; CHECK-LABEL: @and_of_icmps0_vec(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%1 = add <2 x i32> %b, <i32 2, i32 2>
%2 = icmp ult <2 x i32> %1, <i32 4, i32 4>
%cmp3 = icmp sgt <2 x i32> %b, <i32 2, i32 2>
%cmp = and <2 x i1> %2, %cmp3
ret <2 x i1> %cmp
}
define i1 @and_of_icmps1(i32 %b) {
; CHECK-LABEL: @and_of_icmps1(
; CHECK-NEXT: ret i1 false
;
%1 = add nsw i32 %b, 2
%2 = icmp slt i32 %1, 4
%cmp3 = icmp sgt i32 %b, 2
%cmp = and i1 %2, %cmp3
ret i1 %cmp
}
define <2 x i1> @and_of_icmps1_vec(<2 x i32> %b) {
; CHECK-LABEL: @and_of_icmps1_vec(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%1 = add nsw <2 x i32> %b, <i32 2, i32 2>
%2 = icmp slt <2 x i32> %1, <i32 4, i32 4>
%cmp3 = icmp sgt <2 x i32> %b, <i32 2, i32 2>
%cmp = and <2 x i1> %2, %cmp3
ret <2 x i1> %cmp
}
define i1 @and_of_icmps2(i32 %b) {
; CHECK-LABEL: @and_of_icmps2(
; CHECK-NEXT: ret i1 false
;
%1 = add i32 %b, 2
%2 = icmp ule i32 %1, 3
%cmp3 = icmp sgt i32 %b, 2
%cmp = and i1 %2, %cmp3
ret i1 %cmp
}
define <2 x i1> @and_of_icmps2_vec(<2 x i32> %b) {
; CHECK-LABEL: @and_of_icmps2_vec(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%1 = add <2 x i32> %b, <i32 2, i32 2>
%2 = icmp ule <2 x i32> %1, <i32 3, i32 3>
%cmp3 = icmp sgt <2 x i32> %b, <i32 2, i32 2>
%cmp = and <2 x i1> %2, %cmp3
ret <2 x i1> %cmp
}
define i1 @and_of_icmps3(i32 %b) {
; CHECK-LABEL: @and_of_icmps3(
; CHECK-NEXT: ret i1 false
;
%1 = add nsw i32 %b, 2
%2 = icmp sle i32 %1, 3
%cmp3 = icmp sgt i32 %b, 2
%cmp = and i1 %2, %cmp3
ret i1 %cmp
}
define <2 x i1> @and_of_icmps3_vec(<2 x i32> %b) {
; CHECK-LABEL: @and_of_icmps3_vec(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%1 = add nsw <2 x i32> %b, <i32 2, i32 2>
%2 = icmp sle <2 x i32> %1, <i32 3, i32 3>
%cmp3 = icmp sgt <2 x i32> %b, <i32 2, i32 2>
%cmp = and <2 x i1> %2, %cmp3
ret <2 x i1> %cmp
}
define i1 @and_of_icmps4(i32 %b) {
; CHECK-LABEL: @and_of_icmps4(
; CHECK-NEXT: ret i1 false
;
%1 = add nuw i32 %b, 2
%2 = icmp ult i32 %1, 4
%cmp3 = icmp ugt i32 %b, 2
%cmp = and i1 %2, %cmp3
ret i1 %cmp
}
define <2 x i1> @and_of_icmps4_vec(<2 x i32> %b) {
; CHECK-LABEL: @and_of_icmps4_vec(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%1 = add nuw <2 x i32> %b, <i32 2, i32 2>
%2 = icmp ult <2 x i32> %1, <i32 4, i32 4>
%cmp3 = icmp ugt <2 x i32> %b, <i32 2, i32 2>
%cmp = and <2 x i1> %2, %cmp3
ret <2 x i1> %cmp
}
define i1 @and_of_icmps5(i32 %b) {
; CHECK-LABEL: @and_of_icmps5(
; CHECK-NEXT: ret i1 false
;
%1 = add nuw i32 %b, 2
%2 = icmp ule i32 %1, 3
%cmp3 = icmp ugt i32 %b, 2
%cmp = and i1 %2, %cmp3
ret i1 %cmp
}
define <2 x i1> @and_of_icmps5_vec(<2 x i32> %b) {
; CHECK-LABEL: @and_of_icmps5_vec(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%1 = add nuw <2 x i32> %b, <i32 2, i32 2>
%2 = icmp ule <2 x i32> %1, <i32 3, i32 3>
%cmp3 = icmp ugt <2 x i32> %b, <i32 2, i32 2>
%cmp = and <2 x i1> %2, %cmp3
ret <2 x i1> %cmp
}
define i1 @or_of_icmps0(i32 %b) {
; CHECK-LABEL: @or_of_icmps0(
; CHECK-NEXT: ret i1 true
;
%1 = add i32 %b, 2
%2 = icmp uge i32 %1, 4
%cmp3 = icmp sle i32 %b, 2
%cmp = or i1 %2, %cmp3
ret i1 %cmp
}
define <2 x i1> @or_of_icmps0_vec(<2 x i32> %b) {
; CHECK-LABEL: @or_of_icmps0_vec(
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%1 = add <2 x i32> %b, <i32 2, i32 2>
%2 = icmp uge <2 x i32> %1, <i32 4, i32 4>
%cmp3 = icmp sle <2 x i32> %b, <i32 2, i32 2>
%cmp = or <2 x i1> %2, %cmp3
ret <2 x i1> %cmp
}
define i1 @or_of_icmps1(i32 %b) {
; CHECK-LABEL: @or_of_icmps1(
; CHECK-NEXT: ret i1 true
;
%1 = add nsw i32 %b, 2
%2 = icmp sge i32 %1, 4
%cmp3 = icmp sle i32 %b, 2
%cmp = or i1 %2, %cmp3
ret i1 %cmp
}
define <2 x i1> @or_of_icmps1_vec(<2 x i32> %b) {
; CHECK-LABEL: @or_of_icmps1_vec(
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%1 = add nsw <2 x i32> %b, <i32 2, i32 2>
%2 = icmp sge <2 x i32> %1, <i32 4, i32 4>
%cmp3 = icmp sle <2 x i32> %b, <i32 2, i32 2>
%cmp = or <2 x i1> %2, %cmp3
ret <2 x i1> %cmp
}
define i1 @or_of_icmps2(i32 %b) {
; CHECK-LABEL: @or_of_icmps2(
; CHECK-NEXT: ret i1 true
;
%1 = add i32 %b, 2
%2 = icmp ugt i32 %1, 3
%cmp3 = icmp sle i32 %b, 2
%cmp = or i1 %2, %cmp3
ret i1 %cmp
}
define <2 x i1> @or_of_icmps2_vec(<2 x i32> %b) {
; CHECK-LABEL: @or_of_icmps2_vec(
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%1 = add <2 x i32> %b, <i32 2, i32 2>
%2 = icmp ugt <2 x i32> %1, <i32 3, i32 3>
%cmp3 = icmp sle <2 x i32> %b, <i32 2, i32 2>
%cmp = or <2 x i1> %2, %cmp3
ret <2 x i1> %cmp
}
define i1 @or_of_icmps3(i32 %b) {
; CHECK-LABEL: @or_of_icmps3(
; CHECK-NEXT: ret i1 true
;
%1 = add nsw i32 %b, 2
%2 = icmp sgt i32 %1, 3
%cmp3 = icmp sle i32 %b, 2
%cmp = or i1 %2, %cmp3
ret i1 %cmp
}
define <2 x i1> @or_of_icmps3_vec(<2 x i32> %b) {
; CHECK-LABEL: @or_of_icmps3_vec(
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%1 = add nsw <2 x i32> %b, <i32 2, i32 2>
%2 = icmp sgt <2 x i32> %1, <i32 3, i32 3>
%cmp3 = icmp sle <2 x i32> %b, <i32 2, i32 2>
%cmp = or <2 x i1> %2, %cmp3
ret <2 x i1> %cmp
}
define i1 @or_of_icmps4(i32 %b) {
; CHECK-LABEL: @or_of_icmps4(
; CHECK-NEXT: ret i1 true
;
%1 = add nuw i32 %b, 2
%2 = icmp uge i32 %1, 4
%cmp3 = icmp ule i32 %b, 2
%cmp = or i1 %2, %cmp3
ret i1 %cmp
}
define <2 x i1> @or_of_icmps4_vec(<2 x i32> %b) {
; CHECK-LABEL: @or_of_icmps4_vec(
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%1 = add nuw <2 x i32> %b, <i32 2, i32 2>
%2 = icmp uge <2 x i32> %1, <i32 4, i32 4>
%cmp3 = icmp ule <2 x i32> %b, <i32 2, i32 2>
%cmp = or <2 x i1> %2, %cmp3
ret <2 x i1> %cmp
}
define i1 @or_of_icmps5(i32 %b) {
; CHECK-LABEL: @or_of_icmps5(
; CHECK-NEXT: ret i1 true
;
%1 = add nuw i32 %b, 2
%2 = icmp ugt i32 %1, 3
%cmp3 = icmp ule i32 %b, 2
%cmp = or i1 %2, %cmp3
ret i1 %cmp
}
define <2 x i1> @or_of_icmps5_vec(<2 x i32> %b) {
; CHECK-LABEL: @or_of_icmps5_vec(
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%1 = add nuw <2 x i32> %b, <i32 2, i32 2>
%2 = icmp ugt <2 x i32> %1, <i32 3, i32 3>
%cmp3 = icmp ule <2 x i32> %b, <i32 2, i32 2>
%cmp = or <2 x i1> %2, %cmp3
ret <2 x i1> %cmp
}
define i32 @neg_nuw(i32 %x) {
; CHECK-LABEL: @neg_nuw(
; CHECK-NEXT: ret i32 0
;
%neg = sub nuw i32 0, %x
ret i32 %neg
}
; PR27869 - Look through casts to eliminate cmps and bitwise logic.
define i32 @and_of_zexted_icmps(i32 %i) {
; CHECK-LABEL: @and_of_zexted_icmps(
; CHECK-NEXT: ret i32 0
;
%cmp0 = icmp eq i32 %i, 0
%conv0 = zext i1 %cmp0 to i32
%cmp1 = icmp ugt i32 %i, 4
%conv1 = zext i1 %cmp1 to i32
%and = and i32 %conv0, %conv1
ret i32 %and
}
; Make sure vectors work too.
define <4 x i32> @and_of_zexted_icmps_vec(<4 x i32> %i) {
; CHECK-LABEL: @and_of_zexted_icmps_vec(
; CHECK-NEXT: ret <4 x i32> zeroinitializer
;
%cmp0 = icmp eq <4 x i32> %i, zeroinitializer
%conv0 = zext <4 x i1> %cmp0 to <4 x i32>
%cmp1 = icmp slt <4 x i32> %i, zeroinitializer
%conv1 = zext <4 x i1> %cmp1 to <4 x i32>
%and = and <4 x i32> %conv0, %conv1
ret <4 x i32> %and
}
; Try a different cast and weird types.
define i5 @and_of_sexted_icmps(i3 %i) {
; CHECK-LABEL: @and_of_sexted_icmps(
; CHECK-NEXT: ret i5 0
;
%cmp0 = icmp eq i3 %i, 0
%conv0 = sext i1 %cmp0 to i5
%cmp1 = icmp ugt i3 %i, 1
%conv1 = sext i1 %cmp1 to i5
%and = and i5 %conv0, %conv1
ret i5 %and
}
; Try a different cast and weird vector types.
define i3 @and_of_bitcast_icmps_vec(<3 x i65> %i) {
; CHECK-LABEL: @and_of_bitcast_icmps_vec(
; CHECK-NEXT: ret i3 0
;
%cmp0 = icmp sgt <3 x i65> %i, zeroinitializer
%conv0 = bitcast <3 x i1> %cmp0 to i3
%cmp1 = icmp slt <3 x i65> %i, zeroinitializer
%conv1 = bitcast <3 x i1> %cmp1 to i3
%and = and i3 %conv0, %conv1
ret i3 %and
}
; We can't do this if the casts are different.
define i16 @and_of_different_cast_icmps(i8 %i) {
; CHECK-LABEL: @and_of_different_cast_icmps(
; CHECK-NEXT: [[CMP0:%.*]] = icmp eq i8 [[I:%.*]], 0
; CHECK-NEXT: [[CONV0:%.*]] = zext i1 [[CMP0]] to i16
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[I]], 1
; CHECK-NEXT: [[CONV1:%.*]] = sext i1 [[CMP1]] to i16
; CHECK-NEXT: [[AND:%.*]] = and i16 [[CONV0]], [[CONV1]]
; CHECK-NEXT: ret i16 [[AND]]
;
%cmp0 = icmp eq i8 %i, 0
%conv0 = zext i1 %cmp0 to i16
%cmp1 = icmp eq i8 %i, 1
%conv1 = sext i1 %cmp1 to i16
%and = and i16 %conv0, %conv1
ret i16 %and
}
define <2 x i3> @and_of_different_cast_icmps_vec(<2 x i8> %i, <2 x i16> %j) {
; CHECK-LABEL: @and_of_different_cast_icmps_vec(
; CHECK-NEXT: [[CMP0:%.*]] = icmp eq <2 x i8> [[I:%.*]], zeroinitializer
; CHECK-NEXT: [[CONV0:%.*]] = zext <2 x i1> [[CMP0]] to <2 x i3>
; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt <2 x i16> [[J:%.*]], <i16 1, i16 1>
; CHECK-NEXT: [[CONV1:%.*]] = zext <2 x i1> [[CMP1]] to <2 x i3>
; CHECK-NEXT: [[AND:%.*]] = and <2 x i3> [[CONV0]], [[CONV1]]
; CHECK-NEXT: ret <2 x i3> [[AND]]
;
%cmp0 = icmp eq <2 x i8> %i, zeroinitializer
%conv0 = zext <2 x i1> %cmp0 to <2 x i3>
%cmp1 = icmp ugt <2 x i16> %j, <i16 1, i16 1>
%conv1 = zext <2 x i1> %cmp1 to <2 x i3>
%and = and <2 x i3> %conv0, %conv1
ret <2 x i3> %and
}
; limit
define i32 @or_of_zexted_icmps(i32 %i) {
; CHECK-LABEL: @or_of_zexted_icmps(
; CHECK-NEXT: ret i32 1
;
%cmp0 = icmp ne i32 %i, 0
%conv0 = zext i1 %cmp0 to i32
%cmp1 = icmp uge i32 4, %i
%conv1 = zext i1 %cmp1 to i32
%or = or i32 %conv0, %conv1
ret i32 %or
}
; Try a different cast and weird vector types.
define i3 @or_of_bitcast_icmps_vec(<3 x i65> %i) {
; CHECK-LABEL: @or_of_bitcast_icmps_vec(
; CHECK-NEXT: ret i3 -1
;
%cmp0 = icmp sge <3 x i65> %i, zeroinitializer
%conv0 = bitcast <3 x i1> %cmp0 to i3
%cmp1 = icmp slt <3 x i65> %i, zeroinitializer
%conv1 = bitcast <3 x i1> %cmp1 to i3
%or = or i3 %conv0, %conv1
ret i3 %or
}
; We can't simplify if the casts are different.
define i16 @or_of_different_cast_icmps(i8 %i) {
; CHECK-LABEL: @or_of_different_cast_icmps(
; CHECK-NEXT: [[CMP0:%.*]] = icmp ne i8 [[I:%.*]], 0
; CHECK-NEXT: [[CONV0:%.*]] = zext i1 [[CMP0]] to i16
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i8 [[I]], 1
; CHECK-NEXT: [[CONV1:%.*]] = sext i1 [[CMP1]] to i16
; CHECK-NEXT: [[OR:%.*]] = or i16 [[CONV0]], [[CONV1]]
; CHECK-NEXT: ret i16 [[OR]]
;
%cmp0 = icmp ne i8 %i, 0
%conv0 = zext i1 %cmp0 to i16
%cmp1 = icmp ne i8 %i, 1
%conv1 = sext i1 %cmp1 to i16
%or = or i16 %conv0, %conv1
ret i16 %or
}
; (A & ~B) | (A ^ B) -> A ^ B
define i3 @or_xor_andn_commute0(i3 %a, i3 %b) {
; CHECK-LABEL: @or_xor_andn_commute0(
; CHECK-NEXT: [[XOR:%.*]] = xor i3 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: ret i3 [[XOR]]
;
%neg = xor i3 %b, -1
%and = and i3 %a, %neg
%xor = xor i3 %a, %b
%or = or i3 %and, %xor
ret i3 %or
}
define i32 @or_xor_andn_commute1(i32 %a, i32 %b) {
; CHECK-LABEL: @or_xor_andn_commute1(
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: ret i32 [[XOR]]
;
%neg = xor i32 %b, -1
%and = and i32 %neg, %a
%xor = xor i32 %a, %b
%or = or i32 %and, %xor
ret i32 %or
}
define <2 x i32> @or_xor_andn_commute2(<2 x i32> %a, <2 x i32> %b) {
; CHECK-LABEL: @or_xor_andn_commute2(
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i32> [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: ret <2 x i32> [[XOR]]
;
%xor = xor <2 x i32> %a, %b
%neg = xor <2 x i32> %b, <i32 -1, i32 poison>
%and = and <2 x i32> %a, %neg
%or = or <2 x i32> %xor, %and
ret <2 x i32> %or
}
define i32 @or_xor_andn_commute3(i32 %a, i32 %b) {
; CHECK-LABEL: @or_xor_andn_commute3(
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: ret i32 [[XOR]]
;
%xor = xor i32 %a, %b
%neg = xor i32 %b, -1
%and = and i32 %neg, %a
%or = or i32 %xor, %and
ret i32 %or
}
define i32 @or_xor_andn_commute4(i32 %a, i32 %b) {
; CHECK-LABEL: @or_xor_andn_commute4(
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT: ret i32 [[XOR]]
;
%neg = xor i32 %b, -1
%and = and i32 %a, %neg
%xor = xor i32 %b, %a
%or = or i32 %and, %xor
ret i32 %or
}
define i32 @or_xor_andn_commute5(i32 %a, i32 %b) {
; CHECK-LABEL: @or_xor_andn_commute5(
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT: ret i32 [[XOR]]
;
%neg = xor i32 %b, -1
%and = and i32 %neg, %a
%xor = xor i32 %b, %a
%or = or i32 %and, %xor
ret i32 %or
}
define i32 @or_xor_andn_commute6(i32 %a, i32 %b) {
; CHECK-LABEL: @or_xor_andn_commute6(
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT: ret i32 [[XOR]]
;
%xor = xor i32 %b, %a
%neg = xor i32 %b, -1
%and = and i32 %a, %neg
%or = or i32 %xor, %and
ret i32 %or
}
define i32 @or_xor_andn_commute7(i32 %a, i32 %b) {
; CHECK-LABEL: @or_xor_andn_commute7(
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT: ret i32 [[XOR]]
;
%xor = xor i32 %b, %a
%neg = xor i32 %b, -1
%and = and i32 %neg, %a
%or = or i32 %xor, %and
ret i32 %or
}
; (~A ^ B) | (A & B) -> ~A ^ B
define i32 @or_xorn_and_commute0(i32 %a, i32 %b) {
; CHECK-LABEL: @or_xorn_and_commute0(
; CHECK-NEXT: [[NEGA:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[NEGA]], [[B:%.*]]
; CHECK-NEXT: ret i32 [[XOR]]
;
%nega = xor i32 %a, -1
%and = and i32 %a, %b
%xor = xor i32 %nega, %b
%or = or i32 %xor, %and
ret i32 %or
}
define i3 @or_xorn_and_commute1(i3 %a, i3 %b) {
; CHECK-LABEL: @or_xorn_and_commute1(
; CHECK-NEXT: [[NEGA:%.*]] = xor i3 [[A:%.*]], -1
; CHECK-NEXT: [[XOR:%.*]] = xor i3 [[B:%.*]], [[NEGA]]
; CHECK-NEXT: ret i3 [[XOR]]
;
%nega = xor i3 %a, -1
%and = and i3 %a, %b
%xor = xor i3 %b, %nega
%or = or i3 %xor, %and
ret i3 %or
}
define <2 x i32> @or_xorn_and_commute2(<2 x i32> %a, <2 x i32> %b) {
; CHECK-LABEL: @or_xorn_and_commute2(
; CHECK-NEXT: [[NEGA:%.*]] = xor <2 x i32> [[A:%.*]], <i32 -1, i32 -1>
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i32> [[B:%.*]], [[NEGA]]
; CHECK-NEXT: ret <2 x i32> [[XOR]]
;
%nega = xor <2 x i32> %a, <i32 -1, i32 -1>
%and = and <2 x i32> %b, %a
%xor = xor <2 x i32> %b, %nega
%or = or <2 x i32> %xor, %and
ret <2 x i32> %or
}
; This is not safe to fold because the extra logic ops limit the undef-ness of the result.
define <2 x i32> @or_xorn_and_commute2_undef(<2 x i32> %a, <2 x i32> %b) {
; CHECK-LABEL: @or_xorn_and_commute2_undef(
; CHECK-NEXT: [[NEGA:%.*]] = xor <2 x i32> [[A:%.*]], <i32 undef, i32 -1>
; CHECK-NEXT: [[AND:%.*]] = and <2 x i32> [[B:%.*]], [[A]]
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i32> [[B]], [[NEGA]]
; CHECK-NEXT: [[OR:%.*]] = or <2 x i32> [[XOR]], [[AND]]
; CHECK-NEXT: ret <2 x i32> [[OR]]
;
%nega = xor <2 x i32> %a, <i32 undef, i32 -1>
%and = and <2 x i32> %b, %a
%xor = xor <2 x i32> %b, %nega
%or = or <2 x i32> %xor, %and
ret <2 x i32> %or
}
; Unlike the above test, this is safe to fold.
define <2 x i32> @or_xorn_and_commute2_poison(<2 x i32> %a, <2 x i32> %b) {
; CHECK-LABEL: @or_xorn_and_commute2_poison(
; CHECK-NEXT: [[NEGA:%.*]] = xor <2 x i32> [[A:%.*]], <i32 poison, i32 -1>
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i32> [[B:%.*]], [[NEGA]]
; CHECK-NEXT: ret <2 x i32> [[XOR]]
;
%nega = xor <2 x i32> %a, <i32 poison, i32 -1>
%and = and <2 x i32> %b, %a
%xor = xor <2 x i32> %b, %nega
%or = or <2 x i32> %xor, %and
ret <2 x i32> %or
}
define i32 @or_xorn_and_commute3(i32 %a, i32 %b) {
; CHECK-LABEL: @or_xorn_and_commute3(
; CHECK-NEXT: [[NEGA:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[NEGA]], [[B:%.*]]
; CHECK-NEXT: ret i32 [[XOR]]
;
%nega = xor i32 %a, -1
%and = and i32 %b, %a
%xor = xor i32 %nega, %b
%or = or i32 %xor, %and
ret i32 %or
}
define i32 @or_xorn_and_commute4(i32 %a, i32 %b) {
; CHECK-LABEL: @or_xorn_and_commute4(
; CHECK-NEXT: [[NEGA:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[NEGA]], [[B:%.*]]
; CHECK-NEXT: ret i32 [[XOR]]
;
%nega = xor i32 %a, -1
%and = and i32 %a, %b
%xor = xor i32 %nega, %b
%or = or i32 %and, %xor
ret i32 %or
}
define i32 @or_xorn_and_commute5(i32 %a, i32 %b) {
; CHECK-LABEL: @or_xorn_and_commute5(
; CHECK-NEXT: [[NEGA:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[B:%.*]], [[NEGA]]
; CHECK-NEXT: ret i32 [[XOR]]
;
%nega = xor i32 %a, -1
%and = and i32 %a, %b
%xor = xor i32 %b, %nega
%or = or i32 %and, %xor
ret i32 %or
}
define i32 @or_xorn_and_commute6(i32 %a, i32 %b) {
; CHECK-LABEL: @or_xorn_and_commute6(
; CHECK-NEXT: [[NEGA:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[B:%.*]], [[NEGA]]
; CHECK-NEXT: ret i32 [[XOR]]
;
%nega = xor i32 %a, -1
%and = and i32 %b, %a
%xor = xor i32 %b, %nega
%or = or i32 %and, %xor
ret i32 %or
}
define i32 @or_xorn_and_commute7(i32 %a, i32 %b) {
; CHECK-LABEL: @or_xorn_and_commute7(
; CHECK-NEXT: [[NEGA:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[NEGA]], [[B:%.*]]
; CHECK-NEXT: ret i32 [[XOR]]
;
%nega = xor i32 %a, -1
%and = and i32 %b, %a
%xor = xor i32 %nega, %b
%or = or i32 %and, %xor
ret i32 %or
}
define i8 @lshr_perfect_mask(i8 %x) {
; CHECK-LABEL: @lshr_perfect_mask(
; CHECK-NEXT: [[SH:%.*]] = lshr i8 [[X:%.*]], 5
; CHECK-NEXT: ret i8 [[SH]]
;
%sh = lshr i8 %x, 5
%mask = and i8 %sh, 7 ; 0x07
ret i8 %mask
}
define <2 x i8> @lshr_oversized_mask_splat(<2 x i8> %x) {
; CHECK-LABEL: @lshr_oversized_mask_splat(
; CHECK-NEXT: [[SH:%.*]] = lshr <2 x i8> [[X:%.*]], <i8 5, i8 5>
; CHECK-NEXT: ret <2 x i8> [[SH]]
;
%sh = lshr <2 x i8> %x, <i8 5, i8 5>
%mask = and <2 x i8> %sh, <i8 135, i8 135> ; 0x87
ret <2 x i8> %mask
}
define i8 @lshr_undersized_mask(i8 %x) {
; CHECK-LABEL: @lshr_undersized_mask(
; CHECK-NEXT: [[SH:%.*]] = lshr i8 [[X:%.*]], 5
; CHECK-NEXT: [[MASK:%.*]] = and i8 [[SH]], -2
; CHECK-NEXT: ret i8 [[MASK]]
;
%sh = lshr i8 %x, 5
%mask = and i8 %sh, -2 ; 0xFE
ret i8 %mask
}
define <2 x i8> @shl_perfect_mask_splat(<2 x i8> %x) {
; CHECK-LABEL: @shl_perfect_mask_splat(
; CHECK-NEXT: [[SH:%.*]] = shl <2 x i8> [[X:%.*]], <i8 6, i8 6>
; CHECK-NEXT: ret <2 x i8> [[SH]]
;
%sh = shl <2 x i8> %x, <i8 6, i8 6>
%mask = and <2 x i8> %sh, <i8 192, i8 192> ; 0xC0
ret <2 x i8> %mask
}
define i8 @shl_oversized_mask(i8 %x) {
; CHECK-LABEL: @shl_oversized_mask(
; CHECK-NEXT: [[SH:%.*]] = shl i8 [[X:%.*]], 6
; CHECK-NEXT: ret i8 [[SH]]
;
%sh = shl i8 %x, 6
%mask = and i8 %sh, 195 ; 0xC3
ret i8 %mask
}
define <2 x i8> @shl_undersized_mask_splat(<2 x i8> %x) {
; CHECK-LABEL: @shl_undersized_mask_splat(
; CHECK-NEXT: [[SH:%.*]] = shl <2 x i8> [[X:%.*]], <i8 6, i8 6>
; CHECK-NEXT: [[MASK:%.*]] = and <2 x i8> [[SH]], <i8 -120, i8 -120>
; CHECK-NEXT: ret <2 x i8> [[MASK]]
;
%sh = shl <2 x i8> %x, <i8 6, i8 6>
%mask = and <2 x i8> %sh, <i8 136, i8 136> ; 0x88
ret <2 x i8> %mask
}
define i32 @reversed_not(i32 %a) {
; CHECK-LABEL: @reversed_not(
; CHECK-NEXT: ret i32 -1
;
%nega = xor i32 -1, %a
%or = or i32 %a, %nega
ret i32 %or
}
define i64 @shl_or_and1(i32 %a, i1 %b) {
; CHECK-LABEL: @shl_or_and1(
; CHECK-NEXT: [[T2:%.*]] = zext i1 [[B:%.*]] to i64
; CHECK-NEXT: ret i64 [[T2]]
;
%t1 = zext i32 %a to i64
%t2 = zext i1 %b to i64
%t3 = shl nuw i64 %t1, 32
%t4 = or i64 %t2, %t3
%t5 = and i64 %t4, 1
ret i64 %t5
}
define i64 @shl_or_and2(i32 %a, i1 %b) {
; CHECK-LABEL: @shl_or_and2(
; CHECK-NEXT: [[T1:%.*]] = zext i1 [[B:%.*]] to i64
; CHECK-NEXT: [[T3:%.*]] = shl nuw i64 [[T1]], 32
; CHECK-NEXT: ret i64 [[T3]]
;
%t1 = zext i1 %b to i64
%t2 = zext i32 %a to i64
%t3 = shl nuw i64 %t1, 32
%t4 = or i64 %t2, %t3
%t5 = and i64 %t4, 4294967296
ret i64 %t5
}
; concatenate two 32-bit integers and extract lower 32-bit
define i64 @shl_or_and3(i32 %a, i32 %b) {
; CHECK-LABEL: @shl_or_and3(
; CHECK-NEXT: [[T2:%.*]] = zext i32 [[B:%.*]] to i64
; CHECK-NEXT: ret i64 [[T2]]
;
%t1 = zext i32 %a to i64
%t2 = zext i32 %b to i64
%t3 = shl nuw i64 %t1, 32
%t4 = or i64 %t2, %t3
%t5 = and i64 %t4, 4294967295
ret i64 %t5
}
; concatenate two 16-bit integers and extract higher 16-bit
define i32 @shl_or_and4(i16 %a, i16 %b) {
; CHECK-LABEL: @shl_or_and4(
; CHECK-NEXT: [[T1:%.*]] = zext i16 [[A:%.*]] to i32
; CHECK-NEXT: [[T3:%.*]] = shl nuw i32 [[T1]], 16
; CHECK-NEXT: ret i32 [[T3]]
;
%t1 = zext i16 %a to i32
%t2 = zext i16 %b to i32
%t3 = shl nuw i32 %t1, 16
%t4 = or i32 %t2, %t3
%t5 = and i32 %t4, 4294901760 ; mask with 0xFFFF0000
ret i32 %t5
}
define i128 @shl_or_and5(i64 %a, i1 %b) {
; CHECK-LABEL: @shl_or_and5(
; CHECK-NEXT: [[T2:%.*]] = zext i1 [[B:%.*]] to i128
; CHECK-NEXT: ret i128 [[T2]]
;
%t1 = zext i64 %a to i128
%t2 = zext i1 %b to i128
%t3 = shl nuw i128 %t1, 64
%t4 = or i128 %t2, %t3
%t5 = and i128 %t4, 1
ret i128 %t5
}
; A variation of above test cases; it fails due to the mask value
define i32 @shl_or_and6(i16 %a, i16 %b) {
; CHECK-LABEL: @shl_or_and6(
; CHECK-NEXT: [[T1:%.*]] = zext i16 [[A:%.*]] to i32
; CHECK-NEXT: [[T2:%.*]] = zext i16 [[B:%.*]] to i32
; CHECK-NEXT: [[T3:%.*]] = shl nuw i32 [[T1]], 16
; CHECK-NEXT: [[T4:%.*]] = or i32 [[T2]], [[T3]]
; CHECK-NEXT: [[T5:%.*]] = and i32 [[T4]], -65535
; CHECK-NEXT: ret i32 [[T5]]
;
%t1 = zext i16 %a to i32
%t2 = zext i16 %b to i32
%t3 = shl nuw i32 %t1, 16
%t4 = or i32 %t2, %t3
%t5 = and i32 %t4, 4294901761 ; mask with 0xFFFF0001
ret i32 %t5
}
; A variation of above test cases; it fails due to the mask value
define i32 @shl_or_and7(i16 %a, i16 %b) {
; CHECK-LABEL: @shl_or_and7(
; CHECK-NEXT: [[T1:%.*]] = zext i16 [[A:%.*]] to i32
; CHECK-NEXT: [[T2:%.*]] = zext i16 [[B:%.*]] to i32
; CHECK-NEXT: [[T3:%.*]] = shl nuw i32 [[T1]], 16
; CHECK-NEXT: [[T4:%.*]] = or i32 [[T2]], [[T3]]
; CHECK-NEXT: [[T5:%.*]] = and i32 [[T4]], -131072
; CHECK-NEXT: ret i32 [[T5]]
;
%t1 = zext i16 %a to i32
%t2 = zext i16 %b to i32
%t3 = shl nuw i32 %t1, 16
%t4 = or i32 %t2, %t3
%t5 = and i32 %t4, 4294836224 ; mask with 0xFFFE0000
ret i32 %t5
}
; A variation of above test cases; it fails due to the mask value
define i32 @shl_or_and8(i16 %a, i16 %b) {
; CHECK-LABEL: @shl_or_and8(
; CHECK-NEXT: [[T1:%.*]] = zext i16 [[A:%.*]] to i32
; CHECK-NEXT: [[T2:%.*]] = zext i16 [[B:%.*]] to i32
; CHECK-NEXT: [[T3:%.*]] = shl nuw i32 [[T1]], 16
; CHECK-NEXT: [[T4:%.*]] = or i32 [[T2]], [[T3]]
; CHECK-NEXT: [[T5:%.*]] = and i32 [[T4]], 131071
; CHECK-NEXT: ret i32 [[T5]]
;
%t1 = zext i16 %a to i32
%t2 = zext i16 %b to i32
%t3 = shl nuw i32 %t1, 16
%t4 = or i32 %t2, %t3
%t5 = and i32 %t4, 131071 ; mask with 0x1FFFF
ret i32 %t5
}
define <2 x i64> @shl_or_and1v(<2 x i32> %a, <2 x i1> %b) {
; CHECK-LABEL: @shl_or_and1v(
; CHECK-NEXT: [[T2:%.*]] = zext <2 x i1> [[B:%.*]] to <2 x i64>
; CHECK-NEXT: ret <2 x i64> [[T2]]
;
%t1 = zext <2 x i32> %a to <2 x i64>
%t2 = zext <2 x i1> %b to <2 x i64>
%t3 = shl nuw <2 x i64> %t1, <i64 32, i64 32>
%t4 = or <2 x i64> %t3, %t2
%t5 = and <2 x i64> %t4, <i64 1, i64 1>
ret <2 x i64> %t5
}
define <2 x i64> @shl_or_and2v(<2 x i32> %a, <2 x i1> %b) {
; CHECK-LABEL: @shl_or_and2v(
; CHECK-NEXT: [[T1:%.*]] = zext <2 x i1> [[B:%.*]] to <2 x i64>
; CHECK-NEXT: [[T3:%.*]] = shl nuw <2 x i64> [[T1]], <i64 32, i64 32>
; CHECK-NEXT: ret <2 x i64> [[T3]]
;
%t1 = zext <2 x i1> %b to <2 x i64>
%t2 = zext <2 x i32> %a to <2 x i64>
%t3 = shl nuw <2 x i64> %t1, <i64 32, i64 32>
%t4 = or <2 x i64> %t2, %t3
%t5 = and <2 x i64> %t4, <i64 4294967296, i64 4294967296>
ret <2 x i64> %t5
}
; A variation of above test case, but fails due to the mask value
define <2 x i32> @shl_or_and3v(<2 x i16> %a, <2 x i16> %b) {
; CHECK-LABEL: @shl_or_and3v(
; CHECK-NEXT: [[T1:%.*]] = zext <2 x i16> [[A:%.*]] to <2 x i32>
; CHECK-NEXT: [[T2:%.*]] = zext <2 x i16> [[B:%.*]] to <2 x i32>
; CHECK-NEXT: [[T3:%.*]] = shl nuw <2 x i32> [[T1]], <i32 16, i32 16>
; CHECK-NEXT: [[T4:%.*]] = or <2 x i32> [[T2]], [[T3]]
; CHECK-NEXT: [[T5:%.*]] = and <2 x i32> [[T4]], <i32 -65535, i32 -65535>
; CHECK-NEXT: ret <2 x i32> [[T5]]
;
%t1 = zext <2 x i16> %a to <2 x i32>
%t2 = zext <2 x i16> %b to <2 x i32>
%t3 = shl nuw <2 x i32> %t1, <i32 16, i32 16>
%t4 = or <2 x i32> %t2, %t3
%t5 = and <2 x i32> %t4, <i32 4294901761, i32 4294901761> ; mask with 0xFFFF0001
ret <2 x i32> %t5
}
define i8 @and_add_sub(i8 %x) {
; CHECK-LABEL: @and_add_sub(
; CHECK-NEXT: ret i8 0
;
%a = add i8 %x, -1
%s = sub i8 0, %x
%r = and i8 %a, %s
ret i8 %r
}
define <2 x i8> @and_sub_add(<2 x i8> %x) {
; CHECK-LABEL: @and_sub_add(
; CHECK-NEXT: ret <2 x i8> zeroinitializer
;
%a = add <2 x i8> %x, <i8 -4, i8 -4>
%s = sub <2 x i8> <i8 3, i8 3>, %x
%r = and <2 x i8> %s, %a
ret <2 x i8> %r
}
define i89 @or_add_sub(i89 %x) {
; CHECK-LABEL: @or_add_sub(
; CHECK-NEXT: ret i89 -1
;
%a = add i89 %x, 5
%s = sub i89 -6, %x
%r = or i89 %a, %s
ret i89 %r
}
define <3 x i8> @or_sub_add(<3 x i8> %x) {
; CHECK-LABEL: @or_sub_add(
; CHECK-NEXT: ret <3 x i8> <i8 -1, i8 -1, i8 -1>
;
%a = add <3 x i8> %x, <i8 42, i8 -12, i8 0>
%s = sub <3 x i8> <i8 -43, i8 11, i8 -1>, %x
%r = or <3 x i8> %s, %a
ret <3 x i8> %r
}
define <2 x i17> @xor_add_sub(<2 x i17> %x) {
; CHECK-LABEL: @xor_add_sub(
; CHECK-NEXT: ret <2 x i17> <i17 -1, i17 -1>
;
%a = add <2 x i17> %x, <i17 3000, i17 23>
%s = sub <2 x i17> <i17 -3001, i17 -24>, %x
%r = xor <2 x i17> %a, %s
ret <2 x i17> %r
}
define i8 @xor_sub_add(i8 %x) {
; CHECK-LABEL: @xor_sub_add(
; CHECK-NEXT: ret i8 -1
;
%a = add i8 %x, 33
%s = sub i8 -34, %x
%r = xor i8 %s, %a
ret i8 %r
}
; Negative test
define i8 @and_add_sub_wrong_const(i8 %x) {
; CHECK-LABEL: @and_add_sub_wrong_const(
; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], 6
; CHECK-NEXT: [[S:%.*]] = sub i8 -6, [[X]]
; CHECK-NEXT: [[R:%.*]] = and i8 [[A]], [[S]]
; CHECK-NEXT: ret i8 [[R]]
;
%a = add i8 %x, 6
%s = sub i8 -6, %x
%r = and i8 %a, %s
ret i8 %r
}
; Negative test
define i8 @or_add_sub_wrong_var(i8 %x, i8 %y) {
; CHECK-LABEL: @or_add_sub_wrong_var(
; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], 5
; CHECK-NEXT: [[S:%.*]] = sub i8 -6, [[Y:%.*]]
; CHECK-NEXT: [[R:%.*]] = or i8 [[A]], [[S]]
; CHECK-NEXT: ret i8 [[R]]
;
%a = add i8 %x, 5
%s = sub i8 -6, %y
%r = or i8 %a, %s
ret i8 %r
}
; Negative test
define i8 @xor_add_sub_wrong_op(i8 %x) {
; CHECK-LABEL: @xor_add_sub_wrong_op(
; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], 5
; CHECK-NEXT: [[S:%.*]] = sub i8 [[X]], -6
; CHECK-NEXT: [[R:%.*]] = xor i8 [[A]], [[S]]
; CHECK-NEXT: ret i8 [[R]]
;
%a = add i8 %x, 5
%s = sub i8 %x, -6
%r = xor i8 %a, %s
ret i8 %r
}
; `and` isn't needed if it doesn't actually change any bits.
define i8 @noop_and_t0(i8 %x) {
; CHECK-LABEL: @noop_and_t0(
; CHECK-NEXT: [[A:%.*]] = shl i8 [[X:%.*]], 3
; CHECK-NEXT: [[B:%.*]] = lshr i8 [[A]], 2
; CHECK-NEXT: [[R:%.*]] = and i8 [[B]], 62
; CHECK-NEXT: ret i8 [[R]]
;
%a = shl i8 %x, 3
%b = lshr i8 %a, 2
%r = and i8 %b, 62
ret i8 %r
}
define i8 @noop_and_t1(i8 %x) {
; CHECK-LABEL: @noop_and_t1(
; CHECK-NEXT: [[A:%.*]] = shl i8 [[X:%.*]], 3
; CHECK-NEXT: [[B:%.*]] = lshr i8 [[A]], 2
; CHECK-NEXT: [[R:%.*]] = and i8 [[B]], 126
; CHECK-NEXT: ret i8 [[R]]
;
%a = shl i8 %x, 3
%b = lshr i8 %a, 2
%r = and i8 %b, 126
ret i8 %r
}
; hidden simplifydemandedbits constant.
define i8 @noop_and_t2(i8 %x) {
; CHECK-LABEL: @noop_and_t2(
; CHECK-NEXT: [[A:%.*]] = and i8 [[X:%.*]], 2
; CHECK-NEXT: [[B:%.*]] = or i8 [[A]], 127
; CHECK-NEXT: [[C:%.*]] = and i8 [[B]], 62
; CHECK-NEXT: ret i8 [[C]]
;
%a = and i8 %x, 2
%b = or i8 %a, 127
%c = and i8 %b, 62
ret i8 %c
}