llc.cpp revision c8896771951d0cc769b6b40b27bcb420685cf718
1//===-- llc.cpp - Implement the LLVM Compiler -----------------------------===//
2//
3// This is the llc compiler driver.
4//
5//===----------------------------------------------------------------------===//
6
7#include "llvm/Bytecode/Reader.h"
8#include "llvm/Target/Sparc.h"
9#include "llvm/Target/TargetMachine.h"
10#include "llvm/Transforms/Instrumentation/TraceValues.h"
11#include "llvm/Transforms/ChangeAllocations.h"
12#include "llvm/Transforms/HoistPHIConstants.h"
13#include "llvm/Assembly/PrintModulePass.h"
14#include "llvm/Bytecode/WriteBytecodePass.h"
15#include "llvm/Transforms/ConstantMerge.h"
16#include "llvm/Module.h"
17#include "llvm/Method.h"
18#include "llvm/PassManager.h"
19#include "Support/CommandLine.h"
20#include <memory>
21#include <string>
22#include <fstream>
23using std::string;
24
25cl::String InputFilename ("", "Input filename", cl::NoFlags, "-");
26cl::String OutputFilename("o", "Output filename", cl::NoFlags, "");
27cl::Flag   Force         ("f", "Overwrite output files");
28cl::Flag   DumpAsm       ("d", "Print bytecode before native code generation",
29                          cl::Hidden);
30cl::Flag   DoNotEmitAssembly("noasm", "Do not emit assembly code", cl::Hidden);
31cl::Flag   TraceBBValues ("trace",
32                          "Trace values at basic block and method exits");
33cl::Flag   TraceMethodValues("tracem", "Trace values only at method exits");
34
35
36// GetFileNameRoot - Helper function to get the basename of a filename...
37static inline string GetFileNameRoot(const string &InputFilename) {
38  string IFN = InputFilename;
39  string outputFilename;
40  int Len = IFN.length();
41  if (IFN[Len-3] == '.' && IFN[Len-2] == 'b' && IFN[Len-1] == 'c') {
42    outputFilename = string(IFN.begin(), IFN.end()-3); // s/.bc/.s/
43  } else {
44    outputFilename = IFN;
45  }
46  return outputFilename;
47}
48
49
50//===---------------------------------------------------------------------===//
51// GenerateCodeForTarget Pass
52//
53// Native code generation for a specified target.
54//===---------------------------------------------------------------------===//
55
56class GenerateCodeForTarget : public MethodPass {
57  TargetMachine &Target;
58public:
59  inline GenerateCodeForTarget(TargetMachine &T) : Target(T) {}
60
61  // runOnMethod - This method does the actual work of generating code for
62  // the specified method.
63  //
64  bool runOnMethod(Method *M) {
65    if (Target.compileMethod(M))
66      cerr << "Error compiling " << InputFilename << "!\n";
67
68    return true;
69  }
70};
71
72
73//===---------------------------------------------------------------------===//
74// EmitMethodAssembly Pass
75//
76// Write assembly code for each method to specified output stream
77//===---------------------------------------------------------------------===//
78
79class EmitMethodAssembly : public MethodPass {
80  TargetMachine &Target;   // Target to compile for
81  std::ostream *Out;             // Stream to print on
82public:
83  inline EmitMethodAssembly(TargetMachine &T, std::ostream *O)
84    : Target(T), Out(O) {}
85
86  virtual bool runOnMethod(Method *M) {
87    Target.emitAssembly(M, *Out);
88    Target.freeCompiledMethod(M);  // Release memory for the method
89    return false;
90  }
91};
92
93
94//===---------------------------------------------------------------------===//
95// EmitGlobalsAssembly Pass
96//
97// Write assembly code for global values to specified output stream
98//===---------------------------------------------------------------------===//
99
100class EmitGlobalsAssembly : public Pass {
101  const TargetMachine &Target;   // Target to compile for
102  std::ostream *Out;             // Stream to print on
103  bool DeleteStream;             // Delete stream in dtor?
104public:
105  inline EmitGlobalsAssembly(const TargetMachine &T, std::ostream *O, bool D)
106    : Target(T), Out(O), DeleteStream(D) {}
107
108  virtual bool run(Module *M) {
109    Target.emitAssembly(M, *Out);
110    if (DeleteStream) delete Out;
111    return false;
112  }
113};
114
115
116
117//===---------------------------------------------------------------------===//
118// Function main()
119//
120// Entry point for the llc compiler.
121//===---------------------------------------------------------------------===//
122
123int main(int argc, char **argv) {
124  cl::ParseCommandLineOptions(argc, argv, " llvm system compiler\n");
125
126  // Allocate a target... in the future this will be controllable on the
127  // command line.
128  std::auto_ptr<TargetMachine> target(allocateSparcTargetMachine());
129  assert(target.get() && "Could not allocate target machine!");
130
131  TargetMachine &Target = *target.get();
132
133  // Load the module to be compiled...
134  std::auto_ptr<Module> M(ParseBytecodeFile(InputFilename));
135  if (M.get() == 0) {
136    cerr << "bytecode didn't read correctly.\n";
137    return 1;
138  }
139
140  // Build up all of the passes that we want to do to the module...
141  PassManager Passes;
142
143  // Hoist constants out of PHI nodes into predecessor BB's
144  Passes.add(new HoistPHIConstants());
145
146  if (TraceBBValues || TraceMethodValues) {   // If tracing enabled...
147    // Insert trace code in all methods in the module
148    Passes.add(new InsertTraceCode(TraceBBValues,
149                                   TraceBBValues ||TraceMethodValues));
150
151    // Eliminate duplication in constant pool
152    Passes.add(new DynamicConstantMerge());
153
154    // Then write out the module with tracing code before code generation
155    assert(InputFilename != "-" &&
156           "files on stdin not supported with tracing");
157    string traceFileName = GetFileNameRoot(InputFilename) + ".trace.bc";
158
159    if (!Force && std::ifstream(OutputFilename.c_str())) {
160      // If force is not specified, make sure not to overwrite a file!
161      cerr << "Error opening '" << OutputFilename << "': File exists!\n"
162           << "Use -f command line argument to force output\n";
163      return 1;
164    }
165
166    std::ostream *os = new std::ofstream(traceFileName.c_str());
167    if (!os->good()) {
168      cerr << "Error opening " << traceFileName
169           << "! SKIPPING OUTPUT OF TRACE CODE\n";
170      delete os;
171      return 1;
172    }
173
174    Passes.add(new WriteBytecodePass(os, true));
175  }
176
177  // Replace malloc and free instructions with library calls.
178  // Do this after tracing until lli implements these lib calls.
179  // For now, it will emulate malloc and free internally.
180  Passes.add(new LowerAllocations(Target.DataLayout));
181
182  // If LLVM dumping after transformations is requested, add it to the pipeline
183  if (DumpAsm)
184    Passes.add(new PrintMethodPass("Code after xformations: \n",&cerr));
185
186  // Generate Target code...
187  Passes.add(new GenerateCodeForTarget(Target));
188
189  if (!DoNotEmitAssembly) {                // If asm output is enabled...
190    // Figure out where we are going to send the output...
191    std::ostream *Out = 0;
192    if (OutputFilename != "") {   // Specified an output filename?
193      if (!Force && std::ifstream(OutputFilename.c_str())) {
194        // If force is not specified, make sure not to overwrite a file!
195        cerr << "Error opening '" << OutputFilename << "': File exists!\n"
196             << "Use -f command line argument to force output\n";
197        return 1;
198      }
199      Out = new std::ofstream(OutputFilename.c_str());
200    } else {
201      if (InputFilename == "-") {
202        OutputFilename = "-";
203        Out = &std::cout;
204      } else {
205        string OutputFilename = GetFileNameRoot(InputFilename);
206        OutputFilename += ".s";
207
208        if (!Force && std::ifstream(OutputFilename.c_str())) {
209          // If force is not specified, make sure not to overwrite a file!
210          cerr << "Error opening '" << OutputFilename << "': File exists!\n"
211               << "Use -f command line argument to force output\n";
212          return 1;
213        }
214
215        Out = new std::ofstream(OutputFilename.c_str());
216        if (!Out->good()) {
217          cerr << "Error opening " << OutputFilename << "!\n";
218          delete Out;
219          return 1;
220        }
221      }
222    }
223
224    // Output assembly language to the .s file.  Assembly emission is split into
225    // two parts: Method output and Global value output.  This is because method
226    // output is pipelined with all of the rest of code generation stuff,
227    // allowing machine code representations for methods to be free'd after the
228    // method has been emitted.
229    //
230    Passes.add(new EmitMethodAssembly(Target, Out));  // for methods
231
232    // For global values...
233    Passes.add(new EmitGlobalsAssembly(Target, Out, Out != &std::cout));
234  }
235
236  // Run our queue of passes all at once now, efficiently.
237  Passes.run(M.get());
238
239  return 0;
240}
241
242
243