Index: lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineSelect.cpp +++ lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -61,23 +61,37 @@ /// To /// %C = select i1 %A, i8 %z, i8 %y /// OP: binop with an identity constant -/// TODO: support for non-commutative and FP opcodes +// TODO: support for undefs static Instruction *foldSelectBinOpIdentity(SelectInst &Sel) { - Value *Cond = Sel.getCondition(); Value *X, *Z; Constant *C; CmpInst::Predicate Pred; - if (!match(Cond, m_ICmp(Pred, m_Value(X), m_Constant(C))) || - !ICmpInst::isEquality(Pred)) + if (!match(Cond, m_Cmp(Pred, m_Value(X), m_Constant(C)))) + return nullptr; + + bool IsEq; + if (ICmpInst::isEquality(Pred)) { + IsEq = Pred == ICmpInst::ICMP_EQ; + } else if (FCmpInst::isEquality(Pred)) { + IsEq = Pred == FCmpInst::FCMP_OEQ || Pred == FCmpInst::FCMP_UEQ; + } else { return nullptr; + } - bool IsEq = Pred == ICmpInst::ICMP_EQ; auto *BO = dyn_cast(IsEq ? Sel.getTrueValue() : Sel.getFalseValue()); - // TODO: support for undefs - if (BO && match(BO, m_c_BinOp(m_Specific(X), m_Value(Z))) && - ConstantExpr::getBinOpIdentity(BO->getOpcode(), X->getType()) == C) { + if (!BO) + return nullptr; + + if (match(BO, m_c_BinOp(m_Specific(X), m_Value(Z))) && + ConstantExpr::getBinOpIdentity(BO->getOpcode(), X->getType()) == + C) { + Sel.setOperand(IsEq ? 1 : 2, Z); + return &Sel; + } else if (match(BO, m_BinOp(m_Specific(X), m_Value(Z))) && + ConstantExpr::getBinOpIdentity(BO->getOpcode(), X->getType(), + true) == C) { Sel.setOperand(IsEq ? 1 : 2, Z); return &Sel; } Index: test/Transforms/InstCombine/select-binop-icmp.ll =================================================================== --- test/Transforms/InstCombine/select-binop-icmp.ll +++ test/Transforms/InstCombine/select-binop-icmp.ll @@ -137,12 +137,10 @@ ret i32 %C } -; TODO: Support for FP opcodes define float @select_fadd_icmp(float %x, float %y, float %z) { ; CHECK-LABEL: @select_fadd_icmp( ; CHECK-NEXT: [[A:%.*]] = fcmp oeq float [[X:%.*]], -0.000000e+00 -; CHECK-NEXT: [[B:%.*]] = fadd float [[X]], [[Z:%.*]] -; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], float [[B]], float [[Y:%.*]] +; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], float [[Z:%.*]], float [[Y:%.*]] ; CHECK-NEXT: ret float [[C]] ; %A = fcmp oeq float %x, -0.0 @@ -154,8 +152,7 @@ define float @select_fadd_icmp2(float %x, float %y, float %z) { ; CHECK-LABEL: @select_fadd_icmp2( ; CHECK-NEXT: [[A:%.*]] = fcmp ueq float [[X:%.*]], -0.000000e+00 -; CHECK-NEXT: [[B:%.*]] = fadd float [[X]], [[Z:%.*]] -; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], float [[B]], float [[Y:%.*]] +; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], float [[Z:%.*]], float [[Y:%.*]] ; CHECK-NEXT: ret float [[C]] ; %A = fcmp ueq float %x, -0.0 @@ -167,8 +164,7 @@ define float @select_fmul_icmp(float %x, float %y, float %z) { ; CHECK-LABEL: @select_fmul_icmp( ; CHECK-NEXT: [[A:%.*]] = fcmp oeq float [[X:%.*]], 1.000000e+00 -; CHECK-NEXT: [[B:%.*]] = fmul float [[X]], [[Z:%.*]] -; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], float [[B]], float [[Y:%.*]] +; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], float [[Z:%.*]], float [[Y:%.*]] ; CHECK-NEXT: ret float [[C]] ; %A = fcmp oeq float %x, 1.0 @@ -177,12 +173,10 @@ ret float %C } -; TODO: Support for non-commutative opcodes define i32 @select_sub_icmp(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: @select_sub_icmp( ; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 0 -; CHECK-NEXT: [[B:%.*]] = sub i32 [[X]], [[Z:%.*]] -; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[B]], i32 [[Y:%.*]] +; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[Z:%.*]], i32 [[Y:%.*]] ; CHECK-NEXT: ret i32 [[C]] ; %A = icmp eq i32 %x, 0 @@ -194,8 +188,7 @@ define i32 @select_shl_icmp(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: @select_shl_icmp( ; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 0 -; CHECK-NEXT: [[B:%.*]] = shl i32 [[X]], [[Z:%.*]] -; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[B]], i32 [[Y:%.*]] +; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[Z:%.*]], i32 [[Y:%.*]] ; CHECK-NEXT: ret i32 [[C]] ; %A = icmp eq i32 %x, 0 @@ -207,8 +200,7 @@ define i32 @select_lshr_icmp(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: @select_lshr_icmp( ; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 0 -; CHECK-NEXT: [[B:%.*]] = lshr i32 [[X]], [[Z:%.*]] -; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[B]], i32 [[Y:%.*]] +; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[Z:%.*]], i32 [[Y:%.*]] ; CHECK-NEXT: ret i32 [[C]] ; %A = icmp eq i32 %x, 0 @@ -220,8 +212,7 @@ define i32 @select_ashr_icmp(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: @select_ashr_icmp( ; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 0 -; CHECK-NEXT: [[B:%.*]] = ashr i32 [[X]], [[Z:%.*]] -; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[B]], i32 [[Y:%.*]] +; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[Z:%.*]], i32 [[Y:%.*]] ; CHECK-NEXT: ret i32 [[C]] ; %A = icmp eq i32 %x, 0