Skip to content

Commit

Permalink
[DebugInfo] Introduce DW_OP_LLVM_convert
Browse files Browse the repository at this point in the history
Introduce a DW_OP_LLVM_convert Dwarf expression pseudo op that allows
for a convenient way to perform type conversions on the Dwarf expression
stack. As an additional bonus it paves the way for using other Dwarf
v5 ops that need to reference a base_type.

The new DW_OP_LLVM_convert is used from lib/Transforms/Utils/Local.cpp
to perform sext/zext on debug values but mainly the patch is about
preparing terrain for adding other Dwarf v5 ops that need to reference a
base_type.

For Dwarf v5 the op maps to DW_OP_convert and for earlier versions a
complex shift & mask pattern is generated to emulate sext/zext.

Differential Revision: https://reviews.llvm.org/D56587

llvm-svn: 356442
  • Loading branch information
markuslavin committed Mar 19, 2019
1 parent f170dff commit cd8a940
Show file tree
Hide file tree
Showing 37 changed files with 671 additions and 85 deletions.
4 changes: 4 additions & 0 deletions llvm/docs/LangRef.rst
Expand Up @@ -4682,6 +4682,10 @@ The current supported opcode vocabulary is limited:
here, respectively) of the variable fragment from the working expression. Note
that contrary to DW_OP_bit_piece, the offset is describing the location
within the described source variable.
- ``DW_OP_LLVM_convert, 16, DW_ATE_signed`` specifies a bit size and encoding
(``16`` and ``DW_ATE_signed`` here, respectively) to which the top of the
expression stack is to be converted. Maps into a ``DW_OP_convert`` operation
that references a base type constructed from the supplied values.
- ``DW_OP_swap`` swaps top two stack entries.
- ``DW_OP_xderef`` provides extended dereference mechanism. The entry at the top
of the stack is treated as an address. The second stack entry is treated as an
Expand Down
3 changes: 2 additions & 1 deletion llvm/include/llvm/BinaryFormat/Dwarf.h
Expand Up @@ -129,7 +129,8 @@ enum LocationAtom {
#include "llvm/BinaryFormat/Dwarf.def"
DW_OP_lo_user = 0xe0,
DW_OP_hi_user = 0xff,
DW_OP_LLVM_fragment = 0x1000 ///< Only used in LLVM metadata.
DW_OP_LLVM_fragment = 0x1000, ///< Only used in LLVM metadata.
DW_OP_LLVM_convert = 0x1001 ///< Only used in LLVM metadata.
};

enum TypeKind : uint8_t {
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/CodeGen/AsmPrinter.h
Expand Up @@ -510,7 +510,7 @@ class AsmPrinter : public MachineFunctionPass {
void EmitSLEB128(int64_t Value, const char *Desc = nullptr) const;

/// Emit the specified unsigned leb128 value.
void EmitULEB128(uint64_t Value, const char *Desc = nullptr) const;
void EmitULEB128(uint64_t Value, const char *Desc = nullptr, unsigned PadTo = 0) const;

/// Emit a .byte 42 directive that corresponds to an encoding. If verbose
/// assembly output is enabled, we output comments describing the encoding.
Expand Down
48 changes: 47 additions & 1 deletion llvm/include/llvm/CodeGen/DIE.h
Expand Up @@ -38,6 +38,7 @@ namespace llvm {
class AsmPrinter;
class DIE;
class DIEUnit;
class DwarfCompileUnit;
class MCExpr;
class MCSection;
class MCSymbol;
Expand Down Expand Up @@ -229,6 +230,25 @@ class DIELabel {
void print(raw_ostream &O) const;
};

//===--------------------------------------------------------------------===//
/// A BaseTypeRef DIE.
class DIEBaseTypeRef {
const DwarfCompileUnit *CU;
const uint64_t Index;
static constexpr unsigned ULEB128PadSize = 4;

public:
explicit DIEBaseTypeRef(const DwarfCompileUnit *TheCU, uint64_t Idx)
: CU(TheCU), Index(Idx) {}

/// EmitValue - Emit base type reference.
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
/// SizeOf - Determine size of the base type reference in bytes.
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;

void print(raw_ostream &O) const;
};

//===--------------------------------------------------------------------===//
/// A simple label difference DIE.
///
Expand Down Expand Up @@ -349,7 +369,7 @@ class DIEValue {
/// should be stored by reference instead of by value.
using ValTy = AlignedCharArrayUnion<DIEInteger, DIEString, DIEExpr, DIELabel,
DIEDelta *, DIEEntry, DIEBlock *,
DIELoc *, DIELocList>;
DIELoc *, DIELocList, DIEBaseTypeRef *>;

static_assert(sizeof(ValTy) <= sizeof(uint64_t) ||
sizeof(ValTy) <= sizeof(void *),
Expand Down Expand Up @@ -501,15 +521,34 @@ struct IntrusiveBackListBase {
}
Last = &N;
}

void push_front(Node &N) {
assert(N.Next.getPointer() == &N && "Expected unlinked node");
assert(N.Next.getInt() == true && "Expected unlinked node");

if (Last) {
N.Next.setPointerAndInt(Last->Next.getPointer(), false);
Last->Next.setPointerAndInt(&N, true);
} else {
Last = &N;
}
}
};

template <class T> class IntrusiveBackList : IntrusiveBackListBase {
public:
using IntrusiveBackListBase::empty;

void push_back(T &N) { IntrusiveBackListBase::push_back(N); }
void push_front(T &N) { IntrusiveBackListBase::push_front(N); }
T &back() { return *static_cast<T *>(Last); }
const T &back() const { return *static_cast<T *>(Last); }
T &front() {
return *static_cast<T *>(Last ? Last->Next.getPointer() : nullptr);
}
const T &front() const {
return *static_cast<T *>(Last ? Last->Next.getPointer() : nullptr);
}

class const_iterator;
class iterator
Expand Down Expand Up @@ -772,6 +811,13 @@ class DIE : IntrusiveBackListNode, public DIEValueList {
return Children.back();
}

DIE &addChildFront(DIE *Child) {
assert(!Child->getParent() && "Child should be orphaned");
Child->Owner = this;
Children.push_front(*Child);
return Children.front();
}

/// Find a value in the DIE with the attribute given.
///
/// Returns a default-constructed DIEValue (where \a DIEValue::getType()
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/CodeGen/DIEValue.def
Expand Up @@ -34,6 +34,7 @@ HANDLE_DIEVALUE_SMALL(Integer)
HANDLE_DIEVALUE_SMALL(String)
HANDLE_DIEVALUE_SMALL(Expr)
HANDLE_DIEVALUE_SMALL(Label)
HANDLE_DIEVALUE_LARGE(BaseTypeRef)
HANDLE_DIEVALUE_LARGE(Delta)
HANDLE_DIEVALUE_SMALL(Entry)
HANDLE_DIEVALUE_LARGE(Block)
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h
Expand Up @@ -86,7 +86,7 @@ class DWARFDebugLoclists {
SmallVector<Entry, 2> Entries;
void dump(raw_ostream &OS, uint64_t BaseAddr, bool IsLittleEndian,
unsigned AddressSize, const MCRegisterInfo *RegInfo,
unsigned Indent) const;
DWARFUnit *U, unsigned Indent) const;
};

private:
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h
Expand Up @@ -79,11 +79,13 @@ class DWARFExpression {
bool Error;
uint32_t EndOffset;
uint64_t Operands[2];
uint32_t OperandEndOffsets[2];

public:
Description &getDescription() { return Desc; }
uint8_t getCode() { return Opcode; }
uint64_t getRawOperand(unsigned Idx) { return Operands[Idx]; }
uint32_t getOperandEndOffset(unsigned Idx) { return OperandEndOffsets[Idx]; }
uint32_t getEndOffset() { return EndOffset; }
bool extract(DataExtractor Data, uint16_t Version, uint8_t AddressSize,
uint32_t Offset);
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/MC/MCStreamer.h
Expand Up @@ -634,7 +634,7 @@ class MCStreamer {

/// Special case of EmitULEB128Value that avoids the client having to
/// pass in a MCExpr for constant integers.
void EmitULEB128IntValue(uint64_t Value);
void EmitULEB128IntValue(uint64_t Value, unsigned PadTo = 0);

/// Special case of EmitSLEB128Value that avoids the client having to
/// pass in a MCExpr for constant integers.
Expand Down
9 changes: 9 additions & 0 deletions llvm/lib/AsmParser/LLParser.cpp
Expand Up @@ -4838,6 +4838,15 @@ bool LLParser::ParseDIExpression(MDNode *&Result, bool IsDistinct) {
return TokError(Twine("invalid DWARF op '") + Lex.getStrVal() + "'");
}

if (Lex.getKind() == lltok::DwarfAttEncoding) {
if (unsigned Op = dwarf::getAttributeEncoding(Lex.getStrVal())) {
Lex.Lex();
Elements.push_back(Op);
continue;
}
return TokError(Twine("invalid DWARF attribute encoding '") + Lex.getStrVal() + "'");
}

if (Lex.getKind() != lltok::APSInt || Lex.getAPSIntVal().isSigned())
return TokError("expected unsigned integer");

Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/BinaryFormat/Dwarf.cpp
Expand Up @@ -143,6 +143,8 @@ StringRef llvm::dwarf::OperationEncodingString(unsigned Encoding) {
case DW_OP_##NAME: \
return "DW_OP_" #NAME;
#include "llvm/BinaryFormat/Dwarf.def"
case DW_OP_LLVM_convert:
return "DW_OP_LLVM_convert";
case DW_OP_LLVM_fragment:
return "DW_OP_LLVM_fragment";
}
Expand All @@ -153,6 +155,7 @@ unsigned llvm::dwarf::getOperationEncoding(StringRef OperationEncodingString) {
#define HANDLE_DW_OP(ID, NAME, VERSION, VENDOR) \
.Case("DW_OP_" #NAME, DW_OP_##NAME)
#include "llvm/BinaryFormat/Dwarf.def"
.Case("DW_OP_LLVM_convert", DW_OP_LLVM_convert)
.Case("DW_OP_LLVM_fragment", DW_OP_LLVM_fragment)
.Default(0);
}
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
Expand Up @@ -42,11 +42,11 @@ void AsmPrinter::EmitSLEB128(int64_t Value, const char *Desc) const {
OutStreamer->EmitSLEB128IntValue(Value);
}

void AsmPrinter::EmitULEB128(uint64_t Value, const char *Desc) const {
void AsmPrinter::EmitULEB128(uint64_t Value, const char *Desc, unsigned PadTo) const {
if (isVerbose() && Desc)
OutStreamer->AddComment(Desc);

OutStreamer->EmitULEB128IntValue(Value);
OutStreamer->EmitULEB128IntValue(Value, PadTo);
}

/// Emit something like ".uleb128 Hi-Lo".
Expand Down
10 changes: 5 additions & 5 deletions llvm/lib/CodeGen/AsmPrinter/ByteStreamer.h
Expand Up @@ -31,7 +31,7 @@ class ByteStreamer {
// For now we're just handling the calls we need for dwarf emission/hashing.
virtual void EmitInt8(uint8_t Byte, const Twine &Comment = "") = 0;
virtual void EmitSLEB128(uint64_t DWord, const Twine &Comment = "") = 0;
virtual void EmitULEB128(uint64_t DWord, const Twine &Comment = "") = 0;
virtual void EmitULEB128(uint64_t DWord, const Twine &Comment = "", unsigned PadTo = 0) = 0;
};

class APByteStreamer final : public ByteStreamer {
Expand All @@ -48,7 +48,7 @@ class APByteStreamer final : public ByteStreamer {
AP.OutStreamer->AddComment(Comment);
AP.EmitSLEB128(DWord);
}
void EmitULEB128(uint64_t DWord, const Twine &Comment) override {
void EmitULEB128(uint64_t DWord, const Twine &Comment, unsigned PadTo) override {
AP.OutStreamer->AddComment(Comment);
AP.EmitULEB128(DWord);
}
Expand All @@ -65,7 +65,7 @@ class HashingByteStreamer final : public ByteStreamer {
void EmitSLEB128(uint64_t DWord, const Twine &Comment) override {
Hash.addSLEB128(DWord);
}
void EmitULEB128(uint64_t DWord, const Twine &Comment) override {
void EmitULEB128(uint64_t DWord, const Twine &Comment, unsigned PadTo) override {
Hash.addULEB128(DWord);
}
};
Expand Down Expand Up @@ -102,9 +102,9 @@ class BufferByteStreamer final : public ByteStreamer {

}
}
void EmitULEB128(uint64_t DWord, const Twine &Comment) override {
void EmitULEB128(uint64_t DWord, const Twine &Comment, unsigned PadTo) override {
raw_svector_ostream OSE(Buffer);
unsigned Length = encodeULEB128(DWord, OSE);
unsigned Length = encodeULEB128(DWord, OSE, PadTo);
if (GenerateComments) {
Comments.push_back(Comment.str());
// Add some empty comments to keep the Buffer and Comments vectors aligned
Expand Down
17 changes: 17 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/DIE.cpp
Expand Up @@ -505,6 +505,23 @@ unsigned DIELabel::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const {
LLVM_DUMP_METHOD
void DIELabel::print(raw_ostream &O) const { O << "Lbl: " << Label->getName(); }

//===----------------------------------------------------------------------===//
// DIEBaseTypeRef Implementation
//===----------------------------------------------------------------------===//

void DIEBaseTypeRef::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const {
uint64_t Offset = CU->ExprRefedBaseTypes[Index].Die->getOffset();
assert(Offset < (1ULL << (ULEB128PadSize * 7)) && "Offset wont fit");
AP->EmitULEB128(Offset, nullptr, ULEB128PadSize);
}

unsigned DIEBaseTypeRef::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const {
return ULEB128PadSize;
}

LLVM_DUMP_METHOD
void DIEBaseTypeRef::print(raw_ostream &O) const { O << "BaseTypeRef: " << Index; }

//===----------------------------------------------------------------------===//
// DIEDelta Implementation
//===----------------------------------------------------------------------===//
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/CodeGen/AsmPrinter/DIEHash.cpp
Expand Up @@ -225,7 +225,7 @@ void DIEHash::hashLocList(const DIELocList &LocList) {
DwarfDebug &DD = *AP->getDwarfDebug();
const DebugLocStream &Locs = DD.getDebugLocs();
for (const auto &Entry : Locs.getEntries(Locs.getList(LocList.getValue())))
DD.emitDebugLocEntry(Streamer, Entry);
DD.emitDebugLocEntry(Streamer, Entry, nullptr);
}

// Hash an individual attribute \param Attr based on the type of attribute and
Expand Down Expand Up @@ -309,6 +309,7 @@ void DIEHash::hashAttribute(const DIEValue &Value, dwarf::Tag Tag) {
// FIXME: It's uncertain whether or not we should handle this at the moment.
case DIEValue::isExpr:
case DIEValue::isLabel:
case DIEValue::isBaseTypeRef:
case DIEValue::isDelta:
llvm_unreachable("Add support for additional value types.");
}
Expand Down
6 changes: 4 additions & 2 deletions llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h
Expand Up @@ -148,8 +148,10 @@ class DebugLocEntry {
}

/// Lower this entry into a DWARF expression.
void finalize(const AsmPrinter &AP, DebugLocStream::ListBuilder &List,
const DIBasicType *BT);
void finalize(const AsmPrinter &AP,
DebugLocStream::ListBuilder &List,
const DIBasicType *BT,
DwarfCompileUnit &TheCU);
};

/// Compare two Values for equality.
Expand Down
24 changes: 24 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
Expand Up @@ -17,6 +17,7 @@
#include "DwarfUnit.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/Dwarf.h"
Expand Down Expand Up @@ -1185,3 +1186,26 @@ void DwarfCompileUnit::addAddrTableBase() {
: dwarf::DW_AT_GNU_addr_base,
Label, TLOF.getDwarfAddrSection()->getBeginSymbol());
}

void DwarfCompileUnit::addBaseTypeRef(DIEValueList &Die, int64_t Idx) {
Die.addValue(DIEValueAllocator, (dwarf::Attribute)0, dwarf::DW_FORM_udata,
new (DIEValueAllocator) DIEBaseTypeRef(this, Idx));
}

void DwarfCompileUnit::createBaseTypeDIEs() {
// Insert the base_type DIEs directly after the CU so that their offsets will
// fit in the fixed size ULEB128 used inside the location expressions.
// Maintain order by iterating backwards and inserting to the front of CU
// child list.
for (auto &Btr : reverse(ExprRefedBaseTypes)) {
DIE &Die = getUnitDie().addChildFront(
DIE::get(DIEValueAllocator, dwarf::DW_TAG_base_type));
Twine T(dwarf::AttributeEncodingString(Btr.Encoding) + "_" + Twine(Btr.BitSize));
SmallString<32> Str;
addString(Die, dwarf::DW_AT_name, T.toStringRef(Str));
addUInt(Die, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1, Btr.Encoding);
addUInt(Die, dwarf::DW_AT_byte_size, None, Btr.BitSize / 8);

Btr.Die = &Die;
}
}
14 changes: 14 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
Expand Up @@ -124,6 +124,16 @@ class DwarfCompileUnit final : public DwarfUnit {
const DIExpression *Expr;
};

struct BaseTypeRef {
BaseTypeRef(unsigned BitSize, dwarf::TypeKind Encoding) :
BitSize(BitSize), Encoding(Encoding) {}
unsigned BitSize;
dwarf::TypeKind Encoding;
DIE *Die = nullptr;
};

std::vector<BaseTypeRef> ExprRefedBaseTypes;

/// Get or create global variable DIE.
DIE *
getOrCreateGlobalVariableDIE(const DIGlobalVariable *GV,
Expand Down Expand Up @@ -199,6 +209,8 @@ class DwarfCompileUnit final : public DwarfUnit {
SmallVectorImpl<DIE *> &Children,
bool *HasNonScopeChildren = nullptr);

void createBaseTypeDIEs();

/// Construct a DIE for this subprogram scope.
DIE &constructSubprogramScopeDIE(const DISubprogram *Sub,
LexicalScope *Scope);
Expand Down Expand Up @@ -313,6 +325,8 @@ class DwarfCompileUnit final : public DwarfUnit {
void setDWOId(uint64_t DwoId) { DWOId = DwoId; }

bool hasDwarfPubSections() const;

void addBaseTypeRef(DIEValueList &Die, int64_t Idx);
};

} // end namespace llvm
Expand Down

0 comments on commit cd8a940

Please sign in to comment.