diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index 69ef2ea40c6d..f8f8ffd8c741 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -1973,15 +1973,6 @@ public: return Elements[I]; } - /// Return whether this is a piece of an aggregate variable. - bool isFragment() const; - - /// Return the offset of this fragment in bits. - uint64_t getFragmentOffsetInBits() const; - - /// Return the size of this fragment in bits. - uint64_t getFragmentSizeInBits() const; - /// Determine whether this represents a standalone constant value. bool isConstant() const; @@ -2085,6 +2076,24 @@ public: bool startsWithDeref() const { return getNumElements() > 0 && getElement(0) == dwarf::DW_OP_deref; } + + /// Holds the characteristics of one fragment of a larger variable. + struct FragmentInfo { + uint64_t SizeInBits; + uint64_t OffsetInBits; + }; + + /// Retrieve the details of this fragment expression. + static Optional getFragmentInfo(expr_op_iterator Start, + expr_op_iterator End); + + /// Retrieve the details of this fragment expression. + Optional getFragmentInfo() const { + return getFragmentInfo(expr_op_begin(), expr_op_end()); + } + + /// Return whether this is a piece of an aggregate variable. + bool isFragment() const { return getFragmentInfo().hasValue(); } }; /// Global variables. diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 7adac4cbf944..f0537e04165f 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -713,9 +713,10 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) { OS << V->getName(); const DIExpression *Expr = MI->getDebugExpression(); - if (Expr->isFragment()) - OS << " [fragment offset=" << Expr->getFragmentOffsetInBits() - << " size=" << Expr->getFragmentSizeInBits() << "]"; + auto Fragment = Expr->getFragmentInfo(); + if (Fragment) + OS << " [fragment offset=" << Fragment->OffsetInBits + << " size=" << Fragment->SizeInBits << "]"; OS << " <- "; // The second operand is only an offset if it's an immediate. diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index 3d0ae1a93992..8dde4a1031b0 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -944,9 +944,10 @@ void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) { unsigned StructOffset = 0; // Handle fragments. - if (DIExpr && DIExpr->isFragment()) { + auto Fragment = DIExpr->getFragmentInfo(); + if (DIExpr && Fragment) { IsSubfield = true; - StructOffset = DIExpr->getFragmentOffsetInBits() / 8; + StructOffset = Fragment->OffsetInBits / 8; } else if (DIExpr && DIExpr->getNumElements() > 0) { continue; // Ignore unrecognized exprs. } diff --git a/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp b/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp index aa71449b2c08..94190981e88e 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp @@ -65,10 +65,12 @@ MCSymbol *DebugHandlerBase::getLabelAfterInsn(const MachineInstr *MI) { int DebugHandlerBase::fragmentCmp(const DIExpression *P1, const DIExpression *P2) { - unsigned l1 = P1->getFragmentOffsetInBits(); - unsigned l2 = P2->getFragmentOffsetInBits(); - unsigned r1 = l1 + P1->getFragmentSizeInBits(); - unsigned r2 = l2 + P2->getFragmentSizeInBits(); + auto Fragment1 = *P1->getFragmentInfo(); + auto Fragment2 = *P2->getFragmentInfo(); + unsigned l1 = Fragment1.OffsetInBits; + unsigned l2 = Fragment2.OffsetInBits; + unsigned r1 = l1 + Fragment1.SizeInBits; + unsigned r2 = l2 + Fragment2.SizeInBits; if (r1 <= l2) return -1; else if (r2 <= l1) diff --git a/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h b/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h index 9444fad048f3..36fb1507ddc6 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h +++ b/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h @@ -175,8 +175,8 @@ inline bool operator==(const DebugLocEntry::Value &A, /// Compare two fragments based on their offset. inline bool operator<(const DebugLocEntry::Value &A, const DebugLocEntry::Value &B) { - return A.getExpression()->getFragmentOffsetInBits() < - B.getExpression()->getFragmentOffsetInBits(); + return A.getExpression()->getFragmentInfo()->OffsetInBits < + B.getExpression()->getFragmentInfo()->OffsetInBits; } } diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 45d6e38aea7f..b465b98f368a 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -469,10 +469,12 @@ static SmallVectorImpl & sortGlobalExprs(SmallVectorImpl &GVEs) { std::sort(GVEs.begin(), GVEs.end(), [](DwarfCompileUnit::GlobalExpr A, DwarfCompileUnit::GlobalExpr B) { - if (A.Expr != B.Expr && A.Expr && B.Expr && - A.Expr->isFragment() && B.Expr->isFragment()) - return A.Expr->getFragmentOffsetInBits() < - B.Expr->getFragmentOffsetInBits(); + if (A.Expr != B.Expr && A.Expr && B.Expr) { + auto FragmentA = A.Expr->getFragmentInfo(); + auto FragmentB = B.Expr->getFragmentInfo(); + if (FragmentA && FragmentB) + return FragmentA->OffsetInBits < FragmentB->OffsetInBits; + } return false; }); GVEs.erase(std::unique(GVEs.begin(), GVEs.end(), diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp index a17776f2ce9c..5419a10f4f9a 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -285,7 +285,7 @@ void DwarfExpression::addFragmentOffset(const DIExpression *Expr) { if (!Expr || !Expr->isFragment()) return; - uint64_t FragmentOffset = Expr->getFragmentOffsetInBits(); + uint64_t FragmentOffset = Expr->getFragmentInfo()->OffsetInBits; assert(FragmentOffset >= OffsetInBits && "overlapping or duplicate fragments"); if (FragmentOffset > OffsetInBits) diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index 75c397e13456..1003093760fe 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -601,22 +601,14 @@ bool DIExpression::isValid() const { return true; } -bool DIExpression::isFragment() const { - assert(isValid() && "Expected valid expression"); - if (unsigned N = getNumElements()) - if (N >= 3) - return getElement(N - 3) == dwarf::DW_OP_LLVM_fragment; - return false; -} - -uint64_t DIExpression::getFragmentOffsetInBits() const { - assert(isFragment() && "Expected fragment"); - return getElement(getNumElements() - 2); -} - -uint64_t DIExpression::getFragmentSizeInBits() const { - assert(isFragment() && "Expected fragment"); - return getElement(getNumElements() - 1); +Optional +DIExpression::getFragmentInfo(expr_op_iterator Start, expr_op_iterator End) { + for (auto I = Start; I != End; ++I) + if (I->getOp() == dwarf::DW_OP_LLVM_fragment) { + DIExpression::FragmentInfo Info = {I->getArg(1), I->getArg(0)}; + return Info; + } + return None; } bool DIExpression::isConstant() const { diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 2b9dfcea2fb6..9a19354e2558 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -4344,7 +4344,8 @@ void Verifier::verifyFragmentExpression(const DbgInfoIntrinsic &I) { return; // Nothing to do if this isn't a bit piece expression. - if (!E->isFragment()) + auto Fragment = E->getFragmentInfo(); + if (!Fragment) return; // The frontend helps out GDB by emitting the members of local anonymous @@ -4362,8 +4363,8 @@ void Verifier::verifyFragmentExpression(const DbgInfoIntrinsic &I) { if (!VarSize) return; - unsigned FragSize = E->getFragmentSizeInBits(); - unsigned FragOffset = E->getFragmentOffsetInBits(); + unsigned FragSize = Fragment->SizeInBits; + unsigned FragOffset = Fragment->OffsetInBits; AssertDI(FragSize + FragOffset <= VarSize, "fragment is larger than or outside of variable", &I, V, E); AssertDI(FragSize != VarSize, "fragment covers entire variable", &I, V, E); diff --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp index 887818bfdde9..bfcb15530ef5 100644 --- a/llvm/lib/Transforms/Scalar/SROA.cpp +++ b/llvm/lib/Transforms/Scalar/SROA.cpp @@ -4026,13 +4026,13 @@ bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &AS) { if (Fragment.Size < AllocaSize || Expr->isFragment()) { // If this alloca is already a scalar replacement of a larger aggregate, // Fragment.Offset describes the offset inside the scalar. - uint64_t Offset = - Expr->isFragment() ? Expr->getFragmentOffsetInBits() : 0; + auto ExprFragment = Expr->getFragmentInfo(); + uint64_t Offset = ExprFragment ? ExprFragment->OffsetInBits : 0; uint64_t Start = Offset + Fragment.Offset; uint64_t Size = Fragment.Size; - if (Expr->isFragment()) { + if (ExprFragment) { uint64_t AbsEnd = - Expr->getFragmentOffsetInBits() + Expr->getFragmentSizeInBits(); + ExprFragment->OffsetInBits + ExprFragment->SizeInBits; if (Start >= AbsEnd) // No need to describe a SROAed padding. continue; diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index 6de0f34e94cd..6e4174aa0cda 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -1112,9 +1112,10 @@ void llvm::ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI, unsigned FragmentOffset = 0; // If this already is a bit fragment, we drop the bit fragment from the // expression and record the offset. - if (DIExpr->isFragment()) { + auto Fragment = DIExpr->getFragmentInfo(); + if (Fragment) { Ops.append(DIExpr->elements_begin(), DIExpr->elements_end()-3); - FragmentOffset = DIExpr->getFragmentOffsetInBits(); + FragmentOffset = Fragment->OffsetInBits; } else { Ops.append(DIExpr->elements_begin(), DIExpr->elements_end()); }