Index: llvm/include/llvm/Analysis/ComplexLogicCombine.h =================================================================== --- llvm/include/llvm/Analysis/ComplexLogicCombine.h +++ llvm/include/llvm/Analysis/ComplexLogicCombine.h @@ -74,7 +74,7 @@ LogicalOpNode *visitSelect(SelectInst *SI, unsigned Depth); LogicalOpNode *getLogicalOpNode(Value *Val, unsigned Depth = 0); Value *logicalOpToValue(LogicalOpNode *Node); - Value *buildAndChain(Instruction *I, uint64_t Mask); + Value *buildAndChain(IRBuilder<>& Builder, Type* Ty, uint64_t Mask); }; inline raw_ostream &operator<<(raw_ostream &OS, const LogicalOpNode &I) { Index: llvm/lib/Analysis/ComplexLogicCombine.cpp =================================================================== --- llvm/lib/Analysis/ComplexLogicCombine.cpp +++ llvm/lib/Analysis/ComplexLogicCombine.cpp @@ -251,34 +251,61 @@ if (Node->getPoisonMaskSI() != 0) return nullptr; + Instruction *I = cast(Node->getValue()); + Type *Ty = I->getType(); + IRBuilder<> Builder(I); if (Expr.size() == 1) { uint64_t ExprMask = *Expr.begin(); - // ExprZero/ExprAllOne is not in the LeafValues - if (ExprMask == LogicalExpr::ExprZero) - return Constant::getNullValue(Node->getValue()->getType()); - if (ExprMask == LogicalExpr::ExprAllOne) - return Constant::getAllOnesValue(Node->getValue()->getType()); - - unsigned ElementCnt = llvm::popcount(ExprMask); - if (ElementCnt == 1) - return LeafValues[llvm::Log2_64(ExprMask)]; - - unsigned InstCnt = ElementCnt - 1; + unsigned InstCnt = llvm::popcount(ExprMask) - 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)) - return buildAndChain(cast(Node->getValue()), ExprMask); + return buildAndChain(Builder, Ty, ExprMask); return nullptr; } + 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; } -Value *LogicalOpsHelper::buildAndChain(Instruction *I, uint64_t Mask) { - IRBuilder<> Builder(I); +Value *LogicalOpsHelper::buildAndChain(IRBuilder<> &Builder, Type *Ty, + uint64_t Mask) { + + // ExprZero/ExprAllOne is not in the LeafValues + if (Mask == LogicalExpr::ExprZero) + return Constant::getNullValue(Ty); + if (Mask == LogicalExpr::ExprAllOne) + return Constant::getAllOnesValue(Ty); + unsigned ElementCnt = llvm::popcount(Mask); + if (ElementCnt == 1) + return LeafValues[llvm::Log2_64(Mask)]; + unsigned MaskIdx = llvm::countr_zero(Mask); Value *AndChain = LeafValues[MaskIdx]; Mask -= (1ULL << MaskIdx); Index: llvm/test/Transforms/AggressiveInstCombine/complex-logic.ll =================================================================== --- llvm/test/Transforms/AggressiveInstCombine/complex-logic.ll +++ llvm/test/Transforms/AggressiveInstCombine/complex-logic.ll @@ -183,4 +183,61 @@ ret i1 %cond } +define i1 @test12(i1 %a, i1 %b, i1 %c, i1 %d) { +; CHECK-LABEL: @test12( +; 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 @test13(i1 %a, i1 %b, i1 %c, i1 %d) { +; CHECK-LABEL: @test13( +; 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 @test14(i1 %a, i1 %b, i1 %c, i1 %d) { +; CHECK-LABEL: @test14( +; 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)