From f89325d832028de896955978591ba08337653cc2 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Mon, 12 Jan 2015 22:19:22 +0000 Subject: [PATCH] Debug info: Factor out the creation of DWARF expressions from AsmPrinter into a new class DwarfExpression that can be shared between AsmPrinter and DwarfUnit. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 --- lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp | 178 +++++---------------- lib/CodeGen/AsmPrinter/CMakeLists.txt | 1 + lib/CodeGen/AsmPrinter/DwarfExpression.cpp | 143 +++++++++++++++++ lib/CodeGen/AsmPrinter/DwarfExpression.h | 65 ++++++++ test/CodeGen/ARM/debug-info-qreg.ll | 6 +- test/CodeGen/ARM/debug-info-s16-reg.ll | 3 +- test/DebugInfo/X86/subreg.ll | 3 +- 7 files changed, 255 insertions(+), 144 deletions(-) create mode 100644 lib/CodeGen/AsmPrinter/DwarfExpression.cpp create mode 100644 lib/CodeGen/AsmPrinter/DwarfExpression.h diff --git a/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp b/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp index 05f6a68375b..ce4aae3d319 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp @@ -12,8 +12,8 @@ //===----------------------------------------------------------------------===// #include "ByteStreamer.h" +#include "DwarfExpression.h" #include "llvm/CodeGen/AsmPrinter.h" -#include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/Twine.h" #include "llvm/IR/DataLayout.h" #include "llvm/MC/MCAsmInfo.h" @@ -32,6 +32,31 @@ using namespace llvm; #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 //===----------------------------------------------------------------------===// @@ -187,57 +212,6 @@ void AsmPrinter::EmitSectionOffset(const MCSymbol *Label, 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 // register. This function attempts to emit a DWARF register by // emitting a piece of a super-register or by piecing together @@ -247,112 +221,44 @@ void AsmPrinter::EmitDwarfRegOpPiece(ByteStreamer &Streamer, unsigned PieceSizeInBits, unsigned PieceOffsetInBits) const { assert(MLoc.isReg() && "MLoc must be a register"); - const TargetRegisterInfo *TRI = TM.getSubtargetImpl()->getRegisterInfo(); - int Reg = TRI->getDwarfRegNum(MLoc.getReg(), false); - - // If this is a valid register number, emit it. - if (Reg >= 0) { - emitDwarfRegOp(Streamer, Reg); - EmitDwarfOpPiece(Streamer, 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(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); - } - } + DebugLocDwarfExpression Expr(TM, Streamer); + Expr.AddMachineRegPiece(MLoc.getReg(), PieceSizeInBits, PieceOffsetInBits); +} - 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)"); - } +void AsmPrinter::EmitDwarfOpPiece(ByteStreamer &Streamer, + unsigned PieceSizeInBits, + unsigned PieceOffsetInBits) const { + DebugLocDwarfExpression Expr(TM, Streamer); + Expr.AddOpPiece(PieceSizeInBits, PieceOffsetInBits); } /// EmitDwarfRegOp - Emit dwarf register operation. void AsmPrinter::EmitDwarfRegOp(ByteStreamer &Streamer, const MachineLocation &MLoc, bool Indirect) const { + DebugLocDwarfExpression Expr(TM, Streamer); const TargetRegisterInfo *TRI = TM.getSubtargetImpl()->getRegisterInfo(); int Reg = TRI->getDwarfRegNum(MLoc.getReg(), false); if (Reg < 0) { // 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 // caller might be in the middle of a dwarf expression. We should // probably assert that Reg >= 0 once debug info generation is more // mature. - Streamer.EmitInt8(dwarf::DW_OP_nop, - "nop (invalid dwarf register number for indirect loc)"); - return; - } + return Expr.EmitOp(dwarf::DW_OP_nop, + "nop (could not find a dwarf register number)"); // Attempt to find a valid super- or sub-register. - return EmitDwarfRegOpPiece(Streamer, MLoc); + return Expr.AddMachineRegPiece(MLoc.getReg()); } if (MLoc.isIndirect()) - emitDwarfRegOpIndirect(Streamer, Reg, MLoc.getOffset(), Indirect); + Expr.AddRegIndirect(Reg, MLoc.getOffset(), Indirect); else if (Indirect) - emitDwarfRegOpIndirect(Streamer, Reg, 0, false); + Expr.AddRegIndirect(Reg, 0, false); else - emitDwarfRegOp(Streamer, Reg); + Expr.AddReg(Reg); } //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/AsmPrinter/CMakeLists.txt b/lib/CodeGen/AsmPrinter/CMakeLists.txt index e6b7d648abf..01d2c7220ab 100644 --- a/lib/CodeGen/AsmPrinter/CMakeLists.txt +++ b/lib/CodeGen/AsmPrinter/CMakeLists.txt @@ -11,6 +11,7 @@ add_llvm_library(LLVMAsmPrinter DwarfCFIException.cpp DwarfCompileUnit.cpp DwarfDebug.cpp + DwarfExpression.cpp DwarfFile.cpp DwarfStringPool.cpp DwarfUnit.cpp diff --git a/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/lib/CodeGen/AsmPrinter/DwarfExpression.cpp new file mode 100644 index 00000000000..01c9e2497dd --- /dev/null +++ b/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -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)"); +} diff --git a/lib/CodeGen/AsmPrinter/DwarfExpression.h b/lib/CodeGen/AsmPrinter/DwarfExpression.h new file mode 100644 index 00000000000..193f4307d88 --- /dev/null +++ b/lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -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 diff --git a/test/CodeGen/ARM/debug-info-qreg.ll b/test/CodeGen/ARM/debug-info-qreg.ll index 586364192c4..03a7e4b1bf1 100644 --- a/test/CodeGen/ARM/debug-info-qreg.ll +++ b/test/CodeGen/ARM/debug-info-qreg.ll @@ -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 triple = "thumbv7-apple-macosx10.6.7" -;CHECK: sub-register -;CHECK-NEXT: DW_OP_regx +;CHECK: sub-register DW_OP_regx ;CHECK-NEXT: ascii ;CHECK-NEXT: DW_OP_piece ;CHECK-NEXT: byte 8 -;CHECK-NEXT: sub-register -;CHECK-NEXT: DW_OP_regx +;CHECK-NEXT: sub-register DW_OP_regx ;CHECK-NEXT: ascii ;CHECK-NEXT: DW_OP_piece ;CHECK-NEXT: byte 8 diff --git a/test/CodeGen/ARM/debug-info-s16-reg.ll b/test/CodeGen/ARM/debug-info-s16-reg.ll index 814055b05e9..54c38a751d2 100644 --- a/test/CodeGen/ARM/debug-info-s16-reg.ll +++ b/test/CodeGen/ARM/debug-info-s16-reg.ll @@ -1,8 +1,7 @@ ; RUN: llc < %s - | FileCheck %s ; Radar 9309221 ; Test dwarf reg no for s16 -;CHECK: super-register -;CHECK-NEXT: DW_OP_regx +;CHECK: super-register DW_OP_regx ;CHECK-NEXT: ascii ;CHECK-NEXT: DW_OP_piece ;CHECK-NEXT: 4 diff --git a/test/DebugInfo/X86/subreg.ll b/test/DebugInfo/X86/subreg.ll index 6ba435015ef..a9a566cb077 100644 --- a/test/DebugInfo/X86/subreg.ll +++ b/test/DebugInfo/X86/subreg.ll @@ -3,8 +3,7 @@ ; We are testing that a value in a 16 bit register gets reported as ; being in its superregister. -; CHECK: .byte 80 # super-register -; CHECK-NEXT: # DW_OP_reg0 +; CHECK: .byte 80 # super-register DW_OP_reg0 ; CHECK-NEXT: .byte 147 # DW_OP_piece ; CHECK-NEXT: .byte 2 # 2 -- 2.34.1