[llvm] Introduce DIExpressionOptimizer (PR #69769)
Shubham Sandeep Rastogi via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 20 13:28:12 PDT 2023
https://github.com/rastogishubham created https://github.com/llvm/llvm-project/pull/69769
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 unnecessary operations.
>From d16393bd60213e2c83b9275bcc7d9f5bc4060997 Mon Sep 17 00:00:00 2001
From: Shubham Sandeep Rastogi <srastogi22 at apple.com>
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 b347664883fd9f2..86ee9f004cfd42b 100644
--- a/llvm/include/llvm/IR/DebugInfoMetadata.h
+++ b/llvm/include/llvm/IR/DebugInfoMetadata.h
@@ -3073,6 +3073,67 @@ template <> struct DenseMapInfo<DIExpression::FragmentInfo> {
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<uint64_t> Expr)
+ : Start(Expr.begin()), End(Expr.end()) {}
+
+ DIExpressionCursor(const DIExpressionCursor &) = default;
+
+ /// Consume one operation.
+ std::optional<DIExpression::ExprOperand> 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<DIExpression::ExprOperand> peek() const {
+ if (Start == End)
+ return std::nullopt;
+ return *(Start);
+ }
+
+ /// Return the next operation.
+ std::optional<DIExpression::ExprOperand> 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<DIExpression::FragmentInfo> 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 667a9efc6f6c04f..4daa78b15b8e298 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<uint64_t> Expr)
- : Start(Expr.begin()), End(Expr.end()) {}
-
- DIExpressionCursor(const DIExpressionCursor &) = default;
-
- /// Consume one operation.
- std::optional<DIExpression::ExprOperand> 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<DIExpression::ExprOperand> peek() const {
- if (Start == End)
- return std::nullopt;
- return *(Start);
- }
-
- /// Return the next operation.
- std::optional<DIExpression::ExprOperand> 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<DIExpression::FragmentInfo> 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 <srastogi22 at apple.com>
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 86ee9f004cfd42b..b9df644e44ccf36 100644
--- a/llvm/include/llvm/IR/DebugInfoMetadata.h
+++ b/llvm/include/llvm/IR/DebugInfoMetadata.h
@@ -3073,6 +3073,48 @@ template <> struct DenseMapInfo<DIExpression::FragmentInfo> {
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<uint64_t> getOperatorLocations(ArrayRef<uint64_t> Ops);
+
+ void reset();
+
+public:
+ bool operatorCanBeOptimized(uint64_t Operator);
+ void optimize(SmallVectorImpl<uint64_t> &NewOps, ArrayRef<uint64_t> 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 f7f36129ec8557c..dfda851b77777ad 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<uint64_t>
+DIExpressionOptimizer::getOperatorLocations(ArrayRef<uint64_t> Ops) {
+ SmallVector<uint64_t> 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<uint64_t> &NewOps,
+ ArrayRef<uint64_t> Ops) {
+
+ if (Ops.size() == 2 && Ops[0] == dwarf::DW_OP_plus_uconst) {
+ // Convert a {DW_OP_plus_uconst, <constant value>} expression to
+ // {DW_OP_constu, <constant value>, 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<uint64_t, 8> Ops;
More information about the llvm-commits
mailing list