From 6639e547bcd8412a4c2999da240fcceb5be18c1d Mon Sep 17 00:00:00 2001 From: Rohan Date: Tue, 19 Aug 2025 10:00:45 +0530 Subject: [PATCH] InstCombine: fold(select C, (X | A), X) | B into X | select C, (A | B), B --- .../InstCombine/InstCombineAndOrXor.cpp | 70 +++++++++++++++++++ .../InstCombine/or-select-factor.ll | 33 +++++++++ 2 files changed, 103 insertions(+) create mode 100644 llvm/test/Transforms/InstCombine/or-select-factor.ll diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 6e46898634070..ac78b0276d594 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2695,6 +2695,40 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) { if (Instruction *FoldedLogic = foldBinOpIntoSelectOrPhi(I)) return FoldedLogic; + // Factor a common operand across select feeding an 'or': + // (select Cond, (X | A), X) | B -> X | select Cond, (A | B), B + // (select Cond, X, (X | A)) | B -> X | select Cond, B, (A | B) + // and commuted variants swapping the operands of the outer 'or'. + auto TryFactorSelectOr = [&](Value *SelOp, Value *OtherOp) -> Instruction * { + auto *SI = dyn_cast(SelOp); + if (!SI) + return nullptr; + + Value *Cond = SI->getCondition(); + Value *T = SI->getTrueValue(); + Value *F = SI->getFalseValue(); + Value *X, *A; + + // Match: select Cond, (X|A), X + if (match(T, m_c_Or(m_Value(X), m_Value(A))) && F == X) { + Value *AorB = Builder.CreateOr(A, OtherOp); + Value *InnerSel = Builder.CreateSelect(Cond, AorB, OtherOp); + return BinaryOperator::CreateOr(X, InnerSel); + } + // Match: select Cond, X, (X|A) + if (match(F, m_c_Or(m_Value(X), m_Value(A))) && T == X) { + Value *AorB = Builder.CreateOr(A, OtherOp); + Value *InnerSel = Builder.CreateSelect(Cond, OtherOp, AorB); + return BinaryOperator::CreateOr(X, InnerSel); + } + return nullptr; + }; + + if (Instruction *R = TryFactorSelectOr(Op0, Op1)) + return R; + if (Instruction *R = TryFactorSelectOr(Op1, Op0)) + return R; + if (Instruction *DeMorgan = matchDeMorgansLaws(I, *this)) return DeMorgan; @@ -4022,6 +4056,42 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) { } } + // Factor a common operand across select feeding an 'or' before pushing the + // constant into the select arms: + // (select Cond, (X | A), X) | B -> X | select Cond, (A | B), B + // (select Cond, X, (X | A)) | B -> X | select Cond, B, (A | B) + // and commuted variants swapping the operands of the outer 'or'. + auto TryFactorSelectOrEarly = [&](Value *SelOp, + Value *OtherOp) -> Instruction * { + auto *SI = dyn_cast(SelOp); + if (!SI) + return nullptr; + + Value *Cond = SI->getCondition(); + Value *T = SI->getTrueValue(); + Value *F = SI->getFalseValue(); + Value *X, *A; + + // Match: select Cond, (X|A), X + if (match(T, m_c_Or(m_Value(X), m_Value(A))) && F == X) { + Value *AorB = Builder.CreateOr(A, OtherOp); + Value *InnerSel = Builder.CreateSelect(Cond, AorB, OtherOp); + return BinaryOperator::CreateOr(X, InnerSel); + } + // Match: select Cond, X, (X|A) + if (match(F, m_c_Or(m_Value(X), m_Value(A))) && T == X) { + Value *AorB = Builder.CreateOr(A, OtherOp); + Value *InnerSel = Builder.CreateSelect(Cond, OtherOp, AorB); + return BinaryOperator::CreateOr(X, InnerSel); + } + return nullptr; + }; + + if (Instruction *R = TryFactorSelectOrEarly(Op0, Op1)) + return R; + if (Instruction *R = TryFactorSelectOrEarly(Op1, Op0)) + return R; + if (Instruction *FoldedLogic = foldBinOpIntoSelectOrPhi(I)) return FoldedLogic; diff --git a/llvm/test/Transforms/InstCombine/or-select-factor.ll b/llvm/test/Transforms/InstCombine/or-select-factor.ll new file mode 100644 index 0000000000000..75f62b2679ca0 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/or-select-factor.ll @@ -0,0 +1,33 @@ +; RUN: opt -passes=instcombine -S < %s | FileCheck %s + +; Fold: (select C, (x | a), x) | b -> x | select C, (a | b), b + +define i8 @src(i8 %x, i8 %y) { +; CHECK-LABEL: @src( +; CHECK-NEXT: [[V0:%.*]] = icmp eq i8 [[Y:%.*]], -1 +; CHECK-NEXT: [[V1:%.*]] = or i8 [[X:%.*]], 4 +; CHECK-NEXT: [[V2:%.*]] = select i1 [[V0]], i8 [[V1]], i8 [[X]] +; CHECK-NEXT: [[V3:%.*]] = or i8 [[V2]], 1 +; CHECK-NEXT: ret i8 [[V3]] +; + %v0 = icmp eq i8 %y, -1 + %v1 = or i8 %x, 4 + %v2 = select i1 %v0, i8 %v1, i8 %x + %v3 = or i8 %v2, 1 + ret i8 %v3 +} + +define i8 @tgt(i8 %x, i8 %y) { +; CHECK-LABEL: @tgt( +; CHECK-NEXT: [[V0:%.*]] = icmp eq i8 [[Y:%.*]], -1 +; CHECK-NEXT: [[V1:%.*]] = select i1 [[V0]], i8 5, i8 1 +; CHECK-NEXT: [[V2:%.*]] = or i8 [[X:%.*]], [[V1]] +; CHECK-NEXT: ret i8 [[V2]] +; + %v0 = icmp eq i8 %y, -1 + %v1 = select i1 %v0, i8 5, i8 1 + %v2 = or i8 %x, %v1 + ret i8 %v2 +} + +