Index: llvm/lib/Analysis/ComplexLogicCombine.cpp =================================================================== --- llvm/lib/Analysis/ComplexLogicCombine.cpp +++ llvm/lib/Analysis/ComplexLogicCombine.cpp @@ -252,16 +252,40 @@ Instruction *I = cast(Node->getValue()); Type *Ty = I->getType(); + IRBuilder<> Builder(I); if (Expr.size() == 1) { uint64_t LeafBits = *Expr.begin(); unsigned InstCnt = llvm::popcount(LeafBits) - 1; // TODO: For now we assume we can't reuse any node from old instruction. // Later we can search if we can reuse the node is not one use. - if (Node->worthToCombine(InstCnt)) { - IRBuilder<> Builder(I); + if (Node->worthToCombine(InstCnt)) return buildAndChain(Builder, Ty, LeafBits); + } + + if (Expr.size() == 2) { + uint64_t LHS = *Expr.begin(); + uint64_t RHS = *(++Expr.begin()); + uint64_t CommonAnd = LHS & RHS; + if (CommonAnd) { + LHS &= ~CommonAnd; + if (LHS == 0) + LHS = LogicalExpr::ExprAllOne; + RHS &= ~CommonAnd; + if (RHS == 0) + RHS = LogicalExpr::ExprAllOne; + } + unsigned InstCnt = llvm::popcount(CommonAnd) + llvm::popcount(LHS) + + llvm::popcount(RHS) - 1; + if (Node->worthToCombine(InstCnt)) { + Value *LHSV = buildAndChain(Builder, Ty, LHS); + Value *RHSV = buildAndChain(Builder, Ty, RHS); + Value *Ret = Builder.CreateXor(LHSV, RHSV); + if (CommonAnd) + Ret = Builder.CreateAnd(Ret, buildAndChain(Builder, Ty, CommonAnd)); + return Ret; } } + // TODO: complex pattern simpilify return nullptr; Index: llvm/test/Transforms/AggressiveInstCombine/complex-logic.ll =================================================================== --- llvm/test/Transforms/AggressiveInstCombine/complex-logic.ll +++ llvm/test/Transforms/AggressiveInstCombine/complex-logic.ll @@ -106,6 +106,17 @@ ret i1 %and.ab.a } +define i1 @leaf2_ret_xor(i1 %a, i1 %b) { +; CHECK-LABEL: @leaf2_ret_xor( +; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: ret i1 [[TMP1]] +; + %or.ab = or i1 %a, %b + %and.ab = and i1 %a, %b + %xor = xor i1 %or.ab, %and.ab + ret i1 %xor +} + define i1 @leaf3_complex_ret_const_false(i1 %a, i1 %b, i1 %c) { ; CHECK-LABEL: @leaf3_complex_ret_const_false( ; CHECK-NEXT: ret i1 false @@ -361,4 +372,61 @@ ret i1 %cond } +define i1 @leaf4_complex_ret_xor(i1 %a, i1 %b, i1 %c, i1 %d) { +; CHECK-LABEL: @leaf4_complex_ret_xor( +; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[D:%.*]], [[B:%.*]] +; CHECK-NEXT: ret i1 [[TMP1]] +; + %bd = and i1 %b, %d + %xor = xor i1 %bd, %c + %not.bd = xor i1 %xor, true + %xor.ab = xor i1 %a, %b + %or1 = or i1 %xor.ab, %c + %or2 = or i1 %or1, %not.bd + %or3 = or i1 %or2, %a + %and = and i1 %or3, %b + %xor.bd = xor i1 %and, %d + ret i1 %xor.bd +} + +define i1 @leaf4_complex_ret_xor_oneside_and(i1 %a, i1 %b, i1 %c, i1 %d) { +; CHECK-LABEL: @leaf4_complex_ret_xor_oneside_and( +; CHECK-NEXT: [[TMP1:%.*]] = xor i1 true, [[D:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[B:%.*]] +; CHECK-NEXT: ret i1 [[TMP2]] +; + %bd = and i1 %b, %d + %xor = xor i1 %bd, %c + %not.bd = xor i1 %xor, true + %xor.ab = xor i1 %a, %b + %or1 = or i1 %xor.ab, %c + %or2 = or i1 %or1, %not.bd + %or3 = or i1 %or2, %a + %and = and i1 %or3, %b + %and2 = and i1 %d, %b + %xor.bd = xor i1 %and, %and2 + ret i1 %xor.bd +} + +define i1 @leaf4_complex_ret_xor_both_and(i1 %a, i1 %b, i1 %c, i1 %d) { +; CHECK-LABEL: @leaf4_complex_ret_xor_both_and( +; CHECK-NEXT: [[AND2:%.*]] = and i1 [[A:%.*]], [[C:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[D:%.*]], [[B:%.*]] +; CHECK-NEXT: [[XOR_BD:%.*]] = xor i1 [[AND2]], [[TMP1]] +; CHECK-NEXT: ret i1 [[XOR_BD]] +; + %bd = and i1 %b, %d + %xor = xor i1 %bd, %c + %not.bd = xor i1 %xor, true + %xor.ab = xor i1 %a, %b + %or1 = or i1 %xor.ab, %c + %or2 = or i1 %or1, %not.bd + %or3 = or i1 %or2, %a + %and = and i1 %or3, %b + %and2 = and i1 %a, %c + %and3 = and i1 %d, %and + %xor.bd = xor i1 %and2, %and3 + ret i1 %xor.bd +} + declare void @use1(i1)