X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fllc%2Fllc.cpp;h=959bdbe36cbec178841434e50e51f5070177db30;hb=1d29a6d6c7a7f6203065c003d3d2d002870e38a1;hp=29449f5cfe3ebf79f58f7ddbd9616227e5e697e7;hpb=68492725a08ca3b356f24b90cdfc57a247abbeb3;p=oota-llvm.git diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index 29449f5cfe3..959bdbe36cb 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -1,41 +1,29 @@ -//===-- 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/TargetMachineImpls.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Transforms/Instrumentation.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 "llvm/Support/PassNameParser.h" #include "Support/CommandLine.h" #include "Support/Signals.h" #include #include -//------------------------------------------------------------------------------ -// Option declarations for LLC. -//------------------------------------------------------------------------------ - -// Make all registered optimization passes available to llc. These passes -// will all be run before the simplification and lowering steps used by the -// back-end code generator, and will be run in the order specified on the -// command line. The OptimizationList is automatically populated with -// registered Passes by the PassNameParser. -// -static cl::list > -OptimizationList(cl::desc("Optimizations available:")); - +using namespace llvm; // General options for llc. Other pass-specific options are specified // within the corresponding llc passes, and target-specific options @@ -49,23 +37,16 @@ OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename")); static cl::opt Force("f", cl::desc("Overwrite output files")); -static cl::opt -DisableStrip("disable-strip", - cl::desc("Do not strip the LLVM bytecode included in the executable")); - -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); - - -// flags set from -tracem and -trace options to control tracing -static bool TraceFunctions = false; -static bool TraceBasicBlocks = false; +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 std::string @@ -74,7 +55,8 @@ 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') { + 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; @@ -82,108 +64,73 @@ GetFileNameRoot(const std::string &InputFilename) return outputFilename; } -static bool -insertTraceCodeFor(Module &M) -{ - PassManager Passes; - - // Insert trace code in all functions in the module - if (TraceBasicBlocks) - Passes.add(createTraceValuesPassForBasicBlocks()); - else if (TraceFunctions) - Passes.add(createTraceValuesPassForFunction()); - else - return false; - - // 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"); - - // Check if the TraceLibPath contains a valid module. If not, 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) - std::cerr <<"WARNING: couldn't load trace routines to link into program!\n"; - else - { - // Link in the trace routines... if this fails, don't panic, because the - // compile should still succeed, but the native linker will probably fail. - // - std::auto_ptr TraceRoutines(TraceModule); - if (LinkModules(&M, TraceRoutines.get(), &ErrorMessage)) - std::cerr << "WARNING: Error linking in trace routines: " - << ErrorMessage << "\n"; - } - - // Write out the module with tracing code just before code generation - assert (InputFilename != "-" - && "Cannot write out traced bytecode when reading input from stdin"); - std::string TraceFilename = GetFileNameRoot(InputFilename) + ".trace.bc"; - - std::ofstream Out(TraceFilename.c_str()); - if (!Out.good()) - std::cerr << "Error opening '" << TraceFilename - << "'!: Skipping output of trace code as bytecode\n"; - else - { - std::cerr << "Emitting trace code to '" << TraceFilename - << "' for comparison...\n"; - WriteBytecodeToFile(&M, Out); - } - - return true; -} - -// Making tracing a module pass so the entire module with tracing -// can be written out before continuing. -struct InsertTracingCodePass: public Pass { - virtual bool run(Module &M) { - return insertTraceCodeFor(M); - } -}; - -//===---------------------------------------------------------------------===// -// Function main() -// -// Entry point for the llc compiler. -//===---------------------------------------------------------------------===// - -int -main(int argc, char **argv) -{ +// 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(); - const TargetData &TD = Target.getTargetData(); - // Load the module to be compiled... std::auto_ptr M(ParseBytecodeFile(InputFilename)); - if (M.get() == 0) - { - std::cerr << argv[0] << ": bytecode didn't read correctly.\n"; + if (M.get() == 0) { + 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; @@ -191,53 +138,38 @@ main(int argc, char **argv) Passes.add(new TargetData("llc", TD.isLittleEndian(), TD.getPointerSize(), TD.getPointerAlignment(), TD.getDoubleAlignment())); - // Create a new optimization pass for each one specified on the command line - // Deal specially with tracing passes, which must be run differently than opt. - // - for (unsigned i = 0; i < OptimizationList.size(); ++i) - { - const PassInfo *Opt = OptimizationList[i]; - - if (std::string(Opt->getPassArgument()) == "trace") - TraceFunctions = !(TraceBasicBlocks = true); - else if (std::string(Opt->getPassArgument()) == "tracem") - TraceFunctions = !(TraceBasicBlocks = false); - else - { // handle other passes as normal optimization passes - if (Opt->getNormalCtor()) - Passes.add(Opt->getNormalCtor()()); - else if (Opt->getTargetCtor()) - Passes.add(Opt->getTargetCtor()(Target)); - else - std::cerr << argv[0] << ": cannot create pass: " - << Opt->getPassName() << "\n"; - } - } - - // Run tracing passes after other optimization passes and before llc passes. - if (TraceFunctions || TraceBasicBlocks) - Passes.add(new InsertTracingCodePass); - - // 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()); - - // If LLVM dumping after transformations is requested, add it to the pipeline - if (DumpAsm) - Passes.add(new PrintFunctionPass("Code after xformations: \n", &std::cerr)); - - // Strip all of the symbols from the bytecode so that it will be smaller... - if (!DisableStrip) - Passes.add(createSymbolStrippingPass()); - // Figure out where we are going to send the output... std::ostream *Out = 0; - if (OutputFilename != "") - { // Specified an output filename? + 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; + } + } else { + if (InputFilename == "-") { + OutputFilename = "-"; + Out = &std::cout; + } else { + 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! std::cerr << argv[0] << ": error opening '" << OutputFilename @@ -245,52 +177,28 @@ main(int argc, char **argv) << "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 + if (!Out->good()) { + 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); } - else - { - if (InputFilename == "-") - { - OutputFilename = "-"; - Out = &std::cout; - } - else - { - std::string OutputFilename = GetFileNameRoot(InputFilename); - OutputFilename += ".s"; - - 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()); - if (!Out->good()) - { - 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 - // SIGINT - RemoveFileOnSignal(OutputFilename); - } - } + } - // Ask the target to add backend passes as neccesary + // 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"; + << "' 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());