//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "asm-printer"
+#include "ByteStreamer.h"
+#include "DwarfExpression.h"
#include "llvm/CodeGen/AsmPrinter.h"
-#include "llvm/CodeGen/MachineLocation.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/IR/DataLayout.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/MC/MachineLocation.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Target/TargetFrameLowering.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegisterInfo.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/Support/Dwarf.h"
+#include "llvm/Target/TargetSubtargetInfo.h"
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;
+ unsigned getFrameRegister() override {
+ llvm_unreachable("not available");
+ };
+};
+
+void DebugLocDwarfExpression::EmitOp(uint8_t Op, const char* Comment) {
+ BS.EmitInt8(Op, Comment
+ ? Twine(Comment)+" "+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
//===----------------------------------------------------------------------===//
/// EmitSLEB128 - emit the specified signed leb128 value.
-void AsmPrinter::EmitSLEB128(int Value, const char *Desc) const {
+void AsmPrinter::EmitSLEB128(int64_t Value, const char *Desc) const {
if (isVerbose() && Desc)
OutStreamer.AddComment(Desc);
-
- if (MAI->hasLEB128()) {
- OutStreamer.EmitSLEB128IntValue(Value);
- return;
- }
- // If we don't have .sleb128, emit as .bytes.
- int Sign = Value >> (8 * sizeof(Value) - 1);
- bool IsMore;
-
- do {
- unsigned char Byte = static_cast<unsigned char>(Value & 0x7f);
- Value >>= 7;
- IsMore = Value != Sign || ((Byte ^ Sign) & 0x40) != 0;
- if (IsMore) Byte |= 0x80;
- OutStreamer.EmitIntValue(Byte, 1, /*addrspace*/0);
- } while (IsMore);
+ OutStreamer.EmitSLEB128IntValue(Value);
}
/// EmitULEB128 - emit the specified signed leb128 value.
-void AsmPrinter::EmitULEB128(unsigned Value, const char *Desc,
+void AsmPrinter::EmitULEB128(uint64_t Value, const char *Desc,
unsigned PadTo) const {
if (isVerbose() && Desc)
OutStreamer.AddComment(Desc);
- // FIXME: Should we add a PadTo option to the streamer?
- if (MAI->hasLEB128() && PadTo == 0) {
- OutStreamer.EmitULEB128IntValue(Value);
- return;
- }
-
- // If we don't have .uleb128 or we want to emit padding, emit as .bytes.
- do {
- unsigned char Byte = static_cast<unsigned char>(Value & 0x7f);
- Value >>= 7;
- if (Value || PadTo != 0) Byte |= 0x80;
- OutStreamer.EmitIntValue(Byte, 1, /*addrspace*/0);
- } while (Value);
-
- if (PadTo) {
- if (PadTo > 1)
- OutStreamer.EmitFill(PadTo - 1, 0x80/*fillval*/, 0/*addrspace*/);
- OutStreamer.EmitFill(1, 0/*fillval*/, 0/*addrspace*/);
- }
+ OutStreamer.EmitULEB128IntValue(Value, PadTo);
}
/// EmitCFAByte - Emit a .byte 42 directive for a DW_CFA_xxx value.
void AsmPrinter::EmitCFAByte(unsigned Val) const {
if (isVerbose()) {
- if (Val >= dwarf::DW_CFA_offset && Val < dwarf::DW_CFA_offset+64)
- OutStreamer.AddComment("DW_CFA_offset + Reg (" +
- Twine(Val-dwarf::DW_CFA_offset) + ")");
+ if (Val >= dwarf::DW_CFA_offset && Val < dwarf::DW_CFA_offset + 64)
+ OutStreamer.AddComment("DW_CFA_offset + Reg (" +
+ Twine(Val - dwarf::DW_CFA_offset) + ")");
else
OutStreamer.AddComment(dwarf::CallFrameString(Val));
}
- OutStreamer.EmitIntValue(Val, 1, 0/*addrspace*/);
+ OutStreamer.EmitIntValue(Val, 1);
}
static const char *DecodeDWARFEncoding(unsigned Encoding) {
switch (Encoding) {
- case dwarf::DW_EH_PE_absptr: return "absptr";
- case dwarf::DW_EH_PE_omit: return "omit";
- case dwarf::DW_EH_PE_pcrel: return "pcrel";
- case dwarf::DW_EH_PE_udata4: return "udata4";
- case dwarf::DW_EH_PE_udata8: return "udata8";
- case dwarf::DW_EH_PE_sdata4: return "sdata4";
- case dwarf::DW_EH_PE_sdata8: return "sdata8";
- case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata4: return "pcrel udata4";
- case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4: return "pcrel sdata4";
- case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata8: return "pcrel udata8";
- case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata8: return "pcrel sdata8";
- case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |dwarf::DW_EH_PE_udata4:
+ case dwarf::DW_EH_PE_absptr:
+ return "absptr";
+ case dwarf::DW_EH_PE_omit:
+ return "omit";
+ case dwarf::DW_EH_PE_pcrel:
+ return "pcrel";
+ case dwarf::DW_EH_PE_udata4:
+ return "udata4";
+ case dwarf::DW_EH_PE_udata8:
+ return "udata8";
+ case dwarf::DW_EH_PE_sdata4:
+ return "sdata4";
+ case dwarf::DW_EH_PE_sdata8:
+ return "sdata8";
+ case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata4:
+ return "pcrel udata4";
+ case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4:
+ return "pcrel sdata4";
+ case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata8:
+ return "pcrel udata8";
+ case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata8:
+ return "pcrel sdata8";
+ case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata4
+ :
return "indirect pcrel udata4";
- case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |dwarf::DW_EH_PE_sdata4:
+ case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4
+ :
return "indirect pcrel sdata4";
- case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |dwarf::DW_EH_PE_udata8:
+ case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata8
+ :
return "indirect pcrel udata8";
- case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |dwarf::DW_EH_PE_sdata8:
+ case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata8
+ :
return "indirect pcrel sdata8";
}
-
+
return "<unknown encoding>";
}
-
/// EmitEncodingByte - Emit a .byte 42 directive that corresponds to an
/// encoding. If verbose assembly output is enabled, we output comments
/// describing the encoding. Desc is an optional string saying what the
/// encoding is specifying (e.g. "LSDA").
void AsmPrinter::EmitEncodingByte(unsigned Val, const char *Desc) const {
if (isVerbose()) {
- if (Desc != 0)
- OutStreamer.AddComment(Twine(Desc)+" Encoding = " +
+ if (Desc)
+ OutStreamer.AddComment(Twine(Desc) + " Encoding = " +
Twine(DecodeDWARFEncoding(Val)));
else
- OutStreamer.AddComment(Twine("Encoding = ") +
- DecodeDWARFEncoding(Val));
+ OutStreamer.AddComment(Twine("Encoding = ") + DecodeDWARFEncoding(Val));
}
-
- OutStreamer.EmitIntValue(Val, 1, 0/*addrspace*/);
+
+ OutStreamer.EmitIntValue(Val, 1);
}
/// GetSizeOfEncodedValue - Return the size of the encoding in bytes.
unsigned AsmPrinter::GetSizeOfEncodedValue(unsigned Encoding) const {
if (Encoding == dwarf::DW_EH_PE_omit)
return 0;
-
+
switch (Encoding & 0x07) {
- default: assert(0 && "Invalid encoded value.");
- case dwarf::DW_EH_PE_absptr: return TM.getTargetData()->getPointerSize();
- case dwarf::DW_EH_PE_udata2: return 2;
- case dwarf::DW_EH_PE_udata4: return 4;
- case dwarf::DW_EH_PE_udata8: return 8;
+ default:
+ llvm_unreachable("Invalid encoded value.");
+ case dwarf::DW_EH_PE_absptr:
+ return TM.getSubtargetImpl()->getDataLayout()->getPointerSize();
+ case dwarf::DW_EH_PE_udata2:
+ return 2;
+ case dwarf::DW_EH_PE_udata4:
+ return 4;
+ case dwarf::DW_EH_PE_udata8:
+ return 8;
}
}
-void AsmPrinter::EmitReference(const MCSymbol *Sym, unsigned Encoding) const {
- const TargetLoweringObjectFile &TLOF = getObjFileLowering();
-
- const MCExpr *Exp =
- TLOF.getExprForDwarfReference(Sym, Encoding, OutStreamer);
- OutStreamer.EmitAbsValue(Exp, GetSizeOfEncodedValue(Encoding));
-}
+void AsmPrinter::EmitTTypeReference(const GlobalValue *GV,
+ unsigned Encoding) const {
+ if (GV) {
+ const TargetLoweringObjectFile &TLOF = getObjFileLowering();
-void AsmPrinter::EmitReference(const GlobalValue *GV, unsigned Encoding)const{
- const TargetLoweringObjectFile &TLOF = getObjFileLowering();
-
- const MCExpr *Exp =
- TLOF.getExprForDwarfGlobalReference(GV, Mang, MMI, Encoding, OutStreamer);
- OutStreamer.EmitValue(Exp, GetSizeOfEncodedValue(Encoding), /*addrspace*/0);
+ const MCExpr *Exp =
+ TLOF.getTTypeGlobalReference(GV, Encoding, *Mang, TM, MMI, OutStreamer);
+ OutStreamer.EmitValue(Exp, GetSizeOfEncodedValue(Encoding));
+ } else
+ OutStreamer.EmitIntValue(0, GetSizeOfEncodedValue(Encoding));
}
/// EmitSectionOffset - Emit the 4-byte offset of Label from the start of its
void AsmPrinter::EmitSectionOffset(const MCSymbol *Label,
const MCSymbol *SectionLabel) const {
// On COFF targets, we have to emit the special .secrel32 directive.
- if (const char *SecOffDir = MAI->getDwarfSectionOffsetDirective()) {
- // FIXME: MCize.
- OutStreamer.EmitRawText(SecOffDir + Twine(Label->getName()));
+ if (MAI->needsDwarfSectionOffsetDirective()) {
+ OutStreamer.EmitCOFFSecRel32(Label);
return;
}
-
+
// Get the section that we're referring to, based on SectionLabel.
const MCSection &Section = SectionLabel->getSection();
-
+
// If Label has already been emitted, verify that it is in the same section as
// section label for sanity.
assert((!Label->isInSection() || &Label->getSection() == &Section) &&
"Section offset using wrong section base for label");
-
+
// If the section in question will end up with an address of 0 anyway, we can
// just emit an absolute reference to save a relocation.
if (Section.isBaseAddressKnownZero()) {
- OutStreamer.EmitSymbolValue(Label, 4, 0/*AddrSpace*/);
+ OutStreamer.EmitSymbolValue(Label, 4);
return;
}
-
+
// Otherwise, emit it as a label difference from the start of the section.
EmitLabelDifference(Label, SectionLabel, 4);
}
-//===----------------------------------------------------------------------===//
-// Dwarf Lowering Routines
-//===----------------------------------------------------------------------===//
-
+// 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
+// multiple subregisters that alias the register.
+void AsmPrinter::EmitDwarfRegOpPiece(ByteStreamer &Streamer,
+ const MachineLocation &MLoc,
+ unsigned PieceSizeInBits,
+ unsigned PieceOffsetInBits) const {
+ assert(MLoc.isReg() && "MLoc must be a register");
+ DebugLocDwarfExpression Expr(TM, Streamer);
+ Expr.AddMachineRegPiece(MLoc.getReg(), PieceSizeInBits, PieceOffsetInBits);
+}
-/// EmitFrameMoves - Emit frame instructions to describe the layout of the
-/// frame.
-void AsmPrinter::EmitFrameMoves(const std::vector<MachineMove> &Moves,
- MCSymbol *BaseLabel, bool isEH) const {
- const TargetRegisterInfo *RI = TM.getRegisterInfo();
-
- int stackGrowth = TM.getTargetData()->getPointerSize();
- if (TM.getFrameLowering()->getStackGrowthDirection() !=
- TargetFrameLowering::StackGrowsUp)
- stackGrowth *= -1;
-
- for (unsigned i = 0, N = Moves.size(); i < N; ++i) {
- const MachineMove &Move = Moves[i];
- MCSymbol *Label = Move.getLabel();
- // Throw out move if the label is invalid.
- if (Label && !Label->isDefined()) continue; // Not emitted, in dead code.
-
- const MachineLocation &Dst = Move.getDestination();
- const MachineLocation &Src = Move.getSource();
-
- // Advance row if new location.
- if (BaseLabel && Label) {
- MCSymbol *ThisSym = Label;
- if (ThisSym != BaseLabel) {
- EmitCFAByte(dwarf::DW_CFA_advance_loc4);
- EmitLabelDifference(ThisSym, BaseLabel, 4);
- BaseLabel = ThisSym;
- }
- }
-
- // If advancing cfa.
- if (Dst.isReg() && Dst.getReg() == MachineLocation::VirtualFP) {
- assert(!Src.isReg() && "Machine move not supported yet.");
-
- if (Src.getReg() == MachineLocation::VirtualFP) {
- EmitCFAByte(dwarf::DW_CFA_def_cfa_offset);
- } else {
- EmitCFAByte(dwarf::DW_CFA_def_cfa);
- EmitULEB128(RI->getDwarfRegNum(Src.getReg(), isEH), "Register");
- }
-
- EmitULEB128(-Src.getOffset(), "Offset");
- continue;
- }
-
- if (Src.isReg() && Src.getReg() == MachineLocation::VirtualFP) {
- assert(Dst.isReg() && "Machine move not supported yet.");
- EmitCFAByte(dwarf::DW_CFA_def_cfa_register);
- EmitULEB128(RI->getDwarfRegNum(Dst.getReg(), isEH), "Register");
- continue;
- }
-
- unsigned Reg = RI->getDwarfRegNum(Src.getReg(), isEH);
- int Offset = Dst.getOffset() / stackGrowth;
-
- if (Offset < 0) {
- EmitCFAByte(dwarf::DW_CFA_offset_extended_sf);
- EmitULEB128(Reg, "Reg");
- EmitSLEB128(Offset, "Offset");
- } else if (Reg < 64) {
- EmitCFAByte(dwarf::DW_CFA_offset + Reg);
- EmitULEB128(Offset, "Offset");
- } else {
- EmitCFAByte(dwarf::DW_CFA_offset_extended);
- EmitULEB128(Reg, "Reg");
- EmitULEB128(Offset, "Offset");
- }
- }
+void AsmPrinter::EmitDwarfOpPiece(ByteStreamer &Streamer,
+ unsigned PieceSizeInBits,
+ unsigned PieceOffsetInBits) const {
+ DebugLocDwarfExpression Expr(TM, Streamer);
+ Expr.AddOpPiece(PieceSizeInBits, PieceOffsetInBits);
}
-/// EmitFrameMoves - Emit a frame instruction.
-void AsmPrinter::EmitCFIFrameMove(const MachineMove &Move) const {
- const TargetRegisterInfo *RI = TM.getRegisterInfo();
-
- const MachineLocation &Dst = Move.getDestination();
- const MachineLocation &Src = Move.getSource();
-
- // If advancing cfa.
- if (Dst.isReg() && Dst.getReg() == MachineLocation::VirtualFP) {
- assert(!Src.isReg() && "Machine move not supported yet.");
-
- if (Src.getReg() == MachineLocation::VirtualFP) {
- OutStreamer.EmitCFIDefCfaOffset(-Src.getOffset());
- } else {
- assert("Machine move not supported yet");
- // Reg + Offset
- }
- } else if (Src.isReg() && Src.getReg() == MachineLocation::VirtualFP) {
- assert(Dst.isReg() && "Machine move not supported yet.");
- OutStreamer.EmitCFIDefCfaRegister(RI->getDwarfRegNum(Dst.getReg(), true));
- } else {
- assert(!Dst.isReg() && "Machine move not supported yet.");
- OutStreamer.EmitCFIOffset(RI->getDwarfRegNum(Src.getReg(), true),
- -Dst.getOffset());
+/// 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())
+ // 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.
+ 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 Expr.AddMachineRegPiece(MLoc.getReg());
}
+
+ if (MLoc.isIndirect())
+ Expr.AddRegIndirect(Reg, MLoc.getOffset(), Indirect);
+ else if (Indirect)
+ Expr.AddRegIndirect(Reg, 0, false);
+ else
+ Expr.AddReg(Reg);
}
-/// EmitFrameMoves - Emit frame instructions to describe the layout of the
-/// frame.
-void AsmPrinter::EmitCFIFrameMoves(const std::vector<MachineMove> &Moves) const {
- for (unsigned i = 0, N = Moves.size(); i < N; ++i) {
- const MachineMove &Move = Moves[i];
- MCSymbol *Label = Move.getLabel();
- // Throw out move if the label is invalid.
- if (Label && !Label->isDefined()) continue; // Not emitted, in dead code.
+//===----------------------------------------------------------------------===//
+// Dwarf Lowering Routines
+//===----------------------------------------------------------------------===//
- EmitCFIFrameMove(Move);
+void AsmPrinter::emitCFIInstruction(const MCCFIInstruction &Inst) const {
+ switch (Inst.getOperation()) {
+ default:
+ llvm_unreachable("Unexpected instruction");
+ case MCCFIInstruction::OpDefCfaOffset:
+ OutStreamer.EmitCFIDefCfaOffset(Inst.getOffset());
+ break;
+ case MCCFIInstruction::OpDefCfa:
+ OutStreamer.EmitCFIDefCfa(Inst.getRegister(), Inst.getOffset());
+ break;
+ case MCCFIInstruction::OpDefCfaRegister:
+ OutStreamer.EmitCFIDefCfaRegister(Inst.getRegister());
+ break;
+ case MCCFIInstruction::OpOffset:
+ OutStreamer.EmitCFIOffset(Inst.getRegister(), Inst.getOffset());
+ break;
+ case MCCFIInstruction::OpRegister:
+ OutStreamer.EmitCFIRegister(Inst.getRegister(), Inst.getRegister2());
+ break;
+ case MCCFIInstruction::OpWindowSave:
+ OutStreamer.EmitCFIWindowSave();
+ break;
+ case MCCFIInstruction::OpSameValue:
+ OutStreamer.EmitCFISameValue(Inst.getRegister());
+ break;
}
}