X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fllc%2Fllc.cpp;h=959bdbe36cbec178841434e50e51f5070177db30;hb=1d29a6d6c7a7f6203065c003d3d2d002870e38a1;hp=a3312967d64942c85e79c5410aba57d9c646d737;hpb=1e78f36127fb0e405d2cf893e2ce3381300a667b;p=oota-llvm.git diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index a3312967d64..959bdbe36cb 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -1,66 +1,211 @@ -// $Id$ -//*************************************************************************** -// File: -// llc.cpp +//===-- llc.cpp - Implement the LLVM Native Code Generator ----------------===// // -// Purpose: -// Driver for llc compiler. +// 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. // -// History: -// 7/15/01 - Vikram Adve - Created -// -//**************************************************************************/ +//===----------------------------------------------------------------------===// +// +// This is the llc code generator. +// +//===----------------------------------------------------------------------===// -#include "llvm/Module.h" -#include "llvm/Method.h" #include "llvm/Bytecode/Reader.h" -#include "llvm/CodeGen/InstrSelection.h" -#include "llvm/CodeGen/Sparc.h" -#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetMachineImpls.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Module.h" +#include "llvm/PassManager.h" +#include "llvm/Pass.h" +#include "Support/CommandLine.h" +#include "Support/Signals.h" +#include +#include -cl::String InputFilename ("", "Input filename", cl::NoFlags, "-"); -cl::String OutputFilename("o", "Output filename", cl::NoFlags, ""); +using namespace llvm; -static bool CompileModule(Module *M, TargetMachine &Target) { - bool failed = false; - - for (Module::const_iterator MI = M->begin(), ME = M->end(); MI != ME; ++MI) { - Method * method = *MI; - - if (SelectInstructionsForMethod(method, Target)) { - failed = true; - cerr << "Instruction selection failed for method " - << method->getName() << "\n\n"; - } +// 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")); + +static cl::opt Force("f", cl::desc("Overwrite output files")); + +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 +GetFileNameRoot(const std::string &InputFilename) +{ + std::string IFN = InputFilename; + std::string outputFilename; + int Len = IFN.length(); + 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 failed; + return outputFilename; } -//--------------------------------------------------------------------------- -// Function main() -// -// Entry point for the driver. -//--------------------------------------------------------------------------- - -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"); - UltraSparc Target; - - Module *module = ParseBytecodeFile(InputFilename); - if (module == 0) { - cerr << "bytecode didn't read correctly.\n"; + + // 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"; return 1; } - - if (CompileModule(module, Target)) { - cerr << "Error compiling " << InputFilename << "!\n"; - delete module; + 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; + + 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 != "") { + 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 + << "': 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 unlinked from the disk if we get a + // SIGINT + RemoveFileOnSignal(OutputFilename); + } + } + + // 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()); } - - // Clean up and exit - delete module; + + // Delete the ostream if it's not a stdout stream + if (Out != &std::cout) delete Out; + return 0; }