summaryrefslogtreecommitdiff
path: root/tools/llvm-dis/llvm-dis.cpp
blob: 1351f878b3f841b9217749c4fe7b2993c239c791 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//===----------------------------------------------------------------------===//
// LLVM 'DIS' UTILITY 
//
// This utility may be invoked in the following manner:
//  dis [options]      - Read LLVM bytecode from stdin, write assembly to stdout
//  dis [options] x.bc - Read LLVM bytecode from the x.bc file, write assembly
//                       to the x.ll file.
//  Options:
//      --help   - Output information about command line switches
//       -dfo    - Print basic blocks in depth first order
//       -rdfo   - Print basic blocks in reverse depth first order
//       -po     - Print basic blocks in post order
//       -rpo    - Print basic blocks in reverse post order
// 
//       -c      - Print C code
//
// TODO: add -vcg which prints VCG compatible output.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Support/CFG.h"
#include "Support/DepthFirstIterator.h"
#include "Support/PostOrderIterator.h"
#include "Support/CommandLine.h"
#include "Support/Signals.h"
#include "llvm/Assembly/CWriter.h"
#include <fstream>
#include <iostream>
using std::cerr;

// OutputMode - The different orderings to print basic blocks in...
enum OutputMode {
  Default = 0,           // Function Order (list order)
  dfo,                   // Depth First ordering
  rdfo,                  // Reverse Depth First ordering
  po,                    // Post Order
  rpo,                   // Reverse Post Order

  c,                     // Generate C code
};

cl::String InputFilename ("", "Load <arg> file, print as assembly", 0, "-");
cl::String OutputFilename("o", "Override output filename", cl::NoFlags, "");
cl::Flag   Force         ("f", "Overwrite output files", cl::NoFlags, false);
cl::EnumFlags<enum OutputMode> WriteMode(cl::NoFlags,
  clEnumVal(Default, "Write basic blocks in bytecode order"),
  clEnumVal(dfo    , "Write basic blocks in depth first order"),
  clEnumVal(rdfo   , "Write basic blocks in reverse DFO"),
  clEnumVal(po     , "Write basic blocks in postorder"),
  clEnumVal(rpo    , "Write basic blocks in reverse postorder"),

  clEnumVal(c      , "Write corresponding C code"),
 0);

int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv, " llvm .bc -> .ll disassembler\n");
  std::ostream *Out = &std::cout;  // Default to printing to stdout...

  Module *M = ParseBytecodeFile(InputFilename);
  if (M == 0) {
    cerr << "bytecode didn't read correctly.\n";
    return 1;
  }
  
  if (OutputFilename != "") {   // Specified an output filename?
    if (!Force && std::ifstream(OutputFilename.c_str())) {
      // If force is not specified, make sure not to overwrite a file!
      cerr << "Error opening '" << OutputFilename
           << "': File exists! Sending to standard output.\n";
    } else {
      Out = new std::ofstream(OutputFilename.c_str());
    }
  } else {
    if (InputFilename == "-") {
      OutputFilename = "-";
    } else {
      std::string IFN = InputFilename;
      int Len = IFN.length();
      if (IFN[Len-3] == '.' && IFN[Len-2] == 'b' && IFN[Len-1] == 'c') {
	// Source ends in .bc
	OutputFilename = std::string(IFN.begin(), IFN.end()-3);
      } else {
	OutputFilename = IFN;   // Append a .ll to it
      }
      if (WriteMode == c)
	OutputFilename += ".c";
      else
	OutputFilename += ".ll";

      if (!Force && std::ifstream(OutputFilename.c_str())) {
        // If force is not specified, make sure not to overwrite a file!
        cerr << "Error opening '" << OutputFilename
             << "': File exists! Sending to standard output.\n";
      } else {
        Out = new std::ofstream(OutputFilename.c_str());

        // Make sure that the Out file gets unlink'd from the disk if we get a
        // SIGINT
        RemoveFileOnSignal(OutputFilename);
      }
    }
  }

  if (!Out->good()) {
    cerr << "Error opening " << OutputFilename
	 << ": sending to stdout instead!\n";
    Out = &std::cout;
  }

  // All that dis does is write the assembly or C out to a file... which is 
  // exactly what the writer or cwriter library is supposed to do...
  if (WriteMode == Default) {
    (*Out) << M;           // Print out in list order
  } else if (WriteMode == c) {
    WriteToC(M, *Out);
  } else {
    // TODO: This does not print anything other than the basic blocks in the
    // functions... more should definately be printed.  It should be valid
    // output consumable by the assembler.
    //
    for (Module::iterator I = M->begin(), End = M->end(); I != End; ++I) {
      Function *F = *I;
      (*Out) << "-------------- Method: " << F->getName() << " -------------\n";

      switch (WriteMode) {
      case dfo:                   // Depth First ordering
	copy(df_begin(F), df_end(F),
	     std::ostream_iterator<BasicBlock*>(*Out, "\n"));
	break;
      case rdfo:            // Reverse Depth First ordering
	copy(df_begin(F, true), df_end(F),
	     std::ostream_iterator<BasicBlock*>(*Out, "\n"));
	break;
      case po:                    // Post Order
	copy(po_begin(F), po_end(F),
	     std::ostream_iterator<BasicBlock*>(*Out, "\n"));
	break;
      case rpo: {           // Reverse Post Order
#if 0  // FIXME, GCC 3.0.4 bug
	ReversePostOrderTraversal<Function*> RPOT(F);
	copy(RPOT.begin(), RPOT.end(),
	     std::ostream_iterator<BasicBlock*>(*Out, "\n"));
#endif
	break;
      }
      default:
	abort();
	break;
      }
    }
  }
  delete M;

  if (Out != &std::cout) delete Out;
  return 0;
}