X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fllc%2Fllc.cpp;h=959bdbe36cbec178841434e50e51f5070177db30;hb=1d29a6d6c7a7f6203065c003d3d2d002870e38a1;hp=5e352ec502e7316887f188e535477a4ba0d1a3ea;hpb=655fb5c817cfaa1bd0cc0e0613e3105c59d60dad;p=oota-llvm.git diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index 5e352ec502e..959bdbe36cb 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -1,230 +1,210 @@ -//===-- llc.cpp - Implement the LLVM Compiler -----------------------------===// +//===-- llc.cpp - Implement the LLVM Native Code Generator ----------------===// +// +// The LLVM Compiler Infrastructure // -// This is the llc compiler driver. +// 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 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/Scalar.h" -#include "llvm/Transforms/Utils/Linker.h" -#include "llvm/Assembly/PrintModulePass.h" -#include "llvm/Bytecode/WriteBytecodePass.h" -#include "llvm/Transforms/IPO.h" #include "llvm/Module.h" #include "llvm/PassManager.h" +#include "llvm/Pass.h" #include "Support/CommandLine.h" #include "Support/Signals.h" #include #include -using std::string; -using std::cerr; -static cl::opt +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 +static cl::opt OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename")); static cl::opt Force("f", cl::desc("Overwrite output files")); -static cl::opt -DumpAsm("d", cl::desc("Print bytecode before native code generation"), - cl::Hidden); - -static cl::opt -TraceLibPath("tracelibpath", cl::desc("Path to libinstr for trace code"), - cl::value_desc("directory"), cl::Hidden); +enum ArchName { noarch, X86, Sparc, PowerPC, CBackend }; -enum TraceLevel { - TraceOff, TraceFunctions, TraceBasicBlocks -}; - -static cl::opt -TraceValues("trace", cl::desc("Trace values through functions or basic blocks"), - cl::values( - clEnumValN(TraceOff , "off", "Disable trace code"), - clEnumValN(TraceFunctions , "function", "Trace each function"), - clEnumValN(TraceBasicBlocks, "basicblock", "Trace each basic block"), - 0)); +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; } return outputFilename; } -static void insertTraceCodeFor(Module &M) { - PassManager Passes; - - // Insert trace code in all functions in the module - switch (TraceValues) { - case TraceBasicBlocks: - Passes.add(createTraceValuesPassForBasicBlocks()); - break; - case TraceFunctions: - Passes.add(createTraceValuesPassForFunction()); - break; - default: - assert(0 && "Bad value for TraceValues!"); - abort(); - } - - // Eliminate duplication in constant pool - Passes.add(createConstantMergePass()); - - // Run passes to insert and clean up trace code... - Passes.run(M); - - std::string ErrorMessage; - - // Load the module that contains the runtime helper routines neccesary for - // pointer hashing and stuff... link this module into the program if possible - // - Module *TraceModule = ParseBytecodeFile(TraceLibPath+"libinstr.bc"); - - // Ok, the TraceLibPath didn't contain a valid module. Try to load the module - // from the current LLVM-GCC install directory. This is kindof a hack, but - // allows people to not HAVE to have built the library. - // - if (TraceModule == 0) - TraceModule = ParseBytecodeFile("/home/vadve/lattner/cvs/gcc_install/lib/" - "gcc-lib/llvm/3.1/libinstr.bc"); - - // If we still didn't get it, cancel trying to link it in... - if (TraceModule == 0) { - cerr << "Warning, could not load trace routines to link into program!\n"; - } else { - - // Link in the trace routines... if the link fails, don't panic, because the - // compile should still succeed, just the native linker will probably fail. - // - std::auto_ptr TraceRoutines(TraceModule); - if (LinkModules(&M, TraceRoutines.get(), &ErrorMessage)) - cerr << "Warning: Error linking in trace routines: " - << ErrorMessage << "\n"; - } - - - // Write out the module with tracing code just before code generation - if (InputFilename != "-") { - string TraceFilename = GetFileNameRoot(InputFilename) + ".trace.bc"; - - std::ofstream Out(TraceFilename.c_str()); - if (!Out.good()) { - cerr << "Error opening '" << TraceFilename - << "'!: Skipping output of trace code as bytecode\n"; - } else { - cerr << "Emitting trace code to '" << TraceFilename - << "' for comparison...\n"; - WriteBytecodeToFile(&M, Out); - } - } - -} - - -//===---------------------------------------------------------------------===// -// 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 << argv[0] << ": bytecode didn't read correctly.\n"; + std::cerr << argv[0] << ": bytecode didn't read correctly.\n"; return 1; } - - if (TraceValues != TraceOff) // If tracing enabled... - insertTraceCodeFor(*M.get()); // Hack up module before using passmanager... + 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; - // Decompose multi-dimensional refs into a sequence of 1D refs - Passes.add(createDecomposeMultiDimRefsPass()); - - // 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 PrintFunctionPass("Code after xformations: \n", &cerr)); - - // Strip all of the symbols from the bytecode so that it will be smaller... - Passes.add(createSymbolStrippingPass()); + 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 << 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 (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 unlink'd from the disk if we get a - // SIGINT - RemoveFileOnSignal(OutputFilename); + // Make sure that the Out file gets unlinked from the disk if we get a + // SIGINT + RemoveFileOnSignal(OutputFilename); + } else { + Out = &std::cout; + } } 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 << argv[0] << ": 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 << argv[0] << ": error opening " << OutputFilename << "!\n"; + std::cerr << argv[0] << ": error opening " << OutputFilename << "!\n"; delete Out; return 1; } - // Make sure that the Out file gets unlink'd from the disk if we get a + + // 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;