@@ -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,321 @@ DIExpression::constantFold(const ConstantInt *CI) {
2011
2010
ConstantInt::get (getContext (), NewInt)};
2012
2011
}
2013
2012
2013
+ static bool isConstantVal (uint64_t Op) {
2014
+ return Op == dwarf::DW_OP_constu || Op == dwarf::DW_OP_consts;
2015
+ }
2016
+
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
+ static std::optional<uint64_t >
2033
+ foldOperationIfPossible (uint64_t Op, uint64_t Operand1, uint64_t Operand2) {
2034
+ switch (Op) {
2035
+ case dwarf::DW_OP_plus:
2036
+ return Operand1 + Operand2;
2037
+ case dwarf::DW_OP_minus:
2038
+ return Operand1 - Operand2;
2039
+ case dwarf::DW_OP_shl:
2040
+ return Operand1 << Operand2;
2041
+ case dwarf::DW_OP_shr:
2042
+ return Operand1 >> Operand2;
2043
+ case dwarf::DW_OP_mul:
2044
+ return Operand1 * Operand2;
2045
+ case dwarf::DW_OP_div:
2046
+ return Operand1 / Operand2;
2047
+ default :
2048
+ return std::nullopt;
2049
+ }
2050
+ }
2051
+
2052
+ static bool operationsAreFoldableAndCommutative (uint64_t Op1, uint64_t Op2) {
2053
+ if (Op1 != Op2)
2054
+ return false ;
2055
+ switch (Op1) {
2056
+ case dwarf::DW_OP_plus:
2057
+ case dwarf::DW_OP_mul:
2058
+ return true ;
2059
+ default :
2060
+ return false ;
2061
+ }
2062
+ }
2063
+
2064
+ static void consumeOneOperator (DIExpressionCursor &Cursor, uint64_t &Loc,
2065
+ const DIExpression::ExprOperand &Op) {
2066
+ Cursor.consume (1 );
2067
+ Loc = Loc + Op.getSize ();
2068
+ }
2069
+
2070
+ static void startFromBeginning (uint64_t &Loc, DIExpressionCursor &Cursor,
2071
+ ArrayRef<uint64_t > WorkingOps) {
2072
+ Cursor.assignNewExpr (WorkingOps);
2073
+ Loc = 0 ;
2074
+ }
2075
+
2076
+ static void moveCursorToCurrentOp (uint64_t &Loc, DIExpressionCursor &Cursor,
2077
+ ArrayRef<uint64_t > WorkingOps,
2078
+ uint32_t NumOfOpsConsumed) {
2079
+ Cursor.assignNewExpr (WorkingOps);
2080
+ Cursor.consume (NumOfOpsConsumed);
2081
+ assert (Cursor.peek ()->getOp () == WorkingOps[Loc] &&
2082
+ " Cursor position does not match position of iterator 'Loc' to "
2083
+ " WorkingOps" );
2084
+ }
2085
+
2086
+ // This function will canonicalize:
2087
+ // 1. DW_OP_plus_uconst to DW_OP_constu <const-val> DW_OP_plus
2088
+ // 2. DW_OP_lit<n> to DW_OP_constu <n>
2089
+ static void canonicalizeDwarfOperations (SmallVectorImpl<uint64_t > &WorkingOps) {
2090
+ DIExpressionCursor Cursor (WorkingOps);
2091
+ uint64_t Loc = 0 ;
2092
+ uint32_t NumOfOpsConsumed = 0 ;
2093
+ while (Loc < WorkingOps.size ()) {
2094
+ auto Op = Cursor.peek ();
2095
+ // Expression has no operations, break.
2096
+ if (!Op)
2097
+ break ;
2098
+ auto OpRaw = Op->getOp ();
2099
+ auto OpArg = Op->getArg (0 );
2100
+
2101
+ if (OpRaw >= dwarf::DW_OP_lit0 && OpRaw <= dwarf::DW_OP_lit31) {
2102
+ WorkingOps[Loc] = dwarf::DW_OP_constu;
2103
+ WorkingOps.insert (WorkingOps.begin () + Loc + 1 ,
2104
+ OpRaw - dwarf::DW_OP_lit0);
2105
+ } else if (OpRaw == dwarf::DW_OP_plus_uconst) {
2106
+ WorkingOps[Loc] = dwarf::DW_OP_constu;
2107
+ WorkingOps[Loc + 1 ] = OpArg;
2108
+ WorkingOps.insert (WorkingOps.begin () + Loc + 2 , dwarf::DW_OP_plus);
2109
+ moveCursorToCurrentOp (Loc, Cursor, WorkingOps, NumOfOpsConsumed);
2110
+ }
2111
+ consumeOneOperator (Cursor, Loc, *Cursor.peek ());
2112
+ NumOfOpsConsumed++;
2113
+ }
2114
+ }
2115
+
2116
+ // This function will convert:
2117
+ // DW_OP_constu <const-val> DW_OP_plus to DW_OP_plus_uconst
2118
+ static void optimizeDwarfOperations (SmallVectorImpl<uint64_t > &WorkingOps) {
2119
+ DIExpressionCursor Cursor (WorkingOps);
2120
+ uint64_t Loc = 0 ;
2121
+ uint32_t NumOfOpsConsumed = 0 ;
2122
+ while (Loc < WorkingOps.size ()) {
2123
+ auto Op1 = Cursor.peek ();
2124
+ // Expression has no operations, exit.
2125
+ if (!Op1)
2126
+ break ;
2127
+ auto Op1Raw = Op1->getOp ();
2128
+ auto Op1Arg = Op1->getArg (0 );
2129
+
2130
+ if (Op1Raw == dwarf::DW_OP_constu && Op1Arg == 0 ) {
2131
+ WorkingOps[Loc] = dwarf::DW_OP_lit0;
2132
+ WorkingOps.erase (WorkingOps.begin () + Loc + 1 );
2133
+ moveCursorToCurrentOp (Loc, Cursor, WorkingOps, NumOfOpsConsumed);
2134
+ continue ;
2135
+ }
2136
+
2137
+ auto Op2 = Cursor.peekNext ();
2138
+ // Expression has no more operations, exit.
2139
+ if (!Op2)
2140
+ break ;
2141
+ auto Op2Raw = Op2->getOp ();
2142
+
2143
+ if (Op1Raw == dwarf::DW_OP_constu && Op2Raw == dwarf::DW_OP_plus) {
2144
+ WorkingOps.erase (WorkingOps.begin () + Loc + 2 );
2145
+ WorkingOps[Loc] = dwarf::DW_OP_plus_uconst;
2146
+ WorkingOps[Loc + 1 ] = Op1Arg;
2147
+ moveCursorToCurrentOp (Loc, Cursor, WorkingOps, NumOfOpsConsumed);
2148
+ }
2149
+ consumeOneOperator (Cursor, Loc, *Cursor.peek ());
2150
+ NumOfOpsConsumed++;
2151
+ }
2152
+ }
2153
+
2154
+ // {DW_OP_const[u, s], 0, DW_OP_[plus, minus, shl, shr]} -> {}
2155
+ // {DW_OP_const[u, s], 1, DW_OP_[mul, div]} -> {}
2156
+ static bool tryFoldNoOpMath (uint64_t Op1Raw, uint64_t Op1Arg, uint64_t Op2Raw,
2157
+ uint64_t &Loc, DIExpressionCursor &Cursor,
2158
+ SmallVectorImpl<uint64_t > &WorkingOps) {
2159
+ if (isConstantVal (Op1Raw) && isNeutralElement (Op2Raw, Op1Arg)) {
2160
+ WorkingOps.erase (WorkingOps.begin () + Loc, WorkingOps.begin () + Loc + 3 );
2161
+ startFromBeginning (Loc, Cursor, WorkingOps);
2162
+ return true ;
2163
+ }
2164
+ return false ;
2165
+ }
2166
+
2167
+ // {DW_OP_const[u, s], Const1, DW_OP_const[u, s], Const2, DW_OP_[plus,
2168
+ // minus, mul, div, shl, shr] -> {DW_OP_constu, Const1 [+, -, *, /, <<, >>]
2169
+ // Const2}
2170
+ static bool tryFoldConstants (std::optional<DIExpression::ExprOperand> Op1,
2171
+ uint64_t Op1Raw, uint64_t Op1Arg, uint64_t Op2Raw,
2172
+ uint64_t Op2Arg, uint64_t Op3Raw, uint64_t &Loc,
2173
+ DIExpressionCursor &Cursor,
2174
+ SmallVectorImpl<uint64_t > &WorkingOps) {
2175
+ if (isConstantVal (Op1Raw) && isConstantVal (Op2Raw)) {
2176
+ auto Result = foldOperationIfPossible (Op3Raw, Op1Arg, Op2Arg);
2177
+ if (!Result) {
2178
+ consumeOneOperator (Cursor, Loc, *Op1);
2179
+ return true ;
2180
+ }
2181
+ WorkingOps.erase (WorkingOps.begin () + Loc + 2 ,
2182
+ WorkingOps.begin () + Loc + 5 );
2183
+ WorkingOps[Loc] = dwarf::DW_OP_constu;
2184
+ WorkingOps[Loc + 1 ] = *Result;
2185
+ startFromBeginning (Loc, Cursor, WorkingOps);
2186
+ return true ;
2187
+ }
2188
+ return false ;
2189
+ }
2190
+
2191
+ // {DW_OP_const[u, s], Const1, DW_OP_[plus, mul], DW_OP_const[u, s], Const2,
2192
+ // DW_OP_[plus, mul]} -> {DW_OP_constu, Const1 [+, *] Const2, DW_OP_[plus, mul]}
2193
+ static bool tryFoldCommutativeMath (uint64_t Op1Raw, uint64_t Op1Arg,
2194
+ uint64_t Op2Raw, uint64_t Op2Arg,
2195
+ uint64_t Op3Raw, uint64_t Op3Arg,
2196
+ uint64_t Op4Raw, uint64_t &Loc,
2197
+ DIExpressionCursor &Cursor,
2198
+ SmallVectorImpl<uint64_t > &WorkingOps) {
2199
+
2200
+ if (isConstantVal (Op1Raw) && isConstantVal (Op3Raw) &&
2201
+ operationsAreFoldableAndCommutative (Op2Raw, Op4Raw)) {
2202
+ auto Result = foldOperationIfPossible (Op2Raw, Op1Arg, Op3Arg);
2203
+ if (!Result)
2204
+ llvm_unreachable (
2205
+ " Something went very wrong here! This should always work" );
2206
+ WorkingOps.erase (WorkingOps.begin () + Loc + 3 ,
2207
+ WorkingOps.begin () + Loc + 6 );
2208
+ WorkingOps[Loc] = dwarf::DW_OP_constu;
2209
+ WorkingOps[Loc + 1 ] = *Result;
2210
+ startFromBeginning (Loc, Cursor, WorkingOps);
2211
+ return true ;
2212
+ }
2213
+ return false ;
2214
+ }
2215
+
2216
+ // {DW_OP_const[u, s], Const1, DW_OP_[plus, mul], DW_OP_LLVM_arg, Arg1,
2217
+ // DW_OP_[plus, mul], DW_OP_const[u, s], Const2, DW_OP_[plus, mul]} ->
2218
+ // {DW_OP_constu, Const1 [+, *] Const2, DW_OP_[plus, mul], DW_OP_LLVM_arg,
2219
+ // Arg1, DW_OP_[plus, mul]}
2220
+ static bool tryFoldCommutativeMathWithArgInBetween (
2221
+ uint64_t Op1Raw, uint64_t Op1Arg, uint64_t Op2Raw, uint64_t Op3Raw,
2222
+ uint64_t Op4Raw, uint64_t Op5Raw, uint64_t Op5Arg, uint64_t Op6Raw,
2223
+ uint64_t &Loc, DIExpressionCursor &Cursor,
2224
+ SmallVectorImpl<uint64_t > &WorkingOps) {
2225
+ if (isConstantVal (Op1Raw) && Op3Raw == dwarf::DW_OP_LLVM_arg &&
2226
+ isConstantVal (Op5Raw) &&
2227
+ operationsAreFoldableAndCommutative (Op2Raw, Op4Raw) &&
2228
+ operationsAreFoldableAndCommutative (Op4Raw, Op6Raw)) {
2229
+ auto Result = foldOperationIfPossible (Op2Raw, Op1Arg, Op5Arg);
2230
+ if (!Result)
2231
+ llvm_unreachable (
2232
+ " Something went very wrong here! This should always work" );
2233
+ WorkingOps.erase (WorkingOps.begin () + Loc + 6 ,
2234
+ WorkingOps.begin () + Loc + 9 );
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
+ DIExpression *DIExpression::foldConstantMath () {
2244
+
2245
+ SmallVector<uint64_t , 8 > WorkingOps (Elements.begin (), Elements.end ());
2246
+ uint64_t Loc = 0 ;
2247
+ canonicalizeDwarfOperations (WorkingOps);
2248
+ DIExpressionCursor Cursor (WorkingOps);
2249
+
2250
+ while (Loc < WorkingOps.size ()) {
2251
+
2252
+ auto Op1 = Cursor.peek ();
2253
+ // Expression has no operations, exit.
2254
+ if (!Op1)
2255
+ break ;
2256
+ auto Op1Raw = Op1->getOp ();
2257
+ auto Op1Arg = Op1->getArg (0 );
2258
+
2259
+ if (!isConstantVal (Op1Raw)) {
2260
+ // Early exit, all of the following patterns start with a constant value.
2261
+ consumeOneOperator (Cursor, Loc, *Op1);
2262
+ continue ;
2263
+ }
2264
+
2265
+ auto Op2 = Cursor.peekNext ();
2266
+ // All following patterns require at least 2 Operations, exit.
2267
+ if (!Op2)
2268
+ break ;
2269
+ auto Op2Raw = Op2->getOp ();
2270
+
2271
+ if (tryFoldNoOpMath (Op1Raw, Op1Arg, Op2Raw, Loc, Cursor, WorkingOps))
2272
+ continue ;
2273
+
2274
+ auto Op2Arg = Op2->getArg (0 );
2275
+
2276
+ auto Op3 = Cursor.peekNextN (2 );
2277
+ // Op2 could still match a pattern, skip iteration.
2278
+ if (!Op3) {
2279
+ consumeOneOperator (Cursor, Loc, *Op1);
2280
+ continue ;
2281
+ }
2282
+ auto Op3Raw = Op3->getOp ();
2283
+
2284
+ if (tryFoldConstants (Op1, Op1Raw, Op1Arg, Op2Raw, Op2Arg, Op3Raw, Loc,
2285
+ Cursor, WorkingOps))
2286
+ continue ;
2287
+
2288
+ auto Op3Arg = Op3->getArg (0 );
2289
+
2290
+ auto Op4 = Cursor.peekNextN (3 );
2291
+ // Op2 and Op3 could still match a pattern, skip iteration.
2292
+ if (!Op4) {
2293
+ consumeOneOperator (Cursor, Loc, *Op1);
2294
+ continue ;
2295
+ }
2296
+ auto Op4Raw = Op4->getOp ();
2297
+
2298
+ if (tryFoldCommutativeMath (Op1Raw, Op1Arg, Op2Raw, Op2Arg, Op3Raw, Op3Arg,
2299
+ Op4Raw, Loc, Cursor, WorkingOps))
2300
+ continue ;
2301
+
2302
+ auto Op5 = Cursor.peekNextN (4 );
2303
+ if (!Op5) {
2304
+ consumeOneOperator (Cursor, Loc, *Op1);
2305
+ continue ;
2306
+ }
2307
+ auto Op5Raw = Op5->getOp ();
2308
+ auto Op5Arg = Op5->getArg (0 );
2309
+ auto Op6 = Cursor.peekNextN (5 );
2310
+ if (!Op6) {
2311
+ consumeOneOperator (Cursor, Loc, *Op1);
2312
+ continue ;
2313
+ }
2314
+ auto Op6Raw = Op6->getOp ();
2315
+ if (tryFoldCommutativeMathWithArgInBetween (Op1Raw, Op1Arg, Op2Raw, Op3Raw,
2316
+ Op4Raw, Op5Raw, Op5Arg, Op6Raw,
2317
+ Loc, Cursor, WorkingOps))
2318
+ continue ;
2319
+
2320
+ consumeOneOperator (Cursor, Loc, *Op1);
2321
+ }
2322
+ optimizeDwarfOperations (WorkingOps);
2323
+ auto *Result = DIExpression::get (getContext (), WorkingOps);
2324
+ assert (Result->isValid () && " concatenated expression is not valid" );
2325
+ return Result;
2326
+ }
2327
+
2014
2328
uint64_t DIExpression::getNumLocationOperands () const {
2015
2329
uint64_t Result = 0 ;
2016
2330
for (auto ExprOp : expr_ops ())
0 commit comments