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

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

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

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

433 lines
16 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
define i16 @narrow_sext_and(i16 %x16, i32 %y32) {
; CHECK-LABEL: define i16 @narrow_sext_and(
; CHECK-SAME: i16 [[X16:%.*]], i32 [[Y32:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[Y32]] to i16
; CHECK-NEXT: [[R:%.*]] = and i16 [[X16]], [[TMP1]]
; CHECK-NEXT: ret i16 [[R]]
;
%x32 = sext i16 %x16 to i32
%b = and i32 %x32, %y32
%r = trunc i32 %b to i16
ret i16 %r
}
define i16 @narrow_zext_and(i16 %x16, i32 %y32) {
; CHECK-LABEL: define i16 @narrow_zext_and(
; CHECK-SAME: i16 [[X16:%.*]], i32 [[Y32:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[Y32]] to i16
; CHECK-NEXT: [[R:%.*]] = and i16 [[X16]], [[TMP1]]
; CHECK-NEXT: ret i16 [[R]]
;
%x32 = zext i16 %x16 to i32
%b = and i32 %x32, %y32
%r = trunc i32 %b to i16
ret i16 %r
}
define i16 @narrow_sext_or(i16 %x16, i32 %y32) {
; CHECK-LABEL: define i16 @narrow_sext_or(
; CHECK-SAME: i16 [[X16:%.*]], i32 [[Y32:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[Y32]] to i16
; CHECK-NEXT: [[R:%.*]] = or i16 [[X16]], [[TMP1]]
; CHECK-NEXT: ret i16 [[R]]
;
%x32 = sext i16 %x16 to i32
%b = or i32 %x32, %y32
%r = trunc i32 %b to i16
ret i16 %r
}
define i16 @narrow_zext_or(i16 %x16, i32 %y32) {
; CHECK-LABEL: define i16 @narrow_zext_or(
; CHECK-SAME: i16 [[X16:%.*]], i32 [[Y32:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[Y32]] to i16
; CHECK-NEXT: [[R:%.*]] = or i16 [[X16]], [[TMP1]]
; CHECK-NEXT: ret i16 [[R]]
;
%x32 = zext i16 %x16 to i32
%b = or i32 %x32, %y32
%r = trunc i32 %b to i16
ret i16 %r
}
define i16 @narrow_sext_xor(i16 %x16, i32 %y32) {
; CHECK-LABEL: define i16 @narrow_sext_xor(
; CHECK-SAME: i16 [[X16:%.*]], i32 [[Y32:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[Y32]] to i16
; CHECK-NEXT: [[R:%.*]] = xor i16 [[X16]], [[TMP1]]
; CHECK-NEXT: ret i16 [[R]]
;
%x32 = sext i16 %x16 to i32
%b = xor i32 %x32, %y32
%r = trunc i32 %b to i16
ret i16 %r
}
define i16 @narrow_zext_xor(i16 %x16, i32 %y32) {
; CHECK-LABEL: define i16 @narrow_zext_xor(
; CHECK-SAME: i16 [[X16:%.*]], i32 [[Y32:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[Y32]] to i16
; CHECK-NEXT: [[R:%.*]] = xor i16 [[X16]], [[TMP1]]
; CHECK-NEXT: ret i16 [[R]]
;
%x32 = zext i16 %x16 to i32
%b = xor i32 %x32, %y32
%r = trunc i32 %b to i16
ret i16 %r
}
define i16 @narrow_sext_add(i16 %x16, i32 %y32) {
; CHECK-LABEL: define i16 @narrow_sext_add(
; CHECK-SAME: i16 [[X16:%.*]], i32 [[Y32:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[Y32]] to i16
; CHECK-NEXT: [[R:%.*]] = add i16 [[X16]], [[TMP1]]
; CHECK-NEXT: ret i16 [[R]]
;
%x32 = sext i16 %x16 to i32
%b = add i32 %x32, %y32
%r = trunc i32 %b to i16
ret i16 %r
}
define i16 @narrow_zext_add(i16 %x16, i32 %y32) {
; CHECK-LABEL: define i16 @narrow_zext_add(
; CHECK-SAME: i16 [[X16:%.*]], i32 [[Y32:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[Y32]] to i16
; CHECK-NEXT: [[R:%.*]] = add i16 [[X16]], [[TMP1]]
; CHECK-NEXT: ret i16 [[R]]
;
%x32 = zext i16 %x16 to i32
%b = add i32 %x32, %y32
%r = trunc i32 %b to i16
ret i16 %r
}
define i16 @narrow_sext_sub(i16 %x16, i32 %y32) {
; CHECK-LABEL: define i16 @narrow_sext_sub(
; CHECK-SAME: i16 [[X16:%.*]], i32 [[Y32:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[Y32]] to i16
; CHECK-NEXT: [[R:%.*]] = sub i16 [[X16]], [[TMP1]]
; CHECK-NEXT: ret i16 [[R]]
;
%x32 = sext i16 %x16 to i32
%b = sub i32 %x32, %y32
%r = trunc i32 %b to i16
ret i16 %r
}
define i16 @narrow_zext_sub(i16 %x16, i32 %y32) {
; CHECK-LABEL: define i16 @narrow_zext_sub(
; CHECK-SAME: i16 [[X16:%.*]], i32 [[Y32:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[Y32]] to i16
; CHECK-NEXT: [[R:%.*]] = sub i16 [[X16]], [[TMP1]]
; CHECK-NEXT: ret i16 [[R]]
;
%x32 = zext i16 %x16 to i32
%b = sub i32 %x32, %y32
%r = trunc i32 %b to i16
ret i16 %r
}
define i16 @narrow_sext_mul(i16 %x16, i32 %y32) {
; CHECK-LABEL: define i16 @narrow_sext_mul(
; CHECK-SAME: i16 [[X16:%.*]], i32 [[Y32:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[Y32]] to i16
; CHECK-NEXT: [[R:%.*]] = mul i16 [[X16]], [[TMP1]]
; CHECK-NEXT: ret i16 [[R]]
;
%x32 = sext i16 %x16 to i32
%b = mul i32 %x32, %y32
%r = trunc i32 %b to i16
ret i16 %r
}
define i16 @narrow_zext_mul(i16 %x16, i32 %y32) {
; CHECK-LABEL: define i16 @narrow_zext_mul(
; CHECK-SAME: i16 [[X16:%.*]], i32 [[Y32:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[Y32]] to i16
; CHECK-NEXT: [[R:%.*]] = mul i16 [[X16]], [[TMP1]]
; CHECK-NEXT: ret i16 [[R]]
;
%x32 = zext i16 %x16 to i32
%b = mul i32 %x32, %y32
%r = trunc i32 %b to i16
ret i16 %r
}
; Verify that the commuted patterns work. The div is to ensure that complexity-based
; canonicalization doesn't swap the binop operands. Use vector types to show those work too.
define <2 x i16> @narrow_sext_and_commute(<2 x i16> %x16, <2 x i32> %y32) {
; CHECK-LABEL: define <2 x i16> @narrow_sext_and_commute(
; CHECK-SAME: <2 x i16> [[X16:%.*]], <2 x i32> [[Y32:%.*]]) {
; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> [[Y32]], <i32 7, i32 -17>
; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
; CHECK-NEXT: [[R:%.*]] = and <2 x i16> [[X16]], [[TMP1]]
; CHECK-NEXT: ret <2 x i16> [[R]]
;
%y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
%x32 = sext <2 x i16> %x16 to <2 x i32>
%b = and <2 x i32> %y32op0, %x32
%r = trunc <2 x i32> %b to <2 x i16>
ret <2 x i16> %r
}
define <2 x i16> @narrow_zext_and_commute(<2 x i16> %x16, <2 x i32> %y32) {
; CHECK-LABEL: define <2 x i16> @narrow_zext_and_commute(
; CHECK-SAME: <2 x i16> [[X16:%.*]], <2 x i32> [[Y32:%.*]]) {
; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> [[Y32]], <i32 7, i32 -17>
; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
; CHECK-NEXT: [[R:%.*]] = and <2 x i16> [[X16]], [[TMP1]]
; CHECK-NEXT: ret <2 x i16> [[R]]
;
%y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
%x32 = zext <2 x i16> %x16 to <2 x i32>
%b = and <2 x i32> %y32op0, %x32
%r = trunc <2 x i32> %b to <2 x i16>
ret <2 x i16> %r
}
define <2 x i16> @narrow_sext_or_commute(<2 x i16> %x16, <2 x i32> %y32) {
; CHECK-LABEL: define <2 x i16> @narrow_sext_or_commute(
; CHECK-SAME: <2 x i16> [[X16:%.*]], <2 x i32> [[Y32:%.*]]) {
; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> [[Y32]], <i32 7, i32 -17>
; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
; CHECK-NEXT: [[R:%.*]] = or <2 x i16> [[X16]], [[TMP1]]
; CHECK-NEXT: ret <2 x i16> [[R]]
;
%y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
%x32 = sext <2 x i16> %x16 to <2 x i32>
%b = or <2 x i32> %y32op0, %x32
%r = trunc <2 x i32> %b to <2 x i16>
ret <2 x i16> %r
}
define <2 x i16> @narrow_zext_or_commute(<2 x i16> %x16, <2 x i32> %y32) {
; CHECK-LABEL: define <2 x i16> @narrow_zext_or_commute(
; CHECK-SAME: <2 x i16> [[X16:%.*]], <2 x i32> [[Y32:%.*]]) {
; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> [[Y32]], <i32 7, i32 -17>
; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
; CHECK-NEXT: [[R:%.*]] = or <2 x i16> [[X16]], [[TMP1]]
; CHECK-NEXT: ret <2 x i16> [[R]]
;
%y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
%x32 = zext <2 x i16> %x16 to <2 x i32>
%b = or <2 x i32> %y32op0, %x32
%r = trunc <2 x i32> %b to <2 x i16>
ret <2 x i16> %r
}
define <2 x i16> @narrow_sext_xor_commute(<2 x i16> %x16, <2 x i32> %y32) {
; CHECK-LABEL: define <2 x i16> @narrow_sext_xor_commute(
; CHECK-SAME: <2 x i16> [[X16:%.*]], <2 x i32> [[Y32:%.*]]) {
; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> [[Y32]], <i32 7, i32 -17>
; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
; CHECK-NEXT: [[R:%.*]] = xor <2 x i16> [[X16]], [[TMP1]]
; CHECK-NEXT: ret <2 x i16> [[R]]
;
%y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
%x32 = sext <2 x i16> %x16 to <2 x i32>
%b = xor <2 x i32> %y32op0, %x32
%r = trunc <2 x i32> %b to <2 x i16>
ret <2 x i16> %r
}
define <2 x i16> @narrow_zext_xor_commute(<2 x i16> %x16, <2 x i32> %y32) {
; CHECK-LABEL: define <2 x i16> @narrow_zext_xor_commute(
; CHECK-SAME: <2 x i16> [[X16:%.*]], <2 x i32> [[Y32:%.*]]) {
; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> [[Y32]], <i32 7, i32 -17>
; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
; CHECK-NEXT: [[R:%.*]] = xor <2 x i16> [[X16]], [[TMP1]]
; CHECK-NEXT: ret <2 x i16> [[R]]
;
%y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
%x32 = zext <2 x i16> %x16 to <2 x i32>
%b = xor <2 x i32> %y32op0, %x32
%r = trunc <2 x i32> %b to <2 x i16>
ret <2 x i16> %r
}
define <2 x i16> @narrow_sext_add_commute(<2 x i16> %x16, <2 x i32> %y32) {
; CHECK-LABEL: define <2 x i16> @narrow_sext_add_commute(
; CHECK-SAME: <2 x i16> [[X16:%.*]], <2 x i32> [[Y32:%.*]]) {
; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> [[Y32]], <i32 7, i32 -17>
; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
; CHECK-NEXT: [[R:%.*]] = add <2 x i16> [[X16]], [[TMP1]]
; CHECK-NEXT: ret <2 x i16> [[R]]
;
%y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
%x32 = sext <2 x i16> %x16 to <2 x i32>
%b = add <2 x i32> %y32op0, %x32
%r = trunc <2 x i32> %b to <2 x i16>
ret <2 x i16> %r
}
define <2 x i16> @narrow_zext_add_commute(<2 x i16> %x16, <2 x i32> %y32) {
; CHECK-LABEL: define <2 x i16> @narrow_zext_add_commute(
; CHECK-SAME: <2 x i16> [[X16:%.*]], <2 x i32> [[Y32:%.*]]) {
; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> [[Y32]], <i32 7, i32 -17>
; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
; CHECK-NEXT: [[R:%.*]] = add <2 x i16> [[X16]], [[TMP1]]
; CHECK-NEXT: ret <2 x i16> [[R]]
;
%y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
%x32 = zext <2 x i16> %x16 to <2 x i32>
%b = add <2 x i32> %y32op0, %x32
%r = trunc <2 x i32> %b to <2 x i16>
ret <2 x i16> %r
}
define <2 x i16> @narrow_sext_sub_commute(<2 x i16> %x16, <2 x i32> %y32) {
; CHECK-LABEL: define <2 x i16> @narrow_sext_sub_commute(
; CHECK-SAME: <2 x i16> [[X16:%.*]], <2 x i32> [[Y32:%.*]]) {
; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> [[Y32]], <i32 7, i32 -17>
; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
; CHECK-NEXT: [[R:%.*]] = sub <2 x i16> [[TMP1]], [[X16]]
; CHECK-NEXT: ret <2 x i16> [[R]]
;
%y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
%x32 = sext <2 x i16> %x16 to <2 x i32>
%b = sub <2 x i32> %y32op0, %x32
%r = trunc <2 x i32> %b to <2 x i16>
ret <2 x i16> %r
}
define <2 x i16> @narrow_zext_sub_commute(<2 x i16> %x16, <2 x i32> %y32) {
; CHECK-LABEL: define <2 x i16> @narrow_zext_sub_commute(
; CHECK-SAME: <2 x i16> [[X16:%.*]], <2 x i32> [[Y32:%.*]]) {
; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> [[Y32]], <i32 7, i32 -17>
; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
; CHECK-NEXT: [[R:%.*]] = sub <2 x i16> [[TMP1]], [[X16]]
; CHECK-NEXT: ret <2 x i16> [[R]]
;
%y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
%x32 = zext <2 x i16> %x16 to <2 x i32>
%b = sub <2 x i32> %y32op0, %x32
%r = trunc <2 x i32> %b to <2 x i16>
ret <2 x i16> %r
}
define <2 x i16> @narrow_sext_mul_commute(<2 x i16> %x16, <2 x i32> %y32) {
; CHECK-LABEL: define <2 x i16> @narrow_sext_mul_commute(
; CHECK-SAME: <2 x i16> [[X16:%.*]], <2 x i32> [[Y32:%.*]]) {
; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> [[Y32]], <i32 7, i32 -17>
; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
; CHECK-NEXT: [[R:%.*]] = mul <2 x i16> [[X16]], [[TMP1]]
; CHECK-NEXT: ret <2 x i16> [[R]]
;
%y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
%x32 = sext <2 x i16> %x16 to <2 x i32>
%b = mul <2 x i32> %y32op0, %x32
%r = trunc <2 x i32> %b to <2 x i16>
ret <2 x i16> %r
}
define <2 x i16> @narrow_zext_mul_commute(<2 x i16> %x16, <2 x i32> %y32) {
; CHECK-LABEL: define <2 x i16> @narrow_zext_mul_commute(
; CHECK-SAME: <2 x i16> [[X16:%.*]], <2 x i32> [[Y32:%.*]]) {
; CHECK-NEXT: [[Y32OP0:%.*]] = sdiv <2 x i32> [[Y32]], <i32 7, i32 -17>
; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
; CHECK-NEXT: [[R:%.*]] = mul <2 x i16> [[X16]], [[TMP1]]
; CHECK-NEXT: ret <2 x i16> [[R]]
;
%y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
%x32 = zext <2 x i16> %x16 to <2 x i32>
%b = mul <2 x i32> %y32op0, %x32
%r = trunc <2 x i32> %b to <2 x i16>
ret <2 x i16> %r
}
; Test cases for PR43580
define i8 @narrow_zext_ashr_keep_trunc(i8 %i1, i8 %i2) {
; CHECK-LABEL: define i8 @narrow_zext_ashr_keep_trunc(
; CHECK-SAME: i8 [[I1:%.*]], i8 [[I2:%.*]]) {
; CHECK-NEXT: [[I1_EXT:%.*]] = sext i8 [[I1]] to i16
; CHECK-NEXT: [[I2_EXT:%.*]] = sext i8 [[I2]] to i16
; CHECK-NEXT: [[SUB:%.*]] = add nsw i16 [[I1_EXT]], [[I2_EXT]]
; CHECK-NEXT: [[SHIFT:%.*]] = lshr i16 [[SUB]], 1
; CHECK-NEXT: [[T:%.*]] = trunc i16 [[SHIFT]] to i8
; CHECK-NEXT: ret i8 [[T]]
;
%i1.ext = sext i8 %i1 to i32
%i2.ext = sext i8 %i2 to i32
%sub = add nsw i32 %i1.ext, %i2.ext
%shift = ashr i32 %sub, 1
%t = trunc i32 %shift to i8
ret i8 %t
}
define i8 @narrow_zext_ashr_keep_trunc2(i9 %i1, i9 %i2) {
; CHECK-LABEL: define i8 @narrow_zext_ashr_keep_trunc2(
; CHECK-SAME: i9 [[I1:%.*]], i9 [[I2:%.*]]) {
; CHECK-NEXT: [[I1_EXT:%.*]] = zext i9 [[I1]] to i16
; CHECK-NEXT: [[I2_EXT:%.*]] = zext i9 [[I2]] to i16
; CHECK-NEXT: [[SUB:%.*]] = add nuw nsw i16 [[I1_EXT]], [[I2_EXT]]
; CHECK-NEXT: [[SHIFT:%.*]] = lshr i16 [[SUB]], 1
; CHECK-NEXT: [[T:%.*]] = trunc i16 [[SHIFT]] to i8
; CHECK-NEXT: ret i8 [[T]]
;
%i1.ext = sext i9 %i1 to i64
%i2.ext = sext i9 %i2 to i64
%sub = add nsw i64 %i1.ext, %i2.ext
%shift = ashr i64 %sub, 1
%t = trunc i64 %shift to i8
ret i8 %t
}
define i7 @narrow_zext_ashr_keep_trunc3(i8 %i1, i8 %i2) {
; CHECK-LABEL: define i7 @narrow_zext_ashr_keep_trunc3(
; CHECK-SAME: i8 [[I1:%.*]], i8 [[I2:%.*]]) {
; CHECK-NEXT: [[I1_EXT:%.*]] = zext i8 [[I1]] to i14
; CHECK-NEXT: [[I2_EXT:%.*]] = zext i8 [[I2]] to i14
; CHECK-NEXT: [[SUB:%.*]] = add nuw nsw i14 [[I1_EXT]], [[I2_EXT]]
; CHECK-NEXT: [[SHIFT:%.*]] = lshr i14 [[SUB]], 1
; CHECK-NEXT: [[T:%.*]] = trunc i14 [[SHIFT]] to i7
; CHECK-NEXT: ret i7 [[T]]
;
%i1.ext = sext i8 %i1 to i64
%i2.ext = sext i8 %i2 to i64
%sub = add nsw i64 %i1.ext, %i2.ext
%shift = ashr i64 %sub, 1
%t = trunc i64 %shift to i7
ret i7 %t
}
define <8 x i8> @narrow_zext_ashr_keep_trunc_vector(<8 x i8> %i1, <8 x i8> %i2) {
; CHECK-LABEL: define <8 x i8> @narrow_zext_ashr_keep_trunc_vector(
; CHECK-SAME: <8 x i8> [[I1:%.*]], <8 x i8> [[I2:%.*]]) {
; CHECK-NEXT: [[I1_EXT:%.*]] = sext <8 x i8> [[I1]] to <8 x i32>
; CHECK-NEXT: [[I2_EXT:%.*]] = sext <8 x i8> [[I2]] to <8 x i32>
; CHECK-NEXT: [[SUB:%.*]] = add nsw <8 x i32> [[I1_EXT]], [[I2_EXT]]
; CHECK-NEXT: [[SHIFT:%.*]] = lshr <8 x i32> [[SUB]], <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
; CHECK-NEXT: [[T:%.*]] = trunc <8 x i32> [[SHIFT]] to <8 x i8>
; CHECK-NEXT: ret <8 x i8> [[T]]
;
%i1.ext = sext <8 x i8> %i1 to <8 x i32>
%i2.ext = sext <8 x i8> %i2 to <8 x i32>
%sub = add nsw <8 x i32> %i1.ext, %i2.ext
%shift = ashr <8 x i32> %sub, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
%t = trunc <8 x i32> %shift to <8 x i8>
ret <8 x i8> %t
}
define i8 @dont_narrow_zext_ashr_keep_trunc(i8 %i1, i8 %i2) {
; CHECK-LABEL: define i8 @dont_narrow_zext_ashr_keep_trunc(
; CHECK-SAME: i8 [[I1:%.*]], i8 [[I2:%.*]]) {
; CHECK-NEXT: [[I1_EXT:%.*]] = sext i8 [[I1]] to i16
; CHECK-NEXT: [[I2_EXT:%.*]] = sext i8 [[I2]] to i16
; CHECK-NEXT: [[SUB:%.*]] = add nsw i16 [[I1_EXT]], [[I2_EXT]]
; CHECK-NEXT: [[SHIFT:%.*]] = lshr i16 [[SUB]], 1
; CHECK-NEXT: [[T:%.*]] = trunc i16 [[SHIFT]] to i8
; CHECK-NEXT: ret i8 [[T]]
;
%i1.ext = sext i8 %i1 to i16
%i2.ext = sext i8 %i2 to i16
%sub = add nsw i16 %i1.ext, %i2.ext
%shift = ashr i16 %sub, 1
%t = trunc i16 %shift to i8
ret i8 %t
}