X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fllc%2Fllc.cpp;h=959bdbe36cbec178841434e50e51f5070177db30;hb=1d29a6d6c7a7f6203065c003d3d2d002870e38a1;hp=140151b69f658f156187afbc4eebd54c7038c7f9;hpb=d32e70a09f04abd2b9e3de864871f3218589b856;p=oota-llvm.git diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index 140151b69f6..959bdbe36cb 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -1,51 +1,63 @@ -//===-- llc.cpp - Implement the LLVM Compiler -----------------------------===// +//===-- llc.cpp - Implement the LLVM Native Code Generator ----------------===// +// +// 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 is the llc compiler driver. +// This is the llc code generator. // //===----------------------------------------------------------------------===// #include "llvm/Bytecode/Reader.h" -#include "llvm/Target/Sparc.h" +#include "llvm/Target/TargetMachineImpls.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Transforms/Instrumentation/TraceValues.h" -#include "llvm/Transforms/ChangeAllocations.h" -#include "llvm/Transforms/HoistPHIConstants.h" -#include "llvm/Transforms/Scalar/DecomposeMultiDimRefs.h" -#include "llvm/Assembly/PrintModulePass.h" -#include "llvm/Bytecode/WriteBytecodePass.h" -#include "llvm/Transforms/ConstantMerge.h" +#include "llvm/Transforms/Scalar.h" #include "llvm/Module.h" -#include "llvm/Method.h" #include "llvm/PassManager.h" +#include "llvm/Pass.h" #include "Support/CommandLine.h" +#include "Support/Signals.h" #include -#include #include -using std::string; -static cl::String InputFilename ("", "Input filename", cl::NoFlags, "-"); -static cl::String OutputFilename("o", "Output filename", cl::NoFlags, ""); -static cl::Flag Force ("f", "Overwrite output files"); -static cl::Flag DumpAsm ("d", "Print bytecode before native code generation", cl::Hidden); +using namespace llvm; + +// General options for llc. Other pass-specific options are specified +// within the corresponding llc passes, and target-specific options +// and back-end code generation options are specified with the target machine. +// +static cl::opt +InputFilename(cl::Positional, cl::desc(""), cl::init("-")); + +static cl::opt +OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename")); -enum TraceLevel { - TraceOff, TraceMethods, TraceBasicBlocks -}; +static cl::opt Force("f", cl::desc("Overwrite output files")); -static cl::Enum TraceValues("trace", cl::NoFlags, - "Trace values through methods or basic blocks", - clEnumValN(TraceOff , "off", "Disable trace code"), - clEnumValN(TraceMethods , "method", "Trace each method"), - clEnumValN(TraceBasicBlocks, "basicblock", "Trace each basic block"), 0); +enum ArchName { noarch, X86, Sparc, PowerPC, CBackend }; +static cl::opt +Arch("march", cl::desc("Architecture to generate assembly for:"), cl::Prefix, + cl::values(clEnumValN(X86, "x86", " IA-32 (Pentium and above)"), + clEnumValN(Sparc, "sparc", " SPARC V9"), + clEnumValN(PowerPC, "powerpc", " PowerPC"), + clEnumValN(CBackend, "c", " C backend"), + 0), + cl::init(noarch)); // GetFileNameRoot - Helper function to get the basename of a filename... -static inline string GetFileNameRoot(const string &InputFilename) { - string IFN = InputFilename; - string outputFilename; +static inline std::string +GetFileNameRoot(const std::string &InputFilename) +{ + std::string IFN = InputFilename; + std::string outputFilename; int Len = IFN.length(); - if (IFN[Len-3] == '.' && IFN[Len-2] == 'b' && IFN[Len-1] == 'c') { - outputFilename = string(IFN.begin(), IFN.end()-3); // s/.bc/.s/ + if ((Len > 2) && + IFN[Len-3] == '.' && IFN[Len-2] == 'b' && IFN[Len-1] == 'c') { + outputFilename = std::string(IFN.begin(), IFN.end()-3); // s/.bc/.s/ } else { outputFilename = IFN; } @@ -53,123 +65,146 @@ static inline string GetFileNameRoot(const string &InputFilename) { } -//===---------------------------------------------------------------------===// -// Function main() -// -// Entry point for the llc compiler. -//===---------------------------------------------------------------------===// - +// main - Entry point for the llc compiler. +// int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, " llvm system compiler\n"); - // Allocate a target... in the future this will be controllable on the - // command line. - std::auto_ptr target(allocateSparcTargetMachine()); - assert(target.get() && "Could not allocate target machine!"); - - TargetMachine &Target = *target.get(); - // Load the module to be compiled... std::auto_ptr M(ParseBytecodeFile(InputFilename)); if (M.get() == 0) { - cerr << "bytecode didn't read correctly.\n"; + std::cerr << argv[0] << ": bytecode didn't read correctly.\n"; return 1; } + Module &mod = *M.get(); + + // Allocate target machine. First, check whether the user has + // explicitly specified an architecture to compile for. + TargetMachine* (*TargetMachineAllocator)(const Module&, + IntrinsicLowering *) = 0; + switch (Arch) { + case CBackend: + TargetMachineAllocator = allocateCTargetMachine; + break; + case X86: + TargetMachineAllocator = allocateX86TargetMachine; + break; + case Sparc: + TargetMachineAllocator = allocateSparcTargetMachine; + break; + case PowerPC: + TargetMachineAllocator = allocatePowerPCTargetMachine; + break; + default: + // Decide what the default target machine should be, by looking at + // the module. This heuristic (ILP32, LE -> IA32; LP64, BE -> + // SPARCV9) is kind of gross, but it will work until we have more + // sophisticated target information to work from. + if (mod.getEndianness() == Module::LittleEndian && + mod.getPointerSize() == Module::Pointer32) { + TargetMachineAllocator = allocateX86TargetMachine; + } else if (mod.getEndianness() == Module::BigEndian && + mod.getPointerSize() == Module::Pointer32) { + TargetMachineAllocator = allocatePowerPCTargetMachine; + } else if (mod.getEndianness() == Module::BigEndian && + mod.getPointerSize() == Module::Pointer64) { + TargetMachineAllocator = allocateSparcTargetMachine; + } else { + // If the module is target independent, favor a target which matches the + // current build system. +#if defined(i386) || defined(__i386__) || defined(__x86__) + TargetMachineAllocator = allocateX86TargetMachine; +#elif defined(sparc) || defined(__sparc__) || defined(__sparcv9) + TargetMachineAllocator = allocateSparcTargetMachine; +#elif defined(__POWERPC__) || defined(__ppc__) || defined(__APPLE__) + TargetMachineAllocator = allocatePowerPCTargetMachine; +#else + std::cerr << argv[0] << ": module does not specify a target to use. " + << "You must use the -march option. If no native target is " + << "available, use -march=c to emit C code.\n"; + return 1; +#endif + } + break; + } + std::auto_ptr target(TargetMachineAllocator(mod, 0)); + assert(target.get() && "Could not allocate target machine!"); + TargetMachine &Target = *target.get(); + const TargetData &TD = Target.getTargetData(); // Build up all of the passes that we want to do to the module... PassManager Passes; - // Hoist constants out of PHI nodes into predecessor BB's - Passes.add(createHoistPHIConstantsPass()); - - if (TraceValues != TraceOff) { // If tracing enabled... - // Insert trace code in all methods in the module - if (TraceValues == TraceBasicBlocks) - Passes.add(createTraceValuesPassForBasicBlocks()); - else if (TraceValues == TraceMethods) - Passes.add(createTraceValuesPassForMethod()); - else - assert(0 && "Bad value for TraceValues!"); - - // Eliminate duplication in constant pool - Passes.add(createDynamicConstantMergePass()); - } - - // Decompose multi-dimensional refs into a sequence of 1D refs - Passes.add(createDecomposeMultiDimRefsPass()); - - // Write out the module with tracing code just before code generation - if (TraceValues != TraceOff) { // If tracing enabled... - assert(InputFilename != "-" && - "files on stdin not supported with tracing"); - string traceFileName = GetFileNameRoot(InputFilename) + ".trace.bc"; - - 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!\n" - << "Use -f command line argument to force output\n"; - return 1; - } - - std::ostream *os = new std::ofstream(traceFileName.c_str()); - if (!os->good()) { - cerr << "Error opening " << traceFileName - << "! SKIPPING OUTPUT OF TRACE CODE\n"; - delete os; - return 1; - } - - Passes.add(new WriteBytecodePass(os, true)); - } - - // Replace malloc and free instructions with library calls. - // Do this after tracing until lli implements these lib calls. - // For now, it will emulate malloc and free internally. - Passes.add(createLowerAllocationsPass(Target.DataLayout)); - - // If LLVM dumping after transformations is requested, add it to the pipeline - if (DumpAsm) - Passes.add(new PrintMethodPass("Code after xformations: \n", &cerr)); + Passes.add(new TargetData("llc", TD.isLittleEndian(), TD.getPointerSize(), + TD.getPointerAlignment(), TD.getDoubleAlignment())); // Figure out where we are going to send the output... std::ostream *Out = 0; - 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!\n" - << "Use -f command line argument to force output\n"; - return 1; + if (OutputFilename != "") { + 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! + std::cerr << argv[0] << ": error opening '" << OutputFilename + << "': file exists!\n" + << "Use -f command line argument to force output\n"; + return 1; + } + Out = new std::ofstream(OutputFilename.c_str()); + + // Make sure that the Out file gets unlinked from the disk if we get a + // SIGINT + RemoveFileOnSignal(OutputFilename); + } else { + Out = &std::cout; } - Out = new std::ofstream(OutputFilename.c_str()); } else { if (InputFilename == "-") { OutputFilename = "-"; Out = &std::cout; } else { - string OutputFilename = GetFileNameRoot(InputFilename); - OutputFilename += ".s"; + OutputFilename = GetFileNameRoot(InputFilename); + if (Arch != CBackend) + OutputFilename += ".s"; + else + OutputFilename += ".cbe.c"; + 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!\n" - << "Use -f command line argument to force output\n"; + std::cerr << argv[0] << ": error opening '" << OutputFilename + << "': file exists!\n" + << "Use -f command line argument to force output\n"; return 1; } - + Out = new std::ofstream(OutputFilename.c_str()); if (!Out->good()) { - cerr << "Error opening " << OutputFilename << "!\n"; + std::cerr << argv[0] << ": error opening " << OutputFilename << "!\n"; delete Out; return 1; } + + // Make sure that the Out file gets unlinked from the disk if we get a + // SIGINT + RemoveFileOnSignal(OutputFilename); } } - - Target.addPassesToEmitAssembly(Passes, *Out); - - // Run our queue of passes all at once now, efficiently. - Passes.run(M.get()); + // Ask the target to add backend passes as necessary + if (Target.addPassesToEmitAssembly(Passes, *Out)) { + std::cerr << argv[0] << ": target '" << Target.getName() + << "' does not support static compilation!\n"; + if (Out != &std::cout) delete Out; + // And the Out file is empty and useless, so remove it now. + std::remove(OutputFilename.c_str()); + return 1; + } else { + // Run our queue of passes all at once now, efficiently. + Passes.run(*M.get()); + } + + // Delete the ostream if it's not a stdout stream if (Out != &std::cout) delete Out; return 0;