mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-01 05:01:59 +01:00
5b68045419
This is a fix for: https://bugs.llvm.org/show_bug.cgi?id=43730 ...and as shown there, we have existing test cases that show potential miscompiles. We could just bail out for vector constants that contain any undef elements, or we can do as shown here: allow the transform, but replace the undefs with a safe value. For most of the tests shown, this results in a full splat constant (no undefs) which is probably a win for further IR analysis because we conservatively don't match undefs in most cases. Codegen can probably recover these kinds of undef lanes via demanded elements analysis if that's profitable. Differential Revision: https://reviews.llvm.org/D69519
258 lines
7.6 KiB
LLVM
258 lines
7.6 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -instcombine -S | FileCheck %s
|
|
|
|
; https://bugs.llvm.org/show_bug.cgi?id=38123
|
|
|
|
; Pattern:
|
|
; x s<= x & C
|
|
; Should be transformed into:
|
|
; x s<= C
|
|
; Iff: isPowerOf2(C + 1)
|
|
; C must not be -1, but may be 0.
|
|
|
|
; NOTE: this pattern is not commutative!
|
|
|
|
declare i8 @gen8()
|
|
declare <2 x i8> @gen2x8()
|
|
declare <3 x i8> @gen3x8()
|
|
|
|
; ============================================================================ ;
|
|
; Basic positive tests
|
|
; ============================================================================ ;
|
|
|
|
define i1 @p0() {
|
|
; CHECK-LABEL: @p0(
|
|
; CHECK-NEXT: [[X:%.*]] = call i8 @gen8()
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i8 [[X]], 4
|
|
; CHECK-NEXT: ret i1 [[TMP1]]
|
|
;
|
|
%x = call i8 @gen8()
|
|
%tmp0 = and i8 %x, 3
|
|
%ret = icmp sle i8 %x, %tmp0
|
|
ret i1 %ret
|
|
}
|
|
|
|
; ============================================================================ ;
|
|
; Vector tests
|
|
; ============================================================================ ;
|
|
|
|
define <2 x i1> @p1_vec_splat() {
|
|
; CHECK-LABEL: @p1_vec_splat(
|
|
; CHECK-NEXT: [[X:%.*]] = call <2 x i8> @gen2x8()
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt <2 x i8> [[X]], <i8 4, i8 4>
|
|
; CHECK-NEXT: ret <2 x i1> [[TMP1]]
|
|
;
|
|
%x = call <2 x i8> @gen2x8()
|
|
%tmp0 = and <2 x i8> %x, <i8 3, i8 3>
|
|
%ret = icmp sle <2 x i8> %x, %tmp0
|
|
ret <2 x i1> %ret
|
|
}
|
|
|
|
define <2 x i1> @p2_vec_nonsplat() {
|
|
; CHECK-LABEL: @p2_vec_nonsplat(
|
|
; CHECK-NEXT: [[X:%.*]] = call <2 x i8> @gen2x8()
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt <2 x i8> [[X]], <i8 4, i8 16>
|
|
; CHECK-NEXT: ret <2 x i1> [[TMP1]]
|
|
;
|
|
%x = call <2 x i8> @gen2x8()
|
|
%tmp0 = and <2 x i8> %x, <i8 3, i8 15> ; doesn't have to be splat.
|
|
%ret = icmp sle <2 x i8> %x, %tmp0
|
|
ret <2 x i1> %ret
|
|
}
|
|
|
|
define <2 x i1> @p2_vec_nonsplat_edgecase() {
|
|
; CHECK-LABEL: @p2_vec_nonsplat_edgecase(
|
|
; CHECK-NEXT: [[X:%.*]] = call <2 x i8> @gen2x8()
|
|
; CHECK-NEXT: [[TMP0:%.*]] = and <2 x i8> [[X]], <i8 3, i8 0>
|
|
; CHECK-NEXT: [[RET:%.*]] = icmp sle <2 x i8> [[X]], [[TMP0]]
|
|
; CHECK-NEXT: ret <2 x i1> [[RET]]
|
|
;
|
|
%x = call <2 x i8> @gen2x8()
|
|
%tmp0 = and <2 x i8> %x, <i8 3, i8 0>
|
|
%ret = icmp sle <2 x i8> %x, %tmp0
|
|
ret <2 x i1> %ret
|
|
}
|
|
|
|
define <3 x i1> @p3_vec_splat_undef() {
|
|
; CHECK-LABEL: @p3_vec_splat_undef(
|
|
; CHECK-NEXT: [[X:%.*]] = call <3 x i8> @gen3x8()
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt <3 x i8> [[X]], <i8 4, i8 4, i8 4>
|
|
; CHECK-NEXT: ret <3 x i1> [[TMP1]]
|
|
;
|
|
%x = call <3 x i8> @gen3x8()
|
|
%tmp0 = and <3 x i8> %x, <i8 3, i8 undef, i8 3>
|
|
%ret = icmp sle <3 x i8> %x, %tmp0
|
|
ret <3 x i1> %ret
|
|
}
|
|
|
|
; ============================================================================ ;
|
|
; One-use tests. We don't care about multi-uses here.
|
|
; ============================================================================ ;
|
|
|
|
declare void @use8(i8)
|
|
|
|
define i1 @oneuse0() {
|
|
; CHECK-LABEL: @oneuse0(
|
|
; CHECK-NEXT: [[X:%.*]] = call i8 @gen8()
|
|
; CHECK-NEXT: [[TMP0:%.*]] = and i8 [[X]], 3
|
|
; CHECK-NEXT: call void @use8(i8 [[TMP0]])
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i8 [[X]], 4
|
|
; CHECK-NEXT: ret i1 [[TMP1]]
|
|
;
|
|
%x = call i8 @gen8()
|
|
%tmp0 = and i8 %x, 3
|
|
call void @use8(i8 %tmp0)
|
|
%ret = icmp sle i8 %x, %tmp0
|
|
ret i1 %ret
|
|
}
|
|
|
|
; ============================================================================ ;
|
|
; Negative tests
|
|
; ============================================================================ ;
|
|
|
|
; Commutativity tests.
|
|
|
|
define i1 @c0(i8 %x) {
|
|
; CHECK-LABEL: @c0(
|
|
; CHECK-NEXT: [[TMP0:%.*]] = and i8 [[X:%.*]], 3
|
|
; CHECK-NEXT: [[RET:%.*]] = icmp sle i8 [[TMP0]], [[X]]
|
|
; CHECK-NEXT: ret i1 [[RET]]
|
|
;
|
|
%tmp0 = and i8 %x, 3
|
|
%ret = icmp sle i8 %tmp0, %x ; swapped order
|
|
ret i1 %ret
|
|
}
|
|
|
|
; ============================================================================ ;
|
|
; Rest of negative tests
|
|
; ============================================================================ ;
|
|
|
|
define i1 @n0() {
|
|
; CHECK-LABEL: @n0(
|
|
; CHECK-NEXT: [[X:%.*]] = call i8 @gen8()
|
|
; CHECK-NEXT: [[TMP0:%.*]] = and i8 [[X]], 4
|
|
; CHECK-NEXT: [[RET:%.*]] = icmp sle i8 [[X]], [[TMP0]]
|
|
; CHECK-NEXT: ret i1 [[RET]]
|
|
;
|
|
%x = call i8 @gen8()
|
|
%tmp0 = and i8 %x, 4 ; power-of-two, but invalid.
|
|
%ret = icmp sle i8 %x, %tmp0
|
|
ret i1 %ret
|
|
}
|
|
|
|
define i1 @n1(i8 %y, i8 %notx) {
|
|
; CHECK-LABEL: @n1(
|
|
; CHECK-NEXT: [[X:%.*]] = call i8 @gen8()
|
|
; CHECK-NEXT: [[TMP0:%.*]] = and i8 [[X]], 3
|
|
; CHECK-NEXT: [[RET:%.*]] = icmp sle i8 [[TMP0]], [[NOTX:%.*]]
|
|
; CHECK-NEXT: ret i1 [[RET]]
|
|
;
|
|
%x = call i8 @gen8()
|
|
%tmp0 = and i8 %x, 3
|
|
%ret = icmp sle i8 %tmp0, %notx ; not %x
|
|
ret i1 %ret
|
|
}
|
|
|
|
define <2 x i1> @n2() {
|
|
; CHECK-LABEL: @n2(
|
|
; CHECK-NEXT: [[X:%.*]] = call <2 x i8> @gen2x8()
|
|
; CHECK-NEXT: [[TMP0:%.*]] = and <2 x i8> [[X]], <i8 3, i8 16>
|
|
; CHECK-NEXT: [[RET:%.*]] = icmp sle <2 x i8> [[X]], [[TMP0]]
|
|
; CHECK-NEXT: ret <2 x i1> [[RET]]
|
|
;
|
|
%x = call <2 x i8> @gen2x8()
|
|
%tmp0 = and <2 x i8> %x, <i8 3, i8 16> ; only the first one is valid.
|
|
%ret = icmp sle <2 x i8> %x, %tmp0
|
|
ret <2 x i1> %ret
|
|
}
|
|
|
|
; ============================================================================ ;
|
|
; Potential miscompiles.
|
|
; ============================================================================ ;
|
|
|
|
define i1 @pv(i8 %y) {
|
|
; CHECK-LABEL: @pv(
|
|
; CHECK-NEXT: [[X:%.*]] = call i8 @gen8()
|
|
; CHECK-NEXT: [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[TMP0]], [[X]]
|
|
; CHECK-NEXT: [[RET:%.*]] = icmp sle i8 [[X]], [[TMP1]]
|
|
; CHECK-NEXT: ret i1 [[RET]]
|
|
;
|
|
%x = call i8 @gen8()
|
|
%tmp0 = lshr i8 -1, %y
|
|
%tmp1 = and i8 %tmp0, %x
|
|
%ret = icmp sle i8 %x, %tmp1
|
|
ret i1 %ret
|
|
}
|
|
|
|
define <2 x i1> @n3_vec() {
|
|
; CHECK-LABEL: @n3_vec(
|
|
; CHECK-NEXT: [[X:%.*]] = call <2 x i8> @gen2x8()
|
|
; CHECK-NEXT: [[TMP0:%.*]] = and <2 x i8> [[X]], <i8 3, i8 -1>
|
|
; CHECK-NEXT: [[RET:%.*]] = icmp sle <2 x i8> [[X]], [[TMP0]]
|
|
; CHECK-NEXT: ret <2 x i1> [[RET]]
|
|
;
|
|
%x = call <2 x i8> @gen2x8()
|
|
%tmp0 = and <2 x i8> %x, <i8 3, i8 -1>
|
|
%ret = icmp sle <2 x i8> %x, %tmp0
|
|
ret <2 x i1> %ret
|
|
}
|
|
|
|
define <3 x i1> @n4_vec() {
|
|
; CHECK-LABEL: @n4_vec(
|
|
; CHECK-NEXT: [[X:%.*]] = call <3 x i8> @gen3x8()
|
|
; CHECK-NEXT: [[TMP0:%.*]] = and <3 x i8> [[X]], <i8 3, i8 undef, i8 -1>
|
|
; CHECK-NEXT: [[RET:%.*]] = icmp sle <3 x i8> [[X]], [[TMP0]]
|
|
; CHECK-NEXT: ret <3 x i1> [[RET]]
|
|
;
|
|
%x = call <3 x i8> @gen3x8()
|
|
%tmp0 = and <3 x i8> %x, <i8 3, i8 undef, i8 -1>
|
|
%ret = icmp sle <3 x i8> %x, %tmp0
|
|
ret <3 x i1> %ret
|
|
}
|
|
|
|
; Commutativity tests with variable
|
|
|
|
define i1 @cv0_GOOD(i8 %y) {
|
|
; CHECK-LABEL: @cv0_GOOD(
|
|
; CHECK-NEXT: [[X:%.*]] = call i8 @gen8()
|
|
; CHECK-NEXT: [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[TMP0]], [[X]]
|
|
; CHECK-NEXT: [[RET:%.*]] = icmp sle i8 [[X]], [[TMP1]]
|
|
; CHECK-NEXT: ret i1 [[RET]]
|
|
;
|
|
%x = call i8 @gen8()
|
|
%tmp0 = lshr i8 -1, %y
|
|
%tmp1 = and i8 %tmp0, %x ; swapped order
|
|
%ret = icmp sle i8 %x, %tmp1
|
|
ret i1 %ret
|
|
}
|
|
|
|
define i1 @cv1(i8 %y) {
|
|
; CHECK-LABEL: @cv1(
|
|
; CHECK-NEXT: [[X:%.*]] = call i8 @gen8()
|
|
; CHECK-NEXT: [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X]], [[TMP0]]
|
|
; CHECK-NEXT: [[RET:%.*]] = icmp sle i8 [[TMP1]], [[X]]
|
|
; CHECK-NEXT: ret i1 [[RET]]
|
|
;
|
|
%x = call i8 @gen8()
|
|
%tmp0 = lshr i8 -1, %y
|
|
%tmp1 = and i8 %x, %tmp0
|
|
%ret = icmp sle i8 %tmp1, %x ; swapped order
|
|
ret i1 %ret
|
|
}
|
|
|
|
define i1 @cv2(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @cv2(
|
|
; CHECK-NEXT: [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[TMP0]], [[X:%.*]]
|
|
; CHECK-NEXT: [[RET:%.*]] = icmp sle i8 [[TMP1]], [[X]]
|
|
; CHECK-NEXT: ret i1 [[RET]]
|
|
;
|
|
%tmp0 = lshr i8 -1, %y
|
|
%tmp1 = and i8 %tmp0, %x ; swapped order
|
|
%ret = icmp sle i8 %tmp1, %x ; swapped order
|
|
ret i1 %ret
|
|
}
|