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