[llvm] Introduce DIExpression::foldConstantMath() (PR #71718)
Adrian Prantl via llvm-commits
llvm-commits at lists.llvm.org
Fri Mar 15 08:56:29 PDT 2024
================
@@ -2011,6 +2010,347 @@ DIExpression::constantFold(const ConstantInt *CI) {
ConstantInt::get(getContext(), NewInt)};
}
+// Returns true if the Op is a DW_OP_constu.
+static bool isConstantVal(uint64_t Op) { return Op == dwarf::DW_OP_constu; }
+
+// Returns true if an operation and operand result in a No Op.
+static bool isNeutralElement(uint64_t Op, uint64_t Val) {
+ switch (Op) {
+ case dwarf::DW_OP_plus:
+ case dwarf::DW_OP_minus:
+ case dwarf::DW_OP_shl:
+ case dwarf::DW_OP_shr:
+ return Val == 0;
+ case dwarf::DW_OP_mul:
+ case dwarf::DW_OP_div:
+ return Val == 1;
+ default:
+ return false;
+ }
+}
+
+// Try to fold constant math operations and return the result if possible.
+static std::optional<uint64_t>
+foldOperationIfPossible(uint64_t Op, uint64_t Operand1, uint64_t Operand2) {
+ bool ResultOverflowed;
+ switch (Op) {
+ case dwarf::DW_OP_plus: {
+ auto Result = SaturatingAdd(Operand1, Operand2, &ResultOverflowed);
+ if (ResultOverflowed)
+ return std::nullopt;
+ return Result;
+ }
+ case dwarf::DW_OP_minus: {
+ if (Operand1 < Operand2)
+ return std::nullopt;
+ return Operand1 - Operand2;
+ }
+ case dwarf::DW_OP_shl: {
+ if (Operand2 > 64)
+ return std::nullopt;
+ return Operand1 << Operand2;
+ }
+ case dwarf::DW_OP_shr: {
+ if (Operand2 > 64)
+ return std::nullopt;
+ return Operand1 >> Operand2;
+ }
+ case dwarf::DW_OP_mul: {
+ auto Result = SaturatingMultiply(Operand1, Operand2, &ResultOverflowed);
+ if (ResultOverflowed)
+ return std::nullopt;
+ return Result;
+ }
+ case dwarf::DW_OP_div: {
+ if (Operand2)
+ return Operand1 / Operand2;
+ return std::nullopt;
+ }
+ default:
+ return std::nullopt;
+ }
+}
+
+// Returns true if the two operations are commutative and can be folded.
+static bool operationsAreFoldableAndCommutative(uint64_t Op1, uint64_t Op2) {
+ if (Op1 != Op2)
+ return false;
+ switch (Op1) {
+ case dwarf::DW_OP_plus:
+ case dwarf::DW_OP_mul:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Consume one operator and its operand(s).
+static void consumeOneOperator(DIExpressionCursor &Cursor, uint64_t &Loc,
+ const DIExpression::ExprOperand &Op) {
+ Cursor.consume(1);
+ Loc = Loc + Op.getSize();
+}
+
+// Reset the Cursor to the beginning of the WorkingOps.
+static void startFromBeginning(uint64_t &Loc, DIExpressionCursor &Cursor,
+ ArrayRef<uint64_t> WorkingOps) {
+ Cursor.assignNewExpr(WorkingOps);
+ Loc = 0;
+}
+
+// Move the Cursor to the position of an operation by starting from the
+// beginning and consuming the number of operations that came before.
+static void moveCursorToCurrentOp(uint64_t &Loc, DIExpressionCursor &Cursor,
+ ArrayRef<uint64_t> WorkingOps,
+ uint32_t NumOfOpsConsumed) {
+ Cursor.assignNewExpr(WorkingOps);
+ Cursor.consume(NumOfOpsConsumed);
+ assert(Cursor.peek()->getOp() == WorkingOps[Loc] &&
+ "Cursor position does not match position of iterator 'Loc' to "
+ "WorkingOps");
+}
+
+// This function will canonicalize:
+// 1. DW_OP_plus_uconst to DW_OP_constu <const-val> DW_OP_plus
+// 2. DW_OP_lit<n> to DW_OP_constu <n>
+static void canonicalizeDwarfOperations(SmallVectorImpl<uint64_t> &WorkingOps) {
+ DIExpressionCursor Cursor(WorkingOps);
+ uint64_t Loc = 0;
+ uint32_t NumOfOpsConsumed = 0;
+ while (Loc < WorkingOps.size()) {
+ auto Op = Cursor.peek();
+ // Expression has no operations, break.
+ if (!Op)
+ break;
+ auto OpRaw = Op->getOp();
+ auto OpArg = Op->getArg(0);
+
+ if (OpRaw >= dwarf::DW_OP_lit0 && OpRaw <= dwarf::DW_OP_lit31) {
+ WorkingOps[Loc] = dwarf::DW_OP_constu;
+ WorkingOps.insert(WorkingOps.begin() + Loc + 1,
----------------
adrian-prantl wrote:
Instead of doing these expensive insert operations, why not just build up a result on the fly return a new array?
https://github.com/llvm/llvm-project/pull/71718
More information about the llvm-commits
mailing list