@@ -2036,12 +2036,10 @@ static Instruction *foldComplexAndOrPatterns(BinaryOperator &I,
2036
2036
2037
2037
// (~(A | B) & C) | ... --> ...
2038
2038
// (~(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.
2042
2039
if (matchNotOrAnd (Op0, m_Value (A), m_Value (B), m_Value (C), X)) {
2043
2040
// (~(A | B) & C) | (~(A | C) & B) --> (B ^ C) & ~A
2044
2041
// (~(A & B) | C) & (~(A & C) | B) --> ~((B ^ C) & A)
2042
+
2045
2043
if (matchNotOrAnd (Op1, m_Specific (A), m_Specific (C), m_Specific (B), Dummy,
2046
2044
true )) {
2047
2045
Value *Xor = Builder.CreateXor (B, C);
@@ -2060,25 +2058,37 @@ static Instruction *foldComplexAndOrPatterns(BinaryOperator &I,
2060
2058
: BinaryOperator::CreateNot (Builder.CreateAnd (Xor, B));
2061
2059
}
2062
2060
2061
+ bool Op0OneUse = Op0->hasOneUse ();
2062
+
2063
2063
// (~(A | B) & C) | ~(A | C) --> ~((B & C) | A)
2064
2064
// (~(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)))))
2067
2072
return BinaryOperator::CreateNot (Builder.CreateBinOp (
2068
2073
Opcode, Builder.CreateBinOp (FlippedOpcode, B, C), A));
2069
2074
2070
2075
// (~(A | B) & C) | ~(B | C) --> ~((A & C) | B)
2071
2076
// (~(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)))))
2074
2084
return BinaryOperator::CreateNot (Builder.CreateBinOp (
2075
2085
Opcode, Builder.CreateBinOp (FlippedOpcode, A, C), B));
2076
2086
2077
2087
// (~(A | B) & C) | ~(C | (A ^ B)) --> ~((A | B) & (C | (A ^ B)))
2078
2088
// Note, the pattern with swapped and/or is not handled because the
2079
2089
// result is more undefined than a source:
2080
2090
// (~(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 &&
2082
2092
match (Op1, m_OneUse (m_Not (m_CombineAnd (
2083
2093
m_Value (Y),
2084
2094
m_c_BinOp (Opcode, m_Specific (C),
@@ -2092,30 +2102,29 @@ static Instruction *foldComplexAndOrPatterns(BinaryOperator &I,
2092
2102
2093
2103
// (~A & B & C) | ... --> ...
2094
2104
// (~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
+
2107
2115
// X = ~A
2108
2116
// (~A & B & C) | ~(A | B | C) --> ~(A | (B ^ C))
2109
2117
// (~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 ())) {
2119
2128
Value *Xor = Builder.CreateXor (B, C);
2120
2129
return (Opcode == Instruction::Or)
2121
2130
? BinaryOperator::CreateNot (Builder.CreateOr (Xor, A))
@@ -2124,16 +2133,30 @@ static Instruction *foldComplexAndOrPatterns(BinaryOperator &I,
2124
2133
2125
2134
// (~A & B & C) | ~(A | B) --> (C | ~B) & ~A
2126
2135
// (~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)))))))
2129
2138
return BinaryOperator::Create (
2130
2139
FlippedOpcode, Builder.CreateBinOp (Opcode, C, Builder.CreateNot (B)),
2131
2140
X);
2132
2141
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
+
2133
2156
// (~A & B & C) | ~(A | C) --> (B | ~C) & ~A
2134
2157
// (~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)))))
2137
2160
return BinaryOperator::Create (
2138
2161
FlippedOpcode, Builder.CreateBinOp (Opcode, B, Builder.CreateNot (C)),
2139
2162
X);
0 commit comments