Added LLVM copyright header.
[oota-llvm.git] / utils / TableGen / TableGen.cpp
index 90169e89431155ce5a183dba30dcb93e335af08f..803d0f0fdd5bd2dd641a1ab89a8bf07a29a767a0 100644 (file)
@@ -1,4 +1,11 @@
 //===- TableGen.cpp - Top-Level TableGen implementation -------------------===//
+// 
+//                     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.
+// 
+//===----------------------------------------------------------------------===//
 //
 // TableGen is a tool which can be used to build up a description of something,
 // then invoke one or more "tablegen backends" to emit information about the
 #include "Record.h"
 #include "Support/CommandLine.h"
 #include "Support/Signals.h"
+#include "Support/FileUtilities.h"
 #include "CodeEmitterGen.h"
 #include "RegisterInfoEmitter.h"
+#include "InstrInfoEmitter.h"
+#include "InstrSelectorEmitter.h"
 #include <algorithm>
+#include <cstdio>
 #include <fstream>
 
 enum ActionType {
   PrintRecords,
   GenEmitter,
-  GenRegister, GenRegisterHeader,
+  GenRegisterEnums, GenRegister, GenRegisterHeader,
+  GenInstrEnums, GenInstrs, GenInstrSelector,
   PrintEnums,
   Parse,
 };
@@ -31,10 +43,18 @@ namespace {
                                "Print all records to stdout (default)"),
                     clEnumValN(GenEmitter, "gen-emitter",
                                "Generate machine code emitter"),
+                    clEnumValN(GenRegisterEnums, "gen-register-enums",
+                               "Generate enum values for registers"),
                     clEnumValN(GenRegister, "gen-register-desc",
                                "Generate a register info description"),
                     clEnumValN(GenRegisterHeader, "gen-register-desc-header",
                                "Generate a register info description header"),
+                    clEnumValN(GenInstrEnums, "gen-instr-enums",
+                               "Generate enum values for instructions"),
+                    clEnumValN(GenInstrs, "gen-instr-desc",
+                               "Generate instruction descriptions"),
+                    clEnumValN(GenInstrSelector, "gen-instr-selector",
+                               "Generate an instruction selector"),
                     clEnumValN(PrintEnums, "print-enums",
                                "Print enum values for a class"),
                     clEnumValN(Parse, "parse",
@@ -51,10 +71,14 @@ namespace {
 
   cl::opt<std::string>
   InputFilename(cl::Positional, cl::desc("<input file>"), cl::init("-"));
+
+  cl::opt<std::string>
+  IncludeDir("I", cl::desc("Directory of include files"),
+                  cl::value_desc("directory"), cl::init(""));
 }
 
 
-void ParseFile(const std::string &Filename);
+void ParseFile(const std::string &Filename, const std::string & IncludeDir);
 
 RecordKeeper Records;
 
@@ -176,9 +200,9 @@ static unsigned getFirstFixedBitInSequence(std::vector<Record*>::iterator IB,
 }
 
 // ParseMachineCode - Try to split the vector of instructions (which is
-// intentially taken by-copy) in half, narrowing down the possible instructions
-// that we may have found.  Eventually, this list will get pared down to zero or
-// one instruction, in which case we have a match or failure.
+// intentionally taken by-copy) in half, narrowing down the possible
+// instructions that we may have found.  Eventually, this list will get pared
+// down to zero or one instruction, in which case we have a match or failure.
 //
 static Record *ParseMachineCode(std::vector<Record*>::iterator InstsB, 
                                std::vector<Record*>::iterator InstsE,
@@ -385,47 +409,57 @@ static void ParseMachineCode() {
 
 int main(int argc, char **argv) {
   cl::ParseCommandLineOptions(argc, argv);
-  ParseFile(InputFilename);
+  ParseFile(InputFilename, IncludeDir);
 
   std::ostream *Out = &std::cout;
   if (OutputFilename != "-") {
-    Out = new std::ofstream(OutputFilename.c_str());
+    // Output to a .tmp file, because we don't actually want to overwrite the
+    // output file unless the generated file is different or the specified file
+    // does not exist.
+    Out = new std::ofstream((OutputFilename+".tmp").c_str());
 
     if (!Out->good()) {
-      std::cerr << argv[0] << ": error opening " << OutputFilename << "!\n";
+      std::cerr << argv[0] << ": error opening " << OutputFilename << ".tmp!\n";
       return 1;
     }
 
     // Make sure the file gets removed if *gasp* tablegen crashes...
-    RemoveFileOnSignal(OutputFilename);
+    RemoveFileOnSignal(OutputFilename+".tmp");
   }
 
   try {
     switch (Action) {
+    case PrintRecords:
+      *Out << Records;           // No argument, dump all contents
+      break;
     case Parse:
       ParseMachineCode();
       break;
     case GenEmitter:
       CodeEmitterGen(Records).run(*Out);
       break;
+
+    case GenRegisterEnums:
+      RegisterInfoEmitter(Records).runEnums(*Out);
+      break;
     case GenRegister:
       RegisterInfoEmitter(Records).run(*Out);
       break;
     case GenRegisterHeader:
       RegisterInfoEmitter(Records).runHeader(*Out);
       break;
-    case PrintRecords:
-      *Out << Records;           // No argument, dump all contents
+
+    case GenInstrEnums:
+      InstrInfoEmitter(Records).runEnums(*Out);
+      break;
+    case GenInstrs:
+      InstrInfoEmitter(Records).run(*Out);
+      break;
+    case GenInstrSelector:
+      InstrSelectorEmitter(Records).run(*Out);
       break;
     case PrintEnums:
-      Record *R = Records.getClass(Class);
-      if (R == 0) {
-        std::cerr << "Cannot find class '" << Class << "'!\n";
-        abort();
-      }
-      
       std::vector<Record*> Recs = Records.getAllDerivedDefinitions(Class);
-
       for (unsigned i = 0, e = Recs.size(); i != e; ++i)
         *Out << Recs[i] << ", ";
       *Out << "\n";
@@ -433,10 +467,23 @@ int main(int argc, char **argv) {
     }
   } catch (const std::string &Error) {
     std::cerr << Error << "\n";
-    if (Out != &std::cout) delete Out;
+    if (Out != &std::cout) {
+      delete Out;                             // Close the file
+      std::remove(OutputFilename.c_str());    // Remove the file, it's broken
+    }
     return 1;
   }
 
-  if (Out != &std::cout) delete Out;
+  if (Out != &std::cout) {
+    delete Out;                               // Close the file
+    
+    // Now that we have generated the result, check to see if we either don't
+    // have the requested file, or if the requested file is different than the
+    // file we generated.  If so, move the generated file over the requested
+    // file.  Otherwise, just remove the file we just generated, so 'make'
+    // doesn't try to regenerate tons of dependencies.
+    //
+    MoveFileOverIfUpdated(OutputFilename+".tmp", OutputFilename);
+  }
   return 0;
 }