From d16393bd60213e2c83b9275bcc7d9f5bc4060997 Mon Sep 17 00:00:00 2001 From: Shubham Sandeep Rastogi Date: Wed, 4 Oct 2023 11:34:19 -0700 Subject: [PATCH 1/2] [NFC] Move DIExpressionCursor to DebugInfoMetadata.h --- llvm/include/llvm/IR/DebugInfoMetadata.h | 61 +++++++++++++++++++ llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h | 61 ------------------- 2 files changed, 61 insertions(+), 61 deletions(-) diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index b347664883fd9..86ee9f004cfd4 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -3073,6 +3073,67 @@ template <> struct DenseMapInfo { static bool isEqual(const FragInfo &A, const FragInfo &B) { return A == B; } }; +/// Holds a DIExpression and keeps track of how many operands have been consumed +/// so far. +class DIExpressionCursor { + DIExpression::expr_op_iterator Start, End; + +public: + DIExpressionCursor(const DIExpression *Expr) { + if (!Expr) { + assert(Start == End); + return; + } + Start = Expr->expr_op_begin(); + End = Expr->expr_op_end(); + } + + DIExpressionCursor(ArrayRef Expr) + : Start(Expr.begin()), End(Expr.end()) {} + + DIExpressionCursor(const DIExpressionCursor &) = default; + + /// Consume one operation. + std::optional take() { + if (Start == End) + return std::nullopt; + return *(Start++); + } + + /// Consume N operations. + void consume(unsigned N) { std::advance(Start, N); } + + /// Return the current operation. + std::optional peek() const { + if (Start == End) + return std::nullopt; + return *(Start); + } + + /// Return the next operation. + std::optional peekNext() const { + if (Start == End) + return std::nullopt; + + auto Next = Start.getNext(); + if (Next == End) + return std::nullopt; + + return *Next; + } + + /// Determine whether there are any operations left in this expression. + operator bool() const { return Start != End; } + + DIExpression::expr_op_iterator begin() const { return Start; } + DIExpression::expr_op_iterator end() const { return End; } + + /// Retrieve the fragment information, if any. + std::optional getFragmentInfo() const { + return DIExpression::getFragmentInfo(Start, End); + } +}; + /// Global variables. /// /// TODO: Remove DisplayName. It's always equal to Name. diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h index 667a9efc6f6c0..4daa78b15b8e2 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -31,67 +31,6 @@ class DIELoc; class TargetRegisterInfo; class MachineLocation; -/// Holds a DIExpression and keeps track of how many operands have been consumed -/// so far. -class DIExpressionCursor { - DIExpression::expr_op_iterator Start, End; - -public: - DIExpressionCursor(const DIExpression *Expr) { - if (!Expr) { - assert(Start == End); - return; - } - Start = Expr->expr_op_begin(); - End = Expr->expr_op_end(); - } - - DIExpressionCursor(ArrayRef Expr) - : Start(Expr.begin()), End(Expr.end()) {} - - DIExpressionCursor(const DIExpressionCursor &) = default; - - /// Consume one operation. - std::optional take() { - if (Start == End) - return std::nullopt; - return *(Start++); - } - - /// Consume N operations. - void consume(unsigned N) { std::advance(Start, N); } - - /// Return the current operation. - std::optional peek() const { - if (Start == End) - return std::nullopt; - return *(Start); - } - - /// Return the next operation. - std::optional peekNext() const { - if (Start == End) - return std::nullopt; - - auto Next = Start.getNext(); - if (Next == End) - return std::nullopt; - - return *Next; - } - - /// Determine whether there are any operations left in this expression. - operator bool() const { return Start != End; } - - DIExpression::expr_op_iterator begin() const { return Start; } - DIExpression::expr_op_iterator end() const { return End; } - - /// Retrieve the fragment information, if any. - std::optional getFragmentInfo() const { - return DIExpression::getFragmentInfo(Start, End); - } -}; - /// Base class containing the logic for constructing DWARF expressions /// independently of whether they are emitted into a DIE or into a .debug_loc /// entry. From 412d655a76bad1b687946f9c3ef316ad5e10db82 Mon Sep 17 00:00:00 2001 From: Shubham Sandeep Rastogi Date: Fri, 20 Oct 2023 10:44:22 -0700 Subject: [PATCH 2/2] Introduce DIExpressionOptimizer DIExpressionOptimizer is a lightweight class that can be used to optimize DIExpressions that can get very large, by involving some simple constant folding, and removing appends of unecessary operations. --- llvm/include/llvm/IR/DebugInfoMetadata.h | 42 +++++++ llvm/lib/IR/DebugInfoMetadata.cpp | 137 +++++++++++++++++++++++ 2 files changed, 179 insertions(+) diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index 86ee9f004cfd4..b9df644e44ccf 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -3073,6 +3073,48 @@ template <> struct DenseMapInfo { static bool isEqual(const FragInfo &A, const FragInfo &B) { return A == B; } }; +class DIExpressionOptimizer { + + // When looking at a DIExpression such as {DW_OP_constu, 1, DW_OP_constu, 2, + // DW_OP_plus} and trying to append {DW_OP_consts, 3, DW_OP_minus} + // NewMathOperator = DW_OP_minus + // OperandRight = 3 + // OperatorRight = DW_OP_consts + // CurrMathOperator = DW_OP_plus + // OperandLeft = 2 + // OperandLeft = DW_OP_constu + + /// The math operator of the new subexpression being appended to the + /// DIExpression. + uint64_t NewMathOperator = 0; + + /// The operand of the new subexpression being appended to the DIExpression. + uint64_t OperandRight; + + /// The operator attached to OperandRight. + uint64_t OperatorRight = 0; + + /// The math operator at the end of the current DIExpression. + uint64_t CurrMathOperator = 0; + + /// The operand at the end of the current DIExpression at the top of the + /// stack. + uint64_t OperandLeft; + + /// The operator attached to OperandLeft. + uint64_t OperatorLeft = 0; + + bool operatorIsCommutative(uint64_t Operator); + + SmallVector getOperatorLocations(ArrayRef Ops); + + void reset(); + +public: + bool operatorCanBeOptimized(uint64_t Operator); + void optimize(SmallVectorImpl &NewOps, ArrayRef Ops); +}; + /// Holds a DIExpression and keeps track of how many operands have been consumed /// so far. class DIExpressionCursor { diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index f7f36129ec855..dfda851b77777 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -1734,6 +1734,143 @@ const DIExpression *DIExpression::extractAddressClass(const DIExpression *Expr, return Expr; } +SmallVector +DIExpressionOptimizer::getOperatorLocations(ArrayRef Ops) { + SmallVector OpLocs; + uint64_t Loc = 0; + DIExpressionCursor Cursor(Ops); + + while (Cursor.peek()) { + OpLocs.push_back(Loc); + auto Size = Cursor.peek()->getSize(); + Loc += Size; + Cursor.consume(1); + } + + return OpLocs; +} + +bool DIExpressionOptimizer::operatorIsCommutative(uint64_t Operator) { + return Operator == dwarf::DW_OP_mul || Operator == dwarf::DW_OP_plus; +} + +bool DIExpressionOptimizer::operatorCanBeOptimized(uint64_t Operator) { + switch (Operator) { + case dwarf::DW_OP_plus: + case dwarf::DW_OP_plus_uconst: + case dwarf::DW_OP_minus: + case dwarf::DW_OP_mul: + case dwarf::DW_OP_div: + case dwarf::DW_OP_shl: + case dwarf::DW_OP_shr: + return true; + default: + return false; + } +} + +void DIExpressionOptimizer::reset() { + NewMathOperator = 0; + CurrMathOperator = 0; + OperatorLeft = 0; + OperatorRight = 0; +} + +void DIExpressionOptimizer::optimize(SmallVectorImpl &NewOps, + ArrayRef Ops) { + + if (Ops.size() == 2 && Ops[0] == dwarf::DW_OP_plus_uconst) { + // Convert a {DW_OP_plus_uconst, } expression to + // {DW_OP_constu, , DW_OP_plus} + NewMathOperator = dwarf::DW_OP_plus; + OperandRight = Ops[1]; + OperatorRight = dwarf::DW_OP_constu; + } else if (Ops.size() == 3) { + NewMathOperator = Ops[2]; + OperandRight = Ops[1]; + OperatorRight = Ops[0]; + } else { + // Currently, DIExpressionOptimizer only supports arithmetic operations + // such as Ops = {DW_OP_constu, 1, DW_OP_mul} + NewOps.append(Ops.begin(), Ops.end()); + return; + } + + if (OperatorRight != dwarf::DW_OP_constu && + OperatorRight != dwarf::DW_OP_consts) { + NewOps.append(Ops.begin(), Ops.end()); + return; + } + + uint64_t CurrOperator; + + if ((NewMathOperator == dwarf::DW_OP_mul || + NewMathOperator == dwarf::DW_OP_div) && + OperandRight == 1) { + // It is a multiply or divide by 1 + reset(); + return; + } + if ((NewMathOperator == dwarf::DW_OP_plus || + NewMathOperator == dwarf::DW_OP_minus || + NewMathOperator == dwarf::DW_OP_shl || + NewMathOperator == dwarf::DW_OP_shr) && + OperandRight == 0) { + // It is a add, subtract, shift left, or shift right with 0 + reset(); + return; + } + + // Get the locations of the operators in the DIExpression + auto OperatorLocs = getOperatorLocations(NewOps); + + for (auto It = OperatorLocs.rbegin(); It != OperatorLocs.rend(); It++) { + // Only look at the last two operators of the DIExpression to see if the new + // operators can be constant folded with them. + if (std::distance(OperatorLocs.rbegin(), It) > 1) + break; + CurrOperator = NewOps[*It]; + if (CurrOperator == dwarf::DW_OP_mul || CurrOperator == dwarf::DW_OP_div || + CurrOperator == dwarf::DW_OP_plus || + CurrOperator == dwarf::DW_OP_minus) { + CurrMathOperator = CurrOperator; + continue; + } + if (CurrOperator == dwarf::DW_OP_plus_uconst && + NewMathOperator == dwarf::DW_OP_plus) { + NewOps[*It + 1] = OperandRight + NewOps[*It + 1]; + reset(); + return; + } + if (CurrOperator == dwarf::DW_OP_constu || + CurrOperator == dwarf::DW_OP_consts) { + OperatorLeft = CurrOperator; + OperandLeft = NewOps[*It + 1]; + + if (NewMathOperator == CurrMathOperator && + operatorIsCommutative(NewMathOperator)) { + switch (NewMathOperator) { + case dwarf::DW_OP_plus: + NewOps[*It + 1] = OperandRight + OperandLeft; + break; + case dwarf::DW_OP_mul: + NewOps[*It + 1] = OperandRight * OperandLeft; + break; + default: + llvm_unreachable("Operator is not multiplication or addition!"); + } + reset(); + return; + } + break; + } + break; + } + NewOps.append(Ops.begin(), Ops.end()); + reset(); + return; +} + DIExpression *DIExpression::prepend(const DIExpression *Expr, uint8_t Flags, int64_t Offset) { SmallVector Ops;