[InstSimplify] Fold zext(X) | sext(X) --> sext(X) and zext(X) & sext(X) --> zext(X) (#213313)
fix #213247 alive2: https://alive2.llvm.org/ce/z/G6se2o godbolt: https://godbolt.org/z/M3nz5Tvcn
This commit is contained in:
parent
36b6f48f88
commit
efe31d6dfe
3 changed files with 222 additions and 0 deletions
|
|
@ -2135,6 +2135,16 @@ static Value *simplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
|
|||
if (Value *V = simplifyAndOrOfCmps(Q, Op0, Op1, true))
|
||||
return V;
|
||||
|
||||
// zext(X) & sext(X) --> zext(X)
|
||||
// sext(X) & zext(X) --> zext(X)
|
||||
{
|
||||
Value *X = nullptr;
|
||||
if (match(Op0, m_ZExt(m_Value(X))) && match(Op1, m_SExt(m_Specific(X))))
|
||||
return Op0;
|
||||
if (match(Op1, m_ZExt(m_Value(X))) && match(Op0, m_SExt(m_Specific(X))))
|
||||
return Op1;
|
||||
}
|
||||
|
||||
// Try some generic simplifications for associative operations.
|
||||
if (Value *V =
|
||||
simplifyAssociativeBinOp(Instruction::And, Op0, Op1, Q, MaxRecurse))
|
||||
|
|
@ -2388,6 +2398,16 @@ static Value *simplifyOrInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
|
|||
}
|
||||
}
|
||||
|
||||
// zext(X) | sext(X) --> sext(X)
|
||||
// sext(X) | zext(X) --> sext(X)
|
||||
{
|
||||
Value *X = nullptr;
|
||||
if (match(Op0, m_ZExt(m_Value(X))) && match(Op1, m_SExt(m_Specific(X))))
|
||||
return Op1;
|
||||
if (match(Op1, m_ZExt(m_Value(X))) && match(Op0, m_SExt(m_Specific(X))))
|
||||
return Op0;
|
||||
}
|
||||
|
||||
// A funnel shift (rotate) can be decomposed into simpler shifts. See if we
|
||||
// are mixing in another shift that is redundant with the funnel shift.
|
||||
|
||||
|
|
|
|||
101
llvm/test/Transforms/InstCombine/fold-and-zext-sext.ll
Normal file
101
llvm/test/Transforms/InstCombine/fold-and-zext-sext.ll
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
|
||||
|
||||
declare void @use32(i32)
|
||||
|
||||
define i32 @fold_zext_sext(i8 %x) {
|
||||
; CHECK-LABEL: @fold_zext_sext(
|
||||
; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[X:%.*]] to i32
|
||||
; CHECK-NEXT: ret i32 [[ZEXT]]
|
||||
;
|
||||
%zext = zext i8 %x to i32
|
||||
%sext = sext i8 %x to i32
|
||||
%and = and i32 %zext, %sext
|
||||
ret i32 %and
|
||||
}
|
||||
|
||||
define i32 @fold_zext_sext_commuted(i8 %x) {
|
||||
; CHECK-LABEL: @fold_zext_sext_commuted(
|
||||
; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[X:%.*]] to i32
|
||||
; CHECK-NEXT: ret i32 [[ZEXT]]
|
||||
;
|
||||
%sext = sext i8 %x to i32
|
||||
%zext = zext i8 %x to i32
|
||||
%and = and i32 %sext, %zext
|
||||
ret i32 %and
|
||||
}
|
||||
|
||||
define <4 x i32> @fold_zext_sext_vec(<4 x i16> %x) {
|
||||
; CHECK-LABEL: @fold_zext_sext_vec(
|
||||
; CHECK-NEXT: [[ZEXT:%.*]] = zext <4 x i16> [[X:%.*]] to <4 x i32>
|
||||
; CHECK-NEXT: ret <4 x i32> [[ZEXT]]
|
||||
;
|
||||
%zext = zext <4 x i16> %x to <4 x i32>
|
||||
%sext = sext <4 x i16> %x to <4 x i32>
|
||||
%and = and <4 x i32> %zext, %sext
|
||||
ret <4 x i32> %and
|
||||
}
|
||||
|
||||
define i32 @multi_use_fold_zext_sext_1(i8 %x) {
|
||||
; CHECK-LABEL: @multi_use_fold_zext_sext_1(
|
||||
; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[X:%.*]] to i32
|
||||
; CHECK-NEXT: call void @use32(i32 [[ZEXT]])
|
||||
; CHECK-NEXT: ret i32 [[ZEXT]]
|
||||
;
|
||||
%zext = zext i8 %x to i32
|
||||
%sext = sext i8 %x to i32
|
||||
call void @use32(i32 %zext)
|
||||
%and = and i32 %zext, %sext
|
||||
ret i32 %and
|
||||
}
|
||||
|
||||
define i32 @multi_use_fold_zext_sext_2(i8 %x) {
|
||||
; CHECK-LABEL: @multi_use_fold_zext_sext_2(
|
||||
; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[X:%.*]] to i32
|
||||
; CHECK-NEXT: [[SEXT:%.*]] = sext i8 [[X]] to i32
|
||||
; CHECK-NEXT: call void @use32(i32 [[SEXT]])
|
||||
; CHECK-NEXT: ret i32 [[ZEXT]]
|
||||
;
|
||||
%zext = zext i8 %x to i32
|
||||
%sext = sext i8 %x to i32
|
||||
call void @use32(i32 %sext)
|
||||
%and = and i32 %zext, %sext
|
||||
ret i32 %and
|
||||
}
|
||||
|
||||
define i32 @neg_different_sources(i8 %x, i8 %y) {
|
||||
; CHECK-LABEL: @neg_different_sources(
|
||||
; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[X:%.*]] to i32
|
||||
; CHECK-NEXT: [[SEXT:%.*]] = sext i8 [[Y:%.*]] to i32
|
||||
; CHECK-NEXT: [[R:%.*]] = and i32 [[ZEXT]], [[SEXT]]
|
||||
; CHECK-NEXT: ret i32 [[R]]
|
||||
;
|
||||
%zext = zext i8 %x to i32
|
||||
%sext = sext i8 %y to i32
|
||||
%and = and i32 %zext, %sext
|
||||
ret i32 %and
|
||||
}
|
||||
|
||||
define i32 @neg_zext_only(i8 %x, i8 %y) {
|
||||
; CHECK-LABEL: @neg_zext_only(
|
||||
; CHECK-NEXT: [[R1:%.*]] = and i8 [[X:%.*]], [[Y:%.*]]
|
||||
; CHECK-NEXT: [[R:%.*]] = zext i8 [[R1]] to i32
|
||||
; CHECK-NEXT: ret i32 [[R]]
|
||||
;
|
||||
%z0 = zext i8 %x to i32
|
||||
%z1 = zext i8 %y to i32
|
||||
%and = and i32 %z0, %z1
|
||||
ret i32 %and
|
||||
}
|
||||
|
||||
define i32 @neg_sext_only(i8 %x, i8 %y) {
|
||||
; CHECK-LABEL: @neg_sext_only(
|
||||
; CHECK-NEXT: [[R1:%.*]] = and i8 [[X:%.*]], [[Y:%.*]]
|
||||
; CHECK-NEXT: [[R:%.*]] = sext i8 [[R1]] to i32
|
||||
; CHECK-NEXT: ret i32 [[R]]
|
||||
;
|
||||
%s0 = sext i8 %x to i32
|
||||
%s1 = sext i8 %y to i32
|
||||
%and = and i32 %s0, %s1
|
||||
ret i32 %and
|
||||
}
|
||||
101
llvm/test/Transforms/InstCombine/fold-or-zext-sext.ll
Normal file
101
llvm/test/Transforms/InstCombine/fold-or-zext-sext.ll
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
|
||||
|
||||
declare void @use32(i32)
|
||||
|
||||
define i32 @fold_zext_sext(i8 %x) {
|
||||
; CHECK-LABEL: @fold_zext_sext(
|
||||
; CHECK-NEXT: [[SEXT:%.*]] = sext i8 [[X:%.*]] to i32
|
||||
; CHECK-NEXT: ret i32 [[SEXT]]
|
||||
;
|
||||
%zext = zext i8 %x to i32
|
||||
%sext = sext i8 %x to i32
|
||||
%or = or i32 %zext, %sext
|
||||
ret i32 %or
|
||||
}
|
||||
|
||||
define i32 @fold_zext_sext_commuted(i8 %x) {
|
||||
; CHECK-LABEL: @fold_zext_sext_commuted(
|
||||
; CHECK-NEXT: [[SEXT:%.*]] = sext i8 [[X:%.*]] to i32
|
||||
; CHECK-NEXT: ret i32 [[SEXT]]
|
||||
;
|
||||
%sext = sext i8 %x to i32
|
||||
%zext = zext i8 %x to i32
|
||||
%or = or i32 %sext, %zext
|
||||
ret i32 %or
|
||||
}
|
||||
|
||||
define <4 x i32> @fold_zext_sext_vec(<4 x i16> %x) {
|
||||
; CHECK-LABEL: @fold_zext_sext_vec(
|
||||
; CHECK-NEXT: [[SEXT:%.*]] = sext <4 x i16> [[X:%.*]] to <4 x i32>
|
||||
; CHECK-NEXT: ret <4 x i32> [[SEXT]]
|
||||
;
|
||||
%zext = zext <4 x i16> %x to <4 x i32>
|
||||
%sext = sext <4 x i16> %x to <4 x i32>
|
||||
%or = or <4 x i32> %zext, %sext
|
||||
ret <4 x i32> %or
|
||||
}
|
||||
|
||||
define i32 @multi_use_fold_zext_sext_1(i8 %x) {
|
||||
; CHECK-LABEL: @multi_use_fold_zext_sext_1(
|
||||
; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[X:%.*]] to i32
|
||||
; CHECK-NEXT: [[SEXT:%.*]] = sext i8 [[X]] to i32
|
||||
; CHECK-NEXT: call void @use32(i32 [[ZEXT]])
|
||||
; CHECK-NEXT: ret i32 [[SEXT]]
|
||||
;
|
||||
%zext = zext i8 %x to i32
|
||||
%sext = sext i8 %x to i32
|
||||
call void @use32(i32 %zext)
|
||||
%or = or i32 %zext, %sext
|
||||
ret i32 %or
|
||||
}
|
||||
|
||||
define i32 @multi_use_fold_zext_sext_2(i8 %x) {
|
||||
; CHECK-LABEL: @multi_use_fold_zext_sext_2(
|
||||
; CHECK-NEXT: [[SEXT:%.*]] = sext i8 [[X:%.*]] to i32
|
||||
; CHECK-NEXT: call void @use32(i32 [[SEXT]])
|
||||
; CHECK-NEXT: ret i32 [[SEXT]]
|
||||
;
|
||||
%zext = zext i8 %x to i32
|
||||
%sext = sext i8 %x to i32
|
||||
call void @use32(i32 %sext)
|
||||
%or = or i32 %zext, %sext
|
||||
ret i32 %or
|
||||
}
|
||||
|
||||
define i32 @neg_different_sources(i8 %x, i8 %y) {
|
||||
; CHECK-LABEL: @neg_different_sources(
|
||||
; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[X:%.*]] to i32
|
||||
; CHECK-NEXT: [[SEXT:%.*]] = sext i8 [[Y:%.*]] to i32
|
||||
; CHECK-NEXT: [[R:%.*]] = or i32 [[ZEXT]], [[SEXT]]
|
||||
; CHECK-NEXT: ret i32 [[R]]
|
||||
;
|
||||
%zext = zext i8 %x to i32
|
||||
%sext = sext i8 %y to i32
|
||||
%or = or i32 %zext, %sext
|
||||
ret i32 %or
|
||||
}
|
||||
|
||||
define i32 @neg_zext_only(i8 %x, i8 %y) {
|
||||
; CHECK-LABEL: @neg_zext_only(
|
||||
; CHECK-NEXT: [[R1:%.*]] = or i8 [[X:%.*]], [[Y:%.*]]
|
||||
; CHECK-NEXT: [[R:%.*]] = zext i8 [[R1]] to i32
|
||||
; CHECK-NEXT: ret i32 [[R]]
|
||||
;
|
||||
%z0 = zext i8 %x to i32
|
||||
%z1 = zext i8 %y to i32
|
||||
%or = or i32 %z0, %z1
|
||||
ret i32 %or
|
||||
}
|
||||
|
||||
define i32 @neg_sext_only(i8 %x, i8 %y) {
|
||||
; CHECK-LABEL: @neg_sext_only(
|
||||
; CHECK-NEXT: [[R1:%.*]] = or i8 [[X:%.*]], [[Y:%.*]]
|
||||
; CHECK-NEXT: [[R:%.*]] = sext i8 [[R1]] to i32
|
||||
; CHECK-NEXT: ret i32 [[R]]
|
||||
;
|
||||
%s0 = sext i8 %x to i32
|
||||
%s1 = sext i8 %y to i32
|
||||
%or = or i32 %s0, %s1
|
||||
ret i32 %or
|
||||
}
|
||||
Loading…
Reference in a new issue