1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-20 19:42:54 +02:00

[InstCombine] Fold and(shl(zext(x), width(SIGNMASK) - width(%x)), SIGNMASK) to and(sext(%x), SIGNMASK)

One less instruction and reducing use count of zext.
As alive2 confirms, we're fine with all the weird combinations of
undef elts in constants, but unless the shift amount was undef
for a lane, we must sanitize undef mask to zero, since sign bits
are no longer zeros.

https://rise4fun.com/Alive/d7r
```
----------------------------------------
Optimization: zz
Precondition: ((C1 == (width(%r) - width(%x))) && isSignBit(C2))
  %o0 = zext %x
  %o1 = shl %o0, C1
  %r = and %o1, C2
=>
  %n0 = sext %x
  %r = and %n0, C2

Done: 2016
Optimization is correct!
```
This commit is contained in:
Roman Lebedev 2020-11-20 00:07:48 +03:00
parent 01b8ffbe23
commit 4f26d69f1c
2 changed files with 33 additions and 20 deletions

View File

@ -1846,6 +1846,25 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
}
}
if (match(&I, m_And(m_OneUse(m_Shl(m_ZExt(m_Value(X)), m_Value(Y))),
m_SignMask())) &&
match(Y, m_SpecificInt_ICMP(
ICmpInst::Predicate::ICMP_EQ,
APInt(Ty->getScalarSizeInBits(),
Ty->getScalarSizeInBits() -
X->getType()->getScalarSizeInBits())))) {
auto *SExt = Builder.CreateSExt(X, Ty, X->getName() + ".signext");
auto *SanitizedSignMask = cast<Constant>(Op1);
// We must be careful with the undef elements of the sign bit mask, however:
// the mask elt can be undef iff the shift amount for that lane was undef,
// otherwise we need to sanitize undef masks to zero.
SanitizedSignMask = Constant::replaceUndefsWith(
SanitizedSignMask, ConstantInt::getNullValue(Ty->getScalarType()));
SanitizedSignMask =
Constant::mergeUndefsWith(SanitizedSignMask, cast<Constant>(Y));
return BinaryOperator::CreateAnd(SExt, SanitizedSignMask);
}
if (Instruction *Z = narrowMaskedBinOp(I))
return Z;

View File

@ -12,9 +12,8 @@ declare void @use32(i32)
define i32 @t0(i16 %x) {
; CHECK-LABEL: @t0(
; CHECK-NEXT: [[I0:%.*]] = zext i16 [[X:%.*]] to i32
; CHECK-NEXT: [[I1:%.*]] = shl nuw i32 [[I0]], 16
; CHECK-NEXT: [[R:%.*]] = and i32 [[I1]], -2147483648
; CHECK-NEXT: [[X_SIGNEXT:%.*]] = sext i16 [[X:%.*]] to i32
; CHECK-NEXT: [[R:%.*]] = and i32 [[X_SIGNEXT]], -2147483648
; CHECK-NEXT: ret i32 [[R]]
;
%i0 = zext i16 %x to i32
@ -24,9 +23,8 @@ define i32 @t0(i16 %x) {
}
define i32 @t1(i8 %x) {
; CHECK-LABEL: @t1(
; CHECK-NEXT: [[I0:%.*]] = zext i8 [[X:%.*]] to i32
; CHECK-NEXT: [[I1:%.*]] = shl nuw i32 [[I0]], 24
; CHECK-NEXT: [[R:%.*]] = and i32 [[I1]], -2147483648
; CHECK-NEXT: [[X_SIGNEXT:%.*]] = sext i8 [[X:%.*]] to i32
; CHECK-NEXT: [[R:%.*]] = and i32 [[X_SIGNEXT]], -2147483648
; CHECK-NEXT: ret i32 [[R]]
;
%i0 = zext i8 %x to i32
@ -77,8 +75,8 @@ define i32 @t5(i16 %x) {
; CHECK-LABEL: @t5(
; CHECK-NEXT: [[I0:%.*]] = zext i16 [[X:%.*]] to i32
; CHECK-NEXT: call void @use32(i32 [[I0]])
; CHECK-NEXT: [[I1:%.*]] = shl nuw i32 [[I0]], 16
; CHECK-NEXT: [[R:%.*]] = and i32 [[I1]], -2147483648
; CHECK-NEXT: [[X_SIGNEXT:%.*]] = sext i16 [[X]] to i32
; CHECK-NEXT: [[R:%.*]] = and i32 [[X_SIGNEXT]], -2147483648
; CHECK-NEXT: ret i32 [[R]]
;
%i0 = zext i16 %x to i32
@ -122,9 +120,8 @@ define i32 @n7(i16 %x) {
define <2 x i32> @t8(<2 x i16> %x) {
; CHECK-LABEL: @t8(
; CHECK-NEXT: [[I0:%.*]] = zext <2 x i16> [[X:%.*]] to <2 x i32>
; CHECK-NEXT: [[I1:%.*]] = shl nuw <2 x i32> [[I0]], <i32 16, i32 16>
; CHECK-NEXT: [[R:%.*]] = and <2 x i32> [[I1]], <i32 -2147483648, i32 -2147483648>
; CHECK-NEXT: [[X_SIGNEXT:%.*]] = sext <2 x i16> [[X:%.*]] to <2 x i32>
; CHECK-NEXT: [[R:%.*]] = and <2 x i32> [[X_SIGNEXT]], <i32 -2147483648, i32 -2147483648>
; CHECK-NEXT: ret <2 x i32> [[R]]
;
%i0 = zext <2 x i16> %x to <2 x i32>
@ -134,9 +131,8 @@ define <2 x i32> @t8(<2 x i16> %x) {
}
define <2 x i32> @t9(<2 x i16> %x) {
; CHECK-LABEL: @t9(
; CHECK-NEXT: [[I0:%.*]] = zext <2 x i16> [[X:%.*]] to <2 x i32>
; CHECK-NEXT: [[I1:%.*]] = shl <2 x i32> [[I0]], <i32 16, i32 undef>
; CHECK-NEXT: [[R:%.*]] = and <2 x i32> [[I1]], <i32 -2147483648, i32 -2147483648>
; CHECK-NEXT: [[X_SIGNEXT:%.*]] = sext <2 x i16> [[X:%.*]] to <2 x i32>
; CHECK-NEXT: [[R:%.*]] = and <2 x i32> [[X_SIGNEXT]], <i32 -2147483648, i32 undef>
; CHECK-NEXT: ret <2 x i32> [[R]]
;
%i0 = zext <2 x i16> %x to <2 x i32>
@ -147,9 +143,8 @@ define <2 x i32> @t9(<2 x i16> %x) {
}
define <2 x i32> @t10(<2 x i16> %x) {
; CHECK-LABEL: @t10(
; CHECK-NEXT: [[I0:%.*]] = zext <2 x i16> [[X:%.*]] to <2 x i32>
; CHECK-NEXT: [[I1:%.*]] = shl nuw <2 x i32> [[I0]], <i32 16, i32 16>
; CHECK-NEXT: [[R:%.*]] = and <2 x i32> [[I1]], <i32 -2147483648, i32 undef>
; CHECK-NEXT: [[X_SIGNEXT:%.*]] = sext <2 x i16> [[X:%.*]] to <2 x i32>
; CHECK-NEXT: [[R:%.*]] = and <2 x i32> [[X_SIGNEXT]], <i32 -2147483648, i32 0>
; CHECK-NEXT: ret <2 x i32> [[R]]
;
%i0 = zext <2 x i16> %x to <2 x i32>
@ -161,9 +156,8 @@ define <2 x i32> @t10(<2 x i16> %x) {
}
define <2 x i32> @t11(<2 x i16> %x) {
; CHECK-LABEL: @t11(
; CHECK-NEXT: [[I0:%.*]] = zext <2 x i16> [[X:%.*]] to <2 x i32>
; CHECK-NEXT: [[I1:%.*]] = shl <2 x i32> [[I0]], <i32 16, i32 undef>
; CHECK-NEXT: [[R:%.*]] = and <2 x i32> [[I1]], <i32 -2147483648, i32 undef>
; CHECK-NEXT: [[X_SIGNEXT:%.*]] = sext <2 x i16> [[X:%.*]] to <2 x i32>
; CHECK-NEXT: [[R:%.*]] = and <2 x i32> [[X_SIGNEXT]], <i32 -2147483648, i32 undef>
; CHECK-NEXT: ret <2 x i32> [[R]]
;
%i0 = zext <2 x i16> %x to <2 x i32>