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