Index: llvm/include/llvm/CodeGen/DIE.h =================================================================== --- llvm/include/llvm/CodeGen/DIE.h +++ llvm/include/llvm/CodeGen/DIE.h @@ -550,6 +550,14 @@ return *static_cast(Last ? Last->Next.getPointer() : nullptr); } + void takeNodes(IntrusiveBackList &Other) { + for (auto &N : Other) { + N.Next.setPointerAndInt(&N, true); + push_back(N); + } + Other.Last = nullptr; + } + class const_iterator; class iterator : public iterator_facade_base { @@ -685,6 +693,10 @@ return addValue(Alloc, DIEValue(Attribute, Form, std::forward(Value))); } + /// Take ownership of the nodes in \p Other, and append them to the back of + /// the list. + void takeValues(DIEValueList &Other) { List.takeNodes(Other.List); } + value_range values() { return make_range(value_iterator(List.begin()), value_iterator(List.end())); } Index: llvm/lib/CodeGen/AsmPrinter/ByteStreamer.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/ByteStreamer.h +++ llvm/lib/CodeGen/AsmPrinter/ByteStreamer.h @@ -75,12 +75,12 @@ SmallVectorImpl &Buffer; SmallVectorImpl &Comments; +public: /// Only verbose textual output needs comments. This will be set to /// true for that case, and false otherwise. If false, comments passed in to /// the emit methods will be ignored. - bool GenerateComments; + const bool GenerateComments; -public: BufferByteStreamer(SmallVectorImpl &Buffer, SmallVectorImpl &Comments, bool GenerateComments) Index: llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -170,26 +170,26 @@ static constexpr unsigned ULEB128PadSize = 4; void DebugLocDwarfExpression::emitOp(uint8_t Op, const char *Comment) { - BS.EmitInt8( + getActiveStreamer().EmitInt8( Op, Comment ? Twine(Comment) + " " + dwarf::OperationEncodingString(Op) : dwarf::OperationEncodingString(Op)); } void DebugLocDwarfExpression::emitSigned(int64_t Value) { - BS.EmitSLEB128(Value, Twine(Value)); + getActiveStreamer().EmitSLEB128(Value, Twine(Value)); } void DebugLocDwarfExpression::emitUnsigned(uint64_t Value) { - BS.EmitULEB128(Value, Twine(Value)); + getActiveStreamer().EmitULEB128(Value, Twine(Value)); } void DebugLocDwarfExpression::emitData1(uint8_t Value) { - BS.EmitInt8(Value, Twine(Value)); + getActiveStreamer().EmitInt8(Value, Twine(Value)); } void DebugLocDwarfExpression::emitBaseTypeRef(uint64_t Idx) { assert(Idx < (1ULL << (ULEB128PadSize * 7)) && "Idx wont fit"); - BS.EmitULEB128(Idx, Twine(Idx), ULEB128PadSize); + getActiveStreamer().EmitULEB128(Idx, Twine(Idx), ULEB128PadSize); } bool DebugLocDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI, @@ -198,6 +198,28 @@ return false; } +void DebugLocDwarfExpression::enableTemporaryBuffer() { + assert(!IsBuffering && "Already buffering?"); + IsBuffering = true; +} + +void DebugLocDwarfExpression::disableTemporaryBuffer() { IsBuffering = false; } + +unsigned DebugLocDwarfExpression::getTemporaryBufferSize() { + return TmpBytes.size(); +} + +void DebugLocDwarfExpression::commitTemporaryBuffer() { + for (auto Byte : enumerate(TmpBytes)) { + const char *Comment = (Byte.index() < TmpComments.size()) + ? TmpComments[Byte.index()].c_str() + : ""; + OutBS.EmitInt8(Byte.value(), Comment); + } + TmpBytes.clear(); + TmpComments.clear(); +} + bool DbgVariable::isBlockByrefVariable() const { assert(getVariable() && "Invalid complex DbgVariable!"); return getVariable()->getType()->isBlockByrefStruct(); Index: llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h +++ llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -13,6 +13,7 @@ #ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DWARFEXPRESSION_H #define LLVM_LIB_CODEGEN_ASMPRINTER_DWARFEXPRESSION_H +#include "ByteStreamer.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" @@ -26,7 +27,6 @@ class AsmPrinter; class APInt; -class ByteStreamer; class DwarfCompileUnit; class DIELoc; class TargetRegisterInfo; @@ -95,6 +95,13 @@ /// Base class containing the logic for constructing DWARF expressions /// independently of whether they are emitted into a DIE or into a .debug_loc /// entry. +/// +/// Some DWARF operations, e.g. DW_OP_entry_value, need to calculate the size +/// of a succeeding DWARF block before the latter is emitted to the output. +/// To handle such cases, data can conditionally be emitted to a temporary +/// buffer, which can later on be committed to the main output. The size of the +/// temporary buffer is queryable, allowing for the size of the data to be +/// emitted before the data is committed. class DwarfExpression { protected: /// Holds information about all subregisters comprising a register location. @@ -178,6 +185,22 @@ virtual void emitBaseTypeRef(uint64_t Idx) = 0; + /// Start emitting data to the temporary buffer. The data stored in the + /// temporary buffer can be committed to the main output using + /// commitTemporaryBuffer(). + virtual void enableTemporaryBuffer() = 0; + + /// Disable emission to the temporary buffer. This does not commit data + /// in the temporary buffer to the main output. + virtual void disableTemporaryBuffer() = 0; + + /// Return the emitted size, in number of bytes, for the data stored in the + /// temporary buffer. + virtual unsigned getTemporaryBufferSize() = 0; + + /// Commit the data stored in the temporary buffer to the main output. + virtual void commitTemporaryBuffer() = 0; + /// Emit a normalized unsigned constant. void emitConstu(uint64_t Value); @@ -308,31 +331,56 @@ /// DwarfExpression implementation for .debug_loc entries. class DebugLocDwarfExpression final : public DwarfExpression { - ByteStreamer &BS; + BufferByteStreamer &OutBS; + SmallString<32> TmpBytes; + SmallVector TmpComments; + BufferByteStreamer TmpBS; + bool IsBuffering = false; + + /// Return the byte streamer that currently is being emitted to. + ByteStreamer &getActiveStreamer() { return IsBuffering ? TmpBS : OutBS; } void emitOp(uint8_t Op, const char *Comment = nullptr) override; void emitSigned(int64_t Value) override; void emitUnsigned(uint64_t Value) override; void emitData1(uint8_t Value) override; void emitBaseTypeRef(uint64_t Idx) override; + + void enableTemporaryBuffer() override; + void disableTemporaryBuffer() override; + unsigned getTemporaryBufferSize() override; + void commitTemporaryBuffer() override; + bool isFrameRegister(const TargetRegisterInfo &TRI, unsigned MachineReg) override; - public: - DebugLocDwarfExpression(unsigned DwarfVersion, ByteStreamer &BS, DwarfCompileUnit &CU) - : DwarfExpression(DwarfVersion, CU), BS(BS) {} + DebugLocDwarfExpression(unsigned DwarfVersion, BufferByteStreamer &BS, + DwarfCompileUnit &CU) + : DwarfExpression(DwarfVersion, CU), OutBS(BS), + TmpBS(TmpBytes, TmpComments, BS.GenerateComments) {} }; /// DwarfExpression implementation for singular DW_AT_location. class DIEDwarfExpression final : public DwarfExpression { -const AsmPrinter &AP; - DIELoc &DIE; + const AsmPrinter &AP; + DIELoc &OutDIE; + DIELoc TmpDIE; + bool IsBuffering = false; + + /// Return the DIE that currently is being emitted to. + DIELoc &getActiveDIE() { return IsBuffering ? TmpDIE : OutDIE; } void emitOp(uint8_t Op, const char *Comment = nullptr) override; void emitSigned(int64_t Value) override; void emitUnsigned(uint64_t Value) override; void emitData1(uint8_t Value) override; void emitBaseTypeRef(uint64_t Idx) override; + + void enableTemporaryBuffer() override; + void disableTemporaryBuffer() override; + unsigned getTemporaryBufferSize() override; + void commitTemporaryBuffer() override; + bool isFrameRegister(const TargetRegisterInfo &TRI, unsigned MachineReg) override; public: @@ -340,7 +388,7 @@ DIELoc *finalize() { DwarfExpression::finalize(); - return &DIE; + return &OutDIE; } }; Index: llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -47,31 +47,42 @@ #define DEBUG_TYPE "dwarfdebug" DIEDwarfExpression::DIEDwarfExpression(const AsmPrinter &AP, - DwarfCompileUnit &CU, - DIELoc &DIE) - : DwarfExpression(AP.getDwarfVersion(), CU), AP(AP), - DIE(DIE) {} + DwarfCompileUnit &CU, DIELoc &DIE) + : DwarfExpression(AP.getDwarfVersion(), CU), AP(AP), OutDIE(DIE) {} void DIEDwarfExpression::emitOp(uint8_t Op, const char* Comment) { - CU.addUInt(DIE, dwarf::DW_FORM_data1, Op); + CU.addUInt(getActiveDIE(), dwarf::DW_FORM_data1, Op); } void DIEDwarfExpression::emitSigned(int64_t Value) { - CU.addSInt(DIE, dwarf::DW_FORM_sdata, Value); + CU.addSInt(getActiveDIE(), dwarf::DW_FORM_sdata, Value); } void DIEDwarfExpression::emitUnsigned(uint64_t Value) { - CU.addUInt(DIE, dwarf::DW_FORM_udata, Value); + CU.addUInt(getActiveDIE(), dwarf::DW_FORM_udata, Value); } void DIEDwarfExpression::emitData1(uint8_t Value) { - CU.addUInt(DIE, dwarf::DW_FORM_data1, Value); + CU.addUInt(getActiveDIE(), dwarf::DW_FORM_data1, Value); } void DIEDwarfExpression::emitBaseTypeRef(uint64_t Idx) { - CU.addBaseTypeRef(DIE, Idx); + CU.addBaseTypeRef(getActiveDIE(), Idx); } +void DIEDwarfExpression::enableTemporaryBuffer() { + assert(!IsBuffering && "Already buffering?"); + IsBuffering = true; +} + +void DIEDwarfExpression::disableTemporaryBuffer() { IsBuffering = false; } + +unsigned DIEDwarfExpression::getTemporaryBufferSize() { + return TmpDIE.ComputeSize(&AP); +} + +void DIEDwarfExpression::commitTemporaryBuffer() { OutDIE.takeValues(TmpDIE); } + bool DIEDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI, unsigned MachineReg) { return MachineReg == TRI.getFrameRegister(*AP.MF);