diff --git a/llvm/include/llvm/MC/MCInstPrinter.h b/llvm/include/llvm/MC/MCInstPrinter.h --- a/llvm/include/llvm/MC/MCInstPrinter.h +++ b/llvm/include/llvm/MC/MCInstPrinter.h @@ -34,6 +34,60 @@ } // end namespace HexStyle +enum class MarkupType { + Reg, + Imm, + Mem, +}; + +/// MarkupSpan represents a marked up range in the disassembly. For example: +/// +/// Pos InnerPos +/// v v +/// ... )> ... +/// ~~~~~~~~~~~~~~~ InnerLenth +/// ~~~~~~~~~~~~~~~~~~~~~ Length +/// +struct MarkupSpan { + MarkupType Type; + /// The offset of the beginning of the marked up range in the stream. + size_t Pos; + /// The length of the marked up range. + size_t Length; + /// The offset of the beginning of the inner text in the stream. + size_t InnerPos; + /// The length of the inner text. + size_t InnerLength; + /// Marked up ranges in the inner text. In the example above, + /// InnerSpans contains one MarkupSpan which represents ``. + std::vector InnerSpans; + + MarkupSpan(MarkupType Type, size_t Pos, size_t Length, size_t InnerPos, + size_t InnerLength) + : Type(Type), Pos(Pos), Length(Length), InnerPos(InnerPos), + InnerLength(InnerLength) {} +}; + +struct MarkupStart { + bool Enabled; + std::vector *> &Spans; + MarkupType Type; + + MarkupStart(bool Enabled, std::vector *> &Spans, + MarkupType Type) + : Enabled(Enabled), Spans(Spans), Type(Type) {} + friend raw_ostream &operator<<(raw_ostream &OS, const MarkupStart &M); +}; + +struct MarkupEnd { + bool Enabled; + std::vector *> &Spans; + + MarkupEnd(bool Enabled, std::vector *> &Spans) + : Enabled(Enabled), Spans(Spans) {} + friend raw_ostream &operator<<(raw_ostream &OS, const MarkupEnd &M); +}; + /// This is an instance of a target assembly language printer that /// converts an MCInst to valid target assembly syntax. class MCInstPrinter { @@ -55,6 +109,11 @@ /// Which style to use for printing hexadecimal values. HexStyle::Style PrintHexStyle = HexStyle::C; + /// A stack of pointers which points to &MS set by setMarkupSpans or + /// InnerSpans of unclosed MarkupSpans. Here we use std::vector as a stack + /// instead of std::stack because we need "clear" method. + std::vector *> MarkupSpans; + /// Utility function for printing annotations. void printAnnotation(raw_ostream &OS, StringRef Annot); @@ -85,8 +144,16 @@ bool getUseMarkup() const { return UseMarkup; } void setUseMarkup(bool Value) { UseMarkup = Value; } + /// Set the vector to write marked up ranges to. + void setMarkupSpans(std::vector &MS) { + MarkupSpans.clear(); + MarkupSpans.push_back(&MS); + } + /// Utility functions to make adding mark ups simpler. StringRef markup(StringRef s) const; + MarkupStart startMarkup(MarkupType Type); + MarkupEnd endMarkup(); bool getPrintImmHex() const { return PrintImmHex; } void setPrintImmHex(bool Value) { PrintImmHex = Value; } diff --git a/llvm/lib/MC/MCInstPrinter.cpp b/llvm/lib/MC/MCInstPrinter.cpp --- a/llvm/lib/MC/MCInstPrinter.cpp +++ b/llvm/lib/MC/MCInstPrinter.cpp @@ -117,3 +117,56 @@ } llvm_unreachable("unsupported print style"); } + +MarkupStart MCInstPrinter::startMarkup(MarkupType Type) { + return MarkupStart(getUseMarkup(), MarkupSpans, Type); +} + +MarkupEnd MCInstPrinter::endMarkup() { + return MarkupEnd(getUseMarkup(), MarkupSpans); +} + +raw_ostream &llvm::operator<<(raw_ostream &OS, const MarkupStart &M) { + if (M.Enabled) { + StringRef TypeStr; + switch (M.Type) { + case MarkupType::Imm: + TypeStr = "imm"; + break; + case MarkupType::Reg: + TypeStr = "reg"; + break; + case MarkupType::Mem: + TypeStr = "mem"; + break; + } + + // TODO: support tag-modifier-list. See: + // https://llvm.org/docs/MarkedUpDisassembly.html + size_t Length = 2 + TypeStr.size(); + if (!M.Spans.empty()) { + // Length and InnerLength will be set later. + MarkupSpan Span = MarkupSpan(M.Type, OS.tell(), 0, OS.tell() + Length, 0); + M.Spans.back()->push_back(std::move(Span)); + M.Spans.push_back(&M.Spans.back()->back().InnerSpans); + } + OS << "<" << TypeStr << ":"; + } + + return OS; +} + +raw_ostream &llvm::operator<<(raw_ostream &OS, const MarkupEnd &M) { + if (M.Enabled) { + if (!M.Spans.empty()) { + assert(M.Spans.size() > 1 && "Missing the corresponding markupStart()."); + M.Spans.pop_back(); + MarkupSpan &Span = M.Spans.back()->back(); + Span.Length = OS.tell() - Span.Pos + 1; + Span.InnerLength = OS.tell() - Span.InnerPos; + } + OS << ">"; + } + + return OS; +}