@@ -1870,7 +1870,6 @@ DIExpression *DIExpression::append(const DIExpression *Expr,
1870
1870
}
1871
1871
Op.appendToVector (NewOps);
1872
1872
}
1873
-
1874
1873
NewOps.append (Ops.begin (), Ops.end ());
1875
1874
auto *result = DIExpression::get (Expr->getContext (), NewOps);
1876
1875
assert (result->isValid () && " concatenated expression is not valid" );
@@ -2011,6 +2010,347 @@ DIExpression::constantFold(const ConstantInt *CI) {
2011
2010
ConstantInt::get (getContext (), NewInt)};
2012
2011
}
2013
2012
2013
+ // / Returns true if the Op is a DW_OP_constu.
2014
+ static bool isConstantVal (uint64_t Op) { return Op == dwarf::DW_OP_constu; }
2015
+
2016
+ // / Returns true if an operation and operand result in a No Op.
2017
+ static bool isNeutralElement (uint64_t Op, uint64_t Val) {
2018
+ switch (Op) {
2019
+ case dwarf::DW_OP_plus:
2020
+ case dwarf::DW_OP_minus:
2021
+ case dwarf::DW_OP_shl:
2022
+ case dwarf::DW_OP_shr:
2023
+ return Val == 0 ;
2024
+ case dwarf::DW_OP_mul:
2025
+ case dwarf::DW_OP_div:
2026
+ return Val == 1 ;
2027
+ default :
2028
+ return false ;
2029
+ }
2030
+ }
2031
+
2032
+ // / Try to fold constant math operations and return the result if possible.
2033
+ static std::optional<uint64_t >
2034
+ foldOperationIfPossible (uint64_t Op, uint64_t Operand1, uint64_t Operand2) {
2035
+ bool ResultOverflowed;
2036
+ switch (Op) {
2037
+ case dwarf::DW_OP_plus: {
2038
+ auto Result = SaturatingAdd (Operand1, Operand2, &ResultOverflowed);
2039
+ if (ResultOverflowed)
2040
+ return std::nullopt;
2041
+ return Result;
2042
+ }
2043
+ case dwarf::DW_OP_minus: {
2044
+ if (Operand1 < Operand2)
2045
+ return std::nullopt;
2046
+ return Operand1 - Operand2;
2047
+ }
2048
+ case dwarf::DW_OP_shl: {
2049
+ if ((uint64_t )__builtin_clz (Operand1) < Operand2)
2050
+ return std::nullopt;
2051
+ return Operand1 << Operand2;
2052
+ }
2053
+ case dwarf::DW_OP_shr: {
2054
+ if ((uint64_t )__builtin_ctz (Operand1) < Operand2)
2055
+ return std::nullopt;
2056
+ return Operand1 >> Operand2;
2057
+ }
2058
+ case dwarf::DW_OP_mul: {
2059
+ auto Result = SaturatingMultiply (Operand1, Operand2, &ResultOverflowed);
2060
+ if (ResultOverflowed)
2061
+ return std::nullopt;
2062
+ return Result;
2063
+ }
2064
+ case dwarf::DW_OP_div: {
2065
+ if (Operand2)
2066
+ return Operand1 / Operand2;
2067
+ return std::nullopt;
2068
+ }
2069
+ default :
2070
+ return std::nullopt;
2071
+ }
2072
+ }
2073
+
2074
+ // / Returns true if the two operations are commutative and can be folded.
2075
+ static bool operationsAreFoldableAndCommutative (uint64_t Op1, uint64_t Op2) {
2076
+ if (Op1 != Op2)
2077
+ return false ;
2078
+ switch (Op1) {
2079
+ case dwarf::DW_OP_plus:
2080
+ case dwarf::DW_OP_mul:
2081
+ return true ;
2082
+ default :
2083
+ return false ;
2084
+ }
2085
+ }
2086
+
2087
+ // / Consume one operator and its operand(s).
2088
+ static void consumeOneOperator (DIExpressionCursor &Cursor, uint64_t &Loc,
2089
+ const DIExpression::ExprOperand &Op) {
2090
+ Cursor.consume (1 );
2091
+ Loc = Loc + Op.getSize ();
2092
+ }
2093
+
2094
+ // / Reset the Cursor to the beginning of the WorkingOps.
2095
+ static void startFromBeginning (uint64_t &Loc, DIExpressionCursor &Cursor,
2096
+ ArrayRef<uint64_t > WorkingOps) {
2097
+ Cursor.assignNewExpr (WorkingOps);
2098
+ Loc = 0 ;
2099
+ }
2100
+
2101
+ // / This function will canonicalize:
2102
+ // / 1. DW_OP_plus_uconst to DW_OP_constu <const-val> DW_OP_plus
2103
+ // / 2. DW_OP_lit<n> to DW_OP_constu <n>
2104
+ static SmallVector<uint64_t >
2105
+ canonicalizeDwarfOperations (ArrayRef<uint64_t > WorkingOps) {
2106
+ DIExpressionCursor Cursor (WorkingOps);
2107
+ uint64_t Loc = 0 ;
2108
+ SmallVector<uint64_t > ResultOps;
2109
+ while (Loc < WorkingOps.size ()) {
2110
+ auto Op = Cursor.peek ();
2111
+ // / Expression has no operations, break.
2112
+ if (!Op)
2113
+ break ;
2114
+ auto OpRaw = Op->getOp ();
2115
+ auto OpArg = Op->getArg (0 );
2116
+
2117
+ if (OpRaw >= dwarf::DW_OP_lit0 && OpRaw <= dwarf::DW_OP_lit31) {
2118
+ ResultOps.push_back (dwarf::DW_OP_constu);
2119
+ ResultOps.push_back (OpRaw - dwarf::DW_OP_lit0);
2120
+ consumeOneOperator (Cursor, Loc, *Cursor.peek ());
2121
+ continue ;
2122
+ }
2123
+ if (OpRaw == dwarf::DW_OP_plus_uconst) {
2124
+ ResultOps.push_back (dwarf::DW_OP_constu);
2125
+ ResultOps.push_back (OpArg);
2126
+ ResultOps.push_back (dwarf::DW_OP_plus);
2127
+ consumeOneOperator (Cursor, Loc, *Cursor.peek ());
2128
+ continue ;
2129
+ }
2130
+ uint64_t PrevLoc = Loc;
2131
+ consumeOneOperator (Cursor, Loc, *Cursor.peek ());
2132
+ ResultOps.append (WorkingOps.begin () + PrevLoc, WorkingOps.begin () + Loc);
2133
+ }
2134
+ return ResultOps;
2135
+ }
2136
+
2137
+ // / This function will convert:
2138
+ // / 1. DW_OP_constu <const-val> DW_OP_plus to DW_OP_plus_uconst
2139
+ // / 2. DW_OP_constu, 0 to DW_OP_lit0
2140
+ static SmallVector<uint64_t >
2141
+ optimizeDwarfOperations (ArrayRef<uint64_t > WorkingOps) {
2142
+ DIExpressionCursor Cursor (WorkingOps);
2143
+ uint64_t Loc = 0 ;
2144
+ SmallVector<uint64_t > ResultOps;
2145
+ while (Loc < WorkingOps.size ()) {
2146
+ auto Op1 = Cursor.peek ();
2147
+ // / Expression has no operations, exit.
2148
+ if (!Op1)
2149
+ break ;
2150
+ auto Op1Raw = Op1->getOp ();
2151
+ auto Op1Arg = Op1->getArg (0 );
2152
+
2153
+ if (Op1Raw == dwarf::DW_OP_constu && Op1Arg == 0 ) {
2154
+ ResultOps.push_back (dwarf::DW_OP_lit0);
2155
+ consumeOneOperator (Cursor, Loc, *Cursor.peek ());
2156
+ continue ;
2157
+ }
2158
+
2159
+ auto Op2 = Cursor.peekNext ();
2160
+ // / Expression has no more operations, copy into ResultOps and exit.
2161
+ if (!Op2) {
2162
+ uint64_t PrevLoc = Loc;
2163
+ consumeOneOperator (Cursor, Loc, *Cursor.peek ());
2164
+ ResultOps.append (WorkingOps.begin () + PrevLoc, WorkingOps.begin () + Loc);
2165
+ break ;
2166
+ }
2167
+ auto Op2Raw = Op2->getOp ();
2168
+
2169
+ if (Op1Raw == dwarf::DW_OP_constu && Op2Raw == dwarf::DW_OP_plus) {
2170
+ ResultOps.push_back (dwarf::DW_OP_plus_uconst);
2171
+ ResultOps.push_back (Op1Arg);
2172
+ consumeOneOperator (Cursor, Loc, *Cursor.peek ());
2173
+ consumeOneOperator (Cursor, Loc, *Cursor.peek ());
2174
+ continue ;
2175
+ }
2176
+ uint64_t PrevLoc = Loc;
2177
+ consumeOneOperator (Cursor, Loc, *Cursor.peek ());
2178
+ ResultOps.append (WorkingOps.begin () + PrevLoc, WorkingOps.begin () + Loc);
2179
+ }
2180
+ return ResultOps;
2181
+ }
2182
+
2183
+ // / {DW_OP_constu, 0, DW_OP_[plus, minus, shl, shr]} -> {}
2184
+ // / {DW_OP_constu, 1, DW_OP_[mul, div]} -> {}
2185
+ static bool tryFoldNoOpMath (uint64_t Op1Raw, uint64_t Op1Arg, uint64_t Op2Raw,
2186
+ uint64_t &Loc, DIExpressionCursor &Cursor,
2187
+ SmallVectorImpl<uint64_t > &WorkingOps) {
2188
+ if (isConstantVal (Op1Raw) && isNeutralElement (Op2Raw, Op1Arg)) {
2189
+ WorkingOps.erase (WorkingOps.begin () + Loc, WorkingOps.begin () + Loc + 3 );
2190
+ startFromBeginning (Loc, Cursor, WorkingOps);
2191
+ return true ;
2192
+ }
2193
+ return false ;
2194
+ }
2195
+
2196
+ // / {DW_OP_constu, Const1, DW_OP_constu, Const2, DW_OP_[plus,
2197
+ // / minus, mul, div, shl, shr] -> {DW_OP_constu, Const1 [+, -, *, /, <<, >>]
2198
+ // / Const2}
2199
+ static bool tryFoldConstants (std::optional<DIExpression::ExprOperand> Op1,
2200
+ uint64_t Op1Raw, uint64_t Op1Arg, uint64_t Op2Raw,
2201
+ uint64_t Op2Arg, uint64_t Op3Raw, uint64_t &Loc,
2202
+ DIExpressionCursor &Cursor,
2203
+ SmallVectorImpl<uint64_t > &WorkingOps) {
2204
+ if (isConstantVal (Op1Raw) && isConstantVal (Op2Raw)) {
2205
+ auto Result = foldOperationIfPossible (Op3Raw, Op1Arg, Op2Arg);
2206
+ if (!Result) {
2207
+ consumeOneOperator (Cursor, Loc, *Op1);
2208
+ return true ;
2209
+ }
2210
+ WorkingOps.erase (WorkingOps.begin () + Loc + 2 ,
2211
+ WorkingOps.begin () + Loc + 5 );
2212
+ WorkingOps[Loc] = dwarf::DW_OP_constu;
2213
+ WorkingOps[Loc + 1 ] = *Result;
2214
+ startFromBeginning (Loc, Cursor, WorkingOps);
2215
+ return true ;
2216
+ }
2217
+ return false ;
2218
+ }
2219
+
2220
+ // / {DW_OP_constu, Const1, DW_OP_[plus, mul], DW_OP_constu, Const2,
2221
+ // / DW_OP_[plus, mul]} -> {DW_OP_constu, Const1 [+, *] Const2, DW_OP_[plus,
2222
+ // / mul]}
2223
+ static bool tryFoldCommutativeMath (uint64_t Op1Raw, uint64_t Op1Arg,
2224
+ uint64_t Op2Raw, uint64_t Op2Arg,
2225
+ uint64_t Op3Raw, uint64_t Op3Arg,
2226
+ uint64_t Op4Raw, uint64_t &Loc,
2227
+ DIExpressionCursor &Cursor,
2228
+ SmallVectorImpl<uint64_t > &WorkingOps) {
2229
+
2230
+ if (isConstantVal (Op1Raw) && isConstantVal (Op3Raw) &&
2231
+ operationsAreFoldableAndCommutative (Op2Raw, Op4Raw)) {
2232
+ auto Result = foldOperationIfPossible (Op2Raw, Op1Arg, Op3Arg);
2233
+ if (!Result)
2234
+ return false ;
2235
+ WorkingOps.erase (WorkingOps.begin () + Loc + 3 ,
2236
+ WorkingOps.begin () + Loc + 6 );
2237
+ WorkingOps[Loc] = dwarf::DW_OP_constu;
2238
+ WorkingOps[Loc + 1 ] = *Result;
2239
+ startFromBeginning (Loc, Cursor, WorkingOps);
2240
+ return true ;
2241
+ }
2242
+ return false ;
2243
+ }
2244
+
2245
+ // / {DW_OP_constu, Const1, DW_OP_[plus, mul], DW_OP_LLVM_arg, Arg1,
2246
+ // / DW_OP_[plus, mul], DW_OP_constu, Const2, DW_OP_[plus, mul]} ->
2247
+ // / {DW_OP_constu, Const1 [+, *] Const2, DW_OP_[plus, mul], DW_OP_LLVM_arg,
2248
+ // / Arg1, DW_OP_[plus, mul]}
2249
+ static bool tryFoldCommutativeMathWithArgInBetween (
2250
+ uint64_t Op1Raw, uint64_t Op1Arg, uint64_t Op2Raw, uint64_t Op3Raw,
2251
+ uint64_t Op4Raw, uint64_t Op5Raw, uint64_t Op5Arg, uint64_t Op6Raw,
2252
+ uint64_t &Loc, DIExpressionCursor &Cursor,
2253
+ SmallVectorImpl<uint64_t > &WorkingOps) {
2254
+ if (isConstantVal (Op1Raw) && Op3Raw == dwarf::DW_OP_LLVM_arg &&
2255
+ isConstantVal (Op5Raw) &&
2256
+ operationsAreFoldableAndCommutative (Op2Raw, Op4Raw) &&
2257
+ operationsAreFoldableAndCommutative (Op4Raw, Op6Raw)) {
2258
+ auto Result = foldOperationIfPossible (Op2Raw, Op1Arg, Op5Arg);
2259
+ if (!Result)
2260
+ return false ;
2261
+ WorkingOps.erase (WorkingOps.begin () + Loc + 6 ,
2262
+ WorkingOps.begin () + Loc + 9 );
2263
+ WorkingOps[Loc] = dwarf::DW_OP_constu;
2264
+ WorkingOps[Loc + 1 ] = *Result;
2265
+ startFromBeginning (Loc, Cursor, WorkingOps);
2266
+ return true ;
2267
+ }
2268
+ return false ;
2269
+ }
2270
+
2271
+ SmallVector<uint64_t >
2272
+ DIExpression::foldConstantMath (ArrayRef<uint64_t > WorkingOps) {
2273
+
2274
+ uint64_t Loc = 0 ;
2275
+ SmallVector<uint64_t > ResultOps = canonicalizeDwarfOperations (WorkingOps);
2276
+ DIExpressionCursor Cursor (ResultOps);
2277
+
2278
+ while (Loc < ResultOps.size ()) {
2279
+
2280
+ auto Op1 = Cursor.peek ();
2281
+ // Expression has no operations, exit.
2282
+ if (!Op1)
2283
+ break ;
2284
+ auto Op1Raw = Op1->getOp ();
2285
+ auto Op1Arg = Op1->getArg (0 );
2286
+
2287
+ if (!isConstantVal (Op1Raw)) {
2288
+ // Early exit, all of the following patterns start with a constant value.
2289
+ consumeOneOperator (Cursor, Loc, *Op1);
2290
+ continue ;
2291
+ }
2292
+
2293
+ auto Op2 = Cursor.peekNext ();
2294
+ // All following patterns require at least 2 Operations, exit.
2295
+ if (!Op2)
2296
+ break ;
2297
+ auto Op2Raw = Op2->getOp ();
2298
+
2299
+ if (tryFoldNoOpMath (Op1Raw, Op1Arg, Op2Raw, Loc, Cursor, ResultOps))
2300
+ continue ;
2301
+
2302
+ auto Op2Arg = Op2->getArg (0 );
2303
+
2304
+ auto Op3 = Cursor.peekNextN (2 );
2305
+ // Op2 could still match a pattern, skip iteration.
2306
+ if (!Op3) {
2307
+ consumeOneOperator (Cursor, Loc, *Op1);
2308
+ continue ;
2309
+ }
2310
+ auto Op3Raw = Op3->getOp ();
2311
+
2312
+ if (tryFoldConstants (Op1, Op1Raw, Op1Arg, Op2Raw, Op2Arg, Op3Raw, Loc,
2313
+ Cursor, ResultOps))
2314
+ continue ;
2315
+
2316
+ auto Op3Arg = Op3->getArg (0 );
2317
+
2318
+ auto Op4 = Cursor.peekNextN (3 );
2319
+ // Op2 and Op3 could still match a pattern, skip iteration.
2320
+ if (!Op4) {
2321
+ consumeOneOperator (Cursor, Loc, *Op1);
2322
+ continue ;
2323
+ }
2324
+ auto Op4Raw = Op4->getOp ();
2325
+
2326
+ if (tryFoldCommutativeMath (Op1Raw, Op1Arg, Op2Raw, Op2Arg, Op3Raw, Op3Arg,
2327
+ Op4Raw, Loc, Cursor, ResultOps))
2328
+ continue ;
2329
+
2330
+ auto Op5 = Cursor.peekNextN (4 );
2331
+ if (!Op5) {
2332
+ consumeOneOperator (Cursor, Loc, *Op1);
2333
+ continue ;
2334
+ }
2335
+ auto Op5Raw = Op5->getOp ();
2336
+ auto Op5Arg = Op5->getArg (0 );
2337
+ auto Op6 = Cursor.peekNextN (5 );
2338
+ if (!Op6) {
2339
+ consumeOneOperator (Cursor, Loc, *Op1);
2340
+ continue ;
2341
+ }
2342
+ auto Op6Raw = Op6->getOp ();
2343
+ if (tryFoldCommutativeMathWithArgInBetween (Op1Raw, Op1Arg, Op2Raw, Op3Raw,
2344
+ Op4Raw, Op5Raw, Op5Arg, Op6Raw,
2345
+ Loc, Cursor, ResultOps))
2346
+ continue ;
2347
+
2348
+ consumeOneOperator (Cursor, Loc, *Op1);
2349
+ }
2350
+ ResultOps = optimizeDwarfOperations (ResultOps);
2351
+ return ResultOps;
2352
+ }
2353
+
2014
2354
uint64_t DIExpression::getNumLocationOperands () const {
2015
2355
uint64_t Result = 0 ;
2016
2356
for (auto ExprOp : expr_ops ())
0 commit comments