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