@@ -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 (Operand2 > 64 )
2050
+ return std::nullopt;
2051
+ return Operand1 << Operand2;
2052
+ }
2053
+ case dwarf::DW_OP_shr: {
2054
+ if (Operand2 > 64 )
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
+ // Move the Cursor to the position of an operation by starting from the
2102
+ // beginning and consuming the number of operations that came before.
2103
+ static void moveCursorToCurrentOp (uint64_t &Loc, DIExpressionCursor &Cursor,
2104
+ ArrayRef<uint64_t > WorkingOps,
2105
+ uint32_t NumOfOpsConsumed) {
2106
+ Cursor.assignNewExpr (WorkingOps);
2107
+ Cursor.consume (NumOfOpsConsumed);
2108
+ assert (Cursor.peek ()->getOp () == WorkingOps[Loc] &&
2109
+ " Cursor position does not match position of iterator 'Loc' to "
2110
+ " WorkingOps" );
2111
+ }
2112
+
2113
+ // This function will canonicalize:
2114
+ // 1. DW_OP_plus_uconst to DW_OP_constu <const-val> DW_OP_plus
2115
+ // 2. DW_OP_lit<n> to DW_OP_constu <n>
2116
+ static void canonicalizeDwarfOperations (SmallVectorImpl<uint64_t > &WorkingOps) {
2117
+ DIExpressionCursor Cursor (WorkingOps);
2118
+ uint64_t Loc = 0 ;
2119
+ uint32_t NumOfOpsConsumed = 0 ;
2120
+ while (Loc < WorkingOps.size ()) {
2121
+ auto Op = Cursor.peek ();
2122
+ // Expression has no operations, break.
2123
+ if (!Op)
2124
+ break ;
2125
+ auto OpRaw = Op->getOp ();
2126
+ auto OpArg = Op->getArg (0 );
2127
+
2128
+ if (OpRaw >= dwarf::DW_OP_lit0 && OpRaw <= dwarf::DW_OP_lit31) {
2129
+ WorkingOps[Loc] = dwarf::DW_OP_constu;
2130
+ WorkingOps.insert (WorkingOps.begin () + Loc + 1 ,
2131
+ OpRaw - dwarf::DW_OP_lit0);
2132
+ } else if (OpRaw == dwarf::DW_OP_plus_uconst) {
2133
+ WorkingOps[Loc] = dwarf::DW_OP_constu;
2134
+ WorkingOps[Loc + 1 ] = OpArg;
2135
+ WorkingOps.insert (WorkingOps.begin () + Loc + 2 , dwarf::DW_OP_plus);
2136
+ moveCursorToCurrentOp (Loc, Cursor, WorkingOps, NumOfOpsConsumed);
2137
+ }
2138
+ consumeOneOperator (Cursor, Loc, *Cursor.peek ());
2139
+ NumOfOpsConsumed++;
2140
+ }
2141
+ }
2142
+
2143
+ // This function will convert:
2144
+ // 1. DW_OP_constu <const-val> DW_OP_plus to DW_OP_plus_uconst
2145
+ // 2. DW_OP_constu, 0 to DW_OP_lit0
2146
+ static void optimizeDwarfOperations (SmallVectorImpl<uint64_t > &WorkingOps) {
2147
+ DIExpressionCursor Cursor (WorkingOps);
2148
+ uint64_t Loc = 0 ;
2149
+ uint32_t NumOfOpsConsumed = 0 ;
2150
+ while (Loc < WorkingOps.size ()) {
2151
+ auto Op1 = Cursor.peek ();
2152
+ // Expression has no operations, exit.
2153
+ if (!Op1)
2154
+ break ;
2155
+ auto Op1Raw = Op1->getOp ();
2156
+ auto Op1Arg = Op1->getArg (0 );
2157
+
2158
+ if (Op1Raw == dwarf::DW_OP_constu && Op1Arg == 0 ) {
2159
+ WorkingOps[Loc] = dwarf::DW_OP_lit0;
2160
+ WorkingOps.erase (WorkingOps.begin () + Loc + 1 );
2161
+ moveCursorToCurrentOp (Loc, Cursor, WorkingOps, NumOfOpsConsumed);
2162
+ continue ;
2163
+ }
2164
+
2165
+ auto Op2 = Cursor.peekNext ();
2166
+ // Expression has no more operations, exit.
2167
+ if (!Op2)
2168
+ break ;
2169
+ auto Op2Raw = Op2->getOp ();
2170
+
2171
+ if (Op1Raw == dwarf::DW_OP_constu && Op2Raw == dwarf::DW_OP_plus) {
2172
+ WorkingOps.erase (WorkingOps.begin () + Loc + 2 );
2173
+ WorkingOps[Loc] = dwarf::DW_OP_plus_uconst;
2174
+ WorkingOps[Loc + 1 ] = Op1Arg;
2175
+ moveCursorToCurrentOp (Loc, Cursor, WorkingOps, NumOfOpsConsumed);
2176
+ }
2177
+ consumeOneOperator (Cursor, Loc, *Cursor.peek ());
2178
+ NumOfOpsConsumed++;
2179
+ }
2180
+ }
2181
+
2182
+ // {DW_OP_constu, 0, DW_OP_[plus, minus, shl, shr]} -> {}
2183
+ // {DW_OP_constu, 1, DW_OP_[mul, div]} -> {}
2184
+ static bool tryFoldNoOpMath (uint64_t Op1Raw, uint64_t Op1Arg, uint64_t Op2Raw,
2185
+ uint64_t &Loc, DIExpressionCursor &Cursor,
2186
+ SmallVectorImpl<uint64_t > &WorkingOps) {
2187
+ if (isConstantVal (Op1Raw) && isNeutralElement (Op2Raw, Op1Arg)) {
2188
+ WorkingOps.erase (WorkingOps.begin () + Loc, WorkingOps.begin () + Loc + 3 );
2189
+ startFromBeginning (Loc, Cursor, WorkingOps);
2190
+ return true ;
2191
+ }
2192
+ return false ;
2193
+ }
2194
+
2195
+ // {DW_OP_constu, Const1, DW_OP_constu, Const2, DW_OP_[plus,
2196
+ // minus, mul, div, shl, shr] -> {DW_OP_constu, Const1 [+, -, *, /, <<, >>]
2197
+ // Const2}
2198
+ static bool tryFoldConstants (std::optional<DIExpression::ExprOperand> Op1,
2199
+ uint64_t Op1Raw, uint64_t Op1Arg, uint64_t Op2Raw,
2200
+ uint64_t Op2Arg, uint64_t Op3Raw, uint64_t &Loc,
2201
+ DIExpressionCursor &Cursor,
2202
+ SmallVectorImpl<uint64_t > &WorkingOps) {
2203
+ if (isConstantVal (Op1Raw) && isConstantVal (Op2Raw)) {
2204
+ auto Result = foldOperationIfPossible (Op3Raw, Op1Arg, Op2Arg);
2205
+ if (!Result) {
2206
+ consumeOneOperator (Cursor, Loc, *Op1);
2207
+ return true ;
2208
+ }
2209
+ WorkingOps.erase (WorkingOps.begin () + Loc + 2 ,
2210
+ WorkingOps.begin () + Loc + 5 );
2211
+ WorkingOps[Loc] = dwarf::DW_OP_constu;
2212
+ WorkingOps[Loc + 1 ] = *Result;
2213
+ startFromBeginning (Loc, Cursor, WorkingOps);
2214
+ return true ;
2215
+ }
2216
+ return false ;
2217
+ }
2218
+
2219
+ // {DW_OP_constu, Const1, DW_OP_[plus, mul], DW_OP_constu, Const2,
2220
+ // DW_OP_[plus, mul]} -> {DW_OP_constu, Const1 [+, *] Const2, DW_OP_[plus, mul]}
2221
+ static bool tryFoldCommutativeMath (uint64_t Op1Raw, uint64_t Op1Arg,
2222
+ uint64_t Op2Raw, uint64_t Op2Arg,
2223
+ uint64_t Op3Raw, uint64_t Op3Arg,
2224
+ uint64_t Op4Raw, uint64_t &Loc,
2225
+ DIExpressionCursor &Cursor,
2226
+ SmallVectorImpl<uint64_t > &WorkingOps) {
2227
+
2228
+ if (isConstantVal (Op1Raw) && isConstantVal (Op3Raw) &&
2229
+ operationsAreFoldableAndCommutative (Op2Raw, Op4Raw)) {
2230
+ auto Result = foldOperationIfPossible (Op2Raw, Op1Arg, Op3Arg);
2231
+ if (!Result)
2232
+ return false ;
2233
+ WorkingOps.erase (WorkingOps.begin () + Loc + 3 ,
2234
+ WorkingOps.begin () + Loc + 6 );
2235
+ WorkingOps[Loc] = dwarf::DW_OP_constu;
2236
+ WorkingOps[Loc + 1 ] = *Result;
2237
+ startFromBeginning (Loc, Cursor, WorkingOps);
2238
+ return true ;
2239
+ }
2240
+ return false ;
2241
+ }
2242
+
2243
+ // {DW_OP_constu, Const1, DW_OP_[plus, mul], DW_OP_LLVM_arg, Arg1,
2244
+ // DW_OP_[plus, mul], DW_OP_constu, Const2, DW_OP_[plus, mul]} ->
2245
+ // {DW_OP_constu, Const1 [+, *] Const2, DW_OP_[plus, mul], DW_OP_LLVM_arg,
2246
+ // Arg1, DW_OP_[plus, mul]}
2247
+ static bool tryFoldCommutativeMathWithArgInBetween (
2248
+ uint64_t Op1Raw, uint64_t Op1Arg, uint64_t Op2Raw, uint64_t Op3Raw,
2249
+ uint64_t Op4Raw, uint64_t Op5Raw, uint64_t Op5Arg, uint64_t Op6Raw,
2250
+ uint64_t &Loc, DIExpressionCursor &Cursor,
2251
+ SmallVectorImpl<uint64_t > &WorkingOps) {
2252
+ if (isConstantVal (Op1Raw) && Op3Raw == dwarf::DW_OP_LLVM_arg &&
2253
+ isConstantVal (Op5Raw) &&
2254
+ operationsAreFoldableAndCommutative (Op2Raw, Op4Raw) &&
2255
+ operationsAreFoldableAndCommutative (Op4Raw, Op6Raw)) {
2256
+ auto Result = foldOperationIfPossible (Op2Raw, Op1Arg, Op5Arg);
2257
+ if (!Result)
2258
+ return false ;
2259
+ WorkingOps.erase (WorkingOps.begin () + Loc + 6 ,
2260
+ WorkingOps.begin () + Loc + 9 );
2261
+ WorkingOps[Loc] = dwarf::DW_OP_constu;
2262
+ WorkingOps[Loc + 1 ] = *Result;
2263
+ startFromBeginning (Loc, Cursor, WorkingOps);
2264
+ return true ;
2265
+ }
2266
+ return false ;
2267
+ }
2268
+
2269
+ DIExpression *DIExpression::foldConstantMath () {
2270
+
2271
+ SmallVector<uint64_t , 8 > WorkingOps (Elements.begin (), Elements.end ());
2272
+ uint64_t Loc = 0 ;
2273
+ canonicalizeDwarfOperations (WorkingOps);
2274
+ DIExpressionCursor Cursor (WorkingOps);
2275
+
2276
+ while (Loc < WorkingOps.size ()) {
2277
+
2278
+ auto Op1 = Cursor.peek ();
2279
+ // Expression has no operations, exit.
2280
+ if (!Op1)
2281
+ break ;
2282
+ auto Op1Raw = Op1->getOp ();
2283
+ auto Op1Arg = Op1->getArg (0 );
2284
+
2285
+ if (!isConstantVal (Op1Raw)) {
2286
+ // Early exit, all of the following patterns start with a constant value.
2287
+ consumeOneOperator (Cursor, Loc, *Op1);
2288
+ continue ;
2289
+ }
2290
+
2291
+ auto Op2 = Cursor.peekNext ();
2292
+ // All following patterns require at least 2 Operations, exit.
2293
+ if (!Op2)
2294
+ break ;
2295
+ auto Op2Raw = Op2->getOp ();
2296
+
2297
+ if (tryFoldNoOpMath (Op1Raw, Op1Arg, Op2Raw, Loc, Cursor, WorkingOps))
2298
+ continue ;
2299
+
2300
+ auto Op2Arg = Op2->getArg (0 );
2301
+
2302
+ auto Op3 = Cursor.peekNextN (2 );
2303
+ // Op2 could still match a pattern, skip iteration.
2304
+ if (!Op3) {
2305
+ consumeOneOperator (Cursor, Loc, *Op1);
2306
+ continue ;
2307
+ }
2308
+ auto Op3Raw = Op3->getOp ();
2309
+
2310
+ if (tryFoldConstants (Op1, Op1Raw, Op1Arg, Op2Raw, Op2Arg, Op3Raw, Loc,
2311
+ Cursor, WorkingOps))
2312
+ continue ;
2313
+
2314
+ auto Op3Arg = Op3->getArg (0 );
2315
+
2316
+ auto Op4 = Cursor.peekNextN (3 );
2317
+ // Op2 and Op3 could still match a pattern, skip iteration.
2318
+ if (!Op4) {
2319
+ consumeOneOperator (Cursor, Loc, *Op1);
2320
+ continue ;
2321
+ }
2322
+ auto Op4Raw = Op4->getOp ();
2323
+
2324
+ if (tryFoldCommutativeMath (Op1Raw, Op1Arg, Op2Raw, Op2Arg, Op3Raw, Op3Arg,
2325
+ Op4Raw, Loc, Cursor, WorkingOps))
2326
+ continue ;
2327
+
2328
+ auto Op5 = Cursor.peekNextN (4 );
2329
+ if (!Op5) {
2330
+ consumeOneOperator (Cursor, Loc, *Op1);
2331
+ continue ;
2332
+ }
2333
+ auto Op5Raw = Op5->getOp ();
2334
+ auto Op5Arg = Op5->getArg (0 );
2335
+ auto Op6 = Cursor.peekNextN (5 );
2336
+ if (!Op6) {
2337
+ consumeOneOperator (Cursor, Loc, *Op1);
2338
+ continue ;
2339
+ }
2340
+ auto Op6Raw = Op6->getOp ();
2341
+ if (tryFoldCommutativeMathWithArgInBetween (Op1Raw, Op1Arg, Op2Raw, Op3Raw,
2342
+ Op4Raw, Op5Raw, Op5Arg, Op6Raw,
2343
+ Loc, Cursor, WorkingOps))
2344
+ continue ;
2345
+
2346
+ consumeOneOperator (Cursor, Loc, *Op1);
2347
+ }
2348
+ optimizeDwarfOperations (WorkingOps);
2349
+ auto *Result = DIExpression::get (getContext (), WorkingOps);
2350
+ assert (Result->isValid () && " concatenated expression is not valid" );
2351
+ return Result;
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