[llvm-commits] [llvm] r75156 - in /llvm/trunk: include/llvm/CodeGen/AsmStream.h lib/CodeGen/AsmStream.cpp

David Greene greened at obbligato.org
Thu Jul 9 11:27:23 PDT 2009


Author: greened
Date: Thu Jul  9 13:27:23 2009
New Revision: 75156

URL: http://llvm.org/viewvc/llvm-project?rev=75156&view=rev
Log:

Add some classes to produce pretty-printed asm.  We'll use these
shortly to provide nicely printed comments and other goodies in
asm files.

Added:
    llvm/trunk/include/llvm/CodeGen/AsmStream.h
    llvm/trunk/lib/CodeGen/AsmStream.cpp

Added: llvm/trunk/include/llvm/CodeGen/AsmStream.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/AsmStream.h?rev=75156&view=auto

==============================================================================
--- llvm/trunk/include/llvm/CodeGen/AsmStream.h (added)
+++ llvm/trunk/include/llvm/CodeGen/AsmStream.h Thu Jul  9 13:27:23 2009
@@ -0,0 +1,442 @@
+//===-- llvm/CodeGen/AsmStream.h - AsmStream Framework --------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains streambuf and ostream implementations for ASM printers
+// to do things like pretty-print comments.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_ASMSTREAM_H
+#define LLVM_CODEGEN_ASMSTREAM_H
+
+#include "llvm/Target/TargetAsmInfo.h"
+
+#include <streambuf>
+#include <iomanip>
+#include <iterator>
+#include <llvm/Support/Streams.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+namespace llvm 
+{
+  /// BasicAsmStreambuf - A stream buffer to count columns and allow
+  /// placement of output at specific columns.
+  ///
+  /// TODO: This only works on POSIX systems for now
+  template<typename charT, typename Traits = std::char_traits<charT> >
+  class BasicAsmStreambuf
+      : public std::basic_streambuf<charT, Traits> {
+  private:
+    static const int bufferSize = 10;
+    charT buffer_array[bufferSize];
+    int column;
+    int fd;
+
+    bool formatted;
+
+    typedef typename std::basic_streambuf<charT, Traits>::int_type int_type;
+
+  protected:
+    void setFD(int f) {
+      fd = f;
+    }
+
+    int getFD(void) const {
+      return(fd);
+    }
+
+    bool FDSet(void) const {
+      return(getFD() != -1);
+    }
+
+  public:
+    BasicAsmStreambuf(void) 
+        : std::basic_streambuf<charT, Traits>(), column(0), fd(-1),
+            formatted(true) {
+      // Assure we have room for one character when overflow is called
+      setp(buffer_array, buffer_array+(bufferSize-1));
+    }
+
+    explicit BasicAsmStreambuf(int f)
+        : std::basic_streambuf<charT, Traits>(), column(0), fd(f),
+            formatted(true) {
+      // Assure we have room for one character when overflow is called
+      setp(buffer_array, buffer_array+(bufferSize-1));
+    }
+
+    virtual ~BasicAsmStreambuf(void) {
+      sync();
+    }
+
+    void setColumn(int newcol, int minpad = 0) {
+      if (formatted) {
+        // Flush the current buffer to get the most recent column
+        if (Traits::eq_int_type(flushBuffer(), Traits::eof())) {
+          // Error
+          assert(0 && "Corrupted output buffer");
+        }
+
+        // Output spaces until we reach the desired column
+        int num = newcol - column;
+        if (num <= 0) {
+          num = minpad;
+        }
+
+        // TODO: Use sputn
+        while (num-- > 0) {
+          if (Traits::eq_int_type(this->sputc(' '), Traits::eof())) {
+            assert(0 && "Corrupted output buffer");
+          }
+        }
+      }
+    };
+
+  protected:
+    void setFormatting(bool v) {
+      formatted = v;
+    }
+
+    int flushBuffer(void) {
+      if (FDSet()) {
+        if (formatted) {
+          // Keep track of the current column by scanning the string for
+          // special characters
+
+          // Find the last newline.  This is our column start.  If there
+          // is no newline, start with the current column.
+          charT *nlpos = NULL;        
+          for (charT *pos = this->pptr(), *epos = this->pbase(); pos > epos; --pos) {
+            if (Traits::eq(*(pos-1), '\n')) {
+              nlpos = pos-1;
+              // The newline will be counted, setting this to zero.
+              // We need to do it this way in case nlpos is pptr(),
+              // which is one after epptr() after overflow is called.
+              column = -1;
+              break;
+            }
+          }
+
+          if (nlpos == NULL) {
+            nlpos = this->pbase();
+          }
+
+          // Walk through looking for tabs and advance column as appropriate
+          for (charT *pos = nlpos, *epos = this->pptr(); pos != epos; ++pos) {
+            ++column;
+            if (Traits::eq(*pos, '\t')) {
+              // Advance to next tab stop (every eight characters)
+              column += ((8 - (column & 0x7)) & 0x7);
+              assert(!(column & 0x3) && "Column out of alignment");
+            }
+          }
+        }
+
+        // Write out the buffer
+        int num = this->pptr() - this->pbase();
+
+        if (write(fd, buffer_array, num) != num) {
+          return(Traits::eof());
+        }
+        this->pbump(-num);
+        return(num);
+      }
+      return(0);
+    }
+
+    // Buffer full, so write c and all buffered characters
+    virtual int_type overflow(int_type c) {
+      if (!Traits::eq_int_type(c, Traits::eof())) {
+        *this->pptr() = c;
+        this->pbump(1);
+        //++column;
+        if (Traits::eq_int_type(flushBuffer(), Traits::eof())) {
+          // Error
+          return Traits::eof();
+        }
+        
+        return Traits::not_eof(c);
+      }
+      return Traits::eof();
+    }
+
+    // Write multiple characters (TODO)
+    //    virtual std::streamsize xsputn(const char *s,
+    //                             std::streamsize num) {
+    //}
+
+    // Flush data in the buffer
+    virtual int sync(void) {
+      if (Traits::eq_int_type(flushBuffer(),Traits::eof())) {
+        // Error
+        return -1;
+      }
+      return 0;
+    }
+  };
+
+  typedef BasicAsmStreambuf<char> AsmStreambuf;
+  typedef BasicAsmStreambuf<wchar_t> AsmWStreambuf;
+
+  /// BasicAsmFilebuf - An AsmStreambuf to write to files
+  ///
+  template<typename charT, typename Traits = std::char_traits<charT> >
+  class BasicAsmFilebuf 
+      : public BasicAsmStreambuf<charT, Traits> {
+  public:
+    BasicAsmFilebuf(void)
+        : BasicAsmStreambuf<charT, Traits>() {}
+    BasicAsmFilebuf(const std::basic_string<charT, Traits> &name,
+                    std::ios_base::openmode mode)
+        : BasicAsmStreambuf<charT, Traits>() {
+      open(name.c_str(), mode);
+    }
+
+    ~BasicAsmFilebuf(void) {
+      close();
+    }
+
+    BasicAsmFilebuf *open(const charT *name, std::ios_base::openmode mode) {
+      int flags = 0;
+      if (mode & std::ios_base::in) {
+        flags |= O_RDONLY;
+      }
+      if (mode & std::ios_base::out) {
+        if (mode & std::ios_base::in) {
+          flags |= O_RDWR;
+        }
+        else {
+          flags |= O_WRONLY;
+        }
+        flags |= O_CREAT;
+      }
+      if (mode & std::ios_base::trunc) {
+        flags |= O_TRUNC;
+      }
+      if (mode & std::ios_base::app) {
+        flags |= O_APPEND;
+      }
+
+      if (mode & std::ios_base::binary) {
+        this->setFormatting(false);
+      }
+      else {
+        this->setFormatting(true);
+      }
+
+      int fd = ::open(name, flags, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+      assert(fd != -1 && "Cannot open output file");
+
+      this->setFD(fd);
+
+      return(this);
+    }
+
+    BasicAsmFilebuf *close(void) {
+      if (is_open()) {
+        int result = ::close(this->getFD());
+        assert(result != -1 && "Could not close output file");
+        this->setFD(-1);
+      }
+
+      return(this);
+    }
+
+    bool is_open(void) const {
+      return(this->getFD() != -1);
+    }
+  };
+
+  typedef BasicAsmFilebuf<char> AsmFilebuf;
+  typedef BasicAsmFilebuf<wchar_t> AsmWFilebuf;
+
+  /// BasicAsmOStream - std::ostream equivalent for BasicAsmStreambuf
+  ///
+  template<typename charT, typename Traits = std::char_traits<charT> >
+  class BasicAsmOStream 
+      : public std::basic_ostream<charT, Traits> {
+  protected:
+    typedef BasicAsmStreambuf<charT, Traits> streambuf;
+    streambuf *bufptr;
+
+  public:
+    explicit BasicAsmOStream(streambuf *b)
+        : std::basic_ostream<charT, Traits>(b), bufptr(b) {
+      assert(b && "Invalid streambuf in OStream constructor");
+      assert(this->rdbuf()
+             && "Invalid basic_ostream buf in OStream constructor");
+    }
+
+    streambuf *buffer(void) {
+      assert(bufptr && "Invalid streambuf in buffer");
+      assert(this->rdbuf()
+             && "Invalid basic_ostream buf in rdbuf");
+      return(bufptr);
+    }
+  };
+
+  typedef BasicAsmOStream<char> AsmOStream;
+  typedef BasicAsmOStream<wchar_t> AsmWOStream;
+
+  /// BasicAsmOFStream - std::ofstream equivalent for BasicAsmFilebuf
+  ///
+  template<typename charT, typename Traits = std::char_traits<charT> >
+  class BasicAsmOFStream 
+      : public BasicAsmOStream<charT, Traits> {
+  protected:
+    BasicAsmFilebuf<charT, Traits> buf;
+
+  public:
+    BasicAsmOFStream(void) : BasicAsmOStream<charT, Traits>(&buf) {}
+    explicit BasicAsmOFStream(const std::basic_string<charT, Traits> &name) 
+        : BasicAsmOStream<charT, Traits>(&buf),
+            buf(name, std::ios_base::out | std::ios_base::trunc) {
+      assert(this->buffer() && "Invalid streambuf in OFStream constructor");
+      assert(this->rdbuf()
+             && "Invalid basic_ostream buf in OFStream constructor");
+    }
+
+    explicit BasicAsmOFStream(const std::basic_string<charT, Traits> &name,
+                              std::ios_base::openmode mode) 
+        : BasicAsmOStream<charT, Traits>(&buf),
+            buf(name, mode) {
+      assert(this->buffer() && "Invalid streambuf in OFStream constructor");
+      assert(this->rdbuf()
+             && "Invalid basic_ostream buf in OFStream constructor");
+    }
+    
+    ~BasicAsmOFStream(void) {
+      close();
+    }
+
+    bool open(const std::basic_string<charT, Traits> &name) {
+      assert(this->buffer() && "Invalid streambuf in open1");
+      assert(this->rdbuf()
+             && "Invalid basic_ostream buf in open1");
+
+      buf.open(name.c_str(), std::ios_base::out | std::ios_base::trunc);
+
+      assert(this->buffer() && "Invalid streambuf in open2");
+      assert(this->rdbuf()
+             && "Invalid basic_ostream buf in open2");
+
+      assert(this->good() && "Not good");
+      assert((bool)(*this) && "Not true");
+
+      return(true);
+    }
+
+    bool close(void) {
+      buf.close();
+      return(true);
+    }
+
+    bool is_open(void) const {
+      return(buf.is_open());
+    }
+  };
+
+  typedef BasicAsmOFStream<char> AsmOFStream;
+  typedef BasicAsmOFStream<wchar_t> AsmWOFStream;
+
+  /// Column - An I/O manipulator to advance the output to a certain column
+  ///
+  class Column {
+  private:
+    int column;
+
+  public:
+    explicit Column(int c) 
+        : column(c) {}
+
+    template<typename OStream>
+    OStream &operator()(OStream &out) const {
+      // Make at least one space before the comment
+      out.buffer()->setColumn(column, 1);
+      return(out);
+    }
+  };
+
+  template<typename OStream>
+  OStream &operator<<(OStream &out, const Column &column)
+  {
+    return(column(out));
+  }
+
+  /// Comment - An I/O manipulator to output an end-of-line comment
+  ///
+  class Comment 
+      : public Column {
+  private:
+    static const int CommentColumn = 60;
+    std::string text;
+    const TargetAsmInfo &TAI;
+    
+  public:
+    Comment(const std::string &comment,
+            const TargetAsmInfo &tai) 
+        : Column(CommentColumn), text(comment), TAI(tai) {}
+
+    template<typename OStream>
+    OStream &operator()(OStream &out) const {
+      Column::operator()(out);
+      out << TAI.getCommentString() << " " << text;
+      return(out);
+    }
+  };
+
+  template<typename OStream>
+  OStream &operator<<(OStream &out, const Comment &comment)
+  {
+    return(comment(out));
+  }
+
+  /// raw_asm_ostream - A raw_ostream that writes to an AsmOStream
+  /// This exposes additional AsmOStream capability.
+  class raw_asm_ostream : public raw_ostream {
+    AsmOStream &OS;
+  public:
+    raw_asm_ostream(AsmOStream &O) : OS(O) {}
+    ~raw_asm_ostream();
+
+    AsmOStream &getStream(void) {
+      flush();
+      return OS;
+    }
+
+    raw_asm_ostream &operator<<(const Column &column) {
+      flush();
+      OS << column;
+      return *this;
+    }
+
+    raw_asm_ostream &operator<<(const Comment &comment) {
+      flush();
+      OS << comment;
+      return *this;
+    }
+
+    /// flush_impl - The is the piece of the class that is implemented by
+    /// subclasses.  This outputs the currently buffered data and resets the
+    /// buffer to empty.
+    virtual void flush_impl();
+  };
+
+  /// WARNING: Do NOT use these streams in the constructors of global
+  /// objects.  There is no mechanism to ensure they are initialized
+  /// before other global objects.
+  ///
+  extern raw_asm_ostream asmout;
+  extern raw_asm_ostream asmerr;
+}
+
+#endif

Added: llvm/trunk/lib/CodeGen/AsmStream.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmStream.cpp?rev=75156&view=auto

==============================================================================
--- llvm/trunk/lib/CodeGen/AsmStream.cpp (added)
+++ llvm/trunk/lib/CodeGen/AsmStream.cpp Thu Jul  9 13:27:23 2009
@@ -0,0 +1,47 @@
+//===-- llvm/CodeGen/AsmStream.cpp - AsmStream Framework --------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains instantiations of "standard" AsmOStreams.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/AsmStream.h"
+
+#include <unistd.h>
+
+namespace llvm {
+  AsmStreambuf asmoutbuf(STDOUT_FILENO);
+  AsmStreambuf asmerrbuf(STDERR_FILENO);
+
+  //===----------------------------------------------------------------------===//
+  //  raw_asm_ostream
+  //===----------------------------------------------------------------------===//
+
+  raw_asm_ostream::~raw_asm_ostream() {
+    flush();
+  }
+
+  /// flush_impl - The is the piece of the class that is implemented by
+  /// subclasses.  This outputs the currently buffered data and resets the
+  /// buffer to empty.
+  void raw_asm_ostream::flush_impl() {
+    if (OutBufCur-OutBufStart)
+      OS.write(OutBufStart, OutBufCur-OutBufStart);
+
+    HandleFlush();
+  }
+
+  namespace {
+    AsmOStream AsmOut(&asmoutbuf);
+    AsmOStream AsmErr(&asmerrbuf);
+  }
+
+  raw_asm_ostream asmout(AsmOut);
+  raw_asm_ostream asmerr(AsmErr);
+}





More information about the llvm-commits mailing list