1//===- DIExpressionOptimizer.cpp - Constant folding of DIExpressions ------===//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//===----------------------------------------------------------------------===//
9// This file implements functions to constant fold DIExpressions. Which were
10// declared in DIExpressionOptimizer.h
12//===----------------------------------------------------------------------===//
19/// Returns true if the Op is a DW_OP_constu.
21 if (
Op.getOp() == dwarf::DW_OP_constu)
26/// Returns true if an operation and operand result in a No Op.
29 case dwarf::DW_OP_plus:
30 case dwarf::DW_OP_minus:
31 case dwarf::DW_OP_shl:
32 case dwarf::DW_OP_shr:
34 case dwarf::DW_OP_mul:
35 case dwarf::DW_OP_div:
42/// Try to fold \p Const1 and \p Const2 by applying \p Operator and returning
43/// the result, if there is an overflow, return a std::nullopt.
44static std::optional<uint64_t>
48 bool ResultOverflowed;
50 case dwarf::DW_OP_plus: {
51 auto Result =
SaturatingAdd(Const1, Const2, &ResultOverflowed);
56 case dwarf::DW_OP_minus: {
59 return Const1 - Const2;
61 case dwarf::DW_OP_shl: {
62 if (Const2 >= std::numeric_limits<uint64_t>::digits ||
65 return Const1 << Const2;
67 case dwarf::DW_OP_shr: {
68 if (Const2 >= std::numeric_limits<uint64_t>::digits ||
71 return Const1 >> Const2;
73 case dwarf::DW_OP_mul: {
79 case dwarf::DW_OP_div: {
81 return Const1 / Const2;
89/// Returns true if the two operations \p Operator1 and \p Operator2 are
90/// commutative and can be folded.
93 return Operator1 == Operator2 &&
94 (Operator1 == dwarf::DW_OP_plus || Operator1 == dwarf::DW_OP_mul);
97/// Consume one operator and its operand(s).
104/// Reset the Cursor to the beginning of the WorkingOps.
107 Cursor.assignNewExpr(WorkingOps);
111/// This function will canonicalize:
112/// 1. DW_OP_plus_uconst to DW_OP_constu <const-val> DW_OP_plus
113/// 2. DW_OP_lit<n> to DW_OP_constu <n>
119 while (
Loc < WorkingOps.
size()) {
120 auto Op = Cursor.peek();
121 /// Expression has no operations, break.
124 auto OpRaw =
Op->getOp();
126 if (OpRaw >= dwarf::DW_OP_lit0 && OpRaw <= dwarf::DW_OP_lit31) {
127 ResultOps.
push_back(dwarf::DW_OP_constu);
128 ResultOps.
push_back(OpRaw - dwarf::DW_OP_lit0);
132 if (OpRaw == dwarf::DW_OP_plus_uconst) {
133 ResultOps.
push_back(dwarf::DW_OP_constu);
146/// This function will convert:
147/// 1. DW_OP_constu <const-val> DW_OP_plus to DW_OP_plus_uconst
148/// 2. DW_OP_constu, 0 to DW_OP_lit0
154 while (
Loc < WorkingOps.
size()) {
155 auto Op1 = Cursor.peek();
156 /// Expression has no operations, exit.
159 auto Op1Raw = Op1->getOp();
161 if (Op1Raw == dwarf::DW_OP_constu && Op1->getArg(0) == 0) {
167 auto Op2 = Cursor.peekNext();
168 /// Expression has no more operations, copy into ResultOps and exit.
175 auto Op2Raw = Op2->getOp();
177 if (Op1Raw == dwarf::DW_OP_constu && Op2Raw == dwarf::DW_OP_plus) {
178 ResultOps.
push_back(dwarf::DW_OP_plus_uconst);
191/// {DW_OP_constu, 0, DW_OP_[plus, minus, shl, shr]} -> {}
192/// {DW_OP_constu, 1, DW_OP_[mul, div]} -> {}
206/// {DW_OP_constu, Const1, DW_OP_constu, Const2, DW_OP_[plus,
207/// minus, mul, div, shl, shr] -> {DW_OP_constu, Const1 [+, -, *, /, <<, >>]
225 WorkingOps[
Loc] = dwarf::DW_OP_constu;
226 WorkingOps[
Loc + 1] = *Result;
231/// {DW_OP_constu, Const1, DW_OP_[plus, mul], DW_OP_constu, Const2,
232/// DW_OP_[plus, mul]} -> {DW_OP_constu, Const1 [+, *] Const2, DW_OP_[plus,
252 WorkingOps[
Loc] = dwarf::DW_OP_constu;
253 WorkingOps[
Loc + 1] = *Result;
258/// {DW_OP_constu, Const1, DW_OP_[plus, mul], DW_OP_LLVM_arg, Arg1,
259/// DW_OP_[plus, mul], DW_OP_constu, Const2, DW_OP_[plus, mul]} ->
260/// {DW_OP_constu, Const1 [+, *] Const2, DW_OP_[plus, mul], DW_OP_LLVM_arg,
261/// Arg1, DW_OP_[plus, mul]}
282 WorkingOps[
Loc] = dwarf::DW_OP_constu;
283 WorkingOps[
Loc + 1] = *Result;
296 // Iterate over all Operations in a DIExpression to match the smallest pattern
297 // that can be folded.
298 while (
Loc < ResultOps.
size()) {
301 auto Op = Cursor.peek();
302 // Expression has no operations, exit.
309 // Early exit, all of the following patterns start with a constant value.
316 Op = Cursor.peekNext();
317 // All following patterns require at least 2 Operations, exit.
323 // Try to fold a constant no-op, such as {+ 0}
327 Op = Cursor.peekNextN(2);
328 // Op[1] could still match a pattern, skip iteration.
336 // Try to fold a pattern of two constants such as {C1 + C2}.
340 Op = Cursor.peekNextN(3);
341 // Op[1] and Op[2] could still match a pattern, skip iteration.
349 // Try to fold commutative constant math, such as {C1 + C2 +}.
353 Op = Cursor.peekNextN(4);
360 Op = Cursor.peekNextN(5);
368 // Try to fold commutative constant math with an LLVM_Arg in between, such
369 // as {C1 + Arg + C2 +}.
378 assert(Result->isValid() &&
"concatenated expression is not valid");
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static bool tryFoldNoOpMath(uint64_t Const1, ArrayRef< DIExpression::ExprOperand > Ops, uint64_t &Loc, DIExpressionCursor &Cursor, SmallVectorImpl< uint64_t > &WorkingOps)
{DW_OP_constu, 0, DW_OP_[plus, minus, shl, shr]} -> {} {DW_OP_constu, 1, DW_OP_[mul,...
static bool operationsAreFoldableAndCommutative(dwarf::LocationAtom Operator1, dwarf::LocationAtom Operator2)
Returns true if the two operations Operator1 and Operator2 are commutative and can be folded.
static bool isNeutralElement(uint64_t Op, uint64_t Val)
Returns true if an operation and operand result in a No Op.
static std::optional< uint64_t > foldOperationIfPossible(uint64_t Const1, uint64_t Const2, dwarf::LocationAtom Operator)
Try to fold Const1 and Const2 by applying Operator and returning the result, if there is an overflow,...
static bool tryFoldCommutativeMath(uint64_t Const1, ArrayRef< DIExpression::ExprOperand > Ops, uint64_t &Loc, DIExpressionCursor &Cursor, SmallVectorImpl< uint64_t > &WorkingOps)
{DW_OP_constu, Const1, DW_OP_[plus, mul], DW_OP_constu, Const2, DW_OP_[plus, mul]}...
void startFromBeginning(uint64_t &Loc, DIExpressionCursor &Cursor, ArrayRef< uint64_t > WorkingOps)
Reset the Cursor to the beginning of the WorkingOps.
static SmallVector< uint64_t > optimizeDwarfOperations(ArrayRef< uint64_t > WorkingOps)
This function will convert:
static bool tryFoldCommutativeMathWithArgInBetween(uint64_t Const1, ArrayRef< DIExpression::ExprOperand > Ops, uint64_t &Loc, DIExpressionCursor &Cursor, SmallVectorImpl< uint64_t > &WorkingOps)
{DW_OP_constu, Const1, DW_OP_[plus, mul], DW_OP_LLVM_arg, Arg1, DW_OP_[plus, mul],...
static bool tryFoldConstants(uint64_t Const1, ArrayRef< DIExpression::ExprOperand > Ops, uint64_t &Loc, DIExpressionCursor &Cursor, SmallVectorImpl< uint64_t > &WorkingOps)
{DW_OP_constu, Const1, DW_OP_constu, Const2, DW_OP_[plus, minus, mul, div, shl, shr] -> {DW_OP_constu...
static void consumeOneOperator(DIExpressionCursor &Cursor, uint64_t &Loc, const DIExpression::ExprOperand &Op)
Consume one operator and its operand(s).
static std::optional< uint64_t > isConstantVal(DIExpression::ExprOperand Op)
Returns true if the Op is a DW_OP_constu.
static SmallVector< uint64_t > canonicalizeDwarfOperations(ArrayRef< uint64_t > WorkingOps)
This function will canonicalize:
This file contains constants used for implementing Dwarf debug support.
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
Holds a DIExpression and keeps track of how many operands have been consumed so far.
A lightweight wrapper around an expression operand.
LLVM_ABI DIExpression * foldConstantMath()
Try to shorten an expression with constant math operations that can be evaluated at compile time.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
LLVMContext & getContext() const
This is a utility class that provides an abstraction for the common functionality between Instruction...
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
iterator erase(const_iterator CI)
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
@ DW_OP_LLVM_arg
Only used in LLVM metadata.
This is an optimization pass for GlobalISel generic memory operations.
int countr_zero(T Val)
Count number of 0's from the least significant bit to the most stopping at the first 1.
int countl_zero(T Val)
Count number of 0's from the most significant bit to the least stopping at the first 1.
std::enable_if_t< std::is_unsigned_v< T >, T > SaturatingMultiply(T X, T Y, bool *ResultOverflowed=nullptr)
Multiply two unsigned integers, X and Y, of type T.
DWARFExpression::Operation Op
std::enable_if_t< std::is_unsigned_v< T >, T > SaturatingAdd(T X, T Y, bool *ResultOverflowed=nullptr)
Add two unsigned integers, X and Y, of type T.