xref: /freebsd-src/contrib/llvm-project/llvm/lib/IR/DIExpressionOptimizer.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===- DIExpressionOptimizer.cpp - Constant folding of DIExpressions ------===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric //
9*0fca6ea1SDimitry Andric // This file implements functions to constant fold DIExpressions. Which were
10*0fca6ea1SDimitry Andric // declared in DIExpressionOptimizer.h
11*0fca6ea1SDimitry Andric //
12*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
13*0fca6ea1SDimitry Andric 
14*0fca6ea1SDimitry Andric #include "llvm/BinaryFormat/Dwarf.h"
15*0fca6ea1SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h"
16*0fca6ea1SDimitry Andric 
17*0fca6ea1SDimitry Andric using namespace llvm;
18*0fca6ea1SDimitry Andric 
19*0fca6ea1SDimitry Andric /// Returns true if the Op is a DW_OP_constu.
20*0fca6ea1SDimitry Andric static std::optional<uint64_t> isConstantVal(DIExpression::ExprOperand Op) {
21*0fca6ea1SDimitry Andric   if (Op.getOp() == dwarf::DW_OP_constu)
22*0fca6ea1SDimitry Andric     return Op.getArg(0);
23*0fca6ea1SDimitry Andric   return std::nullopt;
24*0fca6ea1SDimitry Andric }
25*0fca6ea1SDimitry Andric 
26*0fca6ea1SDimitry Andric /// Returns true if an operation and operand result in a No Op.
27*0fca6ea1SDimitry Andric static bool isNeutralElement(uint64_t Op, uint64_t Val) {
28*0fca6ea1SDimitry Andric   switch (Op) {
29*0fca6ea1SDimitry Andric   case dwarf::DW_OP_plus:
30*0fca6ea1SDimitry Andric   case dwarf::DW_OP_minus:
31*0fca6ea1SDimitry Andric   case dwarf::DW_OP_shl:
32*0fca6ea1SDimitry Andric   case dwarf::DW_OP_shr:
33*0fca6ea1SDimitry Andric     return Val == 0;
34*0fca6ea1SDimitry Andric   case dwarf::DW_OP_mul:
35*0fca6ea1SDimitry Andric   case dwarf::DW_OP_div:
36*0fca6ea1SDimitry Andric     return Val == 1;
37*0fca6ea1SDimitry Andric   default:
38*0fca6ea1SDimitry Andric     return false;
39*0fca6ea1SDimitry Andric   }
40*0fca6ea1SDimitry Andric }
41*0fca6ea1SDimitry Andric 
42*0fca6ea1SDimitry Andric /// Try to fold \p Const1 and \p Const2 by applying \p Operator and returning
43*0fca6ea1SDimitry Andric /// the result, if there is an overflow, return a std::nullopt.
44*0fca6ea1SDimitry Andric static std::optional<uint64_t>
45*0fca6ea1SDimitry Andric foldOperationIfPossible(uint64_t Const1, uint64_t Const2,
46*0fca6ea1SDimitry Andric                         dwarf::LocationAtom Operator) {
47*0fca6ea1SDimitry Andric 
48*0fca6ea1SDimitry Andric   bool ResultOverflowed;
49*0fca6ea1SDimitry Andric   switch (Operator) {
50*0fca6ea1SDimitry Andric   case dwarf::DW_OP_plus: {
51*0fca6ea1SDimitry Andric     auto Result = SaturatingAdd(Const1, Const2, &ResultOverflowed);
52*0fca6ea1SDimitry Andric     if (ResultOverflowed)
53*0fca6ea1SDimitry Andric       return std::nullopt;
54*0fca6ea1SDimitry Andric     return Result;
55*0fca6ea1SDimitry Andric   }
56*0fca6ea1SDimitry Andric   case dwarf::DW_OP_minus: {
57*0fca6ea1SDimitry Andric     if (Const1 < Const2)
58*0fca6ea1SDimitry Andric       return std::nullopt;
59*0fca6ea1SDimitry Andric     return Const1 - Const2;
60*0fca6ea1SDimitry Andric   }
61*0fca6ea1SDimitry Andric   case dwarf::DW_OP_shl: {
62*0fca6ea1SDimitry Andric     if ((uint64_t)countl_zero(Const1) < Const2)
63*0fca6ea1SDimitry Andric       return std::nullopt;
64*0fca6ea1SDimitry Andric     return Const1 << Const2;
65*0fca6ea1SDimitry Andric   }
66*0fca6ea1SDimitry Andric   case dwarf::DW_OP_shr: {
67*0fca6ea1SDimitry Andric     if ((uint64_t)countr_zero(Const1) < Const2)
68*0fca6ea1SDimitry Andric       return std::nullopt;
69*0fca6ea1SDimitry Andric     return Const1 >> Const2;
70*0fca6ea1SDimitry Andric   }
71*0fca6ea1SDimitry Andric   case dwarf::DW_OP_mul: {
72*0fca6ea1SDimitry Andric     auto Result = SaturatingMultiply(Const1, Const2, &ResultOverflowed);
73*0fca6ea1SDimitry Andric     if (ResultOverflowed)
74*0fca6ea1SDimitry Andric       return std::nullopt;
75*0fca6ea1SDimitry Andric     return Result;
76*0fca6ea1SDimitry Andric   }
77*0fca6ea1SDimitry Andric   case dwarf::DW_OP_div: {
78*0fca6ea1SDimitry Andric     if (Const2)
79*0fca6ea1SDimitry Andric       return Const1 / Const2;
80*0fca6ea1SDimitry Andric     return std::nullopt;
81*0fca6ea1SDimitry Andric   }
82*0fca6ea1SDimitry Andric   default:
83*0fca6ea1SDimitry Andric     return std::nullopt;
84*0fca6ea1SDimitry Andric   }
85*0fca6ea1SDimitry Andric }
86*0fca6ea1SDimitry Andric 
87*0fca6ea1SDimitry Andric /// Returns true if the two operations \p Operator1 and \p Operator2 are
88*0fca6ea1SDimitry Andric /// commutative and can be folded.
89*0fca6ea1SDimitry Andric static bool operationsAreFoldableAndCommutative(dwarf::LocationAtom Operator1,
90*0fca6ea1SDimitry Andric                                                 dwarf::LocationAtom Operator2) {
91*0fca6ea1SDimitry Andric   return Operator1 == Operator2 &&
92*0fca6ea1SDimitry Andric          (Operator1 == dwarf::DW_OP_plus || Operator1 == dwarf::DW_OP_mul);
93*0fca6ea1SDimitry Andric }
94*0fca6ea1SDimitry Andric 
95*0fca6ea1SDimitry Andric /// Consume one operator and its operand(s).
96*0fca6ea1SDimitry Andric static void consumeOneOperator(DIExpressionCursor &Cursor, uint64_t &Loc,
97*0fca6ea1SDimitry Andric                                const DIExpression::ExprOperand &Op) {
98*0fca6ea1SDimitry Andric   Cursor.consume(1);
99*0fca6ea1SDimitry Andric   Loc = Loc + Op.getSize();
100*0fca6ea1SDimitry Andric }
101*0fca6ea1SDimitry Andric 
102*0fca6ea1SDimitry Andric /// Reset the Cursor to the beginning of the WorkingOps.
103*0fca6ea1SDimitry Andric void startFromBeginning(uint64_t &Loc, DIExpressionCursor &Cursor,
104*0fca6ea1SDimitry Andric                         ArrayRef<uint64_t> WorkingOps) {
105*0fca6ea1SDimitry Andric   Cursor.assignNewExpr(WorkingOps);
106*0fca6ea1SDimitry Andric   Loc = 0;
107*0fca6ea1SDimitry Andric }
108*0fca6ea1SDimitry Andric 
109*0fca6ea1SDimitry Andric /// This function will canonicalize:
110*0fca6ea1SDimitry Andric /// 1. DW_OP_plus_uconst to DW_OP_constu <const-val> DW_OP_plus
111*0fca6ea1SDimitry Andric /// 2. DW_OP_lit<n> to DW_OP_constu <n>
112*0fca6ea1SDimitry Andric static SmallVector<uint64_t>
113*0fca6ea1SDimitry Andric canonicalizeDwarfOperations(ArrayRef<uint64_t> WorkingOps) {
114*0fca6ea1SDimitry Andric   DIExpressionCursor Cursor(WorkingOps);
115*0fca6ea1SDimitry Andric   uint64_t Loc = 0;
116*0fca6ea1SDimitry Andric   SmallVector<uint64_t> ResultOps;
117*0fca6ea1SDimitry Andric   while (Loc < WorkingOps.size()) {
118*0fca6ea1SDimitry Andric     auto Op = Cursor.peek();
119*0fca6ea1SDimitry Andric     /// Expression has no operations, break.
120*0fca6ea1SDimitry Andric     if (!Op)
121*0fca6ea1SDimitry Andric       break;
122*0fca6ea1SDimitry Andric     auto OpRaw = Op->getOp();
123*0fca6ea1SDimitry Andric 
124*0fca6ea1SDimitry Andric     if (OpRaw >= dwarf::DW_OP_lit0 && OpRaw <= dwarf::DW_OP_lit31) {
125*0fca6ea1SDimitry Andric       ResultOps.push_back(dwarf::DW_OP_constu);
126*0fca6ea1SDimitry Andric       ResultOps.push_back(OpRaw - dwarf::DW_OP_lit0);
127*0fca6ea1SDimitry Andric       consumeOneOperator(Cursor, Loc, *Cursor.peek());
128*0fca6ea1SDimitry Andric       continue;
129*0fca6ea1SDimitry Andric     }
130*0fca6ea1SDimitry Andric     if (OpRaw == dwarf::DW_OP_plus_uconst) {
131*0fca6ea1SDimitry Andric       ResultOps.push_back(dwarf::DW_OP_constu);
132*0fca6ea1SDimitry Andric       ResultOps.push_back(Op->getArg(0));
133*0fca6ea1SDimitry Andric       ResultOps.push_back(dwarf::DW_OP_plus);
134*0fca6ea1SDimitry Andric       consumeOneOperator(Cursor, Loc, *Cursor.peek());
135*0fca6ea1SDimitry Andric       continue;
136*0fca6ea1SDimitry Andric     }
137*0fca6ea1SDimitry Andric     uint64_t PrevLoc = Loc;
138*0fca6ea1SDimitry Andric     consumeOneOperator(Cursor, Loc, *Cursor.peek());
139*0fca6ea1SDimitry Andric     ResultOps.append(WorkingOps.begin() + PrevLoc, WorkingOps.begin() + Loc);
140*0fca6ea1SDimitry Andric   }
141*0fca6ea1SDimitry Andric   return ResultOps;
142*0fca6ea1SDimitry Andric }
143*0fca6ea1SDimitry Andric 
144*0fca6ea1SDimitry Andric /// This function will convert:
145*0fca6ea1SDimitry Andric /// 1. DW_OP_constu <const-val> DW_OP_plus to DW_OP_plus_uconst
146*0fca6ea1SDimitry Andric /// 2. DW_OP_constu, 0 to DW_OP_lit0
147*0fca6ea1SDimitry Andric static SmallVector<uint64_t>
148*0fca6ea1SDimitry Andric optimizeDwarfOperations(ArrayRef<uint64_t> WorkingOps) {
149*0fca6ea1SDimitry Andric   DIExpressionCursor Cursor(WorkingOps);
150*0fca6ea1SDimitry Andric   uint64_t Loc = 0;
151*0fca6ea1SDimitry Andric   SmallVector<uint64_t> ResultOps;
152*0fca6ea1SDimitry Andric   while (Loc < WorkingOps.size()) {
153*0fca6ea1SDimitry Andric     auto Op1 = Cursor.peek();
154*0fca6ea1SDimitry Andric     /// Expression has no operations, exit.
155*0fca6ea1SDimitry Andric     if (!Op1)
156*0fca6ea1SDimitry Andric       break;
157*0fca6ea1SDimitry Andric     auto Op1Raw = Op1->getOp();
158*0fca6ea1SDimitry Andric 
159*0fca6ea1SDimitry Andric     if (Op1Raw == dwarf::DW_OP_constu && Op1->getArg(0) == 0) {
160*0fca6ea1SDimitry Andric       ResultOps.push_back(dwarf::DW_OP_lit0);
161*0fca6ea1SDimitry Andric       consumeOneOperator(Cursor, Loc, *Cursor.peek());
162*0fca6ea1SDimitry Andric       continue;
163*0fca6ea1SDimitry Andric     }
164*0fca6ea1SDimitry Andric 
165*0fca6ea1SDimitry Andric     auto Op2 = Cursor.peekNext();
166*0fca6ea1SDimitry Andric     /// Expression has no more operations, copy into ResultOps and exit.
167*0fca6ea1SDimitry Andric     if (!Op2) {
168*0fca6ea1SDimitry Andric       uint64_t PrevLoc = Loc;
169*0fca6ea1SDimitry Andric       consumeOneOperator(Cursor, Loc, *Cursor.peek());
170*0fca6ea1SDimitry Andric       ResultOps.append(WorkingOps.begin() + PrevLoc, WorkingOps.begin() + Loc);
171*0fca6ea1SDimitry Andric       break;
172*0fca6ea1SDimitry Andric     }
173*0fca6ea1SDimitry Andric     auto Op2Raw = Op2->getOp();
174*0fca6ea1SDimitry Andric 
175*0fca6ea1SDimitry Andric     if (Op1Raw == dwarf::DW_OP_constu && Op2Raw == dwarf::DW_OP_plus) {
176*0fca6ea1SDimitry Andric       ResultOps.push_back(dwarf::DW_OP_plus_uconst);
177*0fca6ea1SDimitry Andric       ResultOps.push_back(Op1->getArg(0));
178*0fca6ea1SDimitry Andric       consumeOneOperator(Cursor, Loc, *Cursor.peek());
179*0fca6ea1SDimitry Andric       consumeOneOperator(Cursor, Loc, *Cursor.peek());
180*0fca6ea1SDimitry Andric       continue;
181*0fca6ea1SDimitry Andric     }
182*0fca6ea1SDimitry Andric     uint64_t PrevLoc = Loc;
183*0fca6ea1SDimitry Andric     consumeOneOperator(Cursor, Loc, *Cursor.peek());
184*0fca6ea1SDimitry Andric     ResultOps.append(WorkingOps.begin() + PrevLoc, WorkingOps.begin() + Loc);
185*0fca6ea1SDimitry Andric   }
186*0fca6ea1SDimitry Andric   return ResultOps;
187*0fca6ea1SDimitry Andric }
188*0fca6ea1SDimitry Andric 
189*0fca6ea1SDimitry Andric /// {DW_OP_constu, 0, DW_OP_[plus, minus, shl, shr]} -> {}
190*0fca6ea1SDimitry Andric /// {DW_OP_constu, 1, DW_OP_[mul, div]} -> {}
191*0fca6ea1SDimitry Andric static bool tryFoldNoOpMath(uint64_t Const1,
192*0fca6ea1SDimitry Andric                             ArrayRef<DIExpression::ExprOperand> Ops,
193*0fca6ea1SDimitry Andric                             uint64_t &Loc, DIExpressionCursor &Cursor,
194*0fca6ea1SDimitry Andric                             SmallVectorImpl<uint64_t> &WorkingOps) {
195*0fca6ea1SDimitry Andric 
196*0fca6ea1SDimitry Andric   if (isNeutralElement(Ops[1].getOp(), Const1)) {
197*0fca6ea1SDimitry Andric     WorkingOps.erase(WorkingOps.begin() + Loc, WorkingOps.begin() + Loc + 3);
198*0fca6ea1SDimitry Andric     startFromBeginning(Loc, Cursor, WorkingOps);
199*0fca6ea1SDimitry Andric     return true;
200*0fca6ea1SDimitry Andric   }
201*0fca6ea1SDimitry Andric   return false;
202*0fca6ea1SDimitry Andric }
203*0fca6ea1SDimitry Andric 
204*0fca6ea1SDimitry Andric /// {DW_OP_constu, Const1, DW_OP_constu, Const2, DW_OP_[plus,
205*0fca6ea1SDimitry Andric /// minus, mul, div, shl, shr] -> {DW_OP_constu, Const1 [+, -, *, /, <<, >>]
206*0fca6ea1SDimitry Andric /// Const2}
207*0fca6ea1SDimitry Andric static bool tryFoldConstants(uint64_t Const1,
208*0fca6ea1SDimitry Andric                              ArrayRef<DIExpression::ExprOperand> Ops,
209*0fca6ea1SDimitry Andric                              uint64_t &Loc, DIExpressionCursor &Cursor,
210*0fca6ea1SDimitry Andric                              SmallVectorImpl<uint64_t> &WorkingOps) {
211*0fca6ea1SDimitry Andric 
212*0fca6ea1SDimitry Andric   auto Const2 = isConstantVal(Ops[1]);
213*0fca6ea1SDimitry Andric   if (!Const2)
214*0fca6ea1SDimitry Andric     return false;
215*0fca6ea1SDimitry Andric 
216*0fca6ea1SDimitry Andric   auto Result = foldOperationIfPossible(
217*0fca6ea1SDimitry Andric       Const1, *Const2, static_cast<dwarf::LocationAtom>(Ops[2].getOp()));
218*0fca6ea1SDimitry Andric   if (!Result) {
219*0fca6ea1SDimitry Andric     consumeOneOperator(Cursor, Loc, Ops[0]);
220*0fca6ea1SDimitry Andric     return true;
221*0fca6ea1SDimitry Andric   }
222*0fca6ea1SDimitry Andric   WorkingOps.erase(WorkingOps.begin() + Loc + 2, WorkingOps.begin() + Loc + 5);
223*0fca6ea1SDimitry Andric   WorkingOps[Loc] = dwarf::DW_OP_constu;
224*0fca6ea1SDimitry Andric   WorkingOps[Loc + 1] = *Result;
225*0fca6ea1SDimitry Andric   startFromBeginning(Loc, Cursor, WorkingOps);
226*0fca6ea1SDimitry Andric   return true;
227*0fca6ea1SDimitry Andric }
228*0fca6ea1SDimitry Andric 
229*0fca6ea1SDimitry Andric /// {DW_OP_constu, Const1, DW_OP_[plus, mul], DW_OP_constu, Const2,
230*0fca6ea1SDimitry Andric /// DW_OP_[plus, mul]} -> {DW_OP_constu, Const1 [+, *] Const2, DW_OP_[plus,
231*0fca6ea1SDimitry Andric /// mul]}
232*0fca6ea1SDimitry Andric static bool tryFoldCommutativeMath(uint64_t Const1,
233*0fca6ea1SDimitry Andric                                    ArrayRef<DIExpression::ExprOperand> Ops,
234*0fca6ea1SDimitry Andric                                    uint64_t &Loc, DIExpressionCursor &Cursor,
235*0fca6ea1SDimitry Andric                                    SmallVectorImpl<uint64_t> &WorkingOps) {
236*0fca6ea1SDimitry Andric 
237*0fca6ea1SDimitry Andric   auto Const2 = isConstantVal(Ops[2]);
238*0fca6ea1SDimitry Andric   auto Operand1 = static_cast<dwarf::LocationAtom>(Ops[1].getOp());
239*0fca6ea1SDimitry Andric   auto Operand2 = static_cast<dwarf::LocationAtom>(Ops[3].getOp());
240*0fca6ea1SDimitry Andric 
241*0fca6ea1SDimitry Andric   if (!Const2 || !operationsAreFoldableAndCommutative(Operand1, Operand2))
242*0fca6ea1SDimitry Andric     return false;
243*0fca6ea1SDimitry Andric 
244*0fca6ea1SDimitry Andric   auto Result = foldOperationIfPossible(Const1, *Const2, Operand1);
245*0fca6ea1SDimitry Andric   if (!Result) {
246*0fca6ea1SDimitry Andric     consumeOneOperator(Cursor, Loc, Ops[0]);
247*0fca6ea1SDimitry Andric     return true;
248*0fca6ea1SDimitry Andric   }
249*0fca6ea1SDimitry Andric   WorkingOps.erase(WorkingOps.begin() + Loc + 3, WorkingOps.begin() + Loc + 6);
250*0fca6ea1SDimitry Andric   WorkingOps[Loc] = dwarf::DW_OP_constu;
251*0fca6ea1SDimitry Andric   WorkingOps[Loc + 1] = *Result;
252*0fca6ea1SDimitry Andric   startFromBeginning(Loc, Cursor, WorkingOps);
253*0fca6ea1SDimitry Andric   return true;
254*0fca6ea1SDimitry Andric }
255*0fca6ea1SDimitry Andric 
256*0fca6ea1SDimitry Andric /// {DW_OP_constu, Const1, DW_OP_[plus, mul], DW_OP_LLVM_arg, Arg1,
257*0fca6ea1SDimitry Andric /// DW_OP_[plus, mul], DW_OP_constu, Const2, DW_OP_[plus, mul]} ->
258*0fca6ea1SDimitry Andric /// {DW_OP_constu, Const1 [+, *] Const2, DW_OP_[plus, mul], DW_OP_LLVM_arg,
259*0fca6ea1SDimitry Andric /// Arg1, DW_OP_[plus, mul]}
260*0fca6ea1SDimitry Andric static bool tryFoldCommutativeMathWithArgInBetween(
261*0fca6ea1SDimitry Andric     uint64_t Const1, ArrayRef<DIExpression::ExprOperand> Ops, uint64_t &Loc,
262*0fca6ea1SDimitry Andric     DIExpressionCursor &Cursor, SmallVectorImpl<uint64_t> &WorkingOps) {
263*0fca6ea1SDimitry Andric 
264*0fca6ea1SDimitry Andric   auto Const2 = isConstantVal(Ops[4]);
265*0fca6ea1SDimitry Andric   auto Operand1 = static_cast<dwarf::LocationAtom>(Ops[1].getOp());
266*0fca6ea1SDimitry Andric   auto Operand2 = static_cast<dwarf::LocationAtom>(Ops[3].getOp());
267*0fca6ea1SDimitry Andric   auto Operand3 = static_cast<dwarf::LocationAtom>(Ops[5].getOp());
268*0fca6ea1SDimitry Andric 
269*0fca6ea1SDimitry Andric   if (!Const2 || Ops[2].getOp() != dwarf::DW_OP_LLVM_arg ||
270*0fca6ea1SDimitry Andric       !operationsAreFoldableAndCommutative(Operand1, Operand2) ||
271*0fca6ea1SDimitry Andric       !operationsAreFoldableAndCommutative(Operand2, Operand3))
272*0fca6ea1SDimitry Andric     return false;
273*0fca6ea1SDimitry Andric 
274*0fca6ea1SDimitry Andric   auto Result = foldOperationIfPossible(Const1, *Const2, Operand1);
275*0fca6ea1SDimitry Andric   if (!Result) {
276*0fca6ea1SDimitry Andric     consumeOneOperator(Cursor, Loc, Ops[0]);
277*0fca6ea1SDimitry Andric     return true;
278*0fca6ea1SDimitry Andric   }
279*0fca6ea1SDimitry Andric   WorkingOps.erase(WorkingOps.begin() + Loc + 6, WorkingOps.begin() + Loc + 9);
280*0fca6ea1SDimitry Andric   WorkingOps[Loc] = dwarf::DW_OP_constu;
281*0fca6ea1SDimitry Andric   WorkingOps[Loc + 1] = *Result;
282*0fca6ea1SDimitry Andric   startFromBeginning(Loc, Cursor, WorkingOps);
283*0fca6ea1SDimitry Andric   return true;
284*0fca6ea1SDimitry Andric }
285*0fca6ea1SDimitry Andric 
286*0fca6ea1SDimitry Andric DIExpression *DIExpression::foldConstantMath() {
287*0fca6ea1SDimitry Andric 
288*0fca6ea1SDimitry Andric   SmallVector<uint64_t, 8> WorkingOps(Elements.begin(), Elements.end());
289*0fca6ea1SDimitry Andric   uint64_t Loc = 0;
290*0fca6ea1SDimitry Andric   SmallVector<uint64_t> ResultOps = canonicalizeDwarfOperations(WorkingOps);
291*0fca6ea1SDimitry Andric   DIExpressionCursor Cursor(ResultOps);
292*0fca6ea1SDimitry Andric   SmallVector<DIExpression::ExprOperand, 8> Ops;
293*0fca6ea1SDimitry Andric 
294*0fca6ea1SDimitry Andric   // Iterate over all Operations in a DIExpression to match the smallest pattern
295*0fca6ea1SDimitry Andric   // that can be folded.
296*0fca6ea1SDimitry Andric   while (Loc < ResultOps.size()) {
297*0fca6ea1SDimitry Andric     Ops.clear();
298*0fca6ea1SDimitry Andric 
299*0fca6ea1SDimitry Andric     auto Op = Cursor.peek();
300*0fca6ea1SDimitry Andric     // Expression has no operations, exit.
301*0fca6ea1SDimitry Andric     if (!Op)
302*0fca6ea1SDimitry Andric       break;
303*0fca6ea1SDimitry Andric 
304*0fca6ea1SDimitry Andric     auto Const1 = isConstantVal(*Op);
305*0fca6ea1SDimitry Andric 
306*0fca6ea1SDimitry Andric     if (!Const1) {
307*0fca6ea1SDimitry Andric       // Early exit, all of the following patterns start with a constant value.
308*0fca6ea1SDimitry Andric       consumeOneOperator(Cursor, Loc, *Op);
309*0fca6ea1SDimitry Andric       continue;
310*0fca6ea1SDimitry Andric     }
311*0fca6ea1SDimitry Andric 
312*0fca6ea1SDimitry Andric     Ops.push_back(*Op);
313*0fca6ea1SDimitry Andric 
314*0fca6ea1SDimitry Andric     Op = Cursor.peekNext();
315*0fca6ea1SDimitry Andric     // All following patterns require at least 2 Operations, exit.
316*0fca6ea1SDimitry Andric     if (!Op)
317*0fca6ea1SDimitry Andric       break;
318*0fca6ea1SDimitry Andric 
319*0fca6ea1SDimitry Andric     Ops.push_back(*Op);
320*0fca6ea1SDimitry Andric 
321*0fca6ea1SDimitry Andric     // Try to fold a constant no-op, such as {+ 0}
322*0fca6ea1SDimitry Andric     if (tryFoldNoOpMath(*Const1, Ops, Loc, Cursor, ResultOps))
323*0fca6ea1SDimitry Andric       continue;
324*0fca6ea1SDimitry Andric 
325*0fca6ea1SDimitry Andric     Op = Cursor.peekNextN(2);
326*0fca6ea1SDimitry Andric     // Op[1] could still match a pattern, skip iteration.
327*0fca6ea1SDimitry Andric     if (!Op) {
328*0fca6ea1SDimitry Andric       consumeOneOperator(Cursor, Loc, Ops[0]);
329*0fca6ea1SDimitry Andric       continue;
330*0fca6ea1SDimitry Andric     }
331*0fca6ea1SDimitry Andric 
332*0fca6ea1SDimitry Andric     Ops.push_back(*Op);
333*0fca6ea1SDimitry Andric 
334*0fca6ea1SDimitry Andric     // Try to fold a pattern of two constants such as {C1 + C2}.
335*0fca6ea1SDimitry Andric     if (tryFoldConstants(*Const1, Ops, Loc, Cursor, ResultOps))
336*0fca6ea1SDimitry Andric       continue;
337*0fca6ea1SDimitry Andric 
338*0fca6ea1SDimitry Andric     Op = Cursor.peekNextN(3);
339*0fca6ea1SDimitry Andric     // Op[1] and Op[2] could still match a pattern, skip iteration.
340*0fca6ea1SDimitry Andric     if (!Op) {
341*0fca6ea1SDimitry Andric       consumeOneOperator(Cursor, Loc, Ops[0]);
342*0fca6ea1SDimitry Andric       continue;
343*0fca6ea1SDimitry Andric     }
344*0fca6ea1SDimitry Andric 
345*0fca6ea1SDimitry Andric     Ops.push_back(*Op);
346*0fca6ea1SDimitry Andric 
347*0fca6ea1SDimitry Andric     // Try to fold commutative constant math, such as {C1 + C2 +}.
348*0fca6ea1SDimitry Andric     if (tryFoldCommutativeMath(*Const1, Ops, Loc, Cursor, ResultOps))
349*0fca6ea1SDimitry Andric       continue;
350*0fca6ea1SDimitry Andric 
351*0fca6ea1SDimitry Andric     Op = Cursor.peekNextN(4);
352*0fca6ea1SDimitry Andric     if (!Op) {
353*0fca6ea1SDimitry Andric       consumeOneOperator(Cursor, Loc, Ops[0]);
354*0fca6ea1SDimitry Andric       continue;
355*0fca6ea1SDimitry Andric     }
356*0fca6ea1SDimitry Andric 
357*0fca6ea1SDimitry Andric     Ops.push_back(*Op);
358*0fca6ea1SDimitry Andric     Op = Cursor.peekNextN(5);
359*0fca6ea1SDimitry Andric     if (!Op) {
360*0fca6ea1SDimitry Andric       consumeOneOperator(Cursor, Loc, Ops[0]);
361*0fca6ea1SDimitry Andric       continue;
362*0fca6ea1SDimitry Andric     }
363*0fca6ea1SDimitry Andric 
364*0fca6ea1SDimitry Andric     Ops.push_back(*Op);
365*0fca6ea1SDimitry Andric 
366*0fca6ea1SDimitry Andric     // Try to fold commutative constant math with an LLVM_Arg in between, such
367*0fca6ea1SDimitry Andric     // as {C1 + Arg + C2 +}.
368*0fca6ea1SDimitry Andric     if (tryFoldCommutativeMathWithArgInBetween(*Const1, Ops, Loc, Cursor,
369*0fca6ea1SDimitry Andric                                                ResultOps))
370*0fca6ea1SDimitry Andric       continue;
371*0fca6ea1SDimitry Andric 
372*0fca6ea1SDimitry Andric     consumeOneOperator(Cursor, Loc, Ops[0]);
373*0fca6ea1SDimitry Andric   }
374*0fca6ea1SDimitry Andric   ResultOps = optimizeDwarfOperations(ResultOps);
375*0fca6ea1SDimitry Andric   auto *Result = DIExpression::get(getContext(), ResultOps);
376*0fca6ea1SDimitry Andric   assert(Result->isValid() && "concatenated expression is not valid");
377*0fca6ea1SDimitry Andric   return Result;
378*0fca6ea1SDimitry Andric }
379