@@ -1857,7 +1857,6 @@ DIExpression *DIExpression::append(const DIExpression *Expr,
1857
1857
}
1858
1858
Op.appendToVector (NewOps);
1859
1859
}
1860
-
1861
1860
NewOps.append (Ops.begin (), Ops.end ());
1862
1861
auto *result = DIExpression::get (Expr->getContext (), NewOps);
1863
1862
assert (result->isValid () && " concatenated expression is not valid" );
@@ -1998,6 +1997,286 @@ DIExpression::constantFold(const ConstantInt *CI) {
1998
1997
ConstantInt::get (getContext (), NewInt)};
1999
1998
}
2000
1999
2000
+ static bool isConstantVal (uint64_t Op) {
2001
+ return Op == dwarf::DW_OP_constu || Op == dwarf::DW_OP_consts;
2002
+ }
2003
+
2004
+ static bool isNeutralElement (uint64_t Op, uint64_t Val) {
2005
+ switch (Op) {
2006
+ case dwarf::DW_OP_plus:
2007
+ case dwarf::DW_OP_minus:
2008
+ case dwarf::DW_OP_shl:
2009
+ case dwarf::DW_OP_shr:
2010
+ return Val == 0 ;
2011
+ case dwarf::DW_OP_mul:
2012
+ case dwarf::DW_OP_div:
2013
+ return Val == 1 ;
2014
+ default :
2015
+ return false ;
2016
+ }
2017
+ }
2018
+
2019
+ static std::optional<uint64_t >
2020
+ foldOperationIfPossible (uint64_t Op, uint64_t Operand1, uint64_t Operand2) {
2021
+ switch (Op) {
2022
+ case dwarf::DW_OP_plus:
2023
+ return Operand1 + Operand2;
2024
+ case dwarf::DW_OP_minus:
2025
+ return Operand1 - Operand2;
2026
+ case dwarf::DW_OP_shl:
2027
+ return Operand1 << Operand2;
2028
+ case dwarf::DW_OP_shr:
2029
+ return Operand1 >> Operand2;
2030
+ case dwarf::DW_OP_mul:
2031
+ return Operand1 * Operand2;
2032
+ case dwarf::DW_OP_div:
2033
+ return Operand1 / Operand2;
2034
+ default :
2035
+ return std::nullopt;
2036
+ }
2037
+ }
2038
+
2039
+ static bool operationsAreFoldableAndCommutative (uint64_t Op1, uint64_t Op2) {
2040
+ if (Op1 != Op2)
2041
+ return false ;
2042
+ switch (Op1) {
2043
+ case dwarf::DW_OP_plus:
2044
+ case dwarf::DW_OP_mul:
2045
+ return true ;
2046
+ default :
2047
+ return false ;
2048
+ }
2049
+ }
2050
+
2051
+ static void consumeOneOperator (DIExpressionCursor &Cursor, uint64_t &Loc,
2052
+ const DIExpression::ExprOperand &Op) {
2053
+ Cursor.consume (1 );
2054
+ Loc = Loc + Op.getSize ();
2055
+ }
2056
+
2057
+ DIExpression *DIExpression::foldConstantMath () {
2058
+
2059
+ SmallVector<uint64_t , 8 > WorkingOps;
2060
+ WorkingOps.append (Elements.begin (), Elements.end ());
2061
+ uint64_t Loc = 0 ;
2062
+ DIExpressionCursor Cursor (WorkingOps);
2063
+
2064
+ while (Loc < WorkingOps.size ()) {
2065
+
2066
+ auto Op1 = Cursor.peek ();
2067
+ // Expression has no operations, exit.
2068
+ if (!Op1)
2069
+ break ;
2070
+ auto Op1Raw = Op1->getOp ();
2071
+ auto Op1Arg = Op1->getArg (0 );
2072
+
2073
+ // {DW_OP_plus_uconst, 0} -> {}
2074
+ if (Op1Raw == dwarf::DW_OP_plus_uconst && Op1Arg == 0 ) {
2075
+ WorkingOps.erase (WorkingOps.begin () + Loc, WorkingOps.begin () + Loc + 2 );
2076
+ consumeOneOperator (Cursor, Loc, *Op1);
2077
+ continue ;
2078
+ }
2079
+
2080
+ if (!isConstantVal (Op1Raw) && Op1Raw != dwarf::DW_OP_plus_uconst) {
2081
+ // Early exit, all of the following patterns start with a constant value.
2082
+ consumeOneOperator (Cursor, Loc, *Op1);
2083
+ continue ;
2084
+ }
2085
+
2086
+ auto Op2 = Cursor.peekNext ();
2087
+ // All following patterns require at least 2 Operations, exit.
2088
+ if (!Op2)
2089
+ break ;
2090
+ auto Op2Raw = Op2->getOp ();
2091
+
2092
+ // {DW_OP_const[u, s], 0, DW_OP_[plus, minus, shl, shr]} -> {}
2093
+ // {DW_OP_const[u, s], 1, DW_OP_[mul, div]} -> {}
2094
+ if (isConstantVal (Op1Raw) && isNeutralElement (Op2Raw, Op1Arg)) {
2095
+ WorkingOps.erase (WorkingOps.begin () + Loc, WorkingOps.begin () + Loc + 3 );
2096
+ Cursor.assignNewExpr (WorkingOps);
2097
+ Loc = 0 ;
2098
+ continue ;
2099
+ }
2100
+
2101
+ auto Op2Arg = Op2->getArg (0 );
2102
+
2103
+ // {DW_OP_plus_uconst, Const1, DW_OP_plus_uconst, Const2} ->
2104
+ // {DW_OP_plus_uconst, Const1 + Const2}
2105
+ if (Op1Raw == dwarf::DW_OP_plus_uconst &&
2106
+ Op2Raw == dwarf::DW_OP_plus_uconst) {
2107
+ auto Result = Op1Arg + Op2Arg;
2108
+ WorkingOps.erase (WorkingOps.begin () + Loc + 2 ,
2109
+ WorkingOps.begin () + Loc + 4 );
2110
+ WorkingOps[Loc + 1 ] = Result;
2111
+ Cursor.assignNewExpr (WorkingOps);
2112
+ Loc = 0 ;
2113
+ continue ;
2114
+ }
2115
+
2116
+ // {DW_OP_const[u, s], Const1, DW_OP_plus_uconst Const2} -> {DW_OP_constu,
2117
+ // Const1 + Const2}
2118
+ if (isConstantVal (Op1Raw) && Op2Raw == dwarf::DW_OP_plus_uconst) {
2119
+ auto Result = Op1Arg + Op2Arg;
2120
+ WorkingOps.erase (WorkingOps.begin () + Loc + 2 ,
2121
+ WorkingOps.begin () + Loc + 4 );
2122
+ WorkingOps[Loc] = dwarf::DW_OP_constu;
2123
+ WorkingOps[Loc + 1 ] = Result;
2124
+ Cursor.assignNewExpr (WorkingOps);
2125
+ Loc = 0 ;
2126
+ continue ;
2127
+ }
2128
+
2129
+ auto Op3 = Cursor.peekNextN (2 );
2130
+ // Op2 could still match a pattern, skip iteration.
2131
+ if (!Op3) {
2132
+ consumeOneOperator (Cursor, Loc, *Op1);
2133
+ continue ;
2134
+ }
2135
+ auto Op3Raw = Op3->getOp ();
2136
+
2137
+ // {DW_OP_const[u, s], Const1, DW_OP_const[u, s], Const2, DW_OP_[plus,
2138
+ // minus, mul, div, shl, shr] -> {DW_OP_constu, Const1 [+, -, *, /, <<, >>]
2139
+ // Const2}
2140
+ if (isConstantVal (Op1Raw) && isConstantVal (Op2Raw)) {
2141
+ auto Result = foldOperationIfPossible (Op3Raw, Op1Arg, Op2Arg);
2142
+ if (!Result) {
2143
+ consumeOneOperator (Cursor, Loc, *Op1);
2144
+ continue ;
2145
+ }
2146
+ WorkingOps.erase (WorkingOps.begin () + Loc + 2 ,
2147
+ WorkingOps.begin () + Loc + 5 );
2148
+ WorkingOps[Loc] = dwarf::DW_OP_constu;
2149
+ WorkingOps[Loc + 1 ] = *Result;
2150
+ Cursor.assignNewExpr (WorkingOps);
2151
+ Loc = 0 ;
2152
+ continue ;
2153
+ }
2154
+
2155
+ // {DW_OP_plus_uconst, Const1, DW_OP_const[u, s], Const1, DW_OP_plus} ->
2156
+ // {DW_OP_plus_uconst, Const1 + Const2}
2157
+ if (Op1Raw == dwarf::DW_OP_plus_uconst && isConstantVal (Op2Raw) &&
2158
+ Op3Raw == dwarf::DW_OP_plus) {
2159
+ auto Result = Op1Arg + Op2Arg;
2160
+ WorkingOps.erase (WorkingOps.begin () + Loc + 2 , WorkingOps.begin () + 5 );
2161
+ WorkingOps[Loc + 1 ] = Result;
2162
+ Cursor.assignNewExpr (WorkingOps);
2163
+ Loc = 0 ;
2164
+ continue ;
2165
+ }
2166
+
2167
+ auto Op3Arg = Op3->getArg (0 );
2168
+ // {DW_OP_const[u, s], Const1, DW_OP_plus, DW_OP_plus_uconst, Const2} ->
2169
+ // {DW_OP_plus_uconst, Const1 + Const2}
2170
+ if (isConstantVal (Op1Raw) && Op2Raw == dwarf::DW_OP_plus &&
2171
+ Op3Raw == dwarf::DW_OP_plus_uconst) {
2172
+ auto Result = Op1Arg + Op3Arg;
2173
+ WorkingOps.erase (WorkingOps.begin () + Loc + 2 , WorkingOps.begin () + 5 );
2174
+ WorkingOps[Loc] = dwarf::DW_OP_plus_uconst;
2175
+ WorkingOps[Loc + 1 ] = Result;
2176
+ Cursor.assignNewExpr (WorkingOps);
2177
+ Loc = 0 ;
2178
+ continue ;
2179
+ }
2180
+
2181
+ auto Op4 = Cursor.peekNextN (3 );
2182
+ // Op2 and Op3 could still match a pattern, skip iteration.
2183
+ if (!Op4) {
2184
+ consumeOneOperator (Cursor, Loc, *Op1);
2185
+ continue ;
2186
+ }
2187
+ auto Op4Raw = Op4->getOp ();
2188
+
2189
+ // {DW_OP_const[u, s], Const1, DW_OP_[plus, mul], Const2, DW_OP_[plus, mul]}
2190
+ // -> {DW_OP_constu, Const1 [+, *] Const2, DW_OP_[plus, mul]}
2191
+ if (isConstantVal (Op1Raw) && isConstantVal (Op3Raw) &&
2192
+ operationsAreFoldableAndCommutative (Op2Raw, Op4Raw)) {
2193
+ auto Result = foldOperationIfPossible (Op2Raw, Op1Arg, Op3Arg);
2194
+ if (!Result)
2195
+ llvm_unreachable (
2196
+ " Something went very wrong here! This should always work" );
2197
+ WorkingOps.erase (WorkingOps.begin () + Loc + 3 ,
2198
+ WorkingOps.begin () + Loc + 6 );
2199
+ WorkingOps[Loc] = dwarf::DW_OP_constu;
2200
+ WorkingOps[Loc + 1 ] = *Result;
2201
+ Cursor.assignNewExpr (WorkingOps);
2202
+ Loc = 0 ;
2203
+ continue ;
2204
+ }
2205
+ auto Op5 = Cursor.peekNextN (4 );
2206
+ if (!Op5) {
2207
+ consumeOneOperator (Cursor, Loc, *Op1);
2208
+ continue ;
2209
+ }
2210
+ auto Op5Raw = Op5->getOp ();
2211
+ auto Op5Arg = Op5->getArg (0 );
2212
+
2213
+ // {DW_OP_const[u, s], Const1, DW_OP_plus, DW_OP_LLVM_arg, Arg1, DW_OP_plus,
2214
+ // DW_OP_plus_uconst, Const2} -> {DW_OP_constu, Const1 + Const2, DW_OP_plus,
2215
+ // DW_OP_LLVM_arg, Arg1, DW_OP_plus}
2216
+ if (isConstantVal (Op1Raw) && Op3Raw == dwarf::DW_OP_LLVM_arg &&
2217
+ Op5Raw == dwarf::DW_OP_plus_uconst && Op2Raw == Op4Raw &&
2218
+ Op4Raw == dwarf::DW_OP_plus) {
2219
+ auto Result = Op1Arg + Op5Arg;
2220
+ WorkingOps.erase (WorkingOps.begin () + Loc + 6 ,
2221
+ WorkingOps.begin () + Loc + 8 );
2222
+ WorkingOps[Loc] = dwarf::DW_OP_constu;
2223
+ WorkingOps[Loc + 1 ] = Result;
2224
+ Cursor.assignNewExpr (WorkingOps);
2225
+ Loc = 0 ;
2226
+ continue ;
2227
+ }
2228
+
2229
+ auto Op4Arg = Op4->getArg (0 );
2230
+
2231
+ // {DW_OP_plus_uconst, Const1, DW_OP_LLVM_arg, Arg1, DW_OP_plus,
2232
+ // DW_OP_const[u, s], Const2, DW_OP_plus} -> {DW_OP_plus_uconst, Const1 +
2233
+ // Const2, DW_OP_LLVM_arg, Arg1, DW_OP_plus}
2234
+ if (Op1Raw == dwarf::DW_OP_plus_uconst && Op2Raw == dwarf::DW_OP_LLVM_arg &&
2235
+ Op3Raw == Op5Raw && Op3Raw == dwarf::DW_OP_plus &&
2236
+ isConstantVal (Op4Raw)) {
2237
+ auto Result = Op1Arg + Op4Arg;
2238
+ WorkingOps.erase (WorkingOps.begin () + Loc + 5 ,
2239
+ WorkingOps.begin () + Loc + 8 );
2240
+ WorkingOps[Loc + 1 ] = Result;
2241
+ Cursor.assignNewExpr (WorkingOps);
2242
+ Loc = 0 ;
2243
+ continue ;
2244
+ }
2245
+
2246
+ auto Op6 = Cursor.peekNextN (5 );
2247
+ if (!Op6) {
2248
+ consumeOneOperator (Cursor, Loc, *Op1);
2249
+ continue ;
2250
+ }
2251
+ auto Op6Raw = Op6->getOp ();
2252
+ // {DW_OP_const[u, s], Const1, DW_OP_[plus, mul], DW_OP_LLVM_arg, Arg1,
2253
+ // DW_OP_[plus, mul], DW_OP_const[u, s], Const2, DW_OP_[plus, mul]} ->
2254
+ // {DW_OP_constu, Const1 [+, *] Const2, DW_OP_[plus, mul], DW_OP_LLVM_arg,
2255
+ // Arg1, DW_OP_[plus, mul]}
2256
+ if (isConstantVal (Op1Raw) && Op3Raw == dwarf::DW_OP_LLVM_arg &&
2257
+ isConstantVal (Op5Raw) &&
2258
+ operationsAreFoldableAndCommutative (Op2Raw, Op4Raw) &&
2259
+ operationsAreFoldableAndCommutative (Op4Raw, Op6Raw)) {
2260
+ auto Result = foldOperationIfPossible (Op2Raw, Op1Arg, Op5Arg);
2261
+ if (!Result)
2262
+ llvm_unreachable (
2263
+ " Something went very wrong here! This should always work" );
2264
+ WorkingOps.erase (WorkingOps.begin () + Loc + 6 ,
2265
+ WorkingOps.begin () + Loc + 9 );
2266
+ WorkingOps[Loc] = dwarf::DW_OP_constu;
2267
+ WorkingOps[Loc + 1 ] = *Result;
2268
+ Cursor.assignNewExpr (WorkingOps);
2269
+ Loc = 0 ;
2270
+ continue ;
2271
+ }
2272
+
2273
+ consumeOneOperator (Cursor, Loc, *Op1);
2274
+ }
2275
+ auto *Result = DIExpression::get (getContext (), WorkingOps);
2276
+ assert (Result->isValid () && " concatenated expression is not valid" );
2277
+ return Result;
2278
+ }
2279
+
2001
2280
uint64_t DIExpression::getNumLocationOperands () const {
2002
2281
uint64_t Result = 0 ;
2003
2282
for (auto ExprOp : expr_ops ())
0 commit comments