X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fllc%2Fllc.cpp;h=959bdbe36cbec178841434e50e51f5070177db30;hb=1d29a6d6c7a7f6203065c003d3d2d002870e38a1;hp=b769cb5cfd48988f10e9661bf72a83af273a8c57;hpb=2f64f9f264d30dd0ac4880eb16ba9eeac538e94c;p=oota-llvm.git diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index b769cb5cfd4..959bdbe36cb 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -1,345 +1,211 @@ -//===-- 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/Optimizations/Normalize.h" -#include "llvm/Target/Sparc.h" +#include "llvm/Target/TargetMachineImpls.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Transforms/Instrumentation/TraceValues.h" -#include "llvm/Support/CommandLine.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 -cl::String InputFilename ("", "Input filename", cl::NoFlags, "-"); -cl::String OutputFilename("o", "Output filename", cl::NoFlags, ""); -cl::Flag Force ("f", "Overwrite output files", cl::NoFlags, false); -cl::Flag DumpAsm ("d", "Print bytecode before native code generation", cl::Hidden,false); -cl::Flag DoNotEmitAssembly("noasm", "Do not emit assembly code", cl::Hidden, false); -cl::Flag TraceBBValues ("trace", - "Trace values at basic block and method exits", - cl::NoFlags, false); -cl::Flag TraceMethodValues("tracem", "Trace values only at method exits", - cl::NoFlags, false); - -#include "llvm/Assembly/Writer.h" // For DumpAsm - -//-------------------------- Internal Functions ------------------------------// - - -///// -// TODO: Remove to external file.... When Chris gets back he'll do it -///// -#include "llvm/DerivedTypes.h" -#include "llvm/iMemory.h" -#include "llvm/iOther.h" -#include "llvm/SymbolTable.h" - - -Method *MallocMeth = 0, *FreeMeth = 0; - -// InsertMallocFreeDecls - Insert an external declaration for malloc and an -// external declaration for free for use by the ReplaceMallocFree function. -// -static void InsertMallocFreeDecls(Module *M) { - const MethodType *MallocType = - MethodType::get(PointerType::get(Type::UByteTy), - vector(1, Type::UIntTy), false); - - SymbolTable *SymTab = M->getSymbolTableSure(); - - // Check for a definition of malloc - if (Value *V = SymTab->lookup(PointerType::get(MallocType), "malloc")) { - MallocMeth = cast(V); // Yup, got it - } else { // Nope, add one - M->getMethodList().push_back(MallocMeth = new Method(MallocType, "malloc")); - } - - const MethodType *FreeType = - MethodType::get(Type::VoidTy, - vector(1, PointerType::get(Type::UByteTy)), - false); - - // Check for a definition of free - if (Value *V = SymTab->lookup(PointerType::get(FreeType), "free")) { - FreeMeth = cast(V); // Yup, got it - } else { // Nope, add one - M->getMethodList().push_back(FreeMeth = new Method(FreeType, "free")); - } -} - - -static void ReplaceMallocFree(Method *M, const TargetData &DataLayout) { - assert(MallocMeth && FreeMeth && M && "Must call InsertMallocFreeDecls!"); - - // Loop over all of the instructions, looking for malloc or free instructions - for (Method::iterator BBI = M->begin(), BBE = M->end(); BBI != BBE; ++BBI) { - BasicBlock *BB = *BBI; - for (unsigned i = 0; i < BB->size(); ++i) { - BasicBlock::InstListType &BBIL = BB->getInstList(); - if (MallocInst *MI = dyn_cast(*(BBIL.begin()+i))) { - BBIL.remove(BBIL.begin()+i); // remove the malloc instr... - - const Type *AllocTy = cast(MI->getType())->getValueType(); - - // If the user is allocating an unsized array with a dynamic size arg, - // start by getting the size of one element. - // - if (const ArrayType *ATy = dyn_cast(AllocTy)) - if (ATy->isUnsized()) AllocTy = ATy->getElementType(); - - // Get the number of bytes to be allocated for one element of the - // requested type... - unsigned Size = DataLayout.getTypeSize(AllocTy); - - // malloc(type) becomes sbyte *malloc(constint) - Value *MallocArg = ConstPoolUInt::get(Type::UIntTy, Size); - if (MI->getNumOperands() && Size == 1) { - MallocArg = MI->getOperand(0); // Operand * 1 = Operand - } else if (MI->getNumOperands()) { - // Multiply it by the array size if neccesary... - MallocArg = BinaryOperator::create(Instruction::Mul,MI->getOperand(0), - MallocArg); - BBIL.insert(BBIL.begin()+i++, cast(MallocArg)); - } - - // Create the call to Malloc... - CallInst *MCall = new CallInst(MallocMeth, - vector(1, MallocArg)); - BBIL.insert(BBIL.begin()+i, MCall); - - // Create a cast instruction to convert to the right type... - CastInst *MCast = new CastInst(MCall, MI->getType()); - BBIL.insert(BBIL.begin()+i+1, MCast); - - // Replace all uses of the old malloc inst with the cast inst - MI->replaceAllUsesWith(MCast); - delete MI; // Delete the malloc inst - } else if (FreeInst *FI = dyn_cast(*(BBIL.begin()+i))) { - BBIL.remove(BB->getInstList().begin()+i); +using namespace llvm; - // Cast the argument to free into a ubyte*... - CastInst *MCast = new CastInst(FI->getOperand(0), - PointerType::get(Type::UByteTy)); - BBIL.insert(BBIL.begin()+i, MCast); +// 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("-")); - // Insert a call to the free function... - CallInst *FCall = new CallInst(FreeMeth, - vector(1, MCast)); - BBIL.insert(BBIL.begin()+i+1, FCall); - - // Delete the old free instruction - delete FI; - } - } - } -} +static cl::opt +OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename")); +static cl::opt Force("f", cl::desc("Overwrite output files")); -// END TODO: Remove to external file.... +enum ArchName { noarch, X86, Sparc, PowerPC, CBackend }; -static void NormalizeMethod(Method *M) { - NormalizePhiConstantArgs(M); -} +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)); -inline string -GetFileNameRoot(const string& InputFilename) +// GetFileNameRoot - Helper function to get the basename of a filename... +static inline std::string +GetFileNameRoot(const std::string &InputFilename) { - string IFN = InputFilename; - string outputFilename; + 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; // Append a .s to it + outputFilename = IFN; } return outputFilename; } -inline string -GetTraceAssemblyFileName(const string& inFilename) -{ - assert(inFilename != "-" && "files on stdin not supported with tracing"); - string traceFileName = GetFileNameRoot(inFilename); - traceFileName += ".trace.ll"; - return traceFileName; -} - -//===---------------------------------------------------------------------===// -// Function PreprocessModule() -// -// Normalization to simplify later passes. -//===---------------------------------------------------------------------===// -int -PreprocessModule(Module* module) -{ - InsertMallocFreeDecls(module); - - for (Module::const_iterator MI=module->begin(); MI != module->end(); ++MI) - if (! (*MI)->isExternal()) - NormalizeMethod(*MI); +// main - Entry point for the llc compiler. +// +int main(int argc, char **argv) { + cl::ParseCommandLineOptions(argc, argv, " llvm system compiler\n"); - return 0; -} - - -//===---------------------------------------------------------------------===// -// Function OptimizeModule() -// -// Module optimization. -//===---------------------------------------------------------------------===// - -int -OptimizeModule(Module* module) -{ - return 0; -} + // 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; + } + 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; -//===---------------------------------------------------------------------===// -// Function GenerateCodeForModule() -// -// Native code generation for a specified target. -//===---------------------------------------------------------------------===// + Passes.add(new TargetData("llc", TD.isLittleEndian(), TD.getPointerSize(), + TD.getPointerAlignment(), TD.getDoubleAlignment())); -int -GenerateCodeForModule(Module* module, TargetMachine* target) -{ - // Since any transformation pass may introduce external function decls - // into the method list, find current methods first and then walk only those. - // - vector initialMethods(module->begin(), module->end()); - - - // Replace malloc and free instructions with library calls - // - for (unsigned i=0, N = initialMethods.size(); i < N; i++) - if (! initialMethods[i]->isExternal()) - ReplaceMallocFree(initialMethods[i], target->DataLayout); - - - // Insert trace code to assist debugging - // - if (TraceBBValues || TraceMethodValues) - { - // Insert trace code in all methods in the module - for (unsigned i=0, N = initialMethods.size(); i < N; i++) - if (! initialMethods[i]->isExternal()) - InsertCodeToTraceValues(initialMethods[i], TraceBBValues, - TraceBBValues || TraceMethodValues); - - // Then write the module with tracing code out in assembly form - string traceFileName = GetTraceAssemblyFileName(InputFilename); - ofstream* ofs = new ofstream(traceFileName.c_str(), - (Force ? 0 : ios::noreplace)|ios::out); - if (!ofs->good()) { - cerr << "Error opening " << traceFileName << "!\n"; - delete ofs; - return 1; - } - WriteToAssembly(module, *ofs); - delete ofs; - } - - - // Generate native target code for all methods - // - for (unsigned i=0, N = initialMethods.size(); i < N; i++) - if (! initialMethods[i]->isExternal()) - { - if (DumpAsm) - cerr << "Method after xformations: \n" << initialMethods[i]; - - if (target->compileMethod(initialMethods[i])) { - cerr << "Error compiling " << InputFilename << "!\n"; - return 1; - } + // 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; } - - return 0; -} - + Out = new std::ofstream(OutputFilename.c_str()); -//===---------------------------------------------------------------------===// -// Function EmitAssemblyForModule() -// -// Write assembly code to specified output file; .s by default. -//===---------------------------------------------------------------------===// - -int -EmitAssemblyForModule(Module* module, TargetMachine* target) -{ - // Figure out where we are going to send the output... - ostream *Out = 0; - if (OutputFilename != "") { // Specified an output filename? - Out = new ofstream(OutputFilename.c_str(), - (Force ? 0 : ios::noreplace)|ios::out); + // 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 = &cout; + Out = &std::cout; } else { - string OutputFilename = GetFileNameRoot(InputFilename); - OutputFilename += ".s"; - Out = new ofstream(OutputFilename.c_str(), - (Force ? 0 : ios::noreplace)|ios::out); + 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()) { - 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); } } - // Emit the output... - target->emitAssembly(module, *Out); + // 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()); + } - if (Out != &cout) delete Out; + // Delete the ostream if it's not a stdout stream + if (Out != &std::cout) delete Out; return 0; } - - -//===---------------------------------------------------------------------===// -// Function main() -// -// Entry point for the llc compiler. -//===---------------------------------------------------------------------===// - -int -main(int argc, char **argv) -{ - // Parse command line options... - cl::ParseCommandLineOptions(argc, argv, " llvm system compiler\n"); - - // Allocate a target... in the future this will be controllable on the - // command line. - auto_ptr target(allocateSparcTargetMachine()); - - // Load the module to be compiled... - auto_ptr M(ParseBytecodeFile(InputFilename)); - if (M.get() == 0) { - cerr << "bytecode didn't read correctly.\n"; - return 1; - } - - int failed = PreprocessModule(M.get()); - - if (!failed) - failed = OptimizeModule(M.get()); - - if (!failed) - failed = GenerateCodeForModule(M.get(), target.get()); - - if (!failed && ! DoNotEmitAssembly) - failed = EmitAssemblyForModule(M.get(), target.get()); - - return failed; -} -