#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCFixupKindInfo.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/FormattedStream.h"
+#include "llvm/Target/TargetAsmBackend.h"
+#include "llvm/Target/TargetAsmInfo.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
+#include <cctype>
using namespace llvm;
namespace {
const MCAsmInfo &MAI;
OwningPtr<MCInstPrinter> InstPrinter;
OwningPtr<MCCodeEmitter> Emitter;
+ OwningPtr<TargetAsmBackend> AsmBackend;
SmallString<128> CommentToEmit;
raw_svector_ostream CommentStream;
- const TargetLoweringObjectFile *TLOF;
- int PointerSize;
-
- unsigned IsLittleEndian : 1;
unsigned IsVerboseAsm : 1;
unsigned ShowInst : 1;
+ unsigned UseLoc : 1;
bool needsSet(const MCExpr *Value);
public:
MCAsmStreamer(MCContext &Context, formatted_raw_ostream &os,
- bool isLittleEndian, bool isVerboseAsm,
- const TargetLoweringObjectFile *tlof, int pointerSize,
- MCInstPrinter *printer, MCCodeEmitter *emitter, bool showInst)
+ bool isVerboseAsm,
+ bool useLoc,
+ MCInstPrinter *printer, MCCodeEmitter *emitter,
+ TargetAsmBackend *asmbackend,
+ bool showInst)
: MCStreamer(Context), OS(os), MAI(Context.getAsmInfo()),
- InstPrinter(printer), Emitter(emitter), CommentStream(CommentToEmit),
- TLOF(tlof), PointerSize(pointerSize),
- IsLittleEndian(isLittleEndian), IsVerboseAsm(isVerboseAsm),
- ShowInst(showInst) {
+ InstPrinter(printer), Emitter(emitter), AsmBackend(asmbackend),
+ CommentStream(CommentToEmit), IsVerboseAsm(isVerboseAsm),
+ ShowInst(showInst), UseLoc(useLoc) {
if (InstPrinter && IsVerboseAsm)
InstPrinter->setCommentStream(CommentStream);
}
~MCAsmStreamer() {}
- bool isLittleEndian() const { return IsLittleEndian; }
-
inline void EmitEOL() {
// If we don't have any comments, just emit a \n.
if (!IsVerboseAsm) {
/// @name MCStreamer Interface
/// @{
- virtual void SwitchSection(const MCSection *Section);
+ virtual void ChangeSection(const MCSection *Section);
virtual void InitSections() {
// FIXME, this is MachO specific, but the testsuite
virtual void EmitBytes(StringRef Data, unsigned AddrSpace);
- virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace);
+ virtual void EmitValueImpl(const MCExpr *Value, unsigned Size,
+ bool isPCRel, unsigned AddrSpace);
virtual void EmitIntValue(uint64_t Value, unsigned Size,
unsigned AddrSpace = 0);
virtual bool EmitCFIDefCfaOffset(int64_t Offset);
virtual bool EmitCFIDefCfaRegister(int64_t Register);
virtual bool EmitCFIOffset(int64_t Register, int64_t Offset);
- virtual bool EmitCFIPersonality(const MCSymbol *Sym);
- virtual bool EmitCFILsda(const MCSymbol *Sym);
+ virtual bool EmitCFIPersonality(const MCSymbol *Sym, unsigned Encoding);
+ virtual bool EmitCFILsda(const MCSymbol *Sym, unsigned Encoding);
+
+ virtual void EmitFnStart();
+ virtual void EmitFnEnd();
+ virtual void EmitCantUnwind();
+ virtual void EmitPersonality(const MCSymbol *Personality);
+ virtual void EmitHandlerData();
+ virtual void EmitSetFP(unsigned FpReg, unsigned SpReg, int64_t Offset = 0);
+ virtual void EmitPad(int64_t Offset);
+ virtual void EmitRegSave(const SmallVectorImpl<unsigned> &RegList, bool);
+
virtual void EmitInstruction(const MCInst &Inst);
return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8));
}
-void MCAsmStreamer::SwitchSection(const MCSection *Section) {
+void MCAsmStreamer::ChangeSection(const MCSection *Section) {
assert(Section && "Cannot switch to a null section!");
- if (Section != CurSection) {
- PrevSection = CurSection;
- CurSection = Section;
- Section->PrintSwitchToSection(MAI, OS);
- }
+ Section->PrintSwitchToSection(MAI, OS);
}
void MCAsmStreamer::EmitLabel(MCSymbol *Symbol) {
assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
assert(!Symbol->isVariable() && "Cannot emit a variable symbol!");
- assert(CurSection && "Cannot emit before setting section!");
+ assert(getCurrentSection() && "Cannot emit before setting section!");
OS << *Symbol << MAI.getLabelSuffix();
EmitEOL();
- Symbol->setSection(*CurSection);
+ Symbol->setSection(*getCurrentSection());
}
void MCAsmStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {
void MCAsmStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta,
const MCSymbol *LastLabel,
const MCSymbol *Label) {
- EmitDwarfSetLineAddr(LineDelta, Label, PointerSize);
+ EmitDwarfSetLineAddr(LineDelta, Label,
+ getContext().getTargetAsmInfo().getPointerSize());
}
void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
void MCAsmStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) {
- assert(CurSection && "Cannot emit contents before setting section!");
+ assert(getCurrentSection() && "Cannot emit contents before setting section!");
if (Data.empty()) return;
if (Data.size() == 1) {
EmitValue(MCConstantExpr::Create(Value, getContext()), Size, AddrSpace);
}
-void MCAsmStreamer::EmitValue(const MCExpr *Value, unsigned Size,
- unsigned AddrSpace) {
- assert(CurSection && "Cannot emit contents before setting section!");
+void MCAsmStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size,
+ bool isPCRel, unsigned AddrSpace) {
+ assert(getCurrentSection() && "Cannot emit contents before setting section!");
+ assert(!isPCRel && "Cannot emit pc relative relocations!");
const char *Directive = 0;
switch (Size) {
default: break;
int64_t IntValue;
if (!Value->EvaluateAsAbsolute(IntValue))
report_fatal_error("Don't know how to emit this value.");
- if (isLittleEndian()) {
+ if (getContext().getTargetAsmInfo().isLittleEndian()) {
EmitIntValue((uint32_t)(IntValue >> 0 ), 4, AddrSpace);
EmitIntValue((uint32_t)(IntValue >> 32), 4, AddrSpace);
} else {
}
bool MCAsmStreamer::EmitDwarfFileDirective(unsigned FileNo, StringRef Filename){
- if (!TLOF) {
+ if (UseLoc) {
OS << "\t.file\t" << FileNo << ' ';
PrintQuotedString(Filename, OS);
EmitEOL();
unsigned Discriminator) {
this->MCStreamer::EmitDwarfLocDirective(FileNo, Line, Column, Flags,
Isa, Discriminator);
- if (TLOF)
+ if (!UseLoc)
return;
OS << "\t.loc\t" << FileNo << " " << Line << " " << Column;
if (this->MCStreamer::EmitCFIStartProc())
return true;
- OS << ".cfi_startproc";
+ OS << "\t.cfi_startproc";
EmitEOL();
return false;
if (this->MCStreamer::EmitCFIEndProc())
return true;
- OS << ".cfi_endproc";
+ OS << "\t.cfi_endproc";
EmitEOL();
return false;
if (this->MCStreamer::EmitCFIDefCfaOffset(Offset))
return true;
- OS << ".cfi_def_cfa_offset " << Offset;
+ OS << "\t.cfi_def_cfa_offset " << Offset;
EmitEOL();
return false;
if (this->MCStreamer::EmitCFIDefCfaRegister(Register))
return true;
- OS << ".cfi_def_cfa_register " << Register;
+ OS << "\t.cfi_def_cfa_register " << Register;
EmitEOL();
return false;
if (this->MCStreamer::EmitCFIOffset(Register, Offset))
return true;
- OS << ".cfi_offset " << Register << ", " << Offset;
+ OS << "\t.cfi_offset " << Register << ", " << Offset;
EmitEOL();
return false;
}
-bool MCAsmStreamer::EmitCFIPersonality(const MCSymbol *Sym) {
- if (this->MCStreamer::EmitCFIPersonality(Sym))
+bool MCAsmStreamer::EmitCFIPersonality(const MCSymbol *Sym,
+ unsigned Encoding) {
+ if (this->MCStreamer::EmitCFIPersonality(Sym, Encoding))
return true;
- OS << ".cfi_personality 0, " << *Sym;
+ OS << "\t.cfi_personality " << Encoding << ", " << *Sym;
EmitEOL();
return false;
}
-bool MCAsmStreamer::EmitCFILsda(const MCSymbol *Sym) {
- if (this->MCStreamer::EmitCFILsda(Sym))
+bool MCAsmStreamer::EmitCFILsda(const MCSymbol *Sym, unsigned Encoding) {
+ if (this->MCStreamer::EmitCFILsda(Sym, Encoding))
return true;
- OS << ".cfi_lsda 0, " << *Sym;
+ OS << "\t.cfi_lsda " << Encoding << ", " << *Sym;
EmitEOL();
return false;
for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
MCFixup &F = Fixups[i];
- const MCFixupKindInfo &Info = Emitter->getFixupKindInfo(F.getKind());
+ const MCFixupKindInfo &Info = AsmBackend->getFixupKindInfo(F.getKind());
for (unsigned j = 0; j != Info.TargetSize; ++j) {
unsigned Index = F.getOffset() * 8 + Info.TargetOffset + j;
assert(Index < Code.size() * 8 && "Invalid offset in fixup!");
}
}
+ // FIXME: Node the fixup comments for Thumb2 are completely bogus since the
+ // high order halfword of a 32-bit Thumb2 instruction is emitted first.
OS << "encoding: [";
for (unsigned i = 0, e = Code.size(); i != e; ++i) {
if (i)
if (MapEntry == 0) {
OS << format("0x%02x", uint8_t(Code[i]));
} else {
- assert(Code[i] == 0 && "Encoder wrote into fixed up bit!");
- OS << char('A' + MapEntry - 1);
+ if (Code[i]) {
+ // FIXME: Some of the 8 bits require fix up.
+ OS << format("0x%02x", uint8_t(Code[i])) << '\''
+ << char('A' + MapEntry - 1) << '\'';
+ } else
+ OS << char('A' + MapEntry - 1);
}
} else {
// Otherwise, write out in binary.
OS << "0b";
for (unsigned j = 8; j--;) {
unsigned Bit = (Code[i] >> j) & 1;
-
+
unsigned FixupBit;
- if (IsLittleEndian)
+ if (getContext().getTargetAsmInfo().isLittleEndian())
FixupBit = i * 8 + j;
else
FixupBit = i * 8 + (7-j);
-
+
if (uint8_t MapEntry = FixupMap[FixupBit]) {
assert(Bit == 0 && "Encoder wrote into fixed up bit!");
OS << char('A' + MapEntry - 1);
for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
MCFixup &F = Fixups[i];
- const MCFixupKindInfo &Info = Emitter->getFixupKindInfo(F.getKind());
+ const MCFixupKindInfo &Info = AsmBackend->getFixupKindInfo(F.getKind());
OS << " fixup " << char('A' + i) << " - " << "offset: " << F.getOffset()
<< ", value: " << *F.getValue() << ", kind: " << Info.Name << "\n";
}
}
+void MCAsmStreamer::EmitFnStart() {
+ OS << "\t.fnstart";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitFnEnd() {
+ OS << "\t.fnend";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCantUnwind() {
+ OS << "\t.cantunwind";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitHandlerData() {
+ OS << "\t.handlerdata";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitPersonality(const MCSymbol *Personality) {
+ OS << "\t.personality " << Personality->getName();
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitSetFP(unsigned FpReg, unsigned SpReg, int64_t Offset) {
+ OS << "\t.setfp\t" << InstPrinter->getRegName(FpReg)
+ << ", " << InstPrinter->getRegName(SpReg);
+ if (Offset)
+ OS << ", #" << Offset;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitPad(int64_t Offset) {
+ OS << "\t.pad\t#" << Offset;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitRegSave(const SmallVectorImpl<unsigned> &RegList,
+ bool isVector) {
+ assert(RegList.size() && "RegList should not be empty");
+ if (isVector)
+ OS << "\t.vsave\t{";
+ else
+ OS << "\t.save\t{";
+
+ OS << InstPrinter->getRegName(RegList[0]);
+
+ for (unsigned i = 1, e = RegList.size(); i != e; ++i)
+ OS << ", " << InstPrinter->getRegName(RegList[i]);
+
+ OS << "}";
+ EmitEOL();
+}
+
void MCAsmStreamer::EmitInstruction(const MCInst &Inst) {
- assert(CurSection && "Cannot emit contents before setting section!");
+ assert(getCurrentSection() && "Cannot emit contents before setting section!");
- if (TLOF)
+ if (!UseLoc)
MCLineEntry::Make(this, getCurrentSection());
// Show the encoding in a comment if we have a code emitter.
void MCAsmStreamer::Finish() {
// Dump out the dwarf file & directory tables and line tables.
- if (getContext().hasDwarfFiles() && TLOF)
- MCDwarfFileTable::Emit(this, TLOF->getDwarfLineSection());
+ if (getContext().hasDwarfFiles() && !UseLoc)
+ MCDwarfFileTable::Emit(this);
}
MCStreamer *llvm::createAsmStreamer(MCContext &Context,
formatted_raw_ostream &OS,
- bool isLittleEndian,
- bool isVerboseAsm, MCInstPrinter *IP,
- MCCodeEmitter *CE, bool ShowInst) {
- return new MCAsmStreamer(Context, OS, isLittleEndian, isVerboseAsm,
- NULL, 0, IP, CE, ShowInst);
-}
-
-
-MCStreamer *llvm::createAsmStreamerNoLoc(MCContext &Context,
- formatted_raw_ostream &OS,
- bool isLittleEndian,
- bool isVerboseAsm,
- const TargetLoweringObjectFile *TLOF,
- int PointerSize,
- MCInstPrinter *IP,
- MCCodeEmitter *CE, bool ShowInst) {
- return new MCAsmStreamer(Context, OS, isLittleEndian, isVerboseAsm,
- TLOF, PointerSize, IP, CE, ShowInst);
+ bool isVerboseAsm, bool useLoc,
+ MCInstPrinter *IP, MCCodeEmitter *CE,
+ TargetAsmBackend *TAB, bool ShowInst) {
+ return new MCAsmStreamer(Context, OS, isVerboseAsm, useLoc,
+ IP, CE, TAB, ShowInst);
}