forked from OSchip/llvm-project
[DebugInfo] Introduce DW_OP_LLVM_convert
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
This commit is contained in:
parent
f170dff3c1
commit
cd8a940b37
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -510,7 +510,7 @@ public:
|
|||
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.
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace llvm {
|
|||
class AsmPrinter;
|
||||
class DIE;
|
||||
class DIEUnit;
|
||||
class DwarfCompileUnit;
|
||||
class MCExpr;
|
||||
class MCSection;
|
||||
class MCSymbol;
|
||||
|
@ -229,6 +230,25 @@ public:
|
|||
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.
|
||||
///
|
||||
|
@ -349,7 +369,7 @@ private:
|
|||
/// 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 *),
|
||||
|
@ -501,6 +521,18 @@ 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 {
|
||||
|
@ -508,8 +540,15 @@ 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
|
||||
|
@ -772,6 +811,13 @@ public:
|
|||
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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -86,7 +86,7 @@ public:
|
|||
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:
|
||||
|
|
|
@ -79,11 +79,13 @@ public:
|
|||
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);
|
||||
|
|
|
@ -634,7 +634,7 @@ public:
|
|||
|
||||
/// 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.
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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".
|
||||
|
|
|
@ -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 {
|
||||
|
@ -48,7 +48,7 @@ public:
|
|||
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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
@ -102,9 +102,9 @@ public:
|
|||
|
||||
}
|
||||
}
|
||||
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
|
||||
|
|
|
@ -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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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
|
||||
|
@ -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.");
|
||||
}
|
||||
|
|
|
@ -148,8 +148,10 @@ public:
|
|||
}
|
||||
|
||||
/// 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.
|
||||
|
|
|
@ -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"
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,6 +124,16 @@ public:
|
|||
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,
|
||||
|
@ -199,6 +209,8 @@ public:
|
|||
SmallVectorImpl<DIE *> &Children,
|
||||
bool *HasNonScopeChildren = nullptr);
|
||||
|
||||
void createBaseTypeDIEs();
|
||||
|
||||
/// Construct a DIE for this subprogram scope.
|
||||
DIE &constructSubprogramScopeDIE(const DISubprogram *Sub,
|
||||
LexicalScope *Scope);
|
||||
|
@ -313,6 +325,8 @@ public:
|
|||
void setDWOId(uint64_t DwoId) { DWOId = DwoId; }
|
||||
|
||||
bool hasDwarfPubSections() const;
|
||||
|
||||
void addBaseTypeRef(DIEValueList &Die, int64_t Idx);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
|
|
@ -41,6 +41,8 @@
|
|||
#include "llvm/CodeGen/TargetInstrInfo.h"
|
||||
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
||||
#include "llvm/CodeGen/TargetSubtargetInfo.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DebugInfoMetadata.h"
|
||||
#include "llvm/IR/DebugLoc.h"
|
||||
|
@ -161,6 +163,7 @@ static const char *const DWARFGroupName = "dwarf";
|
|||
static const char *const DWARFGroupDescription = "DWARF Emission";
|
||||
static const char *const DbgTimerName = "writer";
|
||||
static const char *const DbgTimerDescription = "DWARF Debug Writer";
|
||||
static constexpr unsigned ULEB128PadSize = 4;
|
||||
|
||||
void DebugLocDwarfExpression::emitOp(uint8_t Op, const char *Comment) {
|
||||
BS.EmitInt8(
|
||||
|
@ -176,6 +179,11 @@ void DebugLocDwarfExpression::emitUnsigned(uint64_t Value) {
|
|||
BS.EmitULEB128(Value, Twine(Value));
|
||||
}
|
||||
|
||||
void DebugLocDwarfExpression::emitBaseTypeRef(uint64_t Idx) {
|
||||
assert(Idx < (1ULL << (ULEB128PadSize * 7)) && "Idx wont fit");
|
||||
BS.EmitULEB128(Idx, Twine(Idx), ULEB128PadSize);
|
||||
}
|
||||
|
||||
bool DebugLocDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI,
|
||||
unsigned MachineReg) {
|
||||
// This information is not available while emitting .debug_loc entries.
|
||||
|
@ -940,6 +948,11 @@ void DwarfDebug::endModule() {
|
|||
assert(CurFn == nullptr);
|
||||
assert(CurMI == nullptr);
|
||||
|
||||
for (const auto &P : CUMap) {
|
||||
auto &CU = *P.second;
|
||||
CU.createBaseTypeDIEs();
|
||||
}
|
||||
|
||||
// If we aren't actually generating debug info (check beginModule -
|
||||
// conditionalized on !DisableDebugInfoPrinting and the presence of the
|
||||
// llvm.dbg.cu metadata node)
|
||||
|
@ -1369,7 +1382,7 @@ void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU,
|
|||
|
||||
// Finalize the entry by lowering it into a DWARF bytestream.
|
||||
for (auto &Entry : Entries)
|
||||
Entry.finalize(*Asm, List, BT);
|
||||
Entry.finalize(*Asm, List, BT, TheCU);
|
||||
}
|
||||
|
||||
// For each InlinedEntity collected from DBG_LABEL instructions, convert to
|
||||
|
@ -1911,13 +1924,55 @@ void DwarfDebug::emitDebugStr() {
|
|||
StringOffsetsSection, /* UseRelativeOffsets = */ true);
|
||||
}
|
||||
|
||||
void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer,
|
||||
const DebugLocStream::Entry &Entry) {
|
||||
void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, const
|
||||
DebugLocStream::Entry &Entry,
|
||||
const DwarfCompileUnit *CU) {
|
||||
auto &&Comments = DebugLocs.getComments(Entry);
|
||||
auto Comment = Comments.begin();
|
||||
auto End = Comments.end();
|
||||
for (uint8_t Byte : DebugLocs.getBytes(Entry))
|
||||
Streamer.EmitInt8(Byte, Comment != End ? *(Comment++) : "");
|
||||
|
||||
// The expressions are inserted into a byte stream rather early (see
|
||||
// DwarfExpression::addExpression) so for those ops (e.g. DW_OP_convert) that
|
||||
// need to reference a base_type DIE the offset of that DIE is not yet known.
|
||||
// To deal with this we instead insert a placeholder early and then extract
|
||||
// it here and replace it with the real reference.
|
||||
unsigned PtrSize = Asm->MAI->getCodePointerSize();
|
||||
DWARFDataExtractor Data(StringRef(DebugLocs.getBytes(Entry).data(),
|
||||
DebugLocs.getBytes(Entry).size()),
|
||||
Asm->getDataLayout().isLittleEndian(), PtrSize);
|
||||
DWARFExpression Expr(Data, getDwarfVersion(), PtrSize);
|
||||
|
||||
using Encoding = DWARFExpression::Operation::Encoding;
|
||||
uint32_t Offset = 0;
|
||||
for (auto &Op : Expr) {
|
||||
assert(Op.getCode() != dwarf::DW_OP_const_type &&
|
||||
"3 operand ops not yet supported");
|
||||
Streamer.EmitInt8(Op.getCode(), Comment != End ? *(Comment++) : "");
|
||||
Offset++;
|
||||
for (unsigned I = 0; I < 2; ++I) {
|
||||
if (Op.getDescription().Op[I] == Encoding::SizeNA)
|
||||
continue;
|
||||
if (Op.getDescription().Op[I] == Encoding::BaseTypeRef) {
|
||||
if (CU) {
|
||||
uint64_t Offset = CU->ExprRefedBaseTypes[Op.getRawOperand(I)].Die->getOffset();
|
||||
assert(Offset < (1ULL << (ULEB128PadSize * 7)) && "Offset wont fit");
|
||||
Asm->EmitULEB128(Offset, nullptr, ULEB128PadSize);
|
||||
} else {
|
||||
// Emit a reference to the 'generic type'.
|
||||
Asm->EmitULEB128(0, nullptr, ULEB128PadSize);
|
||||
}
|
||||
// Make sure comments stay aligned.
|
||||
for (unsigned J = 0; J < ULEB128PadSize; ++J)
|
||||
if (Comment != End)
|
||||
Comment++;
|
||||
} else {
|
||||
for (uint32_t J = Offset; J < Op.getOperandEndOffset(I); ++J)
|
||||
Streamer.EmitInt8(Data.getData()[J], Comment != End ? *(Comment++) : "");
|
||||
}
|
||||
Offset = Op.getOperandEndOffset(I);
|
||||
}
|
||||
assert(Offset == Op.getEndOffset());
|
||||
}
|
||||
}
|
||||
|
||||
static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT,
|
||||
|
@ -1951,11 +2006,12 @@ static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT,
|
|||
|
||||
void DebugLocEntry::finalize(const AsmPrinter &AP,
|
||||
DebugLocStream::ListBuilder &List,
|
||||
const DIBasicType *BT) {
|
||||
const DIBasicType *BT,
|
||||
DwarfCompileUnit &TheCU) {
|
||||
assert(Begin != End && "unexpected location list entry with empty range");
|
||||
DebugLocStream::EntryBuilder Entry(List, Begin, End);
|
||||
BufferByteStreamer Streamer = Entry.getStreamer();
|
||||
DebugLocDwarfExpression DwarfExpr(AP.getDwarfVersion(), Streamer);
|
||||
DebugLocDwarfExpression DwarfExpr(AP.getDwarfVersion(), Streamer, TheCU);
|
||||
const DebugLocEntry::Value &Value = Values[0];
|
||||
if (Value.isFragment()) {
|
||||
// Emit all fragments that belong to the same variable and range.
|
||||
|
@ -1975,7 +2031,8 @@ void DebugLocEntry::finalize(const AsmPrinter &AP,
|
|||
DwarfExpr.finalize();
|
||||
}
|
||||
|
||||
void DwarfDebug::emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry) {
|
||||
void DwarfDebug::emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry,
|
||||
const DwarfCompileUnit *CU) {
|
||||
// Emit the size.
|
||||
Asm->OutStreamer->AddComment("Loc expr size");
|
||||
if (getDwarfVersion() >= 5)
|
||||
|
@ -1984,7 +2041,7 @@ void DwarfDebug::emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry) {
|
|||
Asm->emitInt16(DebugLocs.getBytes(Entry).size());
|
||||
// Emit the entry.
|
||||
APByteStreamer Streamer(*Asm);
|
||||
emitDebugLocEntry(Streamer, Entry);
|
||||
emitDebugLocEntry(Streamer, Entry, CU);
|
||||
}
|
||||
|
||||
// Emit the common part of the DWARF 5 range/locations list tables header.
|
||||
|
@ -2084,7 +2141,7 @@ void DwarfDebug::emitDebugLoc() {
|
|||
Asm->EmitLabelDifference(Entry.EndSym, Base, Size);
|
||||
}
|
||||
|
||||
emitDebugLocEntryLocation(Entry);
|
||||
emitDebugLocEntryLocation(Entry, CU);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2105,7 +2162,7 @@ void DwarfDebug::emitDebugLoc() {
|
|||
Asm->OutStreamer->EmitSymbolValue(Entry.EndSym, Size);
|
||||
}
|
||||
|
||||
emitDebugLocEntryLocation(Entry);
|
||||
emitDebugLocEntryLocation(Entry, CU);
|
||||
}
|
||||
|
||||
if (IsLocLists) {
|
||||
|
@ -2141,7 +2198,7 @@ void DwarfDebug::emitDebugLocDWO() {
|
|||
Asm->EmitULEB128(idx);
|
||||
Asm->EmitLabelDifference(Entry.EndSym, Entry.BeginSym, 4);
|
||||
|
||||
emitDebugLocEntryLocation(Entry);
|
||||
emitDebugLocEntryLocation(Entry, List.CU);
|
||||
}
|
||||
Asm->emitInt8(dwarf::DW_LLE_end_of_list);
|
||||
}
|
||||
|
|
|
@ -682,10 +682,12 @@ public:
|
|||
/// Emit an entry for the debug loc section. This can be used to
|
||||
/// handle an entry that's going to be emitted into the debug loc section.
|
||||
void emitDebugLocEntry(ByteStreamer &Streamer,
|
||||
const DebugLocStream::Entry &Entry);
|
||||
const DebugLocStream::Entry &Entry,
|
||||
const DwarfCompileUnit *CU);
|
||||
|
||||
/// Emit the location for a debug loc entry, including the size header.
|
||||
void emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry);
|
||||
void emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry,
|
||||
const DwarfCompileUnit *CU);
|
||||
|
||||
/// Find the MDNode for the given reference.
|
||||
template <typename T> T *resolve(TypedDINodeRef<T> Ref) const {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "DwarfExpression.h"
|
||||
#include "DwarfCompileUnit.h"
|
||||
#include "llvm/ADT/APInt.h"
|
||||
#include "llvm/ADT/SmallBitVector.h"
|
||||
#include "llvm/BinaryFormat/Dwarf.h"
|
||||
|
@ -318,6 +319,8 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor,
|
|||
if (SubRegisterSizeInBits && N && (N->getOp() != dwarf::DW_OP_LLVM_fragment))
|
||||
maskSubRegister();
|
||||
|
||||
Optional<DIExpression::ExprOperand> PrevConvertOp = None;
|
||||
|
||||
while (ExprCursor) {
|
||||
auto Op = ExprCursor.take();
|
||||
switch (Op->getOp()) {
|
||||
|
@ -384,6 +387,42 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor,
|
|||
assert(LocationKind != Register);
|
||||
emitConstu(Op->getArg(0));
|
||||
break;
|
||||
case dwarf::DW_OP_LLVM_convert: {
|
||||
unsigned BitSize = Op->getArg(0);
|
||||
dwarf::TypeKind Encoding = static_cast<dwarf::TypeKind>(Op->getArg(1));
|
||||
if (DwarfVersion >= 5) {
|
||||
emitOp(dwarf::DW_OP_convert);
|
||||
// Reuse the base_type if we already have one in this CU otherwise we
|
||||
// create a new one.
|
||||
unsigned I = 0, E = CU.ExprRefedBaseTypes.size();
|
||||
for (; I != E; ++I)
|
||||
if (CU.ExprRefedBaseTypes[I].BitSize == BitSize &&
|
||||
CU.ExprRefedBaseTypes[I].Encoding == Encoding)
|
||||
break;
|
||||
|
||||
if (I == E)
|
||||
CU.ExprRefedBaseTypes.emplace_back(BitSize, Encoding);
|
||||
|
||||
// If targeting a location-list; simply emit the index into the raw
|
||||
// byte stream as ULEB128, DwarfDebug::emitDebugLocEntry has been
|
||||
// fitted with means to extract it later.
|
||||
// If targeting a inlined DW_AT_location; insert a DIEBaseTypeRef
|
||||
// (containing the index and a resolve mechanism during emit) into the
|
||||
// DIE value list.
|
||||
emitBaseTypeRef(I);
|
||||
} else {
|
||||
if (PrevConvertOp && PrevConvertOp->getArg(0) < BitSize) {
|
||||
if (Encoding == dwarf::DW_ATE_signed)
|
||||
emitLegacySExt(PrevConvertOp->getArg(0));
|
||||
else if (Encoding == dwarf::DW_ATE_unsigned)
|
||||
emitLegacyZExt(PrevConvertOp->getArg(0));
|
||||
PrevConvertOp = None;
|
||||
} else {
|
||||
PrevConvertOp = Op;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case dwarf::DW_OP_stack_value:
|
||||
LocationKind = Implicit;
|
||||
break;
|
||||
|
@ -436,3 +475,25 @@ void DwarfExpression::addFragmentOffset(const DIExpression *Expr) {
|
|||
addOpPiece(FragmentOffset - OffsetInBits);
|
||||
OffsetInBits = FragmentOffset;
|
||||
}
|
||||
|
||||
void DwarfExpression::emitLegacySExt(unsigned FromBits) {
|
||||
// (((X >> (FromBits - 1)) * (~0)) << FromBits) | X
|
||||
emitOp(dwarf::DW_OP_dup);
|
||||
emitOp(dwarf::DW_OP_constu);
|
||||
emitUnsigned(FromBits - 1);
|
||||
emitOp(dwarf::DW_OP_shr);
|
||||
emitOp(dwarf::DW_OP_lit0);
|
||||
emitOp(dwarf::DW_OP_not);
|
||||
emitOp(dwarf::DW_OP_mul);
|
||||
emitOp(dwarf::DW_OP_constu);
|
||||
emitUnsigned(FromBits);
|
||||
emitOp(dwarf::DW_OP_shl);
|
||||
emitOp(dwarf::DW_OP_or);
|
||||
}
|
||||
|
||||
void DwarfExpression::emitLegacyZExt(unsigned FromBits) {
|
||||
// (X & (1 << FromBits - 1))
|
||||
emitOp(dwarf::DW_OP_constu);
|
||||
emitUnsigned((1ULL << FromBits) - 1);
|
||||
emitOp(dwarf::DW_OP_and);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace llvm {
|
|||
class AsmPrinter;
|
||||
class APInt;
|
||||
class ByteStreamer;
|
||||
class DwarfUnit;
|
||||
class DwarfCompileUnit;
|
||||
class DIELoc;
|
||||
class TargetRegisterInfo;
|
||||
|
||||
|
@ -104,6 +104,8 @@ protected:
|
|||
const char *Comment;
|
||||
};
|
||||
|
||||
DwarfCompileUnit &CU;
|
||||
|
||||
/// The register location, if any.
|
||||
SmallVector<Register, 2> DwarfRegs;
|
||||
|
||||
|
@ -137,6 +139,8 @@ protected:
|
|||
/// Emit a raw unsigned value.
|
||||
virtual void emitUnsigned(uint64_t Value) = 0;
|
||||
|
||||
virtual void emitBaseTypeRef(uint64_t Idx) = 0;
|
||||
|
||||
/// Emit a normalized unsigned constant.
|
||||
void emitConstu(uint64_t Value);
|
||||
|
||||
|
@ -199,7 +203,8 @@ protected:
|
|||
~DwarfExpression() = default;
|
||||
|
||||
public:
|
||||
DwarfExpression(unsigned DwarfVersion) : DwarfVersion(DwarfVersion) {}
|
||||
DwarfExpression(unsigned DwarfVersion, DwarfCompileUnit &CU)
|
||||
: CU(CU), DwarfVersion(DwarfVersion) {}
|
||||
|
||||
/// This needs to be called last to commit any pending changes.
|
||||
void finalize();
|
||||
|
@ -247,6 +252,9 @@ public:
|
|||
/// If applicable, emit an empty DW_OP_piece / DW_OP_bit_piece to advance to
|
||||
/// the fragment described by \c Expr.
|
||||
void addFragmentOffset(const DIExpression *Expr);
|
||||
|
||||
void emitLegacySExt(unsigned FromBits);
|
||||
void emitLegacyZExt(unsigned FromBits);
|
||||
};
|
||||
|
||||
/// DwarfExpression implementation for .debug_loc entries.
|
||||
|
@ -256,27 +264,28 @@ class DebugLocDwarfExpression final : public DwarfExpression {
|
|||
void emitOp(uint8_t Op, const char *Comment = nullptr) override;
|
||||
void emitSigned(int64_t Value) override;
|
||||
void emitUnsigned(uint64_t Value) override;
|
||||
void emitBaseTypeRef(uint64_t Idx) override;
|
||||
bool isFrameRegister(const TargetRegisterInfo &TRI,
|
||||
unsigned MachineReg) override;
|
||||
|
||||
public:
|
||||
DebugLocDwarfExpression(unsigned DwarfVersion, ByteStreamer &BS)
|
||||
: DwarfExpression(DwarfVersion), BS(BS) {}
|
||||
DebugLocDwarfExpression(unsigned DwarfVersion, ByteStreamer &BS, DwarfCompileUnit &CU)
|
||||
: DwarfExpression(DwarfVersion, CU), BS(BS) {}
|
||||
};
|
||||
|
||||
/// DwarfExpression implementation for singular DW_AT_location.
|
||||
class DIEDwarfExpression final : public DwarfExpression {
|
||||
const AsmPrinter &AP;
|
||||
DwarfUnit &DU;
|
||||
DIELoc &DIE;
|
||||
|
||||
void emitOp(uint8_t Op, const char *Comment = nullptr) override;
|
||||
void emitSigned(int64_t Value) override;
|
||||
void emitUnsigned(uint64_t Value) override;
|
||||
void emitBaseTypeRef(uint64_t Idx) override;
|
||||
bool isFrameRegister(const TargetRegisterInfo &TRI,
|
||||
unsigned MachineReg) override;
|
||||
public:
|
||||
DIEDwarfExpression(const AsmPrinter &AP, DwarfUnit &DU, DIELoc &DIE);
|
||||
DIEDwarfExpression(const AsmPrinter &AP, DwarfCompileUnit &CU, DIELoc &DIE);
|
||||
|
||||
DIELoc *finalize() {
|
||||
DwarfExpression::finalize();
|
||||
|
|
|
@ -147,7 +147,7 @@ public:
|
|||
void emitUnits(bool UseOffsets);
|
||||
|
||||
/// Emit the given unit to its section.
|
||||
void emitUnit(DwarfUnit *U, bool UseOffsets);
|
||||
void emitUnit(DwarfUnit *TheU, bool UseOffsets);
|
||||
|
||||
/// Emit a set of abbreviations to the specific section.
|
||||
void emitAbbrevs(MCSection *);
|
||||
|
|
|
@ -46,21 +46,26 @@ using namespace llvm;
|
|||
|
||||
#define DEBUG_TYPE "dwarfdebug"
|
||||
|
||||
DIEDwarfExpression::DIEDwarfExpression(const AsmPrinter &AP, DwarfUnit &DU,
|
||||
DIEDwarfExpression::DIEDwarfExpression(const AsmPrinter &AP,
|
||||
DwarfCompileUnit &CU,
|
||||
DIELoc &DIE)
|
||||
: DwarfExpression(AP.getDwarfVersion()), AP(AP), DU(DU),
|
||||
: DwarfExpression(AP.getDwarfVersion(), CU), AP(AP),
|
||||
DIE(DIE) {}
|
||||
|
||||
void DIEDwarfExpression::emitOp(uint8_t Op, const char* Comment) {
|
||||
DU.addUInt(DIE, dwarf::DW_FORM_data1, Op);
|
||||
CU.addUInt(DIE, dwarf::DW_FORM_data1, Op);
|
||||
}
|
||||
|
||||
void DIEDwarfExpression::emitSigned(int64_t Value) {
|
||||
DU.addSInt(DIE, dwarf::DW_FORM_sdata, Value);
|
||||
CU.addSInt(DIE, dwarf::DW_FORM_sdata, Value);
|
||||
}
|
||||
|
||||
void DIEDwarfExpression::emitUnsigned(uint64_t Value) {
|
||||
DU.addUInt(DIE, dwarf::DW_FORM_udata, Value);
|
||||
CU.addUInt(DIE, dwarf::DW_FORM_udata, Value);
|
||||
}
|
||||
|
||||
void DIEDwarfExpression::emitBaseTypeRef(uint64_t Idx) {
|
||||
CU.addBaseTypeRef(DIE, Idx);
|
||||
}
|
||||
|
||||
bool DIEDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI,
|
||||
|
|
|
@ -18,4 +18,4 @@
|
|||
type = Library
|
||||
name = AsmPrinter
|
||||
parent = Libraries
|
||||
required_libraries = Analysis BinaryFormat CodeGen Core DebugInfoCodeView DebugInfoMSF MC MCParser Support Target
|
||||
required_libraries = Analysis BinaryFormat CodeGen Core DebugInfoCodeView DebugInfoDWARF DebugInfoMSF MC MCParser Support Target
|
||||
|
|
|
@ -225,6 +225,7 @@ void DWARFDebugLoclists::LocationList::dump(raw_ostream &OS, uint64_t BaseAddr,
|
|||
bool IsLittleEndian,
|
||||
unsigned AddressSize,
|
||||
const MCRegisterInfo *MRI,
|
||||
DWARFUnit *U,
|
||||
unsigned Indent) const {
|
||||
for (const Entry &E : Entries) {
|
||||
switch (E.Kind) {
|
||||
|
@ -254,7 +255,7 @@ void DWARFDebugLoclists::LocationList::dump(raw_ostream &OS, uint64_t BaseAddr,
|
|||
llvm_unreachable("unreachable locations list kind");
|
||||
}
|
||||
|
||||
dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI, nullptr);
|
||||
dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI, U);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -263,7 +264,7 @@ void DWARFDebugLoclists::dump(raw_ostream &OS, uint64_t BaseAddr,
|
|||
Optional<uint64_t> Offset) const {
|
||||
auto DumpLocationList = [&](const LocationList &L) {
|
||||
OS << format("0x%8.8x: ", L.Offset);
|
||||
L.dump(OS, BaseAddr, IsLittleEndian, AddressSize, MRI, /*Indent=*/12);
|
||||
L.dump(OS, BaseAddr, IsLittleEndian, AddressSize, MRI, nullptr, /*Indent=*/12);
|
||||
OS << "\n\n";
|
||||
};
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ static void dumpLocation(raw_ostream &OS, DWARFFormValue &FormValue,
|
|||
|
||||
if (LL)
|
||||
LL->dump(OS, BaseAddr, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI,
|
||||
Indent);
|
||||
U, Indent);
|
||||
else
|
||||
OS << "error extracting location list.";
|
||||
}
|
||||
|
|
|
@ -188,6 +188,8 @@ bool DWARFExpression::Operation::extract(DataExtractor Data, uint16_t Version,
|
|||
default:
|
||||
llvm_unreachable("Unknown DWARFExpression Op size");
|
||||
}
|
||||
|
||||
OperandEndOffsets[Operand] = Offset;
|
||||
}
|
||||
|
||||
EndOffset = Offset;
|
||||
|
|
|
@ -2123,8 +2123,13 @@ static void writeDIExpression(raw_ostream &Out, const DIExpression *N,
|
|||
assert(!OpStr.empty() && "Expected valid opcode");
|
||||
|
||||
Out << FS << OpStr;
|
||||
for (unsigned A = 0, AE = I->getNumArgs(); A != AE; ++A)
|
||||
Out << FS << I->getArg(A);
|
||||
if (I->getOp() == dwarf::DW_OP_LLVM_convert) {
|
||||
Out << FS << I->getArg(0);
|
||||
Out << FS << dwarf::AttributeEncodingString(I->getArg(1));
|
||||
} else {
|
||||
for (unsigned A = 0, AE = I->getNumArgs(); A != AE; ++A)
|
||||
Out << FS << I->getArg(A);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const auto &I : N->getElements())
|
||||
|
|
|
@ -813,6 +813,7 @@ DIExpression *DIExpression::getImpl(LLVMContext &Context,
|
|||
|
||||
unsigned DIExpression::ExprOperand::getSize() const {
|
||||
switch (getOp()) {
|
||||
case dwarf::DW_OP_LLVM_convert:
|
||||
case dwarf::DW_OP_LLVM_fragment:
|
||||
return 3;
|
||||
case dwarf::DW_OP_constu:
|
||||
|
@ -857,6 +858,7 @@ bool DIExpression::isValid() const {
|
|||
return false;
|
||||
break;
|
||||
}
|
||||
case dwarf::DW_OP_LLVM_convert:
|
||||
case dwarf::DW_OP_constu:
|
||||
case dwarf::DW_OP_plus_uconst:
|
||||
case dwarf::DW_OP_plus:
|
||||
|
|
|
@ -135,10 +135,10 @@ void MCStreamer::EmitIntValue(uint64_t Value, unsigned Size) {
|
|||
|
||||
/// EmitULEB128IntValue - Special case of EmitULEB128Value that avoids the
|
||||
/// client having to pass in a MCExpr for constant integers.
|
||||
void MCStreamer::EmitULEB128IntValue(uint64_t Value) {
|
||||
void MCStreamer::EmitULEB128IntValue(uint64_t Value, unsigned PadTo) {
|
||||
SmallString<128> Tmp;
|
||||
raw_svector_ostream OSE(Tmp);
|
||||
encodeULEB128(Value, OSE);
|
||||
encodeULEB128(Value, OSE, PadTo);
|
||||
EmitBytes(OSE.str());
|
||||
}
|
||||
|
||||
|
|
|
@ -1861,21 +1861,10 @@ bool llvm::replaceAllDbgUsesWith(Instruction &From, Value &To,
|
|||
return None;
|
||||
|
||||
bool Signed = *Signedness == DIBasicType::Signedness::Signed;
|
||||
|
||||
if (!Signed) {
|
||||
// In the unsigned case, assume that a debugger will initialize the
|
||||
// high bits to 0 and do a no-op conversion.
|
||||
return Identity(DII);
|
||||
} else {
|
||||
// In the signed case, the high bits are given by sign extension, i.e:
|
||||
// (To >> (ToBits - 1)) * ((2 ^ FromBits) - 1)
|
||||
// Calculate the high bits and OR them together with the low bits.
|
||||
SmallVector<uint64_t, 8> Ops({dwarf::DW_OP_dup, dwarf::DW_OP_constu,
|
||||
(ToBits - 1), dwarf::DW_OP_shr,
|
||||
dwarf::DW_OP_lit0, dwarf::DW_OP_not,
|
||||
dwarf::DW_OP_mul, dwarf::DW_OP_or});
|
||||
return DIExpression::appendToStack(DII.getExpression(), Ops);
|
||||
}
|
||||
dwarf::TypeKind TK = Signed ? dwarf::DW_ATE_signed : dwarf::DW_ATE_unsigned;
|
||||
SmallVector<uint64_t, 8> Ops({dwarf::DW_OP_LLVM_convert, ToBits, TK,
|
||||
dwarf::DW_OP_LLVM_convert, FromBits, TK});
|
||||
return DIExpression::appendToStack(DII.getExpression(), Ops);
|
||||
};
|
||||
return rewriteDebugUsers(From, To, DomPoint, DT, SignOrZeroExt);
|
||||
}
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
; CHECK-SAME: !DIExpression(DW_OP_LLVM_fragment, 3, 7),
|
||||
; CHECK-SAME: !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 3, DW_OP_LLVM_fragment, 3, 7),
|
||||
; CHECK-SAME: !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef),
|
||||
; CHECK-SAME: !DIExpression(DW_OP_plus_uconst, 3)}
|
||||
; CHECK-SAME: !DIExpression(DW_OP_plus_uconst, 3)
|
||||
; CHECK-SAME: !DIExpression(DW_OP_LLVM_convert, 16, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_signed)}
|
||||
|
||||
!named = !{!0, !1, !2, !3, !4, !5, !6}
|
||||
!named = !{!0, !1, !2, !3, !4, !5, !6, !7}
|
||||
|
||||
!0 = !DIExpression()
|
||||
!1 = !DIExpression(DW_OP_deref)
|
||||
|
@ -19,3 +20,4 @@
|
|||
!4 = !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 3, DW_OP_LLVM_fragment, 3, 7)
|
||||
!5 = !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef)
|
||||
!6 = !DIExpression(DW_OP_plus_uconst, 3)
|
||||
!7 = !DIExpression(DW_OP_LLVM_convert, 16, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_signed)
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
; RUN: llc -dwarf-version=5 -filetype=obj -O0 < %s | llvm-dwarfdump - | FileCheck %s --match-full-lines --check-prefix=DW5-CHECK
|
||||
; RUN: llc -dwarf-version=4 -filetype=obj -O0 < %s | llvm-dwarfdump - | FileCheck %s --match-full-lines --check-prefix=DW4-CHECK
|
||||
|
||||
; DW5-CHECK: .debug_info contents:
|
||||
; DW5-CHECK-NEXT: 0x00000000: Compile Unit: length = 0x0000005c version = 0x0005 unit_type = DW_UT_compile abbr_offset = 0x0000 addr_size = 0x08 (next unit at 0x00000060)
|
||||
; DW5-CHECK-EMPTY:
|
||||
; DW5-CHECK-NEXT: 0x0000000c: DW_TAG_compile_unit
|
||||
; DW5-CHECK-NEXT: DW_AT_producer ("clang version 9.0.0 (trunk 353791) (llvm/trunk 353801)")
|
||||
; DW5-CHECK-NEXT: DW_AT_language (DW_LANG_C99)
|
||||
; DW5-CHECK-NEXT: DW_AT_name ("dbg.c")
|
||||
; DW5-CHECK-NEXT: DW_AT_str_offsets_base (0x00000008)
|
||||
; DW5-CHECK-NEXT: DW_AT_stmt_list (0x00000000)
|
||||
; DW5-CHECK-NEXT: DW_AT_comp_dir ("/tmp")
|
||||
; DW5-CHECK-NEXT: DW_AT_addr_base (0x00000008)
|
||||
; DW5-CHECK-NEXT: DW_AT_low_pc (0x0000000000000000)
|
||||
; DW5-CHECK-NEXT: DW_AT_high_pc (0x0000000000000007)
|
||||
; DW5-CHECK-NEXT: DW_AT_loclists_base (0x0000000c)
|
||||
; DW5-CHECK-EMPTY:
|
||||
; DW5-CHECK-NEXT: 0x00000027: DW_TAG_base_type
|
||||
; DW5-CHECK-NEXT: DW_AT_name ("DW_ATE_signed_8")
|
||||
; DW5-CHECK-NEXT: DW_AT_encoding (DW_ATE_signed)
|
||||
; DW5-CHECK-NEXT: DW_AT_byte_size (0x01)
|
||||
; DW5-CHECK-EMPTY:
|
||||
; DW5-CHECK-NEXT: 0x0000002b: DW_TAG_base_type
|
||||
; DW5-CHECK-NEXT: DW_AT_name ("DW_ATE_signed_32")
|
||||
; DW5-CHECK-NEXT: DW_AT_encoding (DW_ATE_signed)
|
||||
; DW5-CHECK-NEXT: DW_AT_byte_size (0x04)
|
||||
; DW5-CHECK-EMPTY:
|
||||
; DW5-CHECK-NEXT: 0x0000002f: DW_TAG_subprogram
|
||||
; DW5-CHECK-NEXT: DW_AT_low_pc (0x0000000000000000)
|
||||
; DW5-CHECK-NEXT: DW_AT_high_pc (0x0000000000000007)
|
||||
; DW5-CHECK-NEXT: DW_AT_frame_base (DW_OP_reg7 RSP)
|
||||
; DW5-CHECK-NEXT: DW_AT_name ("foo")
|
||||
; DW5-CHECK-NEXT: DW_AT_decl_file ("/tmp/dbg.c")
|
||||
; DW5-CHECK-NEXT: DW_AT_decl_line (1)
|
||||
; DW5-CHECK-NEXT: DW_AT_prototyped (true)
|
||||
; DW5-CHECK-NEXT: DW_AT_type (0x00000057 "signed char")
|
||||
; DW5-CHECK-NEXT: DW_AT_external (true)
|
||||
; DW5-CHECK-EMPTY:
|
||||
; DW5-CHECK-NEXT: 0x0000003e: DW_TAG_formal_parameter
|
||||
; DW5-CHECK-NEXT: DW_AT_location (0x0000000c
|
||||
; DW5-CHECK-NEXT: [0x0000000000000003, 0x0000000000000006): DW_OP_reg0 RAX)
|
||||
; DW5-CHECK-NEXT: DW_AT_name ("x")
|
||||
; DW5-CHECK-NEXT: DW_AT_decl_file ("/tmp/dbg.c")
|
||||
; DW5-CHECK-NEXT: DW_AT_decl_line (1)
|
||||
; DW5-CHECK-NEXT: DW_AT_type (0x00000057 "signed char")
|
||||
; DW5-CHECK-EMPTY:
|
||||
; DW5-CHECK-NEXT: 0x0000004a: DW_TAG_variable
|
||||
; DW5-CHECK-NEXT: DW_AT_location (0x00000012
|
||||
; DW5-CHECK-NEXT: [0x0000000000000003, 0x0000000000000006): DW_OP_breg0 RAX+0, DW_OP_constu 0xff, DW_OP_and, DW_OP_convert (0x00000027) "DW_ATE_signed_8", DW_OP_convert (0x0000002b) "DW_ATE_signed_32", DW_OP_stack_value)
|
||||
; DW5-CHECK-NEXT: DW_AT_name ("y")
|
||||
; DW5-CHECK-NEXT: DW_AT_decl_file ("/tmp/dbg.c")
|
||||
; DW5-CHECK-NEXT: DW_AT_decl_line (3)
|
||||
; DW5-CHECK-NEXT: DW_AT_type (0x0000005b "int")
|
||||
; DW5-CHECK-EMPTY:
|
||||
; DW5-CHECK-NEXT: 0x00000056: NULL
|
||||
; DW5-CHECK-EMPTY:
|
||||
; DW5-CHECK-NEXT: 0x00000057: DW_TAG_base_type
|
||||
; DW5-CHECK-NEXT: DW_AT_name ("signed char")
|
||||
; DW5-CHECK-NEXT: DW_AT_encoding (DW_ATE_signed_char)
|
||||
; DW5-CHECK-NEXT: DW_AT_byte_size (0x01)
|
||||
; DW5-CHECK-EMPTY:
|
||||
; DW5-CHECK-NEXT: 0x0000005b: DW_TAG_base_type
|
||||
; DW5-CHECK-NEXT: DW_AT_name ("int")
|
||||
; DW5-CHECK-NEXT: DW_AT_encoding (DW_ATE_signed)
|
||||
; DW5-CHECK-NEXT: DW_AT_byte_size (0x04)
|
||||
; DW5-CHECK-EMPTY:
|
||||
; DW5-CHECK-NEXT: 0x0000005f: NULL
|
||||
|
||||
|
||||
; DW4-CHECK: .debug_info contents:
|
||||
; DW4-CHECK-NEXT: 0x00000000: Compile Unit: length = 0x0000006d version = 0x0004 abbr_offset = 0x0000 addr_size = 0x08 (next unit at 0x00000071)
|
||||
; DW4-CHECK-EMPTY:
|
||||
; DW4-CHECK-NEXT: 0x0000000b: DW_TAG_compile_unit
|
||||
; DW4-CHECK-NEXT: DW_AT_producer ("clang version 9.0.0 (trunk 353791) (llvm/trunk 353801)")
|
||||
; DW4-CHECK-NEXT: DW_AT_language (DW_LANG_C99)
|
||||
; DW4-CHECK-NEXT: DW_AT_name ("dbg.c")
|
||||
; DW4-CHECK-NEXT: DW_AT_stmt_list (0x00000000)
|
||||
; DW4-CHECK-NEXT: DW_AT_comp_dir ("/tmp")
|
||||
; DW4-CHECK-NEXT: DW_AT_low_pc (0x0000000000000000)
|
||||
; DW4-CHECK-NEXT: DW_AT_high_pc (0x0000000000000007)
|
||||
; DW4-CHECK-EMPTY:
|
||||
; DW4-CHECK-NEXT: 0x0000002a: DW_TAG_subprogram
|
||||
; DW4-CHECK-NEXT: DW_AT_low_pc (0x0000000000000000)
|
||||
; DW4-CHECK-NEXT: DW_AT_high_pc (0x0000000000000007)
|
||||
; DW4-CHECK-NEXT: DW_AT_frame_base (DW_OP_reg7 RSP)
|
||||
; DW4-CHECK-NEXT: DW_AT_name ("foo")
|
||||
; DW4-CHECK-NEXT: DW_AT_decl_file ("/tmp/dbg.c")
|
||||
; DW4-CHECK-NEXT: DW_AT_decl_line (1)
|
||||
; DW4-CHECK-NEXT: DW_AT_prototyped (true)
|
||||
; DW4-CHECK-NEXT: DW_AT_type (0x00000062 "signed char")
|
||||
; DW4-CHECK-NEXT: DW_AT_external (true)
|
||||
; DW4-CHECK-EMPTY:
|
||||
; DW4-CHECK-NEXT: 0x00000043: DW_TAG_formal_parameter
|
||||
; DW4-CHECK-NEXT: DW_AT_location (0x00000000
|
||||
; DW4-CHECK-NEXT: [0x0000000000000003, 0x0000000000000006): DW_OP_reg0 RAX)
|
||||
; DW4-CHECK-NEXT: DW_AT_name ("x")
|
||||
; DW4-CHECK-NEXT: DW_AT_decl_file ("/tmp/dbg.c")
|
||||
; DW4-CHECK-NEXT: DW_AT_decl_line (1)
|
||||
; DW4-CHECK-NEXT: DW_AT_type (0x00000062 "signed char")
|
||||
; DW4-CHECK-EMPTY:
|
||||
; DW4-CHECK-NEXT: 0x00000052: DW_TAG_variable
|
||||
; DW4-CHECK-NEXT: DW_AT_location (0x00000023
|
||||
; DW4-CHECK-NEXT: [0x0000000000000003, 0x0000000000000006): DW_OP_breg0 RAX+0, DW_OP_constu 0xff, DW_OP_and, DW_OP_dup, DW_OP_constu 0x7, DW_OP_shr, DW_OP_lit0, DW_OP_not, DW_OP_mul, DW_OP_constu 0x8, DW_OP_shl, DW_OP_or, DW_OP_stack_value)
|
||||
; DW4-CHECK-NEXT: DW_AT_name ("y")
|
||||
; DW4-CHECK-NEXT: DW_AT_decl_file ("/tmp/dbg.c")
|
||||
; DW4-CHECK-NEXT: DW_AT_decl_line (3)
|
||||
; DW4-CHECK-NEXT: DW_AT_type (0x00000069 "int")
|
||||
; DW4-CHECK-EMPTY:
|
||||
; DW4-CHECK-NEXT: 0x00000061: NULL
|
||||
; DW4-CHECK-EMPTY:
|
||||
; DW4-CHECK-NEXT: 0x00000062: DW_TAG_base_type
|
||||
; DW4-CHECK-NEXT: DW_AT_name ("signed char")
|
||||
; DW4-CHECK-NEXT: DW_AT_encoding (DW_ATE_signed_char)
|
||||
; DW4-CHECK-NEXT: DW_AT_byte_size (0x01)
|
||||
; DW4-CHECK-EMPTY:
|
||||
; DW4-CHECK-NEXT: 0x00000069: DW_TAG_base_type
|
||||
; DW4-CHECK-NEXT: DW_AT_name ("int")
|
||||
; DW4-CHECK-NEXT: DW_AT_encoding (DW_ATE_signed)
|
||||
; DW4-CHECK-NEXT: DW_AT_byte_size (0x04)
|
||||
; DW4-CHECK-EMPTY:
|
||||
; DW4-CHECK-NEXT: 0x00000070: NULL
|
||||
|
||||
|
||||
; ModuleID = 'dbg.ll'
|
||||
source_filename = "dbg.c"
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
; Function Attrs: noinline nounwind uwtable
|
||||
define dso_local signext i8 @foo(i8 signext %x) !dbg !7 {
|
||||
entry:
|
||||
call void @llvm.dbg.value(metadata i8 %x, metadata !11, metadata !DIExpression()), !dbg !12
|
||||
call void @llvm.dbg.value(metadata i8 %x, metadata !13, metadata !DIExpression(DW_OP_LLVM_convert, 8, DW_ATE_signed, DW_OP_LLVM_convert, 32, DW_ATE_signed, DW_OP_stack_value)), !dbg !15
|
||||
ret i8 %x, !dbg !16
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable
|
||||
declare void @llvm.dbg.declare(metadata, metadata, metadata)
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable
|
||||
declare void @llvm.dbg.value(metadata, metadata, metadata)
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!3, !4, !5}
|
||||
!llvm.ident = !{!6}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (trunk 353791) (llvm/trunk 353801)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
|
||||
!1 = !DIFile(filename: "dbg.c", directory: "/tmp", checksumkind: CSK_MD5, checksum: "2a034da6937f5b9cf6dd2d89127f57fd")
|
||||
!2 = !{}
|
||||
!3 = !{i32 2, !"Dwarf Version", i32 5}
|
||||
!4 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!5 = !{i32 1, !"wchar_size", i32 4}
|
||||
!6 = !{!"clang version 9.0.0 (trunk 353791) (llvm/trunk 353801)"}
|
||||
!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !8, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
|
||||
!8 = !DISubroutineType(types: !9)
|
||||
!9 = !{!10, !10}
|
||||
!10 = !DIBasicType(name: "signed char", size: 8, encoding: DW_ATE_signed_char)
|
||||
!11 = !DILocalVariable(name: "x", arg: 1, scope: !7, file: !1, line: 1, type: !10)
|
||||
!12 = !DILocation(line: 1, column: 29, scope: !7)
|
||||
!13 = !DILocalVariable(name: "y", scope: !7, file: !1, line: 3, type: !14)
|
||||
!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||
!15 = !DILocation(line: 3, column: 14, scope: !7)
|
||||
!16 = !DILocation(line: 4, column: 3, scope: !7)
|
|
@ -0,0 +1,87 @@
|
|||
; RUN: llc -dwarf-version=5 -filetype=obj -O0 < %s | llvm-dwarfdump - | FileCheck %s --match-full-lines --check-prefix=DW5-CHECK
|
||||
; RUN: llc -dwarf-version=4 -filetype=obj -O0 < %s | llvm-dwarfdump - | FileCheck %s --match-full-lines --check-prefix=DW4-CHECK
|
||||
|
||||
; DW5-CHECK: .debug_info contents:
|
||||
; DW5-CHECK-NEXT: 0x00000000: Compile Unit: length = 0x0000003e version = 0x0005 unit_type = DW_UT_compile abbr_offset = 0x0000 addr_size = 0x08 (next unit at 0x00000042)
|
||||
; DW5-CHECK-EMPTY:
|
||||
; DW5-CHECK-NEXT: 0x0000000c: DW_TAG_compile_unit
|
||||
; DW5-CHECK-NEXT: DW_AT_producer ("clang version 9.0.0 (trunk 353791) (llvm/trunk 353801)")
|
||||
; DW5-CHECK-NEXT: DW_AT_language (DW_LANG_C99)
|
||||
; DW5-CHECK-NEXT: DW_AT_name ("dbg.c")
|
||||
; DW5-CHECK-NEXT: DW_AT_str_offsets_base (0x00000008)
|
||||
; DW5-CHECK-NEXT: DW_AT_stmt_list (0x00000000)
|
||||
; DW5-CHECK-NEXT: DW_AT_comp_dir ("/tmp")
|
||||
; DW5-CHECK-NEXT: DW_AT_addr_base (0x00000008)
|
||||
; DW5-CHECK-EMPTY:
|
||||
; DW5-CHECK-NEXT: 0x0000001e: DW_TAG_base_type
|
||||
; DW5-CHECK-NEXT: DW_AT_name ("DW_ATE_signed_8")
|
||||
; DW5-CHECK-NEXT: DW_AT_encoding (DW_ATE_signed)
|
||||
; DW5-CHECK-NEXT: DW_AT_byte_size (0x01)
|
||||
; DW5-CHECK-EMPTY:
|
||||
; DW5-CHECK-NEXT: 0x00000022: DW_TAG_base_type
|
||||
; DW5-CHECK-NEXT: DW_AT_name ("DW_ATE_signed_32")
|
||||
; DW5-CHECK-NEXT: DW_AT_encoding (DW_ATE_signed)
|
||||
; DW5-CHECK-NEXT: DW_AT_byte_size (0x04)
|
||||
; DW5-CHECK-EMPTY:
|
||||
; DW5-CHECK-NEXT: 0x00000026: DW_TAG_variable
|
||||
; DW5-CHECK-NEXT: DW_AT_name ("global")
|
||||
; DW5-CHECK-NEXT: DW_AT_type (0x0000003d "int")
|
||||
; DW5-CHECK-NEXT: DW_AT_external (true)
|
||||
; DW5-CHECK-NEXT: DW_AT_decl_file ("/tmp/dbg.c")
|
||||
; DW5-CHECK-NEXT: DW_AT_decl_line (1)
|
||||
; DW5-CHECK-NEXT: DW_AT_location (DW_OP_addrx 0x0, DW_OP_deref, DW_OP_convert (0x0000001e) "DW_ATE_signed_8", DW_OP_convert (0x00000022) "DW_ATE_signed_32", DW_OP_stack_value)
|
||||
; DW5-CHECK-EMPTY:
|
||||
; DW5-CHECK-NEXT: 0x0000003d: DW_TAG_base_type
|
||||
; DW5-CHECK-NEXT: DW_AT_name ("int")
|
||||
; DW5-CHECK-NEXT: DW_AT_encoding (DW_ATE_signed)
|
||||
; DW5-CHECK-NEXT: DW_AT_byte_size (0x04)
|
||||
; DW5-CHECK-EMPTY:
|
||||
; DW5-CHECK-NEXT: 0x00000041: NULL
|
||||
|
||||
|
||||
; DW4-CHECK: .debug_info contents:
|
||||
; DW4-CHECK-NEXT: 0x00000000: Compile Unit: length = 0x00000044 version = 0x0004 abbr_offset = 0x0000 addr_size = 0x08 (next unit at 0x00000048)
|
||||
; DW4-CHECK-EMPTY:
|
||||
; DW4-CHECK-NEXT: 0x0000000b: DW_TAG_compile_unit
|
||||
; DW4-CHECK-NEXT: DW_AT_producer ("clang version 9.0.0 (trunk 353791) (llvm/trunk 353801)")
|
||||
; DW4-CHECK-NEXT: DW_AT_language (DW_LANG_C99)
|
||||
; DW4-CHECK-NEXT: DW_AT_name ("dbg.c")
|
||||
; DW4-CHECK-NEXT: DW_AT_stmt_list (0x00000000)
|
||||
; DW4-CHECK-NEXT: DW_AT_comp_dir ("/tmp")
|
||||
; DW4-CHECK-EMPTY:
|
||||
; DW4-CHECK-NEXT: 0x0000001e: DW_TAG_variable
|
||||
; DW4-CHECK-NEXT: DW_AT_name ("global")
|
||||
; DW4-CHECK-NEXT: DW_AT_type (0x00000040 "int")
|
||||
; DW4-CHECK-NEXT: DW_AT_external (true)
|
||||
; DW4-CHECK-NEXT: DW_AT_decl_file ("/tmp/dbg.c")
|
||||
; DW4-CHECK-NEXT: DW_AT_decl_line (1)
|
||||
; DW4-CHECK-NEXT: DW_AT_location (DW_OP_addr 0x0, DW_OP_deref, DW_OP_dup, DW_OP_constu 0x7, DW_OP_shr, DW_OP_lit0, DW_OP_not, DW_OP_mul, DW_OP_constu 0x8, DW_OP_shl, DW_OP_or, DW_OP_stack_value)
|
||||
; DW4-CHECK-EMPTY:
|
||||
; DW4-CHECK-NEXT: 0x00000040: DW_TAG_base_type
|
||||
; DW4-CHECK-NEXT: DW_AT_name ("int")
|
||||
; DW4-CHECK-NEXT: DW_AT_encoding (DW_ATE_signed)
|
||||
; DW4-CHECK-NEXT: DW_AT_byte_size (0x04)
|
||||
; DW4-CHECK-EMPTY:
|
||||
; DW4-CHECK-NEXT: 0x00000047: NULL
|
||||
|
||||
source_filename = "dbg.c"
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
@global = dso_local global i32 255, align 4, !dbg !0
|
||||
|
||||
!llvm.dbg.cu = !{!2}
|
||||
!llvm.module.flags = !{!7, !8, !9}
|
||||
!llvm.ident = !{!10}
|
||||
|
||||
!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_deref, DW_OP_LLVM_convert, 8, DW_ATE_signed, DW_OP_LLVM_convert, 32, DW_ATE_signed, DW_OP_stack_value))
|
||||
!1 = distinct !DIGlobalVariable(name: "global", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true)
|
||||
!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (trunk 353791) (llvm/trunk 353801)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None)
|
||||
!3 = !DIFile(filename: "dbg.c", directory: "/tmp", checksumkind: CSK_MD5, checksum: "7c731722dd7304ccb8e366ae80269b82")
|
||||
!4 = !{}
|
||||
!5 = !{!0}
|
||||
!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||
!7 = !{i32 2, !"Dwarf Version", i32 5}
|
||||
!8 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!9 = !{i32 1, !"wchar_size", i32 4}
|
||||
!10 = !{!"clang version 9.0.0 (trunk 353791) (llvm/trunk 353801)"}
|
|
@ -0,0 +1,72 @@
|
|||
; RUN: llc -filetype=obj -O0 < %s | llvm-dwarfdump - | FileCheck %s
|
||||
|
||||
; CHECK: DW_TAG_compile_unit
|
||||
; CHECK: [[CU0BT0:0x[0-9a-f]+]]: DW_TAG_base_type
|
||||
; CHECK-NEXT: DW_ATE_signed_8
|
||||
; CHECK: [[CU0BT1:0x[0-9a-f]+]]: DW_TAG_base_type
|
||||
; CHECK-NEXT: DW_ATE_signed_32
|
||||
; CHECK: DW_TAG_variable
|
||||
; CHECK: DW_OP_convert ([[CU0BT0]]) "DW_ATE_signed_8", DW_OP_convert ([[CU0BT1]]) "DW_ATE_signed_32"
|
||||
|
||||
; CHECK: DW_TAG_compile_unit
|
||||
; CHECK: [[CU1BT0:0x[0-9a-f]+]]: DW_TAG_base_type
|
||||
; CHECK-NEXT: DW_ATE_signed_8
|
||||
; CHECK: [[CU1BT1:0x[0-9a-f]+]]: DW_TAG_base_type
|
||||
; CHECK-NEXT: DW_ATE_signed_16
|
||||
; CHECK: DW_TAG_variable
|
||||
; CHECK: DW_OP_convert ([[CU1BT0]]) "DW_ATE_signed_8", DW_OP_convert ([[CU1BT1]]) "DW_ATE_signed_16"
|
||||
|
||||
; ModuleID = 'llvm-link'
|
||||
source_filename = "llvm-link"
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
define dso_local signext i8 @foo(i8 signext %x) !dbg !9 {
|
||||
entry:
|
||||
call void @llvm.dbg.value(metadata i8 %x, metadata !13, metadata !DIExpression()), !dbg !14
|
||||
call void @llvm.dbg.value(metadata i8 %x, metadata !15, metadata !DIExpression(DW_OP_LLVM_convert, 8, DW_ATE_signed, DW_OP_LLVM_convert, 32, DW_ATE_signed, DW_OP_stack_value)), !dbg !17
|
||||
ret i8 %x, !dbg !18
|
||||
}
|
||||
|
||||
define dso_local signext i8 @bar(i8 signext %x) !dbg !19 {
|
||||
entry:
|
||||
call void @llvm.dbg.value(metadata i8 %x, metadata !20, metadata !DIExpression()), !dbg !21
|
||||
call void @llvm.dbg.value(metadata i8 %x, metadata !22, metadata !DIExpression(DW_OP_LLVM_convert, 8, DW_ATE_signed, DW_OP_LLVM_convert, 16, DW_ATE_signed, DW_OP_stack_value)), !dbg !24
|
||||
ret i8 %x, !dbg !25
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable
|
||||
declare void @llvm.dbg.value(metadata, metadata, metadata) #1
|
||||
|
||||
attributes #1 = { nounwind readnone speculatable }
|
||||
|
||||
!llvm.dbg.cu = !{!0, !3}
|
||||
!llvm.ident = !{!5, !5}
|
||||
!llvm.module.flags = !{!6, !7, !8}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
|
||||
!1 = !DIFile(filename: "dbg-foo.c", directory: "/tmp", checksumkind: CSK_MD5, checksum: "b35f80a032deb2a30bc187d564b5a775")
|
||||
!2 = !{}
|
||||
!3 = distinct !DICompileUnit(language: DW_LANG_C99, file: !4, producer: "clang version 9.0.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
|
||||
!4 = !DIFile(filename: "dbg-bar.c", directory: "/tmp", checksumkind: CSK_MD5, checksum: "9836bb594260d883960455e7d8bc51ea")
|
||||
!5 = !{!"clang version 9.0.0 "}
|
||||
!6 = !{i32 2, !"Dwarf Version", i32 5}
|
||||
!7 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!8 = !{i32 1, !"wchar_size", i32 4}
|
||||
!9 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 7, type: !10, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
|
||||
!10 = !DISubroutineType(types: !11)
|
||||
!11 = !{!12, !12}
|
||||
!12 = !DIBasicType(name: "signed char", size: 8, encoding: DW_ATE_signed_char)
|
||||
!13 = !DILocalVariable(name: "x", arg: 1, scope: !9, file: !1, line: 7, type: !12)
|
||||
!14 = !DILocation(line: 7, column: 29, scope: !9)
|
||||
!15 = !DILocalVariable(name: "y", scope: !9, file: !1, line: 9, type: !16)
|
||||
!16 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||
!17 = !DILocation(line: 9, column: 14, scope: !9)
|
||||
!18 = !DILocation(line: 10, column: 3, scope: !9)
|
||||
!19 = distinct !DISubprogram(name: "bar", scope: !4, file: !4, line: 1, type: !10, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !3, retainedNodes: !2)
|
||||
!20 = !DILocalVariable(name: "x", arg: 1, scope: !19, file: !4, line: 1, type: !12)
|
||||
!21 = !DILocation(line: 1, column: 29, scope: !19)
|
||||
!22 = !DILocalVariable(name: "z", scope: !19, file: !4, line: 3, type: !23)
|
||||
!23 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed)
|
||||
!24 = !DILocation(line: 3, column: 16, scope: !19)
|
||||
!25 = !DILocation(line: 4, column: 3, scope: !19)
|
|
@ -14,7 +14,7 @@ define i16 @test5(i16 %A) !dbg !34 {
|
|||
;
|
||||
; The high 16 bits of the original 'and' require sign-extending the new 16-bit and:
|
||||
; CHECK-NEXT: call void @llvm.dbg.value(metadata i16 [[and]], metadata [[C:![0-9]+]],
|
||||
; CHECK-SAME: metadata !DIExpression(DW_OP_dup, DW_OP_constu, 15, DW_OP_shr, DW_OP_lit0, DW_OP_not, DW_OP_mul, DW_OP_or, DW_OP_stack_value)
|
||||
; CHECK-SAME: metadata !DIExpression(DW_OP_LLVM_convert, 16, DW_ATE_signed, DW_OP_LLVM_convert, 32, DW_ATE_signed, DW_OP_stack_value)
|
||||
|
||||
%D = trunc i32 %C to i16, !dbg !42
|
||||
call void @llvm.dbg.value(metadata i16 %D, metadata !38, metadata !DIExpression()), !dbg !42
|
||||
|
|
|
@ -788,31 +788,35 @@ TEST(Local, ReplaceAllDbgUsesWith) {
|
|||
};
|
||||
|
||||
// Case 1: The original expr is empty, so no deref is needed.
|
||||
EXPECT_TRUE(hasADbgVal({DW_OP_dup, DW_OP_constu, 31, DW_OP_shr, DW_OP_lit0,
|
||||
DW_OP_not, DW_OP_mul, DW_OP_or, DW_OP_stack_value}));
|
||||
EXPECT_TRUE(hasADbgVal({DW_OP_LLVM_convert, 32, DW_ATE_signed,
|
||||
DW_OP_LLVM_convert, 64, DW_ATE_signed,
|
||||
DW_OP_stack_value}));
|
||||
|
||||
// Case 2: Perform an address calculation with the original expr, deref it,
|
||||
// then sign-extend the result.
|
||||
EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_deref, DW_OP_dup,
|
||||
DW_OP_constu, 31, DW_OP_shr, DW_OP_lit0, DW_OP_not,
|
||||
DW_OP_mul, DW_OP_or, DW_OP_stack_value}));
|
||||
EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_deref,
|
||||
DW_OP_LLVM_convert, 32, DW_ATE_signed,
|
||||
DW_OP_LLVM_convert, 64, DW_ATE_signed,
|
||||
DW_OP_stack_value}));
|
||||
|
||||
// Case 3: Insert the sign-extension logic before the DW_OP_stack_value.
|
||||
EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_dup, DW_OP_constu, 31,
|
||||
DW_OP_shr, DW_OP_lit0, DW_OP_not, DW_OP_mul, DW_OP_or,
|
||||
DW_OP_stack_value}));
|
||||
EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_LLVM_convert, 32,
|
||||
DW_ATE_signed, DW_OP_LLVM_convert, 64, DW_ATE_signed,
|
||||
DW_OP_stack_value}));
|
||||
|
||||
// Cases 4-6: Just like cases 1-3, but preserve the fragment at the end.
|
||||
EXPECT_TRUE(hasADbgVal({DW_OP_dup, DW_OP_constu, 31, DW_OP_shr, DW_OP_lit0,
|
||||
DW_OP_not, DW_OP_mul, DW_OP_or, DW_OP_stack_value,
|
||||
DW_OP_LLVM_fragment, 0, 8}));
|
||||
EXPECT_TRUE(
|
||||
hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_deref, DW_OP_dup, DW_OP_constu,
|
||||
31, DW_OP_shr, DW_OP_lit0, DW_OP_not, DW_OP_mul, DW_OP_or,
|
||||
DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 8}));
|
||||
EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_dup, DW_OP_constu, 31,
|
||||
DW_OP_shr, DW_OP_lit0, DW_OP_not, DW_OP_mul, DW_OP_or,
|
||||
DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 8}));
|
||||
EXPECT_TRUE(hasADbgVal({DW_OP_LLVM_convert, 32, DW_ATE_signed,
|
||||
DW_OP_LLVM_convert, 64, DW_ATE_signed,
|
||||
DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 8}));
|
||||
|
||||
EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_deref,
|
||||
DW_OP_LLVM_convert, 32, DW_ATE_signed,
|
||||
DW_OP_LLVM_convert, 64, DW_ATE_signed,
|
||||
DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 8}));
|
||||
|
||||
EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_LLVM_convert, 32,
|
||||
DW_ATE_signed, DW_OP_LLVM_convert, 64, DW_ATE_signed,
|
||||
DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 8}));
|
||||
|
||||
verifyModule(*M, &errs(), &BrokenDebugInfo);
|
||||
ASSERT_FALSE(BrokenDebugInfo);
|
||||
|
|
Loading…
Reference in New Issue