Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: include/llvm/Bitcode/NaCl/NaClObjDumpStream.h

Issue 939073008: Rebased PNaCl localmods in LLVM to 223109 (Closed)
Patch Set: undo localmod Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 //===- NaClObjDumpStream.h --------------------------------------*- C++ -*-===//
2 // Models an objdump stream (bitcode records/assembly code).
3 //
4 // The LLVM Compiler Infrastructure
5 //
6 // This file is distributed under the University of Illinois Open Source
7 // License. See LICENSE.TXT for details.
8 //
9 //===----------------------------------------------------------------------===//
10
11 #ifndef LLVM_BITCODE_NACL_NACLOBJDUMPSTREAM_H
12 #define LLVM_BITCODE_NACL_NACLOBJDUMPSTREAM_H
13
14 #include "llvm/ADT/STLExtras.h"
15 #include "llvm/Bitcode/NaCl/NaClBitcodeParser.h"
16 #include "llvm/Support/raw_ostream.h"
17 #include <vector>
18 #include <algorithm>
19
20 namespace llvm {
21 namespace naclbitc {
22
23 // The default string assumed for a tab.
24 static const char *DefaultTab = " ";
25
26 /// Class that implements text indenting for pretty printing text.
27 class TextIndenter {
28 public:
29 /// Creates a text indenter that indents using the given tab.
30 TextIndenter(const char* Tab = DefaultTab)
31 : Indent(""),
32 Tab(Tab),
33 TabSize(strlen(Tab)),
34 NumTabs(0) {
35 Values.push_back(Indent);
36 }
37
38 virtual ~TextIndenter() {}
39
40 /// Returns the current indentation to use.
41 const std::string &GetIndent() const {
42 return Indent;
43 }
44
45 /// Returns the indent with the given number of tabs.
46 const std::string &GetIndent(unsigned Count) {
47 if (Count >= Values.size()) {
48 // Indents not yet generated, fill in cache to size needed.
49 std::string Results;
50 if (Values.size() > 0) Results = Values.back();
51 for (size_t i = Values.size(); i <= Count; ++i) {
52 Results += Tab;
53 Values.push_back(Results);
54 }
55 }
56 return Values[Count];
57 }
58
59 /// Increments the current indentation by one tab.
60 void Inc() {
61 ++NumTabs;
62 if (NumTabs < Values.size()) {
63 Indent = Values[NumTabs];
64 } else {
65 Indent += Tab;
66 Values.push_back(Indent);
67 }
68 }
69
70 /// Decrements the current indentation by one tab.
71 void Dec() {
72 // Be sure not to underflow!
73 if (NumTabs) {
74 --NumTabs;
75 Indent = Values[NumTabs];
76 }
77 }
78
79 /// Returns the current number of tabs in the current indentation.
80 unsigned GetNumTabs() const {
81 return NumTabs;
82 }
83
84 const char *GetTab() const {
85 return Tab;
86 }
87
88 size_t GetTabSize() const {
89 return TabSize;
90 }
91
92 private:
93 // The current indentation to use.
94 std::string Indent;
95 // The set of (previously computed) identations, based on the number
96 // of tabs.
97 std::vector<std::string> Values;
98 // The text defining a tab.
99 const char *Tab;
100 // The size of the tab.
101 size_t TabSize;
102 // The number of tabs currently being used.
103 unsigned NumTabs;
104 };
105
106 class TextFormatter;
107
108 /// This template class maintains a simply pool of directives for
109 /// a text formatter. Assumes that all elements in pool are associated
110 /// with the same formatter.
111 template<class Directive>
112 class DirectiveMemoryPool {
113 public:
114 DirectiveMemoryPool() {}
115
116 ~DirectiveMemoryPool() {
117 DeleteContainerPointers(FreeList);
118 }
119
120 Directive *Allocate(TextFormatter *Fmtr) {
121 if (FreeList.empty()) return new Directive(Fmtr);
122 Directive *Element = FreeList.back();
123 assert(&Element->GetFormatter() == Fmtr
124 && "Directive memory pool formatter mismatch");
125 FreeList.pop_back();
126 return Element;
127 }
128
129 void Free(Directive *Dir) {
130 FreeList.push_back(Dir);
131 }
132
133 private:
134 std::vector<Directive*> FreeList;
135 };
136
137 /// This class defines a simple formatter for a stream that consists
138 /// of a sequence of instructions. In general, this class assumes that
139 /// instructions are a single line. In addition, some instructions
140 /// define a block around a sequence of instructions. Each block of
141 /// instructions is indented to clarify the block structure over that
142 /// set of instructions.
143 ///
144 /// To handle line indentation of blocks, this class inherits class
145 /// TextIndenter. The TextIndenter controls how blocks of lines are
146 /// indented. At the beginning of a block, the user should call method
147 /// Inc. It should then write out the sequence of instructions to be
148 /// indented. Then, after the last indented instruction of the block
149 /// is printed, the user should call method Dec. Nested blocks are
150 /// handled by nesting methods Inc and Dec appropriately.
151 ///
152 /// This class mainly focuses on the tools needed to format an
153 /// instruction, given a specified viewing width. The issue is that
154 /// while instructions should be on a single line, some instructions
155 /// are too wide to fit into the viewing width. Hence, we need a way
156 /// to deal with line overflow.
157 ///
158 /// The way this class handles the line overflow problem is to
159 /// basically force the user to break up the output into a sequence of
160 /// tokens. This is done using two streams. The text stream is used to
161 /// buffer tokens. The base stream is the stream to write tokens to
162 /// once they have been identified and positioned. The goal of the
163 /// formatter is to decide where the instruction text should be cut
164 /// (i.e. between tokens), so that the instruction does not overflow
165 /// the viewing width. It also handles the automatic insertion of line
166 /// indentation into the base stream when needed.
167 ///
168 /// To make it easy to print tokens to the text stream, we use text
169 /// directives. Whenever a text directive is written to the text
170 /// stream, it is assumed that all text written to the text stream
171 /// (since the last directive) is an (indivisible) token. The first
172 /// thing directives do is move the token from the text stream (if
173 /// present) to the base stream.
174 ///
175 /// In addition to defining tokens, text directives can also be
176 /// defined to query the formatter state and apply an appropriate
177 /// action. An example of this is the space text directive. It only
178 /// adds a space if the formatter isn't at the beginning of a new line
179 /// (since a newline can act as whitespace).
180 ///
181 /// The text formatter also has a notion of clustering
182 /// tokens. Clustering forces a consecutive sequence of tokens to
183 /// be treated as a single token, when deciding where to wrap long
184 /// lines. In particular, clustered tokens will not be broken up
185 /// unless there is no other way to print them, because the cluster is
186 /// larger than what can fit in a line.
187 ///
188 /// Clustering is implemented using two passes. In the first pass, the
189 /// sequence of tokens/directives are collected to find the clustered
190 /// text. They are also applied to collect any text internal to the
191 /// directives. Actions that can change (intraline) indenting are
192 /// turned off.
193 ///
194 /// Once the first pass is done, the second pass starts. It begins
195 /// with a check to see if the clustered text can fit on the current
196 /// line, and adds a newline if necessary. Then it replays the
197 /// directives to put the tokens of the cluster into the base stream.
198 /// The replay also changes (intraline) indenting as necessary.
199 ///
200 /// Clusters can be nested. In such cases, they are stripped one layer
201 /// per pass. Nested clusters are replayed after line wrapping of
202 /// outer clusters have been resolved.
203 class TextFormatter : public TextIndenter {
204 public:
205
206 /// Creates a text formatter to print instructions onto the given
207 /// Base Stream. The viewing width is defined by LineWidth. The
208 /// given tab is the assumed value for tab characters and line
209 /// indents.
210 explicit TextFormatter(raw_ostream &BaseStream,
211 unsigned LineWidth = 80,
212 const char *Tab = DefaultTab);
213
214 ~TextFormatter() override;
215
216 /// Returns the user-level text stream of the formatter that tokens
217 /// should be written to.
218 raw_ostream &Tokens() {
219 return TextStream;
220 }
221
222 /// Changes the line width to the given value.
223 void SetLineWidth(unsigned NewLineWidth) {
224 LineWidth = NewLineWidth;
225 if (MinLineWidth > LineWidth) MinLineWidth = LineWidth;
226 }
227
228 // Changes the (default) line-wrap, continuation indent.
229 void SetContinuationIndent(const std::string &Indent) {
230 ContinuationIndent = Indent;
231 }
232
233 /// Base class for all directives. The basic functionality is that it
234 /// has a reference to the text formatter, and is applied by calling
235 /// method apply. This method apply is encorporated into the
236 /// stream operator<<, so that they can be used as part of the
237 /// streamed output.
238 ///
239 /// Method apply extracts any tokens in the text stream. Moves them
240 /// into the base stream. Finally, it calls virtual method MyApply
241 /// to do the actions of the directive.
242 class Directive {
243 Directive(const Directive&) LLVM_DELETED_FUNCTION;
244 void operator=(const Directive&) LLVM_DELETED_FUNCTION;
245 public:
246 /// Creates a directive for the given stream.
247 explicit Directive(TextFormatter *Formatter)
248 : Formatter(Formatter) {}
249
250 virtual ~Directive() {}
251
252 /// Returns the formatter associated with the directive.
253 TextFormatter &GetFormatter() const {
254 return *Formatter;
255 }
256
257 /// Does action of directive.
258 void Apply() const {
259 // Start by writing token if Tokens() buffer (if non-empty).
260 Formatter->WriteToken();
261 // Apply the directive.
262 MyApply(false);
263 // Save the directive for replay if we are clustering.
264 MaybeSaveForReplay();
265 }
266
267 protected:
268 // The formatter associated with the directive.
269 TextFormatter *Formatter;
270
271 // Like Apply, but called instead of Apply whey doing a replay.
272 void Reapply() const;
273
274 // Does directive specific action. Replay is true only if the
275 // directive was in a cluster, and it is being called to replay
276 // the directive a second time.
277 virtual void MyApply(bool Replay) const = 0;
278
279 // Adds the directive to the clustered directives if appropriate
280 // (i.e. inside a cluster).
281 virtual void MaybeSaveForReplay() const {
282 if (IsClustering()) AppendForReplay(this);
283 }
284
285 // ***********************************************************
286 // Note: The following have been added so that derived classes
287 // have public access to protected text formatter methods.
288 // (Otherwise, you get a compiler error that they are protected
289 // in derived classes).
290 // ***********************************************************
291
292 bool IsClustering() const {
293 return Formatter->IsClustering();
294 }
295
296 unsigned GetClusteringLevel() const {
297 return Formatter->GetClusteringLevel();
298 }
299
300 void AppendForReplay(const Directive *D) const {
301 Formatter->AppendForReplay(D);
302 }
303
304 raw_ostream &Tokens() const {
305 return Formatter->Tokens();
306 }
307
308 void WriteToken(const std::string &Token) const {
309 Formatter->WriteToken(Token);
310 }
311
312 void WriteEndline() const {
313 Formatter->WriteEndline();
314 }
315
316 void PopIndent() const {
317 Formatter->PopIndent();
318 }
319
320 void PushIndent() const {
321 Formatter->PushIndent();
322 }
323
324 bool AddLineWrapIfNeeded(unsigned TextSize) const {
325 return Formatter->AddLineWrapIfNeeded(TextSize);
326 }
327
328 void StartClustering() const {
329 Formatter->StartClustering();
330 }
331
332 void FinishClustering() const {
333 Formatter->FinishClustering();
334 }
335 };
336
337 protected:
338 // The base stream to send formatted text to.
339 raw_ostream &BaseStream;
340 // Buffer that holds token text.
341 std::string TextBuffer;
342 // The user-level stream for (token) text and directives.
343 raw_string_ostream TextStream;
344 // The buffered token waiting to be flushed to the base stream.
345 // std::string BufferedToken;
346 // The expected line width the formatter should try and match.
347 unsigned LineWidth;
348 // The current position (i.e. column of previous character on line)
349 // associated with the current line in the base stream.
350 unsigned LinePosition;
351 // The stack of (intraline) indents added by PushIndent.
352 std::vector<unsigned> IntralineIndents;
353 // The current intraline indent to use.
354 unsigned CurrentIndent;
355 // The minimum line width. Used to limit indents so that there
356 // will always be at least this amount of space on the line.
357 unsigned MinLineWidth;
358 // True if no characters have moved to the base stream for the
359 // instruction being printed. Note: This is different than
360 // LinePosition == 0. The latter can be true, when
361 // AtInstructionBeginning is false, if the current line is a
362 // continuation line caused by line overflow.
363 bool AtInstructionBeginning;
364 // The indent string to use for indenting each line of the instruction.
365 std::string LineIndent;
366 // The indent to add on continuation (i.e. overflow) lines for an
367 // instruction.
368 std::string ContinuationIndent;
369 // Counts how nested we are within clustering directives.
370 unsigned ClusteringLevel;
371 // Contains the number of columns needed to hold the generated text,
372 // while clustering. Computed so that we can test if it fits on the
373 // current line.
374 unsigned ClusteredTextSize;
375 // Contains the sequence of directives (including tokens) during
376 // clustering, so that it can be replayed after we determine if a
377 // new line needs to be added.
378 std::vector<const Directive*> ClusteredDirectives;
379
380 // Returns if we are currently inside a cluster.
381 bool IsClustering() const {
382 return ClusteringLevel > 0;
383 }
384
385 // Returns the clustering level of the formatter.
386 unsigned GetClusteringLevel() const {
387 return ClusteringLevel;
388 }
389
390 // Appends the given directive to the list of directives to
391 // replay, if clustering.
392 void AppendForReplay(const Directive *D) {
393 ClusteredDirectives.push_back(D);
394 }
395
396 /// Writes out the token in the text stream. If necessary, moves to
397 // a new line first.
398 void WriteToken() {
399 WriteToken(GetToken());
400 }
401
402 /// Writes out the given token. If necessary, moves to a new line first.
403 void WriteToken(const std::string &Token) {
404 if (Token.empty()) return;
405 AddLineWrapIfNeeded(Token.size());
406 Write(Token);
407 }
408
409 // Extracts the text that has been added to the text stream, and
410 // returns it.
411 std::string GetToken();
412
413 /// Writes out a non-newline character to the base stream.
414 void Write(char ch);
415
416 /// Writes out a string.
417 void Write(const std::string &Text);
418
419 /// Starts a new cluster of tokens.
420 /// Note: We do not allow nested clusterings.
421 void StartClustering();
422
423 /// Ends the existing cluster of tokens.
424 void FinishClustering();
425
426 /// Adds a newline that ends the current instruction being printed.
427 void WriteEndline();
428
429 /// Called just before the first character on a line is printed, to
430 /// add indentation text for the line.
431 virtual void WriteLineIndents();
432
433 /// Analyzes the formatter state to determine if a token of the
434 /// given TextSize can fit on the current line. If it can't fit,
435 /// it wraps the input line. Returns true only if line wrap was
436 /// added by this method.
437 bool AddLineWrapIfNeeded(unsigned TextSize) {
438 if (IsClustering()) {
439 // Don't consider line wrapping until all text is clustered. That
440 // way we have full information on what we should do.
441 return false;
442 } else {
443 // If the text fits on the current line, there is nothing to do.
444 // Otherwise, we should add a newline, unless we are already
445 // at the new line. If we are already at the newline, we can't
446 // split up the token, so just allow line overflow.
447 if (LinePosition + TextSize <= LineWidth
448 || LinePosition == 0)
449 return false;
450 // If reached, it must not fit, so add a line wrap.
451 Write('\n');
452 return true;
453 }
454 }
455
456 /// Pops the current (intraline) indentation and restores it to the
457 /// previous indentation. Used to restore the indentation of
458 /// parenthesized subexpressions, where this should be called on the
459 /// close parenthesis.
460 void PopIndent() {
461 // Be pragmatic. If there is underflow, assume that it was due to
462 // the fact that the caller of this text formatter used a close
463 // directive for a pair of matching parenthesis that crossed
464 // multiple (i.e. instruction) lines.
465 if (IsClustering() || IntralineIndents.empty()) return;
466 CurrentIndent = IntralineIndents.back();
467 IntralineIndents.pop_back();
468 }
469
470 /// Pushes the current (intraline) indentation to match the current
471 /// position within the line. Used to indent parenthesized
472 /// subexpressions, where this should be called on the open
473 /// parenthesis.
474 void PushIndent() {
475 if (IsClustering()) return;
476 IntralineIndents.push_back(CurrentIndent);
477 CurrentIndent = FixIndentValue(LinePosition);
478 }
479
480 /// Fixes the given position, to the appropriate value for setting
481 /// CurrentIndent. That is, it makes sure there is always MinLineWidth
482 /// printable characters on a line.
483 unsigned FixIndentValue(unsigned Position) {
484 return std::min(Position, LineWidth - MinLineWidth);
485 }
486
487 private:
488 /// Directive that generates temporary instances to hold tokens from
489 /// the Tokens() stream. Generated when GetToken() is called. Used
490 /// during clustering to regenerate the corresponding extracted
491 /// tokens during a replay.
492 class GetTokenDirective : public Directive {
493 friend class DirectiveMemoryPool<GetTokenDirective>;
494 GetTokenDirective(TextFormatter *Formatter)
495 : Directive(Formatter) {}
496
497 public:
498 ~GetTokenDirective() override {}
499
500 /// Allocates an instance of a GetTokenDirective.
501 /// Note: Will be reclaimed when MyApply is called.
502 static Directive *Allocate(TextFormatter *Formatter,
503 const std::string &Text);
504
505 protected:
506 void MyApply(bool Replay) const override {
507 WriteToken(Text);
508 if (!IsClustering())
509 Formatter->GetTokenFreeList.Free(const_cast<GetTokenDirective*>(this));
510 }
511
512 private:
513 // The token text.
514 std::string Text;
515 };
516
517 // The set of freed GetTokenDirectives, that can be reused.
518 DirectiveMemoryPool<GetTokenDirective> GetTokenFreeList;
519 };
520
521 inline raw_ostream &operator<<(raw_ostream &Stream,
522 const TextFormatter::Directive &Directive) {
523 // Be sure that the directive is defined for the given stream,
524 // before applying the directive, since directives may have
525 // different meanings on different text streams.
526 assert(&Stream == &Directive.GetFormatter().Tokens());
527 Directive.Apply();
528 return Stream;
529 }
530
531 /// Defines a directive that only tokenizes the text in the Tokens()
532 /// stream.
533 class TokenizeTextDirective : public TextFormatter::Directive {
534 public:
535 explicit TokenizeTextDirective(TextFormatter *Formatter)
536 : TextFormatter::Directive(Formatter) {}
537
538 ~TokenizeTextDirective() override {}
539
540 protected:
541 void MyApply(bool Replay) const override {}
542 };
543
544 /// Defines a token which doesn't need whitespace on either side of
545 /// the token to be a valid token (such as punctuation).
546 class TokenTextDirective : public TextFormatter::Directive {
547 public:
548 TokenTextDirective(TextFormatter *Formatter, const std::string &Str)
549 : TextFormatter::Directive(Formatter), Text(Str) {
550 }
551
552 ~TokenTextDirective() override {}
553
554 protected:
555 void MyApply(bool Replay) const override {
556 WriteToken(Text);
557 }
558
559 private:
560 std::string Text;
561 };
562
563 /// Writes out the current token. Then adds a space if the base
564 /// stream is not at the beginning of a continuation line.
565 class SpaceTextDirective : public TextFormatter::Directive {
566 public:
567 SpaceTextDirective(TextFormatter *Formatter, const std::string &Space)
568 : TextFormatter::Directive(Formatter), Space(Space) {}
569
570 explicit SpaceTextDirective(TextFormatter *Formatter)
571 : TextFormatter::Directive(Formatter), Space(" ") {}
572
573 ~SpaceTextDirective() {}
574
575 protected:
576 void MyApply(bool Replay) const override {
577 if (!AddLineWrapIfNeeded(Space.size()))
578 WriteToken(Space);
579 }
580 private:
581 std::string Space;
582 };
583
584 /// Adds a newline that ends the current instruction being printed.
585 class EndlineTextDirective : public TextFormatter::Directive {
586 public:
587 explicit EndlineTextDirective(TextFormatter *Formatter)
588 : TextFormatter::Directive(Formatter) {}
589
590 ~EndlineTextDirective() override {}
591
592 protected:
593 void MyApply(bool Replay) const override {
594 WriteEndline();
595 }
596 };
597
598 /// Inserts a token and then pushes the current indent to the position
599 /// after the token. Used to model a open parenthesis.
600 class OpenTextDirective : public TokenTextDirective {
601 public:
602
603 // Creates an open using the given indent.
604 OpenTextDirective(TextFormatter *Formatter, const std::string &Text)
605 : TokenTextDirective(Formatter, Text) {}
606
607 ~OpenTextDirective() override {}
608
609 protected:
610 void MyApply(bool Replay) const override {
611 TokenTextDirective::MyApply(Replay);
612 PushIndent();
613 }
614 };
615
616 /// Inserts a token and then pops current indent. Used to model a
617 /// close parenthesis.
618 class CloseTextDirective : public TokenTextDirective {
619 public:
620 CloseTextDirective(TextFormatter *Formatter, const std::string &Text)
621 : TokenTextDirective(Formatter, Text) {}
622
623 ~CloseTextDirective() override {}
624
625 protected:
626 void MyApply(bool Replay) const override {
627 TokenTextDirective::MyApply(Replay);
628 PopIndent();
629 }
630 };
631
632 /// Defines the beginning of a token cluster, which should be put on the
633 /// same line if possible.
634 class StartClusteringDirective : public TextFormatter::Directive {
635 public:
636 explicit StartClusteringDirective(TextFormatter *Formatter)
637 : TextFormatter::Directive(Formatter) {}
638
639 ~StartClusteringDirective() override {}
640
641 protected:
642 void MyApply(bool Replay) const override {
643 StartClustering();
644 }
645
646 void MaybeSaveForReplay() const override {
647 if (GetClusteringLevel() > 1) AppendForReplay(this);
648 }
649 };
650
651 class FinishClusteringDirective : public TextFormatter::Directive {
652 public:
653 explicit FinishClusteringDirective(TextFormatter *Formatter)
654 : TextFormatter::Directive(Formatter) {}
655
656 ~FinishClusteringDirective() override {}
657
658 protected:
659 void MyApply(bool Replay) const override {
660 FinishClustering();
661 }
662 };
663
664 class ObjDumpStream;
665
666 /// Models that an abbreviation index is not specified when dumping a
667 /// bitcode record.
668 static int32_t ABBREV_INDEX_NOT_SPECIFIED = -1;
669
670 /// The formatter used for dumping records in ObjDumpStream.
671 class RecordTextFormatter : public TextFormatter {
672 public:
673 /// The address write width used to print the number of
674 /// bytes in the record bit address, when printing records.
675 static const unsigned AddressWriteWidth = 8;
676
677 explicit RecordTextFormatter(ObjDumpStream *ObjDump);
678
679 ~RecordTextFormatter() override {}
680
681 /// Writes out the given record of values as an instruction.
682 void WriteValues(uint64_t Bit,
683 const llvm::NaClBitcodeValues &Values,
684 int32_t AbbrevIndex = ABBREV_INDEX_NOT_SPECIFIED);
685
686 /// Returns text corresponding to an empty label column.
687 std::string GetEmptyLabelColumn();
688
689 // Converts the given start bit to the corresponding address to
690 // print. That is, generate "Bit/8:Bit%8" value.
691 static std::string RecordAddress(uint64_t Bit, unsigned MinByteWidth);
692
693 // Returns the record address (when printing records) associated with
694 // the given bit.
695 static std::string RecordAddress(uint64_t Bit) {
696 return RecordAddress(Bit, AddressWriteWidth);
697 }
698
699 protected:
700 void WriteLineIndents() override;
701
702 private:
703 // The object dumper this formatter is associated with.
704 ObjDumpStream *ObjDump;
705 // The address label associated with the current line.
706 std::string Label;
707 // The open brace '<' for a record.
708 OpenTextDirective OpenBrace;
709 // The close brace '>' for a record.
710 CloseTextDirective CloseBrace;
711 // A comma between elements in a record.
712 TokenTextDirective Comma;
713 // A space inside a record.
714 SpaceTextDirective Space;
715 // End the line.
716 EndlineTextDirective Endline;
717 // Start clustering tokens.
718 StartClusteringDirective StartCluster;
719 // End clustering tokens.
720 FinishClusteringDirective FinishCluster;
721 };
722
723 /// Implements a stream to print out bitcode records, assembly code,
724 /// comments, and errors. The general format is to print records and
725 /// assembly side by side. Comments and errors (associated with the
726 /// record and/or assembly code) follow each printed record.
727 ///
728 /// Alignment of records, assembly, comments, and errors is done by
729 /// buffering assembly, comments, and errors until a write or flush
730 /// occurs. Then, the various streams are stitched together to
731 /// produce the corresponding output text. There are two buffers: one
732 /// holds the assembly, and the other holds comments and errors.
733 ///
734 /// There are exactly two methods that can cause text to be added to
735 /// the objdump stream. Method Flush just flushes out the assembly and
736 /// comments/errors buffer without printing a record. If there is no
737 /// buffered assembly/comments/errors, nothing is done. Method Write
738 /// prints the given record, and also flushes out the assembly and
739 /// comments/errors buffer. Hence, in general, comments and errors
740 /// follow the record/assembly. However, if you want them to appear
741 /// before, use method Flush.
742 ///
743 /// The constructor is defined with two flags: DumpRecords and
744 /// DumpAssembly. Comments and errors are flushed on every write,
745 /// independent of these flags. Records are printed out only if
746 /// DumpRecords is true. Assembly is flushed only if DumpAssembly is
747 /// true.
748 ///
749 /// To buffer assembly, call method Assembly to get a (string) stream
750 /// to buffer the assembly code. To buffer comments, call method
751 /// Comments() to get a (string) stream to buffer the comments.
752 ///
753 /// To buffer an error, call method Error. This method will increment
754 /// the error count, and return the comments stream after writing
755 /// "Error(byte:bit): ".
756 ///
757 /// If a single line of text is buffered into the assembly stream, no
758 /// new line is needed. The corresponding call to Write will
759 /// automatically insert the newline for you, if you did not add
760 /// it. If multiple lines are to be buffered into the assembly stream,
761 /// each line must be separated with a newline character. It is
762 /// always safe to end all assembly lines with a newline character.
763 ///
764 /// Also note that this class takes care of formatting records to fit
765 /// into a calculated record width (based on value set to
766 /// RecordWidth). On the other hand, we assume that the assembly is
767 /// formatted by the caller (i.e. owner of this object).
768 class ObjDumpStream {
769 ObjDumpStream(const ObjDumpStream&) LLVM_DELETED_FUNCTION;
770 void operator=(const ObjDumpStream&) LLVM_DELETED_FUNCTION;
771 public:
772 /// The default number of error messages that will be printed before
773 /// execution is stopped due to too many errors.
774 static unsigned DefaultMaxErrors;
775
776 /// The default value for the column that separates records and
777 /// assembly, when DumpRecords and DumpAssembly is true.
778 static unsigned ComboObjDumpSeparatorColumn;
779
780 /// The default value for line width when DumpRecords is true,
781 /// and DumpAssembly is false. This value is typically larger
782 /// than ComboObjDumpSeparatorColumn, since the entire line
783 /// can be used to print records.
784 static unsigned RecordObjectDumpLength;
785
786 /// Creates an objdump stream which will dump records, assembly,
787 /// comments and errors into a single (user proved Stream). When
788 /// DumpRecords is true, the contents of records will be
789 /// dumped. When DumpAssembly is true, the corresponding assembly
790 /// will be printed. When both are true, the records and assembly
791 /// will be printed side by side. When both are false, only comments
792 /// and errors will be printed.
793 ObjDumpStream(raw_ostream &Stream, bool DumpRecords, bool DumpAssembly);
794
795 ~ObjDumpStream() { Flush(); }
796
797 /// Returns stream to buffer assembly that will be printed during the
798 /// next write call.
799 raw_ostream &Assembly() {
800 return AssemblyStream;
801 }
802
803 /// Returns stream to buffer records that will be printed during the
804 /// next write call.
805 raw_ostream &Records() {
806 return RecordStream;
807 }
808
809 /// Returns stream to buffer messages that will be printed during the
810 // next write call.
811 raw_ostream &Comments() {
812 return MessageStream;
813 }
814
815 /// Prints "Warning(Bit/8:Bit%8): " onto the comments stream, and
816 /// then returns the comments stream. In general, warnings will be
817 /// printed after the next record, unless a call to Flush is made.
818 raw_ostream &Warning() {
819 return Warning(LastKnownBit);
820 }
821
822 /// Prints "Warning(Bit/8:Bit%8): " onto the comments stream, and
823 /// then returns the comments stream. In general, warnings will be
824 /// printed after the next record, unless a call to Flush is made.
825 raw_ostream &Warning(uint64_t Bit) {
826 LastKnownBit = Bit;
827 return PrintMessagePrefix("Warning", Bit);
828 }
829
830 /// Prints "Error(Bit/8:Bit%8): " onto the comments stream, records
831 /// that an error has occurred, and then returns the comments
832 /// stream. In general errors will be printed after the next record,
833 /// unless a call to Flush is made.
834 raw_ostream &Error() {
835 return Error(LastKnownBit);
836 }
837
838 /// Prints "Error(Bit/8:Bit%8): " onto the comments stream, records
839 /// that an error has occurred, and then returns the comments
840 /// stream. In general errors will be printed after the next record,
841 /// unless a call to Flush is made.
842 raw_ostream &Error(uint64_t Bit);
843
844 /// Write a fatal error message to the dump stream, and then
845 /// stop the executable. If any assembly, comments, or errors have
846 /// been buffered, they will be printed first.
847 void Fatal(const std::string &Message) {
848 Fatal(LastKnownBit, Message);
849 }
850
851 /// Write a fatal error message to the dump stream, and then
852 /// stop the executable. If any assembly, comments, or errors have
853 /// been buffered, they will be printed first. Associates fatal error
854 /// Message with the given Bit.
855 void Fatal(uint64_t Bit, const std::string &Message);
856
857 /// Write a fatal error message to the dump stream, and then
858 /// stop the executable. If any assembly, comments, or errors have
859 /// been buffered, they will be printed first, along with the given record.
860 void Fatal(uint64_t Bit,
861 const llvm::NaClBitcodeRecordData &Record,
862 const std::string &Message);
863
864 /// Dumps a record (at the given bit), along with all buffered assembly,
865 /// comments, and errors, into the objdump stream.
866 void Write(uint64_t Bit,
867 const llvm::NaClBitcodeRecordData &Record,
868 int32_t AbbrevIndex = ABBREV_INDEX_NOT_SPECIFIED) {
869 LastKnownBit = Bit;
870 NaClBitcodeValues Values(Record);
871 RecordFormatter.WriteValues(Bit, Values, AbbrevIndex);
872 Flush();
873 }
874
875 /// Dumps the buffered assembly, comments, and errors, without any
876 /// corresponding record, into the objdump stream.
877 void Flush();
878
879 /// Increments the record indent by one.
880 void IncRecordIndent() {
881 RecordFormatter.Inc();
882 }
883
884 /// Decrements the record indent by one.
885 void DecRecordIndent() {
886 RecordFormatter.Dec();
887 }
888
889 /// Returns the record indenter being used by the objdump stream, for
890 /// the purposes of querying state.
891 const TextIndenter &GetRecordIndenter() {
892 return RecordFormatter;
893 }
894
895 /// Returns the number of errors reported to the dump stream.
896 unsigned GetNumErrors() const {
897 return NumErrors;
898 }
899
900 // Returns true if dumping record.
901 bool GetDumpRecords() const {
902 return DumpRecords;
903 }
904
905 // Returns true if dumping assembly.
906 bool GetDumpAssembly() const {
907 return DumpAssembly;
908 }
909
910 /// Changes the default assumption that bit addresses start
911 /// at index 0.
912 void SetStartOffset(uint64_t Offset) {
913 StartOffset = Offset;
914 }
915
916 /// Changes the maximum number of errors allowed.
917 void SetMaxErrors(unsigned NewMax) {
918 MaxErrors = NewMax;
919 }
920
921 /// Changes the width allowed for records (from the default).
922 void SetRecordWidth(unsigned Width) {
923 RecordWidth = Width;
924 }
925
926 unsigned GetRecordWidth() const {
927 return RecordWidth;
928 }
929
930 /// Changes the column separator character to the given value.
931 void SetColumnSeparator(char Separator) {
932 ColumnSeparator = Separator;
933 }
934
935 /// Changes the internal state, to assume one is processing a record
936 /// at the given bit. Used by Error() and Fatal(Message) to fill in
937 /// the corresponding bit to associate with the error message.
938 void SetRecordBitAddress(uint64_t Bit) {
939 LastKnownBit = Bit;
940 }
941
942 // Converts the given start bit to the corresponding address to
943 // print. That is, generate "Bit/8:Bit%8" value.
944 std::string ObjDumpAddress(uint64_t Bit, unsigned MinByteWidth=1) {
945 return RecordFormatter.RecordAddress(Bit + StartOffset, MinByteWidth);
946 }
947
948 // Returns the record address (when printing records) associated with
949 // the given bit.
950 std::string RecordAddress(uint64_t Bit) {
951 return RecordFormatter.RecordAddress(Bit + StartOffset);
952 }
953
954 private:
955 // The stream to dump to.
956 raw_ostream &Stream;
957 // True if records should be dumped to the dump stream.
958 bool DumpRecords;
959 // True if assembly text should be dumped to the dump stream.
960 bool DumpAssembly;
961 // The number of errors reported.
962 unsigned NumErrors;
963 // The maximum number of errors before quitting.
964 unsigned MaxErrors;
965 // The number of columns available to print bitcode records.
966 unsigned RecordWidth;
967 // The number of bits to add to the record bit address, to correct
968 // the record bit address passed to the write routines.
969 uint64_t StartOffset;
970 // The buffer for assembly to be printed during the next write.
971 std::string AssemblyBuffer;
972 // The stream to buffer assembly into the assembly buffer.
973 raw_string_ostream AssemblyStream;
974 // The buffer for comments and errors.
975 std::string MessageBuffer;
976 // The stream to buffer comments and errors into the message.
977 raw_string_ostream MessageStream;
978 // The character used to separate records from assembly.
979 char ColumnSeparator;
980 // The last known bit passed to the objdump object. Used as default
981 // for automatically generated errors.
982 uint64_t LastKnownBit;
983 /// The buffer for records to be printed to during the next write.
984 std::string RecordBuffer;
985 /// The stream to buffer recordds into the record buffer.
986 raw_string_ostream RecordStream;
987 /// The text formatter for generating records.
988 RecordTextFormatter RecordFormatter;
989
990 // Resets assembly and buffers.
991 void ResetBuffers() {
992 RecordBuffer.clear();
993 AssemblyBuffer.clear();
994 MessageBuffer.clear();
995 }
996
997 // Returns the message stream with 'Label(Bit/8:Bit%8): '.
998 raw_ostream &PrintMessagePrefix(const char *Label, uint64_t Bit) {
999 return Comments() << Label << "(" << ObjDumpAddress(Bit) << "): ";
1000 }
1001 };
1002
1003 }
1004 }
1005
1006 #endif
OLDNEW
« no previous file with comments | « include/llvm/Bitcode/NaCl/NaClLLVMBitCodes.h ('k') | include/llvm/Bitcode/NaCl/NaClReaderWriter.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698