mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
f8a60b9733
This reverts commit ea1a0d7c9ae3e5232a4163fc67efad4aabd51f2b. While this is strictly more powerful, it is also strictly slower. InstSimplify intentionally does not perform many folds that it is allowed to perform, if doing so requires a KnownBits calculation that will be repeated in InstCombine. Maybe it's worthwhile to do this here, but that needs a more explicitly stated motivation, evaluated in a review.
1215 lines
32 KiB
LLVM
1215 lines
32 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -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_undef_elt(<2 x i8> %x) {
|
|
; CHECK-LABEL: @and0_vec_undef_elt(
|
|
; CHECK-NEXT: ret <2 x i8> zeroinitializer
|
|
;
|
|
%r = and <2 x i8> %x, <i8 undef, 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
|
|
}
|
|
|
|
; Undef elements in either constant vector are ok.
|
|
|
|
define <2 x i32> @add_nsw_signbit_undef(<2 x i32> %x) {
|
|
; CHECK-LABEL: @add_nsw_signbit_undef(
|
|
; CHECK-NEXT: ret <2 x i32> [[X:%.*]]
|
|
;
|
|
%y = xor <2 x i32> %x, <i32 undef, i32 -2147483648>
|
|
%z = add nsw <2 x i32> %y, <i32 -2147483648, i32 undef>
|
|
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
|
|
}
|
|
|
|
; Undef elements in either constant vector are ok.
|
|
|
|
define <2 x i5> @add_nuw_signbit_undef(<2 x i5> %x) {
|
|
; CHECK-LABEL: @add_nuw_signbit_undef(
|
|
; CHECK-NEXT: ret <2 x i5> [[X:%.*]]
|
|
;
|
|
%y = xor <2 x i5> %x, <i5 -16, i5 undef>
|
|
%z = add nuw <2 x i5> %y, <i5 undef, 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 bitcast (<3 x i1> <i1 true, i1 true, i1 true> to i3)
|
|
;
|
|
%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 i32 @test43(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test43(
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: ret i32 [[XOR]]
|
|
;
|
|
%neg = xor i32 %b, -1
|
|
%and = and i32 %a, %neg
|
|
%xor = xor i32 %a, %b
|
|
%or = or i32 %and, %xor
|
|
ret i32 %or
|
|
}
|
|
|
|
define i32 @test43_commuted_and(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test43_commuted_and(
|
|
; 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
|
|
}
|
|
|
|
; Commute operands of the 'or'.
|
|
; (A ^ B) | (A & ~B) -> A ^ B
|
|
|
|
define i32 @test44(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test44(
|
|
; 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 %a, %neg
|
|
%or = or i32 %xor, %and
|
|
ret i32 %or
|
|
}
|
|
|
|
define i32 @test44_commuted_and(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test44_commuted_and(
|
|
; 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
|
|
}
|
|
|
|
; (~A & ~B) | (~A ^ B) -> ~A ^ B
|
|
|
|
define i32 @test45(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test45(
|
|
; CHECK-NEXT: [[NEGB:%.*]] = xor i32 [[B:%.*]], -1
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[NEGB]]
|
|
; CHECK-NEXT: ret i32 [[XOR]]
|
|
;
|
|
%nega = xor i32 %a, -1
|
|
%negb = xor i32 %b, -1
|
|
%and = and i32 %nega, %negb
|
|
%xor = xor i32 %a, %negb
|
|
%or = or i32 %and, %xor
|
|
ret i32 %or
|
|
}
|
|
|
|
define i32 @test45_commuted_and(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test45_commuted_and(
|
|
; CHECK-NEXT: [[NEGB:%.*]] = xor i32 [[B:%.*]], -1
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[NEGB]]
|
|
; CHECK-NEXT: ret i32 [[XOR]]
|
|
;
|
|
%nega = xor i32 %a, -1
|
|
%negb = xor i32 %b, -1
|
|
%and = and i32 %negb, %nega
|
|
%xor = xor i32 %a, %negb
|
|
%or = or i32 %and, %xor
|
|
ret i32 %or
|
|
}
|
|
|
|
; Commute operands of the 'or'.
|
|
; (~A ^ B) | (~A & ~B) -> ~A ^ B
|
|
|
|
define i32 @test46(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test46(
|
|
; CHECK-NEXT: [[NEGB:%.*]] = xor i32 [[B:%.*]], -1
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[NEGB]]
|
|
; CHECK-NEXT: ret i32 [[XOR]]
|
|
;
|
|
%nega = xor i32 %a, -1
|
|
%negb = xor i32 %b, -1
|
|
%and = and i32 %nega, %negb
|
|
%xor = xor i32 %a, %negb
|
|
%or = or i32 %xor, %and
|
|
ret i32 %or
|
|
}
|
|
|
|
; (~A & ~B) | (~A ^ B) -> ~A ^ B
|
|
|
|
define i32 @test46_commuted_and(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test46_commuted_and(
|
|
; CHECK-NEXT: [[NEGB:%.*]] = xor i32 [[B:%.*]], -1
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[NEGB]]
|
|
; CHECK-NEXT: ret i32 [[XOR]]
|
|
;
|
|
%nega = xor i32 %a, -1
|
|
%negb = xor i32 %b, -1
|
|
%and = and i32 %negb, %nega
|
|
%xor = xor i32 %a, %negb
|
|
%or = or i32 %xor, %and
|
|
ret i32 %or
|
|
}
|
|
|
|
; (~A ^ B) | (A & B) -> ~A ^ B
|
|
|
|
define i32 @test47(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test47(
|
|
; 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 i32 @test48(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test48(
|
|
; 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 %xor, %and
|
|
ret i32 %or
|
|
}
|
|
|
|
define i32 @test49(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test49(
|
|
; 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 %xor, %and
|
|
ret i32 %or
|
|
}
|
|
|
|
define i32 @test50(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test50(
|
|
; 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 @test51(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test51(
|
|
; 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 @test52(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test52(
|
|
; 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 @test53(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test53(
|
|
; 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 @test54(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test54(
|
|
; 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
|
|
}
|
|
|
|
; (A & B) | ~(A ^ B) -> ~(A ^ B)
|
|
|
|
define i32 @test55(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test55(
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A]], [[B]]
|
|
; CHECK-NEXT: [[XNOR:%.*]] = xor i32 [[XOR]], -1
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[AND]], [[XNOR]]
|
|
; CHECK-NEXT: ret i32 [[OR]]
|
|
;
|
|
%and = and i32 %a, %b
|
|
%xor = xor i32 %a, %b
|
|
%xnor = xor i32 %xor, -1
|
|
%or = or i32 %and, %xnor
|
|
ret i32 %or
|
|
}
|
|
|
|
; ~(A ^ B) | (A & B) -> ~(A ^ B)
|
|
|
|
define i32 @test56(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test56(
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A]], [[B]]
|
|
; CHECK-NEXT: [[XNOR:%.*]] = xor i32 [[XOR]], -1
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[XNOR]], [[AND]]
|
|
; CHECK-NEXT: ret i32 [[OR]]
|
|
;
|
|
%and = and i32 %a, %b
|
|
%xor = xor i32 %a, %b
|
|
%xnor = xor i32 %xor, -1
|
|
%or = or i32 %xnor, %and
|
|
ret i32 %or
|
|
}
|
|
|
|
; (B & A) | ~(A ^ B) -> ~(A ^ B)
|
|
|
|
define i32 @test57(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test57(
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A]], [[B]]
|
|
; CHECK-NEXT: [[XNOR:%.*]] = xor i32 [[XOR]], -1
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[AND]], [[XNOR]]
|
|
; CHECK-NEXT: ret i32 [[OR]]
|
|
;
|
|
%and = and i32 %b, %a
|
|
%xor = xor i32 %a, %b
|
|
%xnor = xor i32 %xor, -1
|
|
%or = or i32 %and, %xnor
|
|
ret i32 %or
|
|
}
|
|
|
|
; ~(A ^ B) | (A & B) -> ~(A ^ B)
|
|
|
|
define i32 @test58(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test58(
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A]], [[B]]
|
|
; CHECK-NEXT: [[XNOR:%.*]] = xor i32 [[XOR]], -1
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[XNOR]], [[AND]]
|
|
; CHECK-NEXT: ret i32 [[OR]]
|
|
;
|
|
%and = and i32 %b, %a
|
|
%xor = xor i32 %a, %b
|
|
%xnor = xor i32 %xor, -1
|
|
%or = or i32 %xnor, %and
|
|
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
|
|
}
|