mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-11 17:08:42 +00:00
[InstCombine,InstSimplify] Optimize select followed by and/or/xor
This patch adds `A & (A && B)` -> `A && B` (similarly for or + logical or) Also, this patch adds `~(select C, (icmp pred X, Y), const)` -> `select C, (icmp pred' X, Y), ~const`. Alive2 proof: merge_and: https://alive2.llvm.org/ce/z/teMR97 merge_or: https://alive2.llvm.org/ce/z/b4yZUp xor_and: https://alive2.llvm.org/ce/z/_-TXHi xor_or: https://alive2.llvm.org/ce/z/2uYx_a Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D94861
This commit is contained in:
parent
14573d44ae
commit
0441df94ad
@ -2127,12 +2127,21 @@ static Value *SimplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
|
||||
Instruction::Xor, Q, MaxRecurse))
|
||||
return V;
|
||||
|
||||
// If the operation is with the result of a select instruction, check whether
|
||||
// operating on either branch of the select always yields the same value.
|
||||
if (isa<SelectInst>(Op0) || isa<SelectInst>(Op1))
|
||||
if (isa<SelectInst>(Op0) || isa<SelectInst>(Op1)) {
|
||||
if (Op0->getType()->isIntOrIntVectorTy(1)) {
|
||||
// A & (A && B) -> A && B
|
||||
if (match(Op1, m_Select(m_Specific(Op0), m_Value(), m_Zero())))
|
||||
return Op1;
|
||||
else if (match(Op0, m_Select(m_Specific(Op1), m_Value(), m_Zero())))
|
||||
return Op0;
|
||||
}
|
||||
// If the operation is with the result of a select instruction, check
|
||||
// whether operating on either branch of the select always yields the same
|
||||
// value.
|
||||
if (Value *V = ThreadBinOpOverSelect(Instruction::And, Op0, Op1, Q,
|
||||
MaxRecurse))
|
||||
return V;
|
||||
}
|
||||
|
||||
// If the operation is with the result of a phi instruction, check whether
|
||||
// operating on all incoming values of the phi always yields the same value.
|
||||
@ -2303,12 +2312,21 @@ static Value *SimplifyOrInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
|
||||
Instruction::And, Q, MaxRecurse))
|
||||
return V;
|
||||
|
||||
// If the operation is with the result of a select instruction, check whether
|
||||
// operating on either branch of the select always yields the same value.
|
||||
if (isa<SelectInst>(Op0) || isa<SelectInst>(Op1))
|
||||
if (isa<SelectInst>(Op0) || isa<SelectInst>(Op1)) {
|
||||
if (Op0->getType()->isIntOrIntVectorTy(1)) {
|
||||
// A | (A || B) -> A || B
|
||||
if (match(Op1, m_Select(m_Specific(Op0), m_One(), m_Value())))
|
||||
return Op1;
|
||||
else if (match(Op0, m_Select(m_Specific(Op1), m_One(), m_Value())))
|
||||
return Op0;
|
||||
}
|
||||
// If the operation is with the result of a select instruction, check
|
||||
// whether operating on either branch of the select always yields the same
|
||||
// value.
|
||||
if (Value *V = ThreadBinOpOverSelect(Instruction::Or, Op0, Op1, Q,
|
||||
MaxRecurse))
|
||||
return V;
|
||||
}
|
||||
|
||||
// (A & C1)|(B & C2)
|
||||
const APInt *C1, *C2;
|
||||
|
@ -3444,19 +3444,32 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) {
|
||||
}
|
||||
}
|
||||
|
||||
// Pull 'not' into operands of select if both operands are one-use compares.
|
||||
// Pull 'not' into operands of select if both operands are one-use compares
|
||||
// or one is one-use compare and the other one is a constant.
|
||||
// Inverting the predicates eliminates the 'not' operation.
|
||||
// Example:
|
||||
// not (select ?, (cmp TPred, ?, ?), (cmp FPred, ?, ?) -->
|
||||
// not (select ?, (cmp TPred, ?, ?), (cmp FPred, ?, ?) -->
|
||||
// select ?, (cmp InvTPred, ?, ?), (cmp InvFPred, ?, ?)
|
||||
// TODO: Canonicalize by hoisting 'not' into an arm of the select if only
|
||||
// 1 select operand is a cmp?
|
||||
// not (select ?, (cmp TPred, ?, ?), true -->
|
||||
// select ?, (cmp InvTPred, ?, ?), false
|
||||
if (auto *Sel = dyn_cast<SelectInst>(Op0)) {
|
||||
auto *CmpT = dyn_cast<CmpInst>(Sel->getTrueValue());
|
||||
auto *CmpF = dyn_cast<CmpInst>(Sel->getFalseValue());
|
||||
if (CmpT && CmpF && CmpT->hasOneUse() && CmpF->hasOneUse()) {
|
||||
CmpT->setPredicate(CmpT->getInversePredicate());
|
||||
CmpF->setPredicate(CmpF->getInversePredicate());
|
||||
Value *TV = Sel->getTrueValue();
|
||||
Value *FV = Sel->getFalseValue();
|
||||
auto *CmpT = dyn_cast<CmpInst>(TV);
|
||||
auto *CmpF = dyn_cast<CmpInst>(FV);
|
||||
bool InvertibleT = (CmpT && CmpT->hasOneUse()) || isa<Constant>(TV);
|
||||
bool InvertibleF = (CmpF && CmpF->hasOneUse()) || isa<Constant>(FV);
|
||||
if (InvertibleT && InvertibleF) {
|
||||
Constant *One = cast<Constant>(Op1);
|
||||
|
||||
if (CmpT)
|
||||
CmpT->setPredicate(CmpT->getInversePredicate());
|
||||
else
|
||||
Sel->setTrueValue(ConstantExpr::getNot(cast<Constant>(TV)));
|
||||
if (CmpF)
|
||||
CmpF->setPredicate(CmpF->getInversePredicate());
|
||||
else
|
||||
Sel->setFalseValue(ConstantExpr::getNot(cast<Constant>(FV)));
|
||||
return replaceInstUsesWith(I, Sel);
|
||||
}
|
||||
}
|
||||
|
@ -56,8 +56,7 @@ define i1 @cond_eq_or_const(i8 %X, i8 %Y) {
|
||||
define i1 @merge_and(i1 %X, i1 %Y) {
|
||||
; CHECK-LABEL: @merge_and(
|
||||
; CHECK-NEXT: [[C:%.*]] = select i1 [[X:%.*]], i1 [[Y:%.*]], i1 false
|
||||
; CHECK-NEXT: [[RES:%.*]] = and i1 [[C]], [[X]]
|
||||
; CHECK-NEXT: ret i1 [[RES]]
|
||||
; CHECK-NEXT: ret i1 [[C]]
|
||||
;
|
||||
%c = select i1 %X, i1 %Y, i1 false
|
||||
%res = and i1 %X, %c
|
||||
@ -67,8 +66,7 @@ define i1 @merge_and(i1 %X, i1 %Y) {
|
||||
define i1 @merge_or(i1 %X, i1 %Y) {
|
||||
; CHECK-LABEL: @merge_or(
|
||||
; CHECK-NEXT: [[C:%.*]] = select i1 [[X:%.*]], i1 true, i1 [[Y:%.*]]
|
||||
; CHECK-NEXT: [[RES:%.*]] = or i1 [[C]], [[X]]
|
||||
; CHECK-NEXT: ret i1 [[RES]]
|
||||
; CHECK-NEXT: ret i1 [[C]]
|
||||
;
|
||||
%c = select i1 %X, i1 true, i1 %Y
|
||||
%res = or i1 %X, %c
|
||||
@ -77,10 +75,10 @@ define i1 @merge_or(i1 %X, i1 %Y) {
|
||||
|
||||
define i1 @xor_and(i1 %c, i32 %X, i32 %Y) {
|
||||
; CHECK-LABEL: @xor_and(
|
||||
; CHECK-NEXT: [[COMP:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C:%.*]], i1 [[COMP]], i1 false
|
||||
; CHECK-NEXT: [[RES:%.*]] = xor i1 [[SEL]], true
|
||||
; CHECK-NEXT: ret i1 [[RES]]
|
||||
; CHECK-NEXT: [[COMP:%.*]] = icmp uge i32 [[X:%.*]], [[Y:%.*]]
|
||||
; CHECK-NEXT: [[NOT_C:%.*]] = xor i1 [[C:%.*]], true
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[NOT_C]], i1 true, i1 [[COMP]]
|
||||
; CHECK-NEXT: ret i1 [[SEL]]
|
||||
;
|
||||
%comp = icmp ult i32 %X, %Y
|
||||
%sel = select i1 %c, i1 %comp, i1 false
|
||||
@ -90,10 +88,9 @@ define i1 @xor_and(i1 %c, i32 %X, i32 %Y) {
|
||||
|
||||
define <2 x i1> @xor_and2(<2 x i1> %c, <2 x i32> %X, <2 x i32> %Y) {
|
||||
; CHECK-LABEL: @xor_and2(
|
||||
; CHECK-NEXT: [[COMP:%.*]] = icmp ult <2 x i32> [[X:%.*]], [[Y:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[C:%.*]], <2 x i1> [[COMP]], <2 x i1> <i1 true, i1 false>
|
||||
; CHECK-NEXT: [[RES:%.*]] = xor <2 x i1> [[SEL]], <i1 true, i1 true>
|
||||
; CHECK-NEXT: ret <2 x i1> [[RES]]
|
||||
; CHECK-NEXT: [[COMP:%.*]] = icmp uge <2 x i32> [[X:%.*]], [[Y:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[C:%.*]], <2 x i1> [[COMP]], <2 x i1> <i1 false, i1 true>
|
||||
; CHECK-NEXT: ret <2 x i1> [[SEL]]
|
||||
;
|
||||
%comp = icmp ult <2 x i32> %X, %Y
|
||||
%sel = select <2 x i1> %c, <2 x i1> %comp, <2 x i1> <i1 true, i1 false>
|
||||
@ -105,10 +102,9 @@ define <2 x i1> @xor_and2(<2 x i1> %c, <2 x i32> %X, <2 x i32> %Y) {
|
||||
|
||||
define <2 x i1> @xor_and3(<2 x i1> %c, <2 x i32> %X, <2 x i32> %Y) {
|
||||
; CHECK-LABEL: @xor_and3(
|
||||
; CHECK-NEXT: [[COMP:%.*]] = icmp ult <2 x i32> [[X:%.*]], [[Y:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[C:%.*]], <2 x i1> [[COMP]], <2 x i1> <i1 icmp eq (i8* inttoptr (i64 1234 to i8*), i8* @glb), i1 false>
|
||||
; CHECK-NEXT: [[RES:%.*]] = xor <2 x i1> [[SEL]], <i1 true, i1 true>
|
||||
; CHECK-NEXT: ret <2 x i1> [[RES]]
|
||||
; CHECK-NEXT: [[COMP:%.*]] = icmp uge <2 x i32> [[X:%.*]], [[Y:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[C:%.*]], <2 x i1> [[COMP]], <2 x i1> <i1 icmp ne (i8* inttoptr (i64 1234 to i8*), i8* @glb), i1 true>
|
||||
; CHECK-NEXT: ret <2 x i1> [[SEL]]
|
||||
;
|
||||
%comp = icmp ult <2 x i32> %X, %Y
|
||||
%sel = select <2 x i1> %c, <2 x i1> %comp, <2 x i1> <i1 icmp eq (i8* @glb, i8* inttoptr (i64 1234 to i8*)), i1 false>
|
||||
@ -118,10 +114,10 @@ define <2 x i1> @xor_and3(<2 x i1> %c, <2 x i32> %X, <2 x i32> %Y) {
|
||||
|
||||
define i1 @xor_or(i1 %c, i32 %X, i32 %Y) {
|
||||
; CHECK-LABEL: @xor_or(
|
||||
; CHECK-NEXT: [[COMP:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C:%.*]], i1 true, i1 [[COMP]]
|
||||
; CHECK-NEXT: [[RES:%.*]] = xor i1 [[SEL]], true
|
||||
; CHECK-NEXT: ret i1 [[RES]]
|
||||
; CHECK-NEXT: [[COMP:%.*]] = icmp uge i32 [[X:%.*]], [[Y:%.*]]
|
||||
; CHECK-NEXT: [[NOT_C:%.*]] = xor i1 [[C:%.*]], true
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[NOT_C]], i1 [[COMP]], i1 false
|
||||
; CHECK-NEXT: ret i1 [[SEL]]
|
||||
;
|
||||
%comp = icmp ult i32 %X, %Y
|
||||
%sel = select i1 %c, i1 true, i1 %comp
|
||||
@ -131,10 +127,9 @@ define i1 @xor_or(i1 %c, i32 %X, i32 %Y) {
|
||||
|
||||
define <2 x i1> @xor_or2(<2 x i1> %c, <2 x i32> %X, <2 x i32> %Y) {
|
||||
; CHECK-LABEL: @xor_or2(
|
||||
; CHECK-NEXT: [[COMP:%.*]] = icmp ult <2 x i32> [[X:%.*]], [[Y:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[C:%.*]], <2 x i1> <i1 true, i1 false>, <2 x i1> [[COMP]]
|
||||
; CHECK-NEXT: [[RES:%.*]] = xor <2 x i1> [[SEL]], <i1 true, i1 true>
|
||||
; CHECK-NEXT: ret <2 x i1> [[RES]]
|
||||
; CHECK-NEXT: [[COMP:%.*]] = icmp uge <2 x i32> [[X:%.*]], [[Y:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[C:%.*]], <2 x i1> <i1 false, i1 true>, <2 x i1> [[COMP]]
|
||||
; CHECK-NEXT: ret <2 x i1> [[SEL]]
|
||||
;
|
||||
%comp = icmp ult <2 x i32> %X, %Y
|
||||
%sel = select <2 x i1> %c, <2 x i1> <i1 true, i1 false>, <2 x i1> %comp
|
||||
@ -144,10 +139,9 @@ define <2 x i1> @xor_or2(<2 x i1> %c, <2 x i32> %X, <2 x i32> %Y) {
|
||||
|
||||
define <2 x i1> @xor_or3(<2 x i1> %c, <2 x i32> %X, <2 x i32> %Y) {
|
||||
; CHECK-LABEL: @xor_or3(
|
||||
; CHECK-NEXT: [[COMP:%.*]] = icmp ult <2 x i32> [[X:%.*]], [[Y:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[C:%.*]], <2 x i1> <i1 icmp eq (i8* inttoptr (i64 1234 to i8*), i8* @glb), i1 false>, <2 x i1> [[COMP]]
|
||||
; CHECK-NEXT: [[RES:%.*]] = xor <2 x i1> [[SEL]], <i1 true, i1 true>
|
||||
; CHECK-NEXT: ret <2 x i1> [[RES]]
|
||||
; CHECK-NEXT: [[COMP:%.*]] = icmp uge <2 x i32> [[X:%.*]], [[Y:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[C:%.*]], <2 x i1> <i1 icmp ne (i8* inttoptr (i64 1234 to i8*), i8* @glb), i1 true>, <2 x i1> [[COMP]]
|
||||
; CHECK-NEXT: ret <2 x i1> [[SEL]]
|
||||
;
|
||||
%comp = icmp ult <2 x i32> %X, %Y
|
||||
%sel = select <2 x i1> %c, <2 x i1> <i1 icmp eq (i8* @glb, i8* inttoptr (i64 1234 to i8*)), i1 false>, <2 x i1> %comp
|
||||
|
Loading…
Reference in New Issue
Block a user