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.
1175 lines
31 KiB
LLVM
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
|
|
}
|