Debug info: Factor out the creation of DWARF expressions from AsmPrinter

into a new class DwarfExpression that can be shared between AsmPrinter
and DwarfUnit.

This is the first step towards unifying the two entirely redundant
implementations of dwarf expression emission in DwarfUnit and AsmPrinter.

Almost no functional change — Testcases were updated because asm comments
that used to be on two lines now appear on the same line, which is
actually preferable.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@225706 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Adrian Prantl 2015-01-12 22:19:22 +00:00
parent 9e8d3bc46a
commit f89325d832
7 changed files with 255 additions and 144 deletions

View File

@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "ByteStreamer.h" #include "ByteStreamer.h"
#include "DwarfExpression.h"
#include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/Twine.h" #include "llvm/ADT/Twine.h"
#include "llvm/IR/DataLayout.h" #include "llvm/IR/DataLayout.h"
#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAsmInfo.h"
@ -32,6 +32,31 @@ using namespace llvm;
#define DEBUG_TYPE "asm-printer" #define DEBUG_TYPE "asm-printer"
/// DwarfExpression implementation for .debug_loc entries.
class DebugLocDwarfExpression : public DwarfExpression {
ByteStreamer &BS;
public:
DebugLocDwarfExpression(TargetMachine &TM, ByteStreamer &BS)
: DwarfExpression(TM), BS(BS) {}
void EmitOp(uint8_t Op, const char* Comment) override;
void EmitSigned(int Value) override;
void EmitUnsigned(unsigned Value) override;
};
void DebugLocDwarfExpression::EmitOp(uint8_t Op, const char* Comment) {
BS.EmitInt8(Op, Comment
? Twine(Comment)+Twine(" ")+Twine(dwarf::OperationEncodingString(Op))
: dwarf::OperationEncodingString(Op));
}
void DebugLocDwarfExpression::EmitSigned(int Value) {
BS.EmitSLEB128(Value, Twine(Value));
}
void DebugLocDwarfExpression::EmitUnsigned(unsigned Value) {
BS.EmitULEB128(Value, Twine(Value));
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Dwarf Emission Helper Routines // Dwarf Emission Helper Routines
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -187,57 +212,6 @@ void AsmPrinter::EmitSectionOffset(const MCSymbol *Label,
EmitLabelDifference(Label, SectionLabel, 4); EmitLabelDifference(Label, SectionLabel, 4);
} }
/// Emit a dwarf register operation.
static void emitDwarfRegOp(ByteStreamer &Streamer, int Reg) {
assert(Reg >= 0);
if (Reg < 32) {
Streamer.EmitInt8(dwarf::DW_OP_reg0 + Reg,
dwarf::OperationEncodingString(dwarf::DW_OP_reg0 + Reg));
} else {
Streamer.EmitInt8(dwarf::DW_OP_regx, "DW_OP_regx");
Streamer.EmitULEB128(Reg, Twine(Reg));
}
}
/// Emit an (double-)indirect dwarf register operation.
static void emitDwarfRegOpIndirect(ByteStreamer &Streamer, int Reg, int Offset,
bool Deref) {
assert(Reg >= 0);
if (Reg < 32) {
Streamer.EmitInt8(dwarf::DW_OP_breg0 + Reg,
dwarf::OperationEncodingString(dwarf::DW_OP_breg0 + Reg));
} else {
Streamer.EmitInt8(dwarf::DW_OP_bregx, "DW_OP_bregx");
Streamer.EmitULEB128(Reg, Twine(Reg));
}
Streamer.EmitSLEB128(Offset);
if (Deref)
Streamer.EmitInt8(dwarf::DW_OP_deref, "DW_OP_deref");
}
void AsmPrinter::EmitDwarfOpPiece(ByteStreamer &Streamer, unsigned SizeInBits,
unsigned OffsetInBits) const {
assert(SizeInBits > 0 && "piece has size zero");
const unsigned SizeOfByte = 8;
if (OffsetInBits > 0 || SizeInBits % SizeOfByte) {
Streamer.EmitInt8(dwarf::DW_OP_bit_piece, "DW_OP_bit_piece");
Streamer.EmitULEB128(SizeInBits, Twine(SizeInBits));
Streamer.EmitULEB128(OffsetInBits, Twine(OffsetInBits));
} else {
Streamer.EmitInt8(dwarf::DW_OP_piece, "DW_OP_piece");
unsigned ByteSize = SizeInBits / SizeOfByte;
Streamer.EmitULEB128(ByteSize, Twine(ByteSize));
}
}
/// Emit a shift-right dwarf expression.
static void emitDwarfOpShr(ByteStreamer &Streamer,
unsigned ShiftBy) {
Streamer.EmitInt8(dwarf::DW_OP_constu, "DW_OP_constu");
Streamer.EmitULEB128(ShiftBy);
Streamer.EmitInt8(dwarf::DW_OP_shr, "DW_OP_shr");
}
// Some targets do not provide a DWARF register number for every // Some targets do not provide a DWARF register number for every
// register. This function attempts to emit a DWARF register by // register. This function attempts to emit a DWARF register by
// emitting a piece of a super-register or by piecing together // emitting a piece of a super-register or by piecing together
@ -247,112 +221,44 @@ void AsmPrinter::EmitDwarfRegOpPiece(ByteStreamer &Streamer,
unsigned PieceSizeInBits, unsigned PieceSizeInBits,
unsigned PieceOffsetInBits) const { unsigned PieceOffsetInBits) const {
assert(MLoc.isReg() && "MLoc must be a register"); assert(MLoc.isReg() && "MLoc must be a register");
const TargetRegisterInfo *TRI = TM.getSubtargetImpl()->getRegisterInfo(); DebugLocDwarfExpression Expr(TM, Streamer);
int Reg = TRI->getDwarfRegNum(MLoc.getReg(), false); Expr.AddMachineRegPiece(MLoc.getReg(), PieceSizeInBits, PieceOffsetInBits);
}
// If this is a valid register number, emit it. void AsmPrinter::EmitDwarfOpPiece(ByteStreamer &Streamer,
if (Reg >= 0) { unsigned PieceSizeInBits,
emitDwarfRegOp(Streamer, Reg); unsigned PieceOffsetInBits) const {
EmitDwarfOpPiece(Streamer, PieceSizeInBits, PieceOffsetInBits); DebugLocDwarfExpression Expr(TM, Streamer);
return; Expr.AddOpPiece(PieceSizeInBits, PieceOffsetInBits);
}
// Walk up the super-register chain until we find a valid number.
// For example, EAX on x86_64 is a 32-bit piece of RAX with offset 0.
for (MCSuperRegIterator SR(MLoc.getReg(), TRI); SR.isValid(); ++SR) {
Reg = TRI->getDwarfRegNum(*SR, false);
if (Reg >= 0) {
unsigned Idx = TRI->getSubRegIndex(*SR, MLoc.getReg());
unsigned Size = TRI->getSubRegIdxSize(Idx);
unsigned RegOffset = TRI->getSubRegIdxOffset(Idx);
OutStreamer.AddComment("super-register");
emitDwarfRegOp(Streamer, Reg);
if (PieceOffsetInBits == RegOffset) {
EmitDwarfOpPiece(Streamer, Size, RegOffset);
} else {
// If this is part of a variable in a sub-register at a
// non-zero offset, we need to manually shift the value into
// place, since the DW_OP_piece describes the part of the
// variable, not the position of the subregister.
if (RegOffset)
emitDwarfOpShr(Streamer, RegOffset);
EmitDwarfOpPiece(Streamer, Size, PieceOffsetInBits);
}
return;
}
}
// Otherwise, attempt to find a covering set of sub-register numbers.
// For example, Q0 on ARM is a composition of D0+D1.
//
// Keep track of the current position so we can emit the more
// efficient DW_OP_piece.
unsigned CurPos = PieceOffsetInBits;
// The size of the register in bits, assuming 8 bits per byte.
unsigned RegSize = TRI->getMinimalPhysRegClass(MLoc.getReg())->getSize() * 8;
// Keep track of the bits in the register we already emitted, so we
// can avoid emitting redundant aliasing subregs.
SmallBitVector Coverage(RegSize, false);
for (MCSubRegIterator SR(MLoc.getReg(), TRI); SR.isValid(); ++SR) {
unsigned Idx = TRI->getSubRegIndex(MLoc.getReg(), *SR);
unsigned Size = TRI->getSubRegIdxSize(Idx);
unsigned Offset = TRI->getSubRegIdxOffset(Idx);
Reg = TRI->getDwarfRegNum(*SR, false);
// Intersection between the bits we already emitted and the bits
// covered by this subregister.
SmallBitVector Intersection(RegSize, false);
Intersection.set(Offset, Offset + Size);
Intersection ^= Coverage;
// If this sub-register has a DWARF number and we haven't covered
// its range, emit a DWARF piece for it.
if (Reg >= 0 && Intersection.any()) {
OutStreamer.AddComment("sub-register");
emitDwarfRegOp(Streamer, Reg);
EmitDwarfOpPiece(Streamer, Size, Offset == CurPos ? 0 : Offset);
CurPos = Offset + Size;
// Mark it as emitted.
Coverage.set(Offset, Offset + Size);
}
}
if (CurPos == PieceOffsetInBits) {
// FIXME: We have no reasonable way of handling errors in here.
Streamer.EmitInt8(dwarf::DW_OP_nop,
"nop (could not find a dwarf register number)");
}
} }
/// EmitDwarfRegOp - Emit dwarf register operation. /// EmitDwarfRegOp - Emit dwarf register operation.
void AsmPrinter::EmitDwarfRegOp(ByteStreamer &Streamer, void AsmPrinter::EmitDwarfRegOp(ByteStreamer &Streamer,
const MachineLocation &MLoc, const MachineLocation &MLoc,
bool Indirect) const { bool Indirect) const {
DebugLocDwarfExpression Expr(TM, Streamer);
const TargetRegisterInfo *TRI = TM.getSubtargetImpl()->getRegisterInfo(); const TargetRegisterInfo *TRI = TM.getSubtargetImpl()->getRegisterInfo();
int Reg = TRI->getDwarfRegNum(MLoc.getReg(), false); int Reg = TRI->getDwarfRegNum(MLoc.getReg(), false);
if (Reg < 0) { if (Reg < 0) {
// We assume that pointers are always in an addressable register. // We assume that pointers are always in an addressable register.
if (Indirect || MLoc.isIndirect()) { if (Indirect || MLoc.isIndirect())
// FIXME: We have no reasonable way of handling errors in here. The // FIXME: We have no reasonable way of handling errors in here. The
// caller might be in the middle of a dwarf expression. We should // caller might be in the middle of a dwarf expression. We should
// probably assert that Reg >= 0 once debug info generation is more // probably assert that Reg >= 0 once debug info generation is more
// mature. // mature.
Streamer.EmitInt8(dwarf::DW_OP_nop, return Expr.EmitOp(dwarf::DW_OP_nop,
"nop (invalid dwarf register number for indirect loc)"); "nop (could not find a dwarf register number)");
return;
}
// Attempt to find a valid super- or sub-register. // Attempt to find a valid super- or sub-register.
return EmitDwarfRegOpPiece(Streamer, MLoc); return Expr.AddMachineRegPiece(MLoc.getReg());
} }
if (MLoc.isIndirect()) if (MLoc.isIndirect())
emitDwarfRegOpIndirect(Streamer, Reg, MLoc.getOffset(), Indirect); Expr.AddRegIndirect(Reg, MLoc.getOffset(), Indirect);
else if (Indirect) else if (Indirect)
emitDwarfRegOpIndirect(Streamer, Reg, 0, false); Expr.AddRegIndirect(Reg, 0, false);
else else
emitDwarfRegOp(Streamer, Reg); Expr.AddReg(Reg);
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -11,6 +11,7 @@ add_llvm_library(LLVMAsmPrinter
DwarfCFIException.cpp DwarfCFIException.cpp
DwarfCompileUnit.cpp DwarfCompileUnit.cpp
DwarfDebug.cpp DwarfDebug.cpp
DwarfExpression.cpp
DwarfFile.cpp DwarfFile.cpp
DwarfStringPool.cpp DwarfStringPool.cpp
DwarfUnit.cpp DwarfUnit.cpp

View File

@ -0,0 +1,143 @@
//===-- llvm/CodeGen/DwarfExpression.cpp - Dwarf Debug Framework ----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains support for writing dwarf debug info into asm files.
//
//===----------------------------------------------------------------------===//
#include "DwarfExpression.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetSubtargetInfo.h"
using namespace llvm;
void DwarfExpression::AddReg(int DwarfReg, const char* Comment) {
assert(DwarfReg >= 0 && "invalid negative dwarf register number");
if (DwarfReg < 32) {
EmitOp(dwarf::DW_OP_reg0 + DwarfReg, Comment);
} else {
EmitOp(dwarf::DW_OP_regx, Comment);
EmitUnsigned(DwarfReg);
}
}
void DwarfExpression::AddRegIndirect(int DwarfReg, int Offset, bool Deref) {
assert(DwarfReg >= 0 && "invalid negative dwarf register number");
if (DwarfReg < 32) {
EmitOp(dwarf::DW_OP_breg0 + DwarfReg);
} else {
EmitOp(dwarf::DW_OP_bregx);
EmitUnsigned(DwarfReg);
}
EmitSigned(Offset);
if (Deref)
EmitOp(dwarf::DW_OP_deref);
}
void DwarfExpression::AddOpPiece(unsigned SizeInBits,
unsigned OffsetInBits) {
assert(SizeInBits > 0 && "piece has size zero");
const unsigned SizeOfByte = 8;
if (OffsetInBits > 0 || SizeInBits % SizeOfByte) {
EmitOp(dwarf::DW_OP_bit_piece);
EmitUnsigned(SizeInBits);
EmitUnsigned(OffsetInBits);
} else {
EmitOp(dwarf::DW_OP_piece);
unsigned ByteSize = SizeInBits / SizeOfByte;
EmitUnsigned(ByteSize);
}
}
void DwarfExpression::AddShr(unsigned ShiftBy) {
EmitOp(dwarf::DW_OP_constu);
EmitUnsigned(ShiftBy);
EmitOp(dwarf::DW_OP_shr);
}
void DwarfExpression::AddMachineRegPiece(unsigned MachineReg,
unsigned PieceSizeInBits,
unsigned PieceOffsetInBits) {
const TargetRegisterInfo *TRI = TM.getSubtargetImpl()->getRegisterInfo();
int Reg = TRI->getDwarfRegNum(MachineReg, false);
// If this is a valid register number, emit it.
if (Reg >= 0) {
AddReg(Reg);
AddOpPiece(PieceSizeInBits, PieceOffsetInBits);
return;
}
// Walk up the super-register chain until we find a valid number.
// For example, EAX on x86_64 is a 32-bit piece of RAX with offset 0.
for (MCSuperRegIterator SR(MachineReg, TRI); SR.isValid(); ++SR) {
Reg = TRI->getDwarfRegNum(*SR, false);
if (Reg >= 0) {
unsigned Idx = TRI->getSubRegIndex(*SR, MachineReg);
unsigned Size = TRI->getSubRegIdxSize(Idx);
unsigned RegOffset = TRI->getSubRegIdxOffset(Idx);
AddReg(Reg, "super-register");
if (PieceOffsetInBits == RegOffset) {
AddOpPiece(Size, RegOffset);
} else {
// If this is part of a variable in a sub-register at a
// non-zero offset, we need to manually shift the value into
// place, since the DW_OP_piece describes the part of the
// variable, not the position of the subregister.
if (RegOffset)
AddShr(RegOffset);
AddOpPiece(Size, PieceOffsetInBits);
}
return;
}
}
// Otherwise, attempt to find a covering set of sub-register numbers.
// For example, Q0 on ARM is a composition of D0+D1.
//
// Keep track of the current position so we can emit the more
// efficient DW_OP_piece.
unsigned CurPos = PieceOffsetInBits;
// The size of the register in bits, assuming 8 bits per byte.
unsigned RegSize = TRI->getMinimalPhysRegClass(MachineReg)->getSize() * 8;
// Keep track of the bits in the register we already emitted, so we
// can avoid emitting redundant aliasing subregs.
SmallBitVector Coverage(RegSize, false);
for (MCSubRegIterator SR(MachineReg, TRI); SR.isValid(); ++SR) {
unsigned Idx = TRI->getSubRegIndex(MachineReg, *SR);
unsigned Size = TRI->getSubRegIdxSize(Idx);
unsigned Offset = TRI->getSubRegIdxOffset(Idx);
Reg = TRI->getDwarfRegNum(*SR, false);
// Intersection between the bits we already emitted and the bits
// covered by this subregister.
SmallBitVector Intersection(RegSize, false);
Intersection.set(Offset, Offset + Size);
Intersection ^= Coverage;
// If this sub-register has a DWARF number and we haven't covered
// its range, emit a DWARF piece for it.
if (Reg >= 0 && Intersection.any()) {
AddReg(Reg, "sub-register");
AddOpPiece(Size, Offset == CurPos ? 0 : Offset);
CurPos = Offset + Size;
// Mark it as emitted.
Coverage.set(Offset, Offset + Size);
}
}
if (CurPos == PieceOffsetInBits)
// FIXME: We have no reasonable way of handling errors in here.
EmitOp(dwarf::DW_OP_nop, "nop (could not find a dwarf register number)");
}

View File

@ -0,0 +1,65 @@
//===-- llvm/CodeGen/DwarfExpression.h - Dwarf Compile Unit ---*- C++ -*--===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains support for writing dwarf compile unit.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DWARFEXPRESSION_H
#define LLVM_LIB_CODEGEN_ASMPRINTER_DWARFEXPRESSION_H
#include "llvm/Support/DataTypes.h"
namespace llvm {
class TargetMachine;
/// Base class containing the logic for constructing DWARF expressions
/// independently of whether they are emitted into a DIE or into a .debug_loc
/// entry.
class DwarfExpression {
TargetMachine &TM;
public:
DwarfExpression(TargetMachine &TM) : TM(TM) {}
virtual void EmitOp(uint8_t Op, const char* Comment = nullptr) = 0;
virtual void EmitSigned(int Value) = 0;
virtual void EmitUnsigned(unsigned Value) = 0;
/// Emit a dwarf register operation.
void AddReg(int DwarfReg, const char* Comment = nullptr);
/// Emit an (double-)indirect dwarf register operation.
void AddRegIndirect(int DwarfReg, int Offset, bool Deref = false);
/// Emit a dwarf register operation for describing
/// - a small value occupying only part of a register or
/// - a register representing only part of a value.
void AddOpPiece(unsigned SizeInBits, unsigned OffsetInBits = 0);
/// Emit a shift-right dwarf expression.
void AddShr(unsigned ShiftBy);
/// \brief Emit a partial DWARF register operation.
/// \param MLoc the register
/// \param PieceSize size and
/// \param PieceOffset offset of the piece in bits, if this is one
/// piece of an aggregate value.
///
/// If size and offset is zero an operation for the entire
/// register is emitted: Some targets do not provide a DWARF
/// register number for every register. If this is the case, this
/// function will attempt to emit a DWARF register by emitting a
/// piece of a super-register or by piecing together multiple
/// subregisters that alias the register.
void AddMachineRegPiece(unsigned MachineReg,
unsigned PieceSizeInBits = 0,
unsigned PieceOffsetInBits = 0);
};
}
#endif

View File

@ -2,13 +2,11 @@
target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:64-v128:32:128-a0:0:32-n32" target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:64-v128:32:128-a0:0:32-n32"
target triple = "thumbv7-apple-macosx10.6.7" target triple = "thumbv7-apple-macosx10.6.7"
;CHECK: sub-register ;CHECK: sub-register DW_OP_regx
;CHECK-NEXT: DW_OP_regx
;CHECK-NEXT: ascii ;CHECK-NEXT: ascii
;CHECK-NEXT: DW_OP_piece ;CHECK-NEXT: DW_OP_piece
;CHECK-NEXT: byte 8 ;CHECK-NEXT: byte 8
;CHECK-NEXT: sub-register ;CHECK-NEXT: sub-register DW_OP_regx
;CHECK-NEXT: DW_OP_regx
;CHECK-NEXT: ascii ;CHECK-NEXT: ascii
;CHECK-NEXT: DW_OP_piece ;CHECK-NEXT: DW_OP_piece
;CHECK-NEXT: byte 8 ;CHECK-NEXT: byte 8

View File

@ -1,8 +1,7 @@
; RUN: llc < %s - | FileCheck %s ; RUN: llc < %s - | FileCheck %s
; Radar 9309221 ; Radar 9309221
; Test dwarf reg no for s16 ; Test dwarf reg no for s16
;CHECK: super-register ;CHECK: super-register DW_OP_regx
;CHECK-NEXT: DW_OP_regx
;CHECK-NEXT: ascii ;CHECK-NEXT: ascii
;CHECK-NEXT: DW_OP_piece ;CHECK-NEXT: DW_OP_piece
;CHECK-NEXT: 4 ;CHECK-NEXT: 4

View File

@ -3,8 +3,7 @@
; We are testing that a value in a 16 bit register gets reported as ; We are testing that a value in a 16 bit register gets reported as
; being in its superregister. ; being in its superregister.
; CHECK: .byte 80 # super-register ; CHECK: .byte 80 # super-register DW_OP_reg0
; CHECK-NEXT: # DW_OP_reg0
; CHECK-NEXT: .byte 147 # DW_OP_piece ; CHECK-NEXT: .byte 147 # DW_OP_piece
; CHECK-NEXT: .byte 2 # 2 ; CHECK-NEXT: .byte 2 # 2