Index: lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineSelect.cpp +++ lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -54,6 +54,31 @@ return Builder.CreateSelect(Builder.CreateICmp(Pred, A, B), A, B); } +/// Fold +/// %A = icmp eq i8 %x, 0 +/// %B = op i8 %x, %z +/// %C = select i1 %A, i8 %B, i8 %y +/// To +/// %C = select i1 %A, i8 %z, i8 %y +/// OP: binop with an identity constant +/// TODO: support for non-commutative and FP opcodes +static Value *foldSelectInstWithBinaryOp(SelectInst &Sel, + InstCombiner::BuilderTy &Builder) { + Value *Cond = Sel.getCondition(); + Value *TrueVal = Sel.getTrueValue(); + Value *FalseVal = Sel.getFalseValue(); + + Value *X, *Z, *C; + CmpInst::Predicate Pred; + if (match(Cond, m_ICmp(Pred, m_Value(X), m_Value(C))) && + Pred == ICmpInst::ICMP_EQ) + if (match(TrueVal, m_c_BinOp(m_Specific(X), m_Value(Z))) && + ConstantExpr::getBinOpIdentity(cast(TrueVal)->getOpcode(), + X->getType()) == C) + return Builder.CreateSelect(Cond, Z, FalseVal); + return nullptr; +} + /// This folds: /// select (icmp eq (and X, C1)), TC, FC /// iff C1 is a power 2 and the difference between TC and FC is a power-of-2. @@ -1961,5 +1986,8 @@ if (Instruction *Select = foldSelectCmpXchg(SI)) return Select; + if (Value *V = foldSelectInstWithBinaryOp(SI, Builder)) + return replaceInstUsesWith(SI, V); + return nullptr; -} +} Index: test/Transforms/InstCombine/select-binop-icmp.ll =================================================================== --- test/Transforms/InstCombine/select-binop-icmp.ll +++ test/Transforms/InstCombine/select-binop-icmp.ll @@ -4,9 +4,8 @@ define i32 @select_xor_icmp(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: @select_xor_icmp( ; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 0 -; CHECK-NEXT: [[B:%.*]] = xor i32 [[X]], [[Z:%.*]] -; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[B]], i32 [[Y:%.*]] -; CHECK-NEXT: ret i32 [[C]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[A]], i32 [[Z:%.*]], i32 [[Y:%.*]] +; CHECK-NEXT: ret i32 [[TMP1]] ; %A = icmp eq i32 %x, 0 %B = xor i32 %x, %z @@ -17,9 +16,8 @@ define i32 @select_mul_icmp(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: @select_mul_icmp( ; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 1 -; CHECK-NEXT: [[B:%.*]] = mul i32 [[X]], [[Z:%.*]] -; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[B]], i32 [[Y:%.*]] -; CHECK-NEXT: ret i32 [[C]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[A]], i32 [[Z:%.*]], i32 [[Y:%.*]] +; CHECK-NEXT: ret i32 [[TMP1]] ; %A = icmp eq i32 %x, 1 %B = mul i32 %x, %z @@ -30,9 +28,8 @@ define i32 @select_add_icmp(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: @select_add_icmp( ; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 0 -; CHECK-NEXT: [[B:%.*]] = add i32 [[X]], [[Z:%.*]] -; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[B]], i32 [[Y:%.*]] -; CHECK-NEXT: ret i32 [[C]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[A]], i32 [[Z:%.*]], i32 [[Y:%.*]] +; CHECK-NEXT: ret i32 [[TMP1]] ; %A = icmp eq i32 %x, 0 %B = add i32 %x, %z @@ -43,9 +40,8 @@ define i32 @select_or_icmp(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: @select_or_icmp( ; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 0 -; CHECK-NEXT: [[B:%.*]] = or i32 [[X]], [[Z:%.*]] -; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[B]], i32 [[Y:%.*]] -; CHECK-NEXT: ret i32 [[C]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[A]], i32 [[Z:%.*]], i32 [[Y:%.*]] +; CHECK-NEXT: ret i32 [[TMP1]] ; %A = icmp eq i32 %x, 0 %B = or i32 %x, %z @@ -56,9 +52,8 @@ define i32 @select_and_icmp(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: @select_and_icmp( ; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], -1 -; CHECK-NEXT: [[B:%.*]] = and i32 [[X]], [[Z:%.*]] -; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[B]], i32 [[Y:%.*]] -; CHECK-NEXT: ret i32 [[C]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[A]], i32 [[Z:%.*]], i32 [[Y:%.*]] +; CHECK-NEXT: ret i32 [[TMP1]] ; %A = icmp eq i32 %x, -1 %B = and i32 %x, %z @@ -69,9 +64,8 @@ define <2 x i8> @select_xor_icmp_vec(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) { ; CHECK-LABEL: @select_xor_icmp_vec( ; CHECK-NEXT: [[A:%.*]] = icmp eq <2 x i8> [[X:%.*]], zeroinitializer -; CHECK-NEXT: [[B:%.*]] = xor <2 x i8> [[X]], [[Z:%.*]] -; CHECK-NEXT: [[C:%.*]] = select <2 x i1> [[A]], <2 x i8> [[B]], <2 x i8> [[Y:%.*]] -; CHECK-NEXT: ret <2 x i8> [[C]] +; CHECK-NEXT: [[TMP1:%.*]] = select <2 x i1> [[A]], <2 x i8> [[Z:%.*]], <2 x i8> [[Y:%.*]] +; CHECK-NEXT: ret <2 x i8> [[TMP1]] ; %A = icmp eq <2 x i8> %x, %B = xor <2 x i8> %x, %z @@ -79,25 +73,11 @@ ret <2 x i8> %C } -define <2 x i8> @select_xor_icmp_vec2(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) { -; CHECK-LABEL: @select_xor_icmp_vec2( -; CHECK-NEXT: [[A:%.*]] = icmp eq <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[B:%.*]] = xor <2 x i8> [[X]], [[Z:%.*]] -; CHECK-NEXT: [[C:%.*]] = select <2 x i1> [[A]], <2 x i8> [[B]], <2 x i8> [[Y:%.*]] -; CHECK-NEXT: ret <2 x i8> [[C]] -; - %A = icmp eq <2 x i8> %x, - %B = xor <2 x i8> %x, %z - %C = select <2 x i1> %A, <2 x i8> %B, <2 x i8> %y - ret <2 x i8> %C -} - define i32 @select_xor_inv_icmp(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: @select_xor_inv_icmp( ; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 0 -; CHECK-NEXT: [[B:%.*]] = xor i32 [[Z:%.*]], [[X]] -; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[B]], i32 [[Y:%.*]] -; CHECK-NEXT: ret i32 [[C]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[A]], i32 [[Z:%.*]], i32 [[Y:%.*]] +; CHECK-NEXT: ret i32 [[TMP1]] ; %A = icmp eq i32 %x, 0 %B = xor i32 %z, %x @@ -184,6 +164,19 @@ ret <2 x i8> %C } +define <2 x i8> @select_xor_icmp_vec_bad_2(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) { +; CHECK-LABEL: @select_xor_icmp_vec_bad_2( +; CHECK-NEXT: [[A:%.*]] = icmp eq <2 x i8> [[X:%.*]], +; CHECK-NEXT: [[B:%.*]] = xor <2 x i8> [[X]], [[Z:%.*]] +; CHECK-NEXT: [[C:%.*]] = select <2 x i1> [[A]], <2 x i8> [[B]], <2 x i8> [[Y:%.*]] +; CHECK-NEXT: ret <2 x i8> [[C]] +; + %A = icmp eq <2 x i8> %x, + %B = xor <2 x i8> %x, %z + %C = select <2 x i1> %A, <2 x i8> %B, <2 x i8> %y + ret <2 x i8> %C +} + define i32 @select_mul_icmp_bad(i32 %x, i32 %y, i32 %z, i32 %k) { ; CHECK-LABEL: @select_mul_icmp_bad( ; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 3