Skip to content

Commit 2b1d040

Browse files
committed
[InstCombine] Factor in op0's usages to decide leniency for one-use in foldComplexAndOrPatterns
If we can eliminate Op0 by replacing, which will happen if Op0 is one use, then we need not check if the other is one-use.
1 parent 96336b2 commit 2b1d040

File tree

1 file changed

+56
-33
lines changed

1 file changed

+56
-33
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 56 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2036,12 +2036,10 @@ static Instruction *foldComplexAndOrPatterns(BinaryOperator &I,
20362036

20372037
// (~(A | B) & C) | ... --> ...
20382038
// (~(A & B) | C) & ... --> ...
2039-
// TODO: One use checks are conservative. We just need to check that a total
2040-
// number of multiple used values does not exceed reduction
2041-
// in operations.
20422039
if (matchNotOrAnd(Op0, m_Value(A), m_Value(B), m_Value(C), X)) {
20432040
// (~(A | B) & C) | (~(A | C) & B) --> (B ^ C) & ~A
20442041
// (~(A & B) | C) & (~(A & C) | B) --> ~((B ^ C) & A)
2042+
20452043
if (matchNotOrAnd(Op1, m_Specific(A), m_Specific(C), m_Specific(B), Dummy,
20462044
true)) {
20472045
Value *Xor = Builder.CreateXor(B, C);
@@ -2060,25 +2058,37 @@ static Instruction *foldComplexAndOrPatterns(BinaryOperator &I,
20602058
: BinaryOperator::CreateNot(Builder.CreateAnd(Xor, B));
20612059
}
20622060

2061+
bool Op0OneUse = Op0->hasOneUse();
2062+
20632063
// (~(A | B) & C) | ~(A | C) --> ~((B & C) | A)
20642064
// (~(A & B) | C) & ~(A & C) --> ~((B | C) & A)
2065-
if (match(Op1, m_OneUse(m_Not(m_OneUse(
2066-
m_c_BinOp(Opcode, m_Specific(A), m_Specific(C)))))))
2065+
if (!Op0OneUse && match(Op1, m_OneUse(m_Not(m_OneUse(m_c_BinOp(
2066+
Opcode, m_Specific(A), m_Specific(C)))))))
2067+
return BinaryOperator::CreateNot(Builder.CreateBinOp(
2068+
Opcode, Builder.CreateBinOp(FlippedOpcode, B, C), A));
2069+
2070+
if (Op0OneUse &&
2071+
match(Op1, m_Not(m_c_BinOp(Opcode, m_Specific(A), m_Specific(C)))))
20672072
return BinaryOperator::CreateNot(Builder.CreateBinOp(
20682073
Opcode, Builder.CreateBinOp(FlippedOpcode, B, C), A));
20692074

20702075
// (~(A | B) & C) | ~(B | C) --> ~((A & C) | B)
20712076
// (~(A & B) | C) & ~(B & C) --> ~((A | C) & B)
2072-
if (match(Op1, m_OneUse(m_Not(m_OneUse(
2073-
m_c_BinOp(Opcode, m_Specific(B), m_Specific(C)))))))
2077+
if (!Op0OneUse && match(Op1, m_OneUse(m_Not(m_OneUse(m_c_BinOp(
2078+
Opcode, m_Specific(B), m_Specific(C)))))))
2079+
return BinaryOperator::CreateNot(Builder.CreateBinOp(
2080+
Opcode, Builder.CreateBinOp(FlippedOpcode, A, C), B));
2081+
2082+
if (Op0OneUse &&
2083+
match(Op1, m_Not(m_c_BinOp(Opcode, m_Specific(B), m_Specific(C)))))
20742084
return BinaryOperator::CreateNot(Builder.CreateBinOp(
20752085
Opcode, Builder.CreateBinOp(FlippedOpcode, A, C), B));
20762086

20772087
// (~(A | B) & C) | ~(C | (A ^ B)) --> ~((A | B) & (C | (A ^ B)))
20782088
// Note, the pattern with swapped and/or is not handled because the
20792089
// result is more undefined than a source:
20802090
// (~(A & B) | C) & ~(C & (A ^ B)) --> (A ^ B ^ C) | ~(A | C) is invalid.
2081-
if (Opcode == Instruction::Or && Op0->hasOneUse() &&
2091+
if (Opcode == Instruction::Or && Op0OneUse &&
20822092
match(Op1, m_OneUse(m_Not(m_CombineAnd(
20832093
m_Value(Y),
20842094
m_c_BinOp(Opcode, m_Specific(C),
@@ -2092,30 +2102,29 @@ static Instruction *foldComplexAndOrPatterns(BinaryOperator &I,
20922102

20932103
// (~A & B & C) | ... --> ...
20942104
// (~A | B | C) | ... --> ...
2095-
// TODO: One use checks are conservative. We just need to check that a total
2096-
// number of multiple used values does not exceed reduction
2097-
// in operations.
2098-
if (match(Op0,
2099-
m_OneUse(m_c_BinOp(FlippedOpcode,
2100-
m_BinOp(FlippedOpcode, m_Value(B), m_Value(C)),
2101-
m_CombineAnd(m_Value(X), m_Not(m_Value(A)))))) ||
2102-
match(Op0, m_OneUse(m_c_BinOp(
2103-
FlippedOpcode,
2104-
m_c_BinOp(FlippedOpcode, m_Value(C),
2105-
m_CombineAnd(m_Value(X), m_Not(m_Value(A)))),
2106-
m_Value(B))))) {
2105+
if (match(Op0, m_c_BinOp(FlippedOpcode,
2106+
m_BinOp(FlippedOpcode, m_Value(B), m_Value(C)),
2107+
m_CombineAnd(m_Value(X), m_Not(m_Value(A))))) ||
2108+
match(Op0,
2109+
m_c_BinOp(FlippedOpcode,
2110+
m_c_BinOp(FlippedOpcode, m_Value(C),
2111+
m_CombineAnd(m_Value(X), m_Not(m_Value(A)))),
2112+
m_Value(B)))) {
2113+
bool Op0OneUse = Op0->hasOneUse();
2114+
21072115
// X = ~A
21082116
// (~A & B & C) | ~(A | B | C) --> ~(A | (B ^ C))
21092117
// (~A | B | C) & ~(A & B & C) --> (~A | (B ^ C))
2110-
if (match(Op1, m_OneUse(m_Not(m_c_BinOp(
2111-
Opcode, m_c_BinOp(Opcode, m_Specific(A), m_Specific(B)),
2112-
m_Specific(C))))) ||
2113-
match(Op1, m_OneUse(m_Not(m_c_BinOp(
2114-
Opcode, m_c_BinOp(Opcode, m_Specific(B), m_Specific(C)),
2115-
m_Specific(A))))) ||
2116-
match(Op1, m_OneUse(m_Not(m_c_BinOp(
2117-
Opcode, m_c_BinOp(Opcode, m_Specific(A), m_Specific(C)),
2118-
m_Specific(B)))))) {
2118+
if ((match(Op1, m_Not(m_c_BinOp(
2119+
Opcode, m_c_BinOp(Opcode, m_Specific(A), m_Specific(B)),
2120+
m_Specific(C)))) ||
2121+
match(Op1, m_Not(m_c_BinOp(
2122+
Opcode, m_c_BinOp(Opcode, m_Specific(B), m_Specific(C)),
2123+
m_Specific(A)))) ||
2124+
match(Op1, m_Not(m_c_BinOp(
2125+
Opcode, m_c_BinOp(Opcode, m_Specific(A), m_Specific(C)),
2126+
m_Specific(B))))) &&
2127+
(Op0OneUse || Op1->hasOneUse())) {
21192128
Value *Xor = Builder.CreateXor(B, C);
21202129
return (Opcode == Instruction::Or)
21212130
? BinaryOperator::CreateNot(Builder.CreateOr(Xor, A))
@@ -2124,16 +2133,30 @@ static Instruction *foldComplexAndOrPatterns(BinaryOperator &I,
21242133

21252134
// (~A & B & C) | ~(A | B) --> (C | ~B) & ~A
21262135
// (~A | B | C) & ~(A & B) --> (C & ~B) | ~A
2127-
if (match(Op1, m_OneUse(m_Not(m_OneUse(
2128-
m_c_BinOp(Opcode, m_Specific(A), m_Specific(B)))))))
2136+
if (!Op0OneUse && match(Op1, m_OneUse(m_Not(m_OneUse(m_c_BinOp(
2137+
Opcode, m_Specific(A), m_Specific(B)))))))
21292138
return BinaryOperator::Create(
21302139
FlippedOpcode, Builder.CreateBinOp(Opcode, C, Builder.CreateNot(B)),
21312140
X);
21322141

2142+
if (Op0OneUse &&
2143+
match(Op1, m_Not(m_c_BinOp(Opcode, m_Specific(A), m_Specific(B)))))
2144+
return BinaryOperator::Create(
2145+
FlippedOpcode, Builder.CreateBinOp(Opcode, C, Builder.CreateNot(B)),
2146+
X);
2147+
2148+
// (~A & B & C) | ~(A | C) --> (B | ~C) & ~A
2149+
// (~A | B | C) & ~(A & C) --> (B & ~C) | ~A
2150+
if (!Op0OneUse && match(Op1, m_OneUse(m_Not(m_OneUse(m_c_BinOp(
2151+
Opcode, m_Specific(A), m_Specific(C)))))))
2152+
return BinaryOperator::Create(
2153+
FlippedOpcode, Builder.CreateBinOp(Opcode, B, Builder.CreateNot(C)),
2154+
X);
2155+
21332156
// (~A & B & C) | ~(A | C) --> (B | ~C) & ~A
21342157
// (~A | B | C) & ~(A & C) --> (B & ~C) | ~A
2135-
if (match(Op1, m_OneUse(m_Not(m_OneUse(
2136-
m_c_BinOp(Opcode, m_Specific(A), m_Specific(C)))))))
2158+
if (Op0OneUse &&
2159+
match(Op1, m_Not(m_c_BinOp(Opcode, m_Specific(A), m_Specific(C)))))
21372160
return BinaryOperator::Create(
21382161
FlippedOpcode, Builder.CreateBinOp(Opcode, B, Builder.CreateNot(C)),
21392162
X);

0 commit comments

Comments
 (0)