[InstCombine] add casts from splat-a-bit pattern if necessary

Splatting a bit of constant-index across a value:
sext (ashr (trunc iN X to iM), M-1) to iN --> ashr (shl X, N-M), N-1
If the dest type is different, use a cast (adjust use check).

https://alive2.llvm.org/ce/z/acAan3

Reviewed By: spatel

Differential Revision: https://reviews.llvm.org/D124590
This commit is contained in:
Chenbing Zheng 2022-05-07 15:34:57 +08:00
parent 83e07916ff
commit 8eaa1ef0d8
2 changed files with 19 additions and 15 deletions

View File

@ -1592,14 +1592,20 @@ Instruction *InstCombinerImpl::visitSExt(SExtInst &CI) {
// Splatting a bit of constant-index across a value:
// sext (ashr (trunc iN X to iM), M-1) to iN --> ashr (shl X, N-M), N-1
// TODO: If the dest type is different, use a cast (adjust use check).
// If the dest type is different, use a cast (adjust use check).
if (match(Src, m_OneUse(m_AShr(m_Trunc(m_Value(X)),
m_SpecificInt(SrcBitSize - 1)))) &&
X->getType() == DestTy) {
Constant *ShlAmtC = ConstantInt::get(DestTy, DestBitSize - SrcBitSize);
Constant *AshrAmtC = ConstantInt::get(DestTy, DestBitSize - 1);
Value *Shl = Builder.CreateShl(X, ShlAmtC);
return BinaryOperator::CreateAShr(Shl, AshrAmtC);
m_SpecificInt(SrcBitSize - 1))))) {
Type *XTy = X->getType();
unsigned XBitSize = XTy->getScalarSizeInBits();
Constant *ShlAmtC = ConstantInt::get(XTy, XBitSize - SrcBitSize);
Constant *AshrAmtC = ConstantInt::get(XTy, XBitSize - 1);
if (XTy == DestTy)
return BinaryOperator::CreateAShr(Builder.CreateShl(X, ShlAmtC),
AshrAmtC);
if (cast<BinaryOperator>(Src)->getOperand(0)->hasOneUse()) {
Value *Ashr = Builder.CreateAShr(Builder.CreateShl(X, ShlAmtC), AshrAmtC);
return CastInst::CreateIntegerCast(Ashr, DestTy, /* isSigned */ true);
}
}
if (match(Src, m_VScale(DL))) {

View File

@ -381,13 +381,11 @@ define i32 @smear_set_bit_wrong_shift_amount(i32 %x) {
ret i32 %s
}
; TODO: this could be mask+compare+sext or shifts+trunc
define i16 @smear_set_bit_different_dest_type(i32 %x) {
; CHECK-LABEL: @smear_set_bit_different_dest_type(
; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8
; CHECK-NEXT: [[A:%.*]] = ashr i8 [[T]], 7
; CHECK-NEXT: [[S:%.*]] = sext i8 [[A]] to i16
; CHECK-NEXT: [[TMP1:%.*]] = shl i32 [[X:%.*]], 24
; CHECK-NEXT: [[TMP2:%.*]] = ashr i32 [[TMP1]], 31
; CHECK-NEXT: [[S:%.*]] = trunc i32 [[TMP2]] to i16
; CHECK-NEXT: ret i16 [[S]]
;
%t = trunc i32 %x to i8
@ -415,9 +413,9 @@ define i16 @smear_set_bit_different_dest_type_extra_use(i32 %x) {
define i64 @smear_set_bit_different_dest_type_wider_dst(i32 %x) {
; CHECK-LABEL: @smear_set_bit_different_dest_type_wider_dst(
; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8
; CHECK-NEXT: [[A:%.*]] = ashr i8 [[T]], 7
; CHECK-NEXT: [[S:%.*]] = sext i8 [[A]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = shl i32 [[X:%.*]], 24
; CHECK-NEXT: [[TMP2:%.*]] = ashr i32 [[TMP1]], 31
; CHECK-NEXT: [[S:%.*]] = sext i32 [[TMP2]] to i64
; CHECK-NEXT: ret i64 [[S]]
;
%t = trunc i32 %x to i8