Move support/lib into lib/Support

Move support/tools into utils

llvm-svn: 8878
This commit is contained in:
Chris Lattner 2003-10-05 19:32:12 +00:00
parent e522cdbdff
commit ae8aec994f
71 changed files with 0 additions and 14629 deletions

View File

@ -1,6 +0,0 @@
LEVEL = ..
DIRS = lib tools
include $(LEVEL)/Makefile.common

View File

@ -1,6 +0,0 @@
LEVEL = ../..
DIRS = Support
include $(LEVEL)/Makefile.common

View File

@ -1,89 +0,0 @@
//===-- Annotation.cpp - Implement the Annotation Classes --------*- C++ -*--=//
//
// This file implements the AnnotationManager class.
//
//===----------------------------------------------------------------------===//
#include <map>
#include "Support/Annotation.h"
typedef std::map<const std::string, unsigned> IDMapType;
static unsigned IDCounter = 0; // Unique ID counter
// Static member to ensure initialiation on demand.
static IDMapType &getIDMap() { static IDMapType TheMap; return TheMap; }
// On demand annotation creation support...
typedef Annotation *(*AnnFactory)(AnnotationID, const Annotable *, void *);
typedef std::map<unsigned, std::pair<AnnFactory,void*> > FactMapType;
static FactMapType *TheFactMap = 0;
static FactMapType &getFactMap() {
if (TheFactMap == 0)
TheFactMap = new FactMapType();
return *TheFactMap;
}
static void eraseFromFactMap(unsigned ID) {
assert(TheFactMap && "No entries found!");
TheFactMap->erase(ID);
if (TheFactMap->empty()) { // Delete when empty
delete TheFactMap;
TheFactMap = 0;
}
}
AnnotationID AnnotationManager::getID(const std::string &Name) { // Name -> ID
IDMapType::iterator I = getIDMap().find(Name);
if (I == getIDMap().end()) {
getIDMap()[Name] = IDCounter++; // Add a new element
return IDCounter-1;
}
return I->second;
}
// getID - Name -> ID + registration of a factory function for demand driven
// annotation support.
AnnotationID AnnotationManager::getID(const std::string &Name, Factory Fact,
void *Data) {
AnnotationID Result(getID(Name));
registerAnnotationFactory(Result, Fact, Data);
return Result;
}
// getName - This function is especially slow, but that's okay because it should
// only be used for debugging.
//
const std::string &AnnotationManager::getName(AnnotationID ID) { // ID -> Name
IDMapType &TheMap = getIDMap();
for (IDMapType::iterator I = TheMap.begin(); ; ++I) {
assert(I != TheMap.end() && "Annotation ID is unknown!");
if (I->second == ID.ID) return I->first;
}
}
// registerAnnotationFactory - This method is used to register a callback
// function used to create an annotation on demand if it is needed by the
// Annotable::findOrCreateAnnotation method.
//
void AnnotationManager::registerAnnotationFactory(AnnotationID ID,
AnnFactory F,
void *ExtraData) {
if (F)
getFactMap()[ID.ID] = std::make_pair(F, ExtraData);
else
eraseFromFactMap(ID.ID);
}
// createAnnotation - Create an annotation of the specified ID for the
// specified object, using a register annotation creation function.
//
Annotation *AnnotationManager::createAnnotation(AnnotationID ID,
const Annotable *Obj) {
FactMapType::iterator I = getFactMap().find(ID.ID);
if (I == getFactMap().end()) return 0;
return I->second.first(ID, Obj, I->second.second);
}

View File

@ -1,877 +0,0 @@
//===-- CommandLine.cpp - Command line parser implementation --------------===//
//
// This class implements a command line argument processor that is useful when
// creating a tool. It provides a simple, minimalistic interface that is easily
// extensible and supports nonlocal (library) command line options.
//
// Note that rather than trying to figure out what this code does, you could try
// reading the library documentation located in docs/CommandLine.html
//
//===----------------------------------------------------------------------===//
#include "Support/CommandLine.h"
#include <algorithm>
#include <map>
#include <set>
#include <iostream>
using namespace cl;
//===----------------------------------------------------------------------===//
// Basic, shared command line option processing machinery...
//
// Return the global command line option vector. Making it a function scoped
// static ensures that it will be initialized correctly before its first use.
//
static std::map<std::string, Option*> *CommandLineOptions = 0;
static std::map<std::string, Option*> &getOpts() {
if (CommandLineOptions == 0)
CommandLineOptions = new std::map<std::string,Option*>();
return *CommandLineOptions;
}
static Option *getOption(const std::string &Str) {
if (CommandLineOptions == 0) return 0;
std::map<std::string,Option*>::iterator I = CommandLineOptions->find(Str);
return I != CommandLineOptions->end() ? I->second : 0;
}
static std::vector<Option*> &getPositionalOpts() {
static std::vector<Option*> Positional;
return Positional;
}
static void AddArgument(const char *ArgName, Option *Opt) {
if (getOption(ArgName)) {
std::cerr << "CommandLine Error: Argument '" << ArgName
<< "' defined more than once!\n";
} else {
// Add argument to the argument map!
getOpts()[ArgName] = Opt;
}
}
// RemoveArgument - It's possible that the argument is no longer in the map if
// options have already been processed and the map has been deleted!
//
static void RemoveArgument(const char *ArgName, Option *Opt) {
if (CommandLineOptions == 0) return;
assert(getOption(ArgName) == Opt && "Arg not in map!");
CommandLineOptions->erase(ArgName);
if (CommandLineOptions->empty()) {
delete CommandLineOptions;
CommandLineOptions = 0;
}
}
static const char *ProgramName = 0;
static const char *ProgramOverview = 0;
static inline bool ProvideOption(Option *Handler, const char *ArgName,
const char *Value, int argc, char **argv,
int &i) {
// Enforce value requirements
switch (Handler->getValueExpectedFlag()) {
case ValueRequired:
if (Value == 0 || *Value == 0) { // No value specified?
if (i+1 < argc) { // Steal the next argument, like for '-o filename'
Value = argv[++i];
} else {
return Handler->error(" requires a value!");
}
}
break;
case ValueDisallowed:
if (*Value != 0)
return Handler->error(" does not allow a value! '" +
std::string(Value) + "' specified.");
break;
case ValueOptional: break;
default: std::cerr << "Bad ValueMask flag! CommandLine usage error:"
<< Handler->getValueExpectedFlag() << "\n"; abort();
}
// Run the handler now!
return Handler->addOccurrence(ArgName, Value);
}
static bool ProvidePositionalOption(Option *Handler, const std::string &Arg) {
int Dummy;
return ProvideOption(Handler, Handler->ArgStr, Arg.c_str(), 0, 0, Dummy);
}
// Option predicates...
static inline bool isGrouping(const Option *O) {
return O->getFormattingFlag() == cl::Grouping;
}
static inline bool isPrefixedOrGrouping(const Option *O) {
return isGrouping(O) || O->getFormattingFlag() == cl::Prefix;
}
// getOptionPred - Check to see if there are any options that satisfy the
// specified predicate with names that are the prefixes in Name. This is
// checked by progressively stripping characters off of the name, checking to
// see if there options that satisfy the predicate. If we find one, return it,
// otherwise return null.
//
static Option *getOptionPred(std::string Name, unsigned &Length,
bool (*Pred)(const Option*)) {
Option *Op = getOption(Name);
if (Op && Pred(Op)) {
Length = Name.length();
return Op;
}
if (Name.size() == 1) return 0;
do {
Name.erase(Name.end()-1, Name.end()); // Chop off the last character...
Op = getOption(Name);
// Loop while we haven't found an option and Name still has at least two
// characters in it (so that the next iteration will not be the empty
// string...
} while ((Op == 0 || !Pred(Op)) && Name.size() > 1);
if (Op && Pred(Op)) {
Length = Name.length();
return Op; // Found one!
}
return 0; // No option found!
}
static bool RequiresValue(const Option *O) {
return O->getNumOccurrencesFlag() == cl::Required ||
O->getNumOccurrencesFlag() == cl::OneOrMore;
}
static bool EatsUnboundedNumberOfValues(const Option *O) {
return O->getNumOccurrencesFlag() == cl::ZeroOrMore ||
O->getNumOccurrencesFlag() == cl::OneOrMore;
}
/// ParseCStringVector - Break INPUT up wherever one or more
/// whitespace characters are found, and store the resulting tokens in
/// OUTPUT. The tokens stored in OUTPUT are dynamically allocated
/// using strdup (), so it is the caller's responsibility to free ()
/// them later.
///
static void ParseCStringVector (std::vector<char *> &output,
const char *input) {
// Characters which will be treated as token separators:
static const char *delims = " \v\f\t\r\n";
std::string work (input);
// Skip past any delims at head of input string.
size_t pos = work.find_first_not_of (delims);
// If the string consists entirely of delims, then exit early.
if (pos == std::string::npos) return;
// Otherwise, jump forward to beginning of first word.
work = work.substr (pos);
// Find position of first delimiter.
pos = work.find_first_of (delims);
while (!work.empty() && pos != std::string::npos) {
// Everything from 0 to POS is the next word to copy.
output.push_back (strdup (work.substr (0,pos).c_str ()));
// Is there another word in the string?
size_t nextpos = work.find_first_not_of (delims, pos + 1);
if (nextpos != std::string::npos) {
// Yes? Then remove delims from beginning ...
work = work.substr (work.find_first_not_of (delims, pos + 1));
// and find the end of the word.
pos = work.find_first_of (delims);
} else {
// No? (Remainder of string is delims.) End the loop.
work = "";
pos = std::string::npos;
}
}
// If `input' ended with non-delim char, then we'll get here with
// the last word of `input' in `work'; copy it now.
if (!work.empty ()) {
output.push_back (strdup (work.c_str ()));
}
}
/// ParseEnvironmentOptions - An alternative entry point to the
/// CommandLine library, which allows you to read the program's name
/// from the caller (as PROGNAME) and its command-line arguments from
/// an environment variable (whose name is given in ENVVAR).
///
void cl::ParseEnvironmentOptions (const char *progName, const char *envVar,
const char *Overview) {
// Check args.
assert (progName && "Program name not specified");
assert (envVar && "Environment variable name missing");
// Get the environment variable they want us to parse options out of.
const char *envValue = getenv (envVar);
if (!envValue)
return;
// Get program's "name", which we wouldn't know without the caller
// telling us.
std::vector<char *> newArgv;
newArgv.push_back (strdup (progName));
// Parse the value of the environment variable into a "command line"
// and hand it off to ParseCommandLineOptions().
ParseCStringVector (newArgv, envValue);
int newArgc = newArgv.size ();
ParseCommandLineOptions (newArgc, &newArgv[0], Overview);
// Free all the strdup()ed strings.
for (std::vector<char *>::iterator i = newArgv.begin (), e = newArgv.end ();
i != e; ++i) {
free (*i);
}
}
void cl::ParseCommandLineOptions(int &argc, char **argv,
const char *Overview) {
assert((!getOpts().empty() || !getPositionalOpts().empty()) &&
"No options specified, or ParseCommandLineOptions called more"
" than once!");
ProgramName = argv[0]; // Save this away safe and snug
ProgramOverview = Overview;
bool ErrorParsing = false;
std::map<std::string, Option*> &Opts = getOpts();
std::vector<Option*> &PositionalOpts = getPositionalOpts();
// Check out the positional arguments to collect information about them.
unsigned NumPositionalRequired = 0;
Option *ConsumeAfterOpt = 0;
if (!PositionalOpts.empty()) {
if (PositionalOpts[0]->getNumOccurrencesFlag() == cl::ConsumeAfter) {
assert(PositionalOpts.size() > 1 &&
"Cannot specify cl::ConsumeAfter without a positional argument!");
ConsumeAfterOpt = PositionalOpts[0];
}
// Calculate how many positional values are _required_.
bool UnboundedFound = false;
for (unsigned i = ConsumeAfterOpt != 0, e = PositionalOpts.size();
i != e; ++i) {
Option *Opt = PositionalOpts[i];
if (RequiresValue(Opt))
++NumPositionalRequired;
else if (ConsumeAfterOpt) {
// ConsumeAfter cannot be combined with "optional" positional options
// unless there is only one positional argument...
if (PositionalOpts.size() > 2)
ErrorParsing |=
Opt->error(" error - this positional option will never be matched, "
"because it does not Require a value, and a "
"cl::ConsumeAfter option is active!");
} else if (UnboundedFound && !Opt->ArgStr[0]) {
// This option does not "require" a value... Make sure this option is
// not specified after an option that eats all extra arguments, or this
// one will never get any!
//
ErrorParsing |= Opt->error(" error - option can never match, because "
"another positional argument will match an "
"unbounded number of values, and this option"
" does not require a value!");
}
UnboundedFound |= EatsUnboundedNumberOfValues(Opt);
}
}
// PositionalVals - A vector of "positional" arguments we accumulate into to
// processes at the end...
//
std::vector<std::string> PositionalVals;
// If the program has named positional arguments, and the name has been run
// across, keep track of which positional argument was named. Otherwise put
// the positional args into the PositionalVals list...
Option *ActivePositionalArg = 0;
// Loop over all of the arguments... processing them.
bool DashDashFound = false; // Have we read '--'?
for (int i = 1; i < argc; ++i) {
Option *Handler = 0;
const char *Value = "";
const char *ArgName = "";
// Check to see if this is a positional argument. This argument is
// considered to be positional if it doesn't start with '-', if it is "-"
// itself, or if we have seen "--" already.
//
if (argv[i][0] != '-' || argv[i][1] == 0 || DashDashFound) {
// Positional argument!
if (ActivePositionalArg) {
ProvidePositionalOption(ActivePositionalArg, argv[i]);
continue; // We are done!
} else if (!PositionalOpts.empty()) {
PositionalVals.push_back(argv[i]);
// All of the positional arguments have been fulfulled, give the rest to
// the consume after option... if it's specified...
//
if (PositionalVals.size() >= NumPositionalRequired &&
ConsumeAfterOpt != 0) {
for (++i; i < argc; ++i)
PositionalVals.push_back(argv[i]);
break; // Handle outside of the argument processing loop...
}
// Delay processing positional arguments until the end...
continue;
}
} else { // We start with a '-', must be an argument...
ArgName = argv[i]+1;
while (*ArgName == '-') ++ArgName; // Eat leading dashes
if (*ArgName == 0 && !DashDashFound) { // Is this the mythical "--"?
DashDashFound = true; // Yup, take note of that fact...
continue; // Don't try to process it as an argument itself.
}
const char *ArgNameEnd = ArgName;
while (*ArgNameEnd && *ArgNameEnd != '=')
++ArgNameEnd; // Scan till end of argument name...
Value = ArgNameEnd;
if (*Value) // If we have an equals sign...
++Value; // Advance to value...
if (*ArgName != 0) {
std::string RealName(ArgName, ArgNameEnd);
// Extract arg name part
std::map<std::string, Option*>::iterator I = Opts.find(RealName);
if (I == Opts.end() && !*Value && RealName.size() > 1) {
// Check to see if this "option" is really a prefixed or grouped
// argument...
//
unsigned Length = 0;
Option *PGOpt = getOptionPred(RealName, Length, isPrefixedOrGrouping);
// If the option is a prefixed option, then the value is simply the
// rest of the name... so fall through to later processing, by
// setting up the argument name flags and value fields.
//
if (PGOpt && PGOpt->getFormattingFlag() == cl::Prefix) {
ArgNameEnd = ArgName+Length;
Value = ArgNameEnd;
I = Opts.find(std::string(ArgName, ArgNameEnd));
assert(I->second == PGOpt);
} else if (PGOpt) {
// This must be a grouped option... handle all of them now...
assert(isGrouping(PGOpt) && "Broken getOptionPred!");
do {
// Move current arg name out of RealName into RealArgName...
std::string RealArgName(RealName.begin(),RealName.begin()+Length);
RealName.erase(RealName.begin(), RealName.begin()+Length);
// Because ValueRequired is an invalid flag for grouped arguments,
// we don't need to pass argc/argv in...
//
assert(PGOpt->getValueExpectedFlag() != cl::ValueRequired &&
"Option can not be cl::Grouping AND cl::ValueRequired!");
int Dummy;
ErrorParsing |= ProvideOption(PGOpt, RealArgName.c_str(), "",
0, 0, Dummy);
// Get the next grouping option...
if (!RealName.empty())
PGOpt = getOptionPred(RealName, Length, isGrouping);
} while (!RealName.empty() && PGOpt);
if (RealName.empty()) // Processed all of the options, move on
continue; // to the next argv[] value...
// If RealName is not empty, that means we did not match one of the
// options! This is an error.
//
I = Opts.end();
}
}
Handler = I != Opts.end() ? I->second : 0;
}
}
if (Handler == 0) {
std::cerr << "Unknown command line argument '" << argv[i] << "'. Try: '"
<< argv[0] << " --help'\n";
ErrorParsing = true;
continue;
}
// Check to see if this option accepts a comma separated list of values. If
// it does, we have to split up the value into multiple values...
if (Handler->getMiscFlags() & CommaSeparated) {
std::string Val(Value);
std::string::size_type Pos = Val.find(',');
while (Pos != std::string::npos) {
// Process the portion before the comma...
ErrorParsing |= ProvideOption(Handler, ArgName,
std::string(Val.begin(),
Val.begin()+Pos).c_str(),
argc, argv, i);
// Erase the portion before the comma, AND the comma...
Val.erase(Val.begin(), Val.begin()+Pos+1);
Value += Pos+1; // Increment the original value pointer as well...
// Check for another comma...
Pos = Val.find(',');
}
}
// If this is a named positional argument, just remember that it is the
// active one...
if (Handler->getFormattingFlag() == cl::Positional)
ActivePositionalArg = Handler;
else
ErrorParsing |= ProvideOption(Handler, ArgName, Value, argc, argv, i);
}
// Check and handle positional arguments now...
if (NumPositionalRequired > PositionalVals.size()) {
std::cerr << "Not enough positional command line arguments specified!\n"
<< "Must specify at least " << NumPositionalRequired
<< " positional arguments: See: " << argv[0] << " --help\n";
ErrorParsing = true;
} else if (ConsumeAfterOpt == 0) {
// Positional args have already been handled if ConsumeAfter is specified...
unsigned ValNo = 0, NumVals = PositionalVals.size();
for (unsigned i = 0, e = PositionalOpts.size(); i != e; ++i) {
if (RequiresValue(PositionalOpts[i])) {
ProvidePositionalOption(PositionalOpts[i], PositionalVals[ValNo++]);
--NumPositionalRequired; // We fulfilled our duty...
}
// If we _can_ give this option more arguments, do so now, as long as we
// do not give it values that others need. 'Done' controls whether the
// option even _WANTS_ any more.
//
bool Done = PositionalOpts[i]->getNumOccurrencesFlag() == cl::Required;
while (NumVals-ValNo > NumPositionalRequired && !Done) {
switch (PositionalOpts[i]->getNumOccurrencesFlag()) {
case cl::Optional:
Done = true; // Optional arguments want _at most_ one value
// FALL THROUGH
case cl::ZeroOrMore: // Zero or more will take all they can get...
case cl::OneOrMore: // One or more will take all they can get...
ProvidePositionalOption(PositionalOpts[i], PositionalVals[ValNo++]);
break;
default:
assert(0 && "Internal error, unexpected NumOccurrences flag in "
"positional argument processing!");
}
}
}
} else {
assert(ConsumeAfterOpt && NumPositionalRequired <= PositionalVals.size());
unsigned ValNo = 0;
for (unsigned j = 1, e = PositionalOpts.size(); j != e; ++j)
if (RequiresValue(PositionalOpts[j]))
ErrorParsing |= ProvidePositionalOption(PositionalOpts[j],
PositionalVals[ValNo++]);
// Handle the case where there is just one positional option, and it's
// optional. In this case, we want to give JUST THE FIRST option to the
// positional option and keep the rest for the consume after. The above
// loop would have assigned no values to positional options in this case.
//
if (PositionalOpts.size() == 2 && ValNo == 0 && !PositionalVals.empty())
ErrorParsing |= ProvidePositionalOption(PositionalOpts[1],
PositionalVals[ValNo++]);
// Handle over all of the rest of the arguments to the
// cl::ConsumeAfter command line option...
for (; ValNo != PositionalVals.size(); ++ValNo)
ErrorParsing |= ProvidePositionalOption(ConsumeAfterOpt,
PositionalVals[ValNo]);
}
// Loop over args and make sure all required args are specified!
for (std::map<std::string, Option*>::iterator I = Opts.begin(),
E = Opts.end(); I != E; ++I) {
switch (I->second->getNumOccurrencesFlag()) {
case Required:
case OneOrMore:
if (I->second->getNumOccurrences() == 0) {
I->second->error(" must be specified at least once!");
ErrorParsing = true;
}
// Fall through
default:
break;
}
}
// Free all of the memory allocated to the map. Command line options may only
// be processed once!
delete CommandLineOptions;
CommandLineOptions = 0;
PositionalOpts.clear();
// If we had an error processing our arguments, don't let the program execute
if (ErrorParsing) exit(1);
}
//===----------------------------------------------------------------------===//
// Option Base class implementation
//
bool Option::error(std::string Message, const char *ArgName) {
if (ArgName == 0) ArgName = ArgStr;
if (ArgName[0] == 0)
std::cerr << HelpStr; // Be nice for positional arguments
else
std::cerr << "-" << ArgName;
std::cerr << " option" << Message << "\n";
return true;
}
bool Option::addOccurrence(const char *ArgName, const std::string &Value) {
NumOccurrences++; // Increment the number of times we have been seen
switch (getNumOccurrencesFlag()) {
case Optional:
if (NumOccurrences > 1)
return error(": may only occur zero or one times!", ArgName);
break;
case Required:
if (NumOccurrences > 1)
return error(": must occur exactly one time!", ArgName);
// Fall through
case OneOrMore:
case ZeroOrMore:
case ConsumeAfter: break;
default: return error(": bad num occurrences flag value!");
}
return handleOccurrence(ArgName, Value);
}
// addArgument - Tell the system that this Option subclass will handle all
// occurrences of -ArgStr on the command line.
//
void Option::addArgument(const char *ArgStr) {
if (ArgStr[0])
AddArgument(ArgStr, this);
if (getFormattingFlag() == Positional)
getPositionalOpts().push_back(this);
else if (getNumOccurrencesFlag() == ConsumeAfter) {
if (!getPositionalOpts().empty() &&
getPositionalOpts().front()->getNumOccurrencesFlag() == ConsumeAfter)
error("Cannot specify more than one option with cl::ConsumeAfter!");
getPositionalOpts().insert(getPositionalOpts().begin(), this);
}
}
void Option::removeArgument(const char *ArgStr) {
if (ArgStr[0])
RemoveArgument(ArgStr, this);
if (getFormattingFlag() == Positional) {
std::vector<Option*>::iterator I =
std::find(getPositionalOpts().begin(), getPositionalOpts().end(), this);
assert(I != getPositionalOpts().end() && "Arg not registered!");
getPositionalOpts().erase(I);
} else if (getNumOccurrencesFlag() == ConsumeAfter) {
assert(!getPositionalOpts().empty() && getPositionalOpts()[0] == this &&
"Arg not registered correctly!");
getPositionalOpts().erase(getPositionalOpts().begin());
}
}
// getValueStr - Get the value description string, using "DefaultMsg" if nothing
// has been specified yet.
//
static const char *getValueStr(const Option &O, const char *DefaultMsg) {
if (O.ValueStr[0] == 0) return DefaultMsg;
return O.ValueStr;
}
//===----------------------------------------------------------------------===//
// cl::alias class implementation
//
// Return the width of the option tag for printing...
unsigned alias::getOptionWidth() const {
return std::strlen(ArgStr)+6;
}
// Print out the option for the alias...
void alias::printOptionInfo(unsigned GlobalWidth) const {
unsigned L = std::strlen(ArgStr);
std::cerr << " -" << ArgStr << std::string(GlobalWidth-L-6, ' ') << " - "
<< HelpStr << "\n";
}
//===----------------------------------------------------------------------===//
// Parser Implementation code...
//
// basic_parser implementation
//
// Return the width of the option tag for printing...
unsigned basic_parser_impl::getOptionWidth(const Option &O) const {
unsigned Len = std::strlen(O.ArgStr);
if (const char *ValName = getValueName())
Len += std::strlen(getValueStr(O, ValName))+3;
return Len + 6;
}
// printOptionInfo - Print out information about this option. The
// to-be-maintained width is specified.
//
void basic_parser_impl::printOptionInfo(const Option &O,
unsigned GlobalWidth) const {
std::cerr << " -" << O.ArgStr;
if (const char *ValName = getValueName())
std::cerr << "=<" << getValueStr(O, ValName) << ">";
std::cerr << std::string(GlobalWidth-getOptionWidth(O), ' ') << " - "
<< O.HelpStr << "\n";
}
// parser<bool> implementation
//
bool parser<bool>::parse(Option &O, const char *ArgName,
const std::string &Arg, bool &Value) {
if (Arg == "" || Arg == "true" || Arg == "TRUE" || Arg == "True" ||
Arg == "1") {
Value = true;
} else if (Arg == "false" || Arg == "FALSE" || Arg == "False" || Arg == "0") {
Value = false;
} else {
return O.error(": '" + Arg +
"' is invalid value for boolean argument! Try 0 or 1");
}
return false;
}
// parser<int> implementation
//
bool parser<int>::parse(Option &O, const char *ArgName,
const std::string &Arg, int &Value) {
char *End;
Value = (int)strtol(Arg.c_str(), &End, 0);
if (*End != 0)
return O.error(": '" + Arg + "' value invalid for integer argument!");
return false;
}
// parser<unsigned> implementation
//
bool parser<unsigned>::parse(Option &O, const char *ArgName,
const std::string &Arg, unsigned &Value) {
char *End;
long long int V = strtoll(Arg.c_str(), &End, 0);
Value = (unsigned)V;
if (*End != 0 || V < 0 || Value != V)
return O.error(": '" + Arg + "' value invalid for uint argument!");
return false;
}
// parser<double>/parser<float> implementation
//
static bool parseDouble(Option &O, const std::string &Arg, double &Value) {
const char *ArgStart = Arg.c_str();
char *End;
Value = strtod(ArgStart, &End);
if (*End != 0)
return O.error(": '" +Arg+ "' value invalid for floating point argument!");
return false;
}
bool parser<double>::parse(Option &O, const char *AN,
const std::string &Arg, double &Val) {
return parseDouble(O, Arg, Val);
}
bool parser<float>::parse(Option &O, const char *AN,
const std::string &Arg, float &Val) {
double dVal;
if (parseDouble(O, Arg, dVal))
return true;
Val = (float)dVal;
return false;
}
// generic_parser_base implementation
//
// findOption - Return the option number corresponding to the specified
// argument string. If the option is not found, getNumOptions() is returned.
//
unsigned generic_parser_base::findOption(const char *Name) {
unsigned i = 0, e = getNumOptions();
std::string N(Name);
while (i != e)
if (getOption(i) == N)
return i;
else
++i;
return e;
}
// Return the width of the option tag for printing...
unsigned generic_parser_base::getOptionWidth(const Option &O) const {
if (O.hasArgStr()) {
unsigned Size = std::strlen(O.ArgStr)+6;
for (unsigned i = 0, e = getNumOptions(); i != e; ++i)
Size = std::max(Size, (unsigned)std::strlen(getOption(i))+8);
return Size;
} else {
unsigned BaseSize = 0;
for (unsigned i = 0, e = getNumOptions(); i != e; ++i)
BaseSize = std::max(BaseSize, (unsigned)std::strlen(getOption(i))+8);
return BaseSize;
}
}
// printOptionInfo - Print out information about this option. The
// to-be-maintained width is specified.
//
void generic_parser_base::printOptionInfo(const Option &O,
unsigned GlobalWidth) const {
if (O.hasArgStr()) {
unsigned L = std::strlen(O.ArgStr);
std::cerr << " -" << O.ArgStr << std::string(GlobalWidth-L-6, ' ')
<< " - " << O.HelpStr << "\n";
for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
unsigned NumSpaces = GlobalWidth-strlen(getOption(i))-8;
std::cerr << " =" << getOption(i) << std::string(NumSpaces, ' ')
<< " - " << getDescription(i) << "\n";
}
} else {
if (O.HelpStr[0])
std::cerr << " " << O.HelpStr << "\n";
for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
unsigned L = std::strlen(getOption(i));
std::cerr << " -" << getOption(i) << std::string(GlobalWidth-L-8, ' ')
<< " - " << getDescription(i) << "\n";
}
}
}
//===----------------------------------------------------------------------===//
// --help and --help-hidden option implementation
//
namespace {
class HelpPrinter {
unsigned MaxArgLen;
const Option *EmptyArg;
const bool ShowHidden;
// isHidden/isReallyHidden - Predicates to be used to filter down arg lists.
inline static bool isHidden(std::pair<std::string, Option *> &OptPair) {
return OptPair.second->getOptionHiddenFlag() >= Hidden;
}
inline static bool isReallyHidden(std::pair<std::string, Option *> &OptPair) {
return OptPair.second->getOptionHiddenFlag() == ReallyHidden;
}
public:
HelpPrinter(bool showHidden) : ShowHidden(showHidden) {
EmptyArg = 0;
}
void operator=(bool Value) {
if (Value == false) return;
// Copy Options into a vector so we can sort them as we like...
std::vector<std::pair<std::string, Option*> > Options;
copy(getOpts().begin(), getOpts().end(), std::back_inserter(Options));
// Eliminate Hidden or ReallyHidden arguments, depending on ShowHidden
Options.erase(std::remove_if(Options.begin(), Options.end(),
std::ptr_fun(ShowHidden ? isReallyHidden : isHidden)),
Options.end());
// Eliminate duplicate entries in table (from enum flags options, f.e.)
{ // Give OptionSet a scope
std::set<Option*> OptionSet;
for (unsigned i = 0; i != Options.size(); ++i)
if (OptionSet.count(Options[i].second) == 0)
OptionSet.insert(Options[i].second); // Add new entry to set
else
Options.erase(Options.begin()+i--); // Erase duplicate
}
if (ProgramOverview)
std::cerr << "OVERVIEW:" << ProgramOverview << "\n";
std::cerr << "USAGE: " << ProgramName << " [options]";
// Print out the positional options...
std::vector<Option*> &PosOpts = getPositionalOpts();
Option *CAOpt = 0; // The cl::ConsumeAfter option, if it exists...
if (!PosOpts.empty() && PosOpts[0]->getNumOccurrencesFlag() == ConsumeAfter)
CAOpt = PosOpts[0];
for (unsigned i = CAOpt != 0, e = PosOpts.size(); i != e; ++i) {
if (PosOpts[i]->ArgStr[0])
std::cerr << " --" << PosOpts[i]->ArgStr;
std::cerr << " " << PosOpts[i]->HelpStr;
}
// Print the consume after option info if it exists...
if (CAOpt) std::cerr << " " << CAOpt->HelpStr;
std::cerr << "\n\n";
// Compute the maximum argument length...
MaxArgLen = 0;
for (unsigned i = 0, e = Options.size(); i != e; ++i)
MaxArgLen = std::max(MaxArgLen, Options[i].second->getOptionWidth());
std::cerr << "OPTIONS:\n";
for (unsigned i = 0, e = Options.size(); i != e; ++i)
Options[i].second->printOptionInfo(MaxArgLen);
// Halt the program if help information is printed
exit(1);
}
};
// Define the two HelpPrinter instances that are used to print out help, or
// help-hidden...
//
HelpPrinter NormalPrinter(false);
HelpPrinter HiddenPrinter(true);
cl::opt<HelpPrinter, true, parser<bool> >
HOp("help", cl::desc("display available options (--help-hidden for more)"),
cl::location(NormalPrinter), cl::ValueDisallowed);
cl::opt<HelpPrinter, true, parser<bool> >
HHOp("help-hidden", cl::desc("display all available options"),
cl::location(HiddenPrinter), cl::Hidden, cl::ValueDisallowed);
} // End anonymous namespace

View File

@ -1,243 +0,0 @@
//===-- ConstantRange.cpp - ConstantRange implementation ------------------===//
//
// Represent a range of possible values that may occur when the program is run
// for an integral value. This keeps track of a lower and upper bound for the
// constant, which MAY wrap around the end of the numeric range. To do this, it
// keeps track of a [lower, upper) bound, which specifies an interval just like
// STL iterators. When used with boolean values, the following are important
// ranges (other integral ranges use min/max values for special range values):
//
// [F, F) = {} = Empty set
// [T, F) = {T}
// [F, T) = {F}
// [T, T) = {F, T} = Full set
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/ConstantRange.h"
#include "llvm/Type.h"
#include "llvm/Instruction.h"
#include "llvm/ConstantHandling.h"
/// Initialize a full (the default) or empty set for the specified type.
///
ConstantRange::ConstantRange(const Type *Ty, bool Full) {
assert(Ty->isIntegral() &&
"Cannot make constant range of non-integral type!");
if (Full)
Lower = Upper = ConstantIntegral::getMaxValue(Ty);
else
Lower = Upper = ConstantIntegral::getMinValue(Ty);
}
/// Initialize a range of values explicitly... this will assert out if
/// Lower==Upper and Lower != Min or Max for its type (or if the two constants
/// have different types)
///
ConstantRange::ConstantRange(ConstantIntegral *L,
ConstantIntegral *U) : Lower(L), Upper(U) {
assert(Lower->getType() == Upper->getType() &&
"Incompatible types for ConstantRange!");
// Make sure that if L & U are equal that they are either Min or Max...
assert((L != U || (L == ConstantIntegral::getMaxValue(L->getType()) ||
L == ConstantIntegral::getMinValue(L->getType()))) &&
"Lower == Upper, but they aren't min or max for type!");
}
static ConstantIntegral *Next(ConstantIntegral *CI) {
if (CI->getType() == Type::BoolTy)
return CI == ConstantBool::True ? ConstantBool::False : ConstantBool::True;
// Otherwise use operator+ in the ConstantHandling Library.
Constant *Result = *ConstantInt::get(CI->getType(), 1) + *CI;
assert(Result && "ConstantHandling not implemented for integral plus!?");
return cast<ConstantIntegral>(Result);
}
/// Initialize a set of values that all satisfy the condition with C.
///
ConstantRange::ConstantRange(unsigned SetCCOpcode, ConstantIntegral *C) {
switch (SetCCOpcode) {
default: assert(0 && "Invalid SetCC opcode to ConstantRange ctor!");
case Instruction::SetEQ: Lower = C; Upper = Next(C); return;
case Instruction::SetNE: Upper = C; Lower = Next(C); return;
case Instruction::SetLT:
Lower = ConstantIntegral::getMinValue(C->getType());
Upper = C;
return;
case Instruction::SetGT:
Lower = Next(C);
Upper = ConstantIntegral::getMinValue(C->getType()); // Min = Next(Max)
return;
case Instruction::SetLE:
Lower = ConstantIntegral::getMinValue(C->getType());
Upper = Next(C);
return;
case Instruction::SetGE:
Lower = C;
Upper = ConstantIntegral::getMinValue(C->getType()); // Min = Next(Max)
return;
}
}
/// getType - Return the LLVM data type of this range.
///
const Type *ConstantRange::getType() const { return Lower->getType(); }
/// isFullSet - Return true if this set contains all of the elements possible
/// for this data-type
bool ConstantRange::isFullSet() const {
return Lower == Upper && Lower == ConstantIntegral::getMaxValue(getType());
}
/// isEmptySet - Return true if this set contains no members.
///
bool ConstantRange::isEmptySet() const {
return Lower == Upper && Lower == ConstantIntegral::getMinValue(getType());
}
/// isWrappedSet - Return true if this set wraps around the top of the range,
/// for example: [100, 8)
///
bool ConstantRange::isWrappedSet() const {
return (*(Constant*)Lower > *(Constant*)Upper)->getValue();
}
/// getSingleElement - If this set contains a single element, return it,
/// otherwise return null.
ConstantIntegral *ConstantRange::getSingleElement() const {
if (Upper == Next(Lower)) // Is it a single element range?
return Lower;
return 0;
}
/// getSetSize - Return the number of elements in this set.
///
uint64_t ConstantRange::getSetSize() const {
if (isEmptySet()) return 0;
if (getType() == Type::BoolTy) {
if (Lower != Upper) // One of T or F in the set...
return 1;
return 2; // Must be full set...
}
// Simply subtract the bounds...
Constant *Result = *(Constant*)Upper - *(Constant*)Lower;
assert(Result && "Subtraction of constant integers not implemented?");
return cast<ConstantInt>(Result)->getRawValue();
}
// intersect1Wrapped - This helper function is used to intersect two ranges when
// it is known that LHS is wrapped and RHS isn't.
//
static ConstantRange intersect1Wrapped(const ConstantRange &LHS,
const ConstantRange &RHS) {
assert(LHS.isWrappedSet() && !RHS.isWrappedSet());
// Check to see if we overlap on the Left side of RHS...
//
if ((*(Constant*)RHS.getLower() < *(Constant*)LHS.getUpper())->getValue()) {
// We do overlap on the left side of RHS, see if we overlap on the right of
// RHS...
if ((*(Constant*)RHS.getUpper() > *(Constant*)LHS.getLower())->getValue()) {
// Ok, the result overlaps on both the left and right sides. See if the
// resultant interval will be smaller if we wrap or not...
//
if (LHS.getSetSize() < RHS.getSetSize())
return LHS;
else
return RHS;
} else {
// No overlap on the right, just on the left.
return ConstantRange(RHS.getLower(), LHS.getUpper());
}
} else {
// We don't overlap on the left side of RHS, see if we overlap on the right
// of RHS...
if ((*(Constant*)RHS.getUpper() > *(Constant*)LHS.getLower())->getValue()) {
// Simple overlap...
return ConstantRange(LHS.getLower(), RHS.getUpper());
} else {
// No overlap...
return ConstantRange(LHS.getType(), false);
}
}
}
static ConstantIntegral *Min(ConstantIntegral *A, ConstantIntegral *B) {
if ((*(Constant*)A < *(Constant*)B)->getValue())
return A;
return B;
}
static ConstantIntegral *Max(ConstantIntegral *A, ConstantIntegral *B) {
if ((*(Constant*)A > *(Constant*)B)->getValue())
return A;
return B;
}
/// intersect - Return the range that results from the intersection of this
/// range with another range.
///
ConstantRange ConstantRange::intersectWith(const ConstantRange &CR) const {
assert(getType() == CR.getType() && "ConstantRange types don't agree!");
// Handle common special cases
if (isEmptySet() || CR.isFullSet()) return *this;
if (isFullSet() || CR.isEmptySet()) return CR;
if (!isWrappedSet()) {
if (!CR.isWrappedSet()) {
ConstantIntegral *L = Max(Lower, CR.Lower);
ConstantIntegral *U = Min(Upper, CR.Upper);
if ((*L < *U)->getValue()) // If range isn't empty...
return ConstantRange(L, U);
else
return ConstantRange(getType(), false); // Otherwise, return empty set
} else
return intersect1Wrapped(CR, *this);
} else { // We know "this" is wrapped...
if (!CR.isWrappedSet())
return intersect1Wrapped(*this, CR);
else {
// Both ranges are wrapped...
ConstantIntegral *L = Max(Lower, CR.Lower);
ConstantIntegral *U = Min(Upper, CR.Upper);
return ConstantRange(L, U);
}
}
return *this;
}
/// union - Return the range that results from the union of this range with
/// another range. The resultant range is guaranteed to include the elements of
/// both sets, but may contain more. For example, [3, 9) union [12,15) is [3,
/// 15), which includes 9, 10, and 11, which were not included in either set
/// before.
///
ConstantRange ConstantRange::unionWith(const ConstantRange &CR) const {
assert(getType() == CR.getType() && "ConstantRange types don't agree!");
assert(0 && "Range union not implemented yet!");
return *this;
}
/// print - Print out the bounds to a stream...
///
void ConstantRange::print(std::ostream &OS) const {
OS << "[" << Lower << "," << Upper << " )";
}
/// dump - Allow printing from a debugger easily...
///
void ConstantRange::dump() const {
print(std::cerr);
}

View File

@ -1,57 +0,0 @@
//===-- Debug.cpp - An easy way to add debug output to your code ----------===//
//
// This file implements a handle way of adding debugging information to your
// code, without it being enabled all of the time, and without having to add
// command line options to enable it.
//
// In particular, just wrap your code with the DEBUG() macro, and it will be
// enabled automatically if you specify '-debug' on the command-line.
// Alternatively, you can also use the SET_DEBUG_TYPE("foo") macro to specify
// that your debug code belongs to class "foo". Then, on the command line, you
// can specify '-debug-only=foo' to enable JUST the debug information for the
// foo class.
//
// When compiling in release mode, the -debug-* options and all code in DEBUG()
// statements disappears, so it does not effect the runtime of the code.
//
//===----------------------------------------------------------------------===//
#include "Support/Statistic.h"
#include "Support/CommandLine.h"
bool DebugFlag; // DebugFlag - Exported boolean set by the -debug option
namespace {
#ifndef NDEBUG
// -debug - Command line option to enable the DEBUG statements in the passes.
// This flag may only be enabled in debug builds.
cl::opt<bool, true>
Debug("debug", cl::desc("Enable debug output"), cl::Hidden,
cl::location(DebugFlag));
std::string CurrentDebugType;
struct DebugOnlyOpt {
void operator=(const std::string &Val) const {
DebugFlag |= !Val.empty();
CurrentDebugType = Val;
}
} DebugOnlyOptLoc;
cl::opt<DebugOnlyOpt, true, cl::parser<std::string> >
DebugOnly("debug-only", cl::desc("Enable a specific type of debug output"),
cl::Hidden, cl::value_desc("debug string"),
cl::location(DebugOnlyOptLoc), cl::ValueRequired);
#endif
}
// isCurrentDebugType - Return true if the specified string is the debug type
// specified on the command line, or if none was specified on the command line
// with the -debug-only=X option.
//
bool isCurrentDebugType(const char *DebugType) {
#ifndef NDEBUG
return CurrentDebugType.empty() || DebugType == CurrentDebugType;
#else
return false;
#endif
}

View File

@ -1,203 +0,0 @@
//===- Support/FileUtilities.cpp - File System Utilities ------------------===//
//
// This file implements a family of utility functions which are useful for doing
// various things with files.
//
//===----------------------------------------------------------------------===//
#include "Support/FileUtilities.h"
#include "Config/unistd.h"
#include "Config/sys/stat.h"
#include "Config/sys/types.h"
#include <fstream>
#include <iostream>
#include <cstdio>
/// DiffFiles - Compare the two files specified, returning true if they are
/// different or if there is a file error. If you specify a string to fill in
/// for the error option, it will set the string to an error message if an error
/// occurs, allowing the caller to distinguish between a failed diff and a file
/// system error.
///
bool DiffFiles(const std::string &FileA, const std::string &FileB,
std::string *Error) {
std::ifstream FileAStream(FileA.c_str());
if (!FileAStream) {
if (Error) *Error = "Couldn't open file '" + FileA + "'";
return true;
}
std::ifstream FileBStream(FileB.c_str());
if (!FileBStream) {
if (Error) *Error = "Couldn't open file '" + FileB + "'";
return true;
}
// Compare the two files...
int C1, C2;
do {
C1 = FileAStream.get();
C2 = FileBStream.get();
if (C1 != C2) return true;
} while (C1 != EOF);
return false;
}
/// MoveFileOverIfUpdated - If the file specified by New is different than Old,
/// or if Old does not exist, move the New file over the Old file. Otherwise,
/// remove the New file.
///
void MoveFileOverIfUpdated(const std::string &New, const std::string &Old) {
if (DiffFiles(New, Old)) {
if (std::rename(New.c_str(), Old.c_str()))
std::cerr << "Error renaming '" << New << "' to '" << Old << "'!\n";
} else {
std::remove(New.c_str());
}
}
/// removeFile - Delete the specified file
///
void removeFile(const std::string &Filename) {
std::remove(Filename.c_str());
}
/// getUniqueFilename - Return a filename with the specified prefix. If the
/// file does not exist yet, return it, otherwise add a suffix to make it
/// unique.
///
std::string getUniqueFilename(const std::string &FilenameBase) {
if (!std::ifstream(FilenameBase.c_str()))
return FilenameBase; // Couldn't open the file? Use it!
// Create a pattern for mkstemp...
char *FNBuffer = new char[FilenameBase.size()+8];
strcpy(FNBuffer, FilenameBase.c_str());
strcpy(FNBuffer+FilenameBase.size(), "-XXXXXX");
// Agree on a temporary file name to use....
int TempFD;
if ((TempFD = mkstemp(FNBuffer)) == -1) {
std::cerr << "bugpoint: ERROR: Cannot create temporary file in the current "
<< " directory!\n";
exit(1);
}
// We don't need to hold the temp file descriptor... we will trust that no one
// will overwrite/delete the file while we are working on it...
close(TempFD);
std::string Result(FNBuffer);
delete[] FNBuffer;
return Result;
}
///
/// Method: MakeFileExecutable ()
///
/// Description:
/// This method makes the specified filename executable by giving it
/// execute permission. It respects the umask value of the process, and it
/// does not enable any unnecessary access bits.
///
/// Algorithm:
/// o Get file's current permissions.
/// o Get the process's current umask.
/// o Take the set of all execute bits and disable those found in the umask.
/// o Add the remaining permissions to the file's permissions.
///
bool
MakeFileExecutable (const std::string & Filename)
{
// Permissions masking value of the user
mode_t mask;
// Permissions currently enabled on the file
struct stat fstat;
//
// Grab the umask value from the operating system. We want to use it when
// changing the file's permissions.
//
// Note:
// Umask() is one of those annoying system calls. You have to call it
// to get the current value and then set it back.
//
mask = umask (0x777);
umask (mask);
//
// Go fetch the file's current permission bits. We want to *add* execute
// access to the file.
//
if ((stat (Filename.c_str(), &fstat)) == -1)
{
return false;
}
//
// Make the file executable...
//
if ((chmod(Filename.c_str(), (fstat.st_mode | (0111 & ~mask)))) == -1)
{
return false;
}
return true;
}
///
/// Method: MakeFileReadable ()
///
/// Description:
/// This method makes the specified filename readable by giving it
/// read permission. It respects the umask value of the process, and it
/// does not enable any unnecessary access bits.
///
/// Algorithm:
/// o Get file's current permissions.
/// o Get the process's current umask.
/// o Take the set of all read bits and disable those found in the umask.
/// o Add the remaining permissions to the file's permissions.
///
bool
MakeFileReadable (const std::string & Filename)
{
// Permissions masking value of the user
mode_t mask;
// Permissions currently enabled on the file
struct stat fstat;
//
// Grab the umask value from the operating system. We want to use it when
// changing the file's permissions.
//
// Note:
// Umask() is one of those annoying system calls. You have to call it
// to get the current value and then set it back.
//
mask = umask (0x777);
umask (mask);
//
// Go fetch the file's current permission bits. We want to *add* execute
// access to the file.
//
if ((stat (Filename.c_str(), &fstat)) == -1)
{
return false;
}
//
// Make the file executable...
//
if ((chmod(Filename.c_str(), (fstat.st_mode | (0444 & ~mask)))) == -1)
{
return false;
}
return true;
}

View File

@ -1,82 +0,0 @@
//===-- LeakDetector.cpp - Implement LeakDetector interface ---------------===//
//
// This file implements the LeakDetector class.
//
//===----------------------------------------------------------------------===//
#include "Support/LeakDetector.h"
#include "llvm/Value.h"
#include <set>
// Lazily allocate set so that release build doesn't have to do anything.
static std::set<const void*> *Objects = 0;
static std::set<const Value*> *LLVMObjects = 0;
// Because the most common usage pattern, by far, is to add a garbage object,
// then remove it immediately, we optimize this case. When an object is added,
// it is not added to the set immediately, it is added to the CachedValue Value.
// If it is immediately removed, no set search need be performed.
//
static const Value *CachedValue;
void LeakDetector::addGarbageObjectImpl(void *Object) {
if (Objects == 0)
Objects = new std::set<const void*>();
assert(Objects->count(Object) == 0 && "Object already in set!");
Objects->insert(Object);
}
void LeakDetector::removeGarbageObjectImpl(void *Object) {
if (Objects)
Objects->erase(Object);
}
void LeakDetector::addGarbageObjectImpl(const Value *Object) {
if (CachedValue) {
if (LLVMObjects == 0)
LLVMObjects = new std::set<const Value*>();
assert(LLVMObjects->count(CachedValue) == 0 && "Object already in set!");
LLVMObjects->insert(CachedValue);
}
CachedValue = Object;
}
void LeakDetector::removeGarbageObjectImpl(const Value *Object) {
if (Object == CachedValue)
CachedValue = 0; // Cache hit!
else if (LLVMObjects)
LLVMObjects->erase(Object);
}
void LeakDetector::checkForGarbageImpl(const std::string &Message) {
if (CachedValue) // Flush the cache to the set...
addGarbageObjectImpl((Value*)0);
assert(CachedValue == 0 && "No value should be cached anymore!");
if ((Objects && !Objects->empty()) || (LLVMObjects && !LLVMObjects->empty())){
std::cerr << "Leaked objects found: " << Message << "\n";
if (Objects && !Objects->empty()) {
std::cerr << " Non-Value objects leaked:";
for (std::set<const void*>::iterator I = Objects->begin(),
E = Objects->end(); I != E; ++I)
std::cerr << " " << *I;
}
if (LLVMObjects && !LLVMObjects->empty()) {
std::cerr << " LLVM Value subclasses leaked:";
for (std::set<const Value*>::iterator I = LLVMObjects->begin(),
E = LLVMObjects->end(); I != E; ++I)
std::cerr << **I << "\n";
}
std::cerr << "This is probably because you removed an LLVM value "
<< "(Instruction, BasicBlock, \netc), but didn't delete it. "
<< "Please check your code for memory leaks.\n";
// Clear out results so we don't get duplicate warnings on next call...
delete Objects; delete LLVMObjects;
Objects = 0; LLVMObjects = 0;
}
}

View File

@ -1,5 +0,0 @@
LEVEL = ../../..
LIBRARYNAME = support
BUILD_ARCHIVE = 1
include $(LEVEL)/Makefile.common

View File

@ -1,94 +0,0 @@
//===-- Mangler.cpp - Self-contained c/asm llvm name mangler --------------===//
//
// Unified name mangler for CWriter and assembly backends.
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/Mangler.h"
#include "llvm/Module.h"
#include "llvm/Type.h"
#include "Support/StringExtras.h"
static char HexDigit(int V) {
return V < 10 ? V+'0' : V+'A'-10;
}
static std::string MangleLetter(unsigned char C) {
return std::string("_")+HexDigit(C >> 4) + HexDigit(C & 15) + "_";
}
/// makeNameProper - We don't want identifier names non-C-identifier characters
/// in them, so mangle them as appropriate.
///
std::string Mangler::makeNameProper(const std::string &X) {
std::string Result;
// Mangle the first letter specially, don't allow numbers...
if ((X[0] < 'a' || X[0] > 'z') && (X[0] < 'A' || X[0] > 'Z') && X[0] != '_')
Result += MangleLetter(X[0]);
else
Result += X[0];
for (std::string::const_iterator I = X.begin()+1, E = X.end(); I != E; ++I)
if ((*I < 'a' || *I > 'z') && (*I < 'A' || *I > 'Z') &&
(*I < '0' || *I > '9') && *I != '_')
Result += MangleLetter(*I);
else
Result += *I;
return Result;
}
std::string Mangler::getValueName(const Value *V) {
// Check to see whether we've already named V.
ValueMap::iterator VI = Memo.find(V);
if (VI != Memo.end()) {
return VI->second; // Return the old name for V.
}
std::string name;
if (V->hasName()) { // Print out the label if it exists...
// Name mangling occurs as follows:
// - If V is not a global, mangling always occurs.
// - Otherwise, mangling occurs when any of the following are true:
// 1) V has internal linkage
// 2) V's name would collide if it is not mangled.
//
const GlobalValue* gv = dyn_cast<GlobalValue>(V);
if (gv && !gv->hasInternalLinkage() && !MangledGlobals.count(gv)) {
name = makeNameProper(gv->getName());
if (AddUnderscorePrefix) name = "_" + name;
} else {
// Non-global, or global with internal linkage / colliding name
// -> mangle.
name = "l" + utostr(V->getType()->getUniqueID()) + "_" +
makeNameProper(V->getName());
}
} else {
name = "ltmp_" + utostr(Count++) + "_"
+ utostr(V->getType()->getUniqueID());
}
Memo[V] = name;
return name;
}
Mangler::Mangler(Module &m, bool addUnderscorePrefix)
: M(m), AddUnderscorePrefix(addUnderscorePrefix) {
// Calculate which global values have names that will collide when we throw
// away type information.
std::set<std::string> FoundNames;
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
if (I->hasName()) // If the global has a name...
if (FoundNames.count(I->getName())) // And the name is already used
MangledGlobals.insert(I); // Mangle the name
else
FoundNames.insert(I->getName()); // Otherwise, keep track of name
for (Module::giterator I = M.gbegin(), E = M.gend(); I != E; ++I)
if (I->hasName()) // If the global has a name...
if (FoundNames.count(I->getName())) // And the name is already used
MangledGlobals.insert(I); // Mangle the name
else
FoundNames.insert(I->getName()); // Otherwise, keep track of name
}

View File

@ -1,31 +0,0 @@
//===-- PluginLoader.cpp - Implement -load command line option ------------===//
//
// This file implements the -load <plugin> command line option processor. When
// linked into a program, this new command line option is available that allows
// users to load shared objects into the running program.
//
// Note that there are no symbols exported by the .o file generated for this
// .cpp file. Because of this, a program must link against support.o instead of
// support.a: otherwise this translation unit will not be included.
//
//===----------------------------------------------------------------------===//
#include "Support/CommandLine.h"
#include "Config/dlfcn.h"
#include "Config/link.h"
#include <iostream>
namespace {
struct PluginLoader {
void operator=(const std::string &Filename) {
if (dlopen(Filename.c_str(), RTLD_NOW|RTLD_GLOBAL) == 0)
std::cerr << "Error opening '" << Filename << "': " << dlerror()
<< "\n -load request ignored.\n";
}
};
}
// This causes operator= above to be invoked for every -load option.
static cl::opt<PluginLoader, false, cl::parser<std::string> >
LoadOpt("load", cl::ZeroOrMore, cl::value_desc("plugin.so"),
cl::desc("Load the specified plugin"));

View File

@ -1,57 +0,0 @@
//===- Signals.cpp - Signal Handling support ------------------------------===//
//
// This file defines some helpful functions for dealing with the possibility of
// Unix signals occuring while your program is running.
//
//===----------------------------------------------------------------------===//
#include "Support/Signals.h"
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <signal.h>
#include "Config/config.h" // Get the signal handler return type
static std::vector<std::string> FilesToRemove;
// IntSigs - Signals that may interrupt the program at any time.
static const int IntSigs[] = {
SIGHUP, SIGINT, SIGQUIT, SIGKILL, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2
};
static const int *IntSigsEnd = IntSigs + sizeof(IntSigs)/sizeof(IntSigs[0]);
// KillSigs - Signals that are synchronous with the program that will cause it
// to die.
static const int KillSigs[] = {
SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV, SIGSYS, SIGXCPU, SIGXFSZ
#ifdef SIGEMT
, SIGEMT
#endif
};
static const int *KillSigsEnd = KillSigs + sizeof(KillSigs)/sizeof(KillSigs[0]);
// SignalHandler - The signal handler that runs...
static RETSIGTYPE SignalHandler(int Sig) {
while (!FilesToRemove.empty()) {
std::remove(FilesToRemove.back().c_str());
FilesToRemove.pop_back();
}
if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd)
exit(1); // If this is an interrupt signal, exit the program
// Otherwise if it is a fault (like SEGV) reissue the signal to die...
signal(Sig, SIG_DFL);
}
static void RegisterHandler(int Signal) { signal(Signal, SignalHandler); }
// RemoveFileOnSignal - The public API
void RemoveFileOnSignal(const std::string &Filename) {
FilesToRemove.push_back(Filename);
std::for_each(IntSigs, IntSigsEnd, RegisterHandler);
std::for_each(KillSigs, KillSigsEnd, RegisterHandler);
}

View File

@ -1,99 +0,0 @@
//===-- Statistic.cpp - Easy way to expose stats information --------------===//
//
// This file implements the 'Statistic' class, which is designed to be an easy
// way to expose various success metrics from passes. These statistics are
// printed at the end of a run, when the -stats command line option is enabled
// on the command line.
//
// This is useful for reporting information like the number of instructions
// simplified, optimized or removed by various transformations, like this:
//
// static Statistic<> NumInstEliminated("GCSE - Number of instructions killed");
//
// Later, in the code: ++NumInstEliminated;
//
//===----------------------------------------------------------------------===//
#include "Support/Statistic.h"
#include "Support/CommandLine.h"
#include <sstream>
#include <iostream>
#include <algorithm>
// GetLibSupportInfoOutputFile - Return a file stream to print our output on...
std::ostream *GetLibSupportInfoOutputFile();
unsigned StatisticBase::NumStats = 0;
// -stats - Command line option to cause transformations to emit stats about
// what they did.
//
static cl::opt<bool>
Enabled("stats", cl::desc("Enable statistics output from program"));
struct StatRecord {
std::string Value;
const char *Name, *Desc;
StatRecord(const std::string V, const char *N, const char *D)
: Value(V), Name(N), Desc(D) {}
bool operator<(const StatRecord &SR) const {
return std::strcmp(Name, SR.Name) < 0;
}
void print(unsigned ValFieldSize, unsigned NameFieldSize,
std::ostream &OS) {
OS << std::string(ValFieldSize-Value.length(), ' ')
<< Value << " " << Name
<< std::string(NameFieldSize-std::strlen(Name), ' ')
<< " - " << Desc << "\n";
}
};
static std::vector<StatRecord> *AccumStats = 0;
// Print information when destroyed, iff command line option is specified
void StatisticBase::destroy() const {
if (Enabled && hasSomeData()) {
if (AccumStats == 0)
AccumStats = new std::vector<StatRecord>();
std::ostringstream Out;
printValue(Out);
AccumStats->push_back(StatRecord(Out.str(), Name, Desc));
}
if (--NumStats == 0 && AccumStats) {
std::ostream *OutStream = GetLibSupportInfoOutputFile();
// Figure out how long the biggest Value and Name fields are...
unsigned MaxNameLen = 0, MaxValLen = 0;
for (unsigned i = 0, e = AccumStats->size(); i != e; ++i) {
MaxValLen = std::max(MaxValLen,
(unsigned)(*AccumStats)[i].Value.length());
MaxNameLen = std::max(MaxNameLen,
(unsigned)std::strlen((*AccumStats)[i].Name));
}
// Sort the fields...
std::stable_sort(AccumStats->begin(), AccumStats->end());
// Print out the statistics header...
*OutStream << "===" << std::string(73, '-') << "===\n"
<< " ... Statistics Collected ...\n"
<< "===" << std::string(73, '-') << "===\n\n";
// Print all of the statistics accumulated...
for (unsigned i = 0, e = AccumStats->size(); i != e; ++i)
(*AccumStats)[i].print(MaxValLen, MaxNameLen, *OutStream);
*OutStream << std::endl; // Flush the output stream...
// Free all accumulated statistics...
delete AccumStats;
AccumStats = 0;
if (OutStream != &std::cerr && OutStream != &std::cout)
delete OutStream; // Close the file...
}
}

View File

@ -1,266 +0,0 @@
//===- SystemUtils.h - Utilities to do low-level system stuff --*- C++ -*--===//
//
// This file contains functions used to do a variety of low-level, often
// system-specific, tasks.
//
//===----------------------------------------------------------------------===//
#include "Support/SystemUtils.h"
#include <algorithm>
#include <fstream>
#include <iostream>
#include <cstdlib>
#include "Config/sys/types.h"
#include "Config/sys/stat.h"
#include "Config/fcntl.h"
#include "Config/sys/wait.h"
#include "Config/unistd.h"
#include "Config/errno.h"
/// isExecutableFile - This function returns true if the filename specified
/// exists and is executable.
///
bool isExecutableFile(const std::string &ExeFileName) {
struct stat Buf;
if (stat(ExeFileName.c_str(), &Buf))
return false; // Must not be executable!
if (!(Buf.st_mode & S_IFREG))
return false; // Not a regular file?
if (Buf.st_uid == getuid()) // Owner of file?
return Buf.st_mode & S_IXUSR;
else if (Buf.st_gid == getgid()) // In group of file?
return Buf.st_mode & S_IXGRP;
else // Unrelated to file?
return Buf.st_mode & S_IXOTH;
}
/// FindExecutable - Find a named executable, giving the argv[0] of program
/// being executed. This allows us to find another LLVM tool if it is built
/// into the same directory, but that directory is neither the current
/// directory, nor in the PATH. If the executable cannot be found, return an
/// empty string.
///
std::string FindExecutable(const std::string &ExeName,
const std::string &ProgramPath) {
// First check the directory that bugpoint is in. We can do this if
// BugPointPath contains at least one / character, indicating that it is a
// relative path to bugpoint itself.
//
std::string Result = ProgramPath;
while (!Result.empty() && Result[Result.size()-1] != '/')
Result.erase(Result.size()-1, 1);
if (!Result.empty()) {
Result += ExeName;
if (isExecutableFile(Result)) return Result; // Found it?
}
// Okay, if the path to the program didn't tell us anything, try using the
// PATH environment variable.
const char *PathStr = getenv("PATH");
if (PathStr == 0) return "";
// Now we have a colon separated list of directories to search... try them...
unsigned PathLen = strlen(PathStr);
while (PathLen) {
// Find the first colon...
const char *Colon = std::find(PathStr, PathStr+PathLen, ':');
// Check to see if this first directory contains the executable...
std::string FilePath = std::string(PathStr, Colon) + '/' + ExeName;
if (isExecutableFile(FilePath))
return FilePath; // Found the executable!
// Nope it wasn't in this directory, check the next range!
PathLen -= Colon-PathStr;
PathStr = Colon;
while (*PathStr == ':') { // Advance past colons
PathStr++;
PathLen--;
}
}
// If we fell out, we ran out of directories in PATH to search, return failure
return "";
}
static void RedirectFD(const std::string &File, int FD) {
if (File.empty()) return; // Noop
// Open the file
int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666);
if (InFD == -1) {
std::cerr << "Error opening file '" << File << "' for "
<< (FD == 0 ? "input" : "output") << "!\n";
exit(1);
}
dup2(InFD, FD); // Install it as the requested FD
close(InFD); // Close the original FD
}
/// RunProgramWithTimeout - This function executes the specified program, with
/// the specified null-terminated argument array, with the stdin/out/err fd's
/// redirected, with a timeout specified on the command line. This terminates
/// the calling program if there is an error executing the specified program.
/// It returns the return value of the program, or -1 if a timeout is detected.
///
int RunProgramWithTimeout(const std::string &ProgramPath, const char **Args,
const std::string &StdInFile,
const std::string &StdOutFile,
const std::string &StdErrFile) {
// FIXME: install sigalarm handler here for timeout...
int Child = fork();
switch (Child) {
case -1:
std::cerr << "ERROR forking!\n";
exit(1);
case 0: // Child
RedirectFD(StdInFile, 0); // Redirect file descriptors...
RedirectFD(StdOutFile, 1);
RedirectFD(StdErrFile, 2);
execv(ProgramPath.c_str(), (char *const *)Args);
std::cerr << "Error executing program '" << ProgramPath;
for (; *Args; ++Args)
std::cerr << " " << *Args;
exit(1);
default: break;
}
// Make sure all output has been written while waiting
std::cout << std::flush;
int Status;
if (wait(&Status) != Child) {
if (errno == EINTR) {
static bool FirstTimeout = true;
if (FirstTimeout) {
std::cout <<
"*** Program execution timed out! This mechanism is designed to handle\n"
" programs stuck in infinite loops gracefully. The -timeout option\n"
" can be used to change the timeout threshold or disable it completely\n"
" (with -timeout=0). This message is only displayed once.\n";
FirstTimeout = false;
}
return -1; // Timeout detected
}
std::cerr << "Error waiting for child process!\n";
exit(1);
}
return Status;
}
//
// Function: ExecWait ()
//
// Description:
// This function executes a program with the specified arguments and
// environment. It then waits for the progarm to termiante and then returns
// to the caller.
//
// Inputs:
// argv - The arguments to the program as an array of C strings. The first
// argument should be the name of the program to execute, and the
// last argument should be a pointer to NULL.
//
// envp - The environment passes to the program as an array of C strings in
// the form of "name=value" pairs. The last element should be a
// pointer to NULL.
//
// Outputs:
// None.
//
// Return value:
// 0 - No errors.
// 1 - The program could not be executed.
// 1 - The program returned a non-zero exit status.
// 1 - The program terminated abnormally.
//
// Notes:
// The program will inherit the stdin, stdout, and stderr file descriptors
// as well as other various configuration settings (umask).
//
// This function should not print anything to stdout/stderr on its own. It is
// a generic library function. The caller or executed program should report
// errors in the way it sees fit.
//
// This function does not use $PATH to find programs.
//
int
ExecWait (const char * const old_argv[], const char * const old_envp[])
{
// Child process ID
register int child;
// Status from child process when it exits
int status;
//
// Create local versions of the parameters that can be passed into execve()
// without creating const problems.
//
char ** const argv = (char ** const) old_argv;
char ** const envp = (char ** const) old_envp;
//
// Create a child process.
//
switch (child=fork())
{
//
// An error occured: Return to the caller.
//
case -1:
return 1;
break;
//
// Child process: Execute the program.
//
case 0:
execve (argv[0], argv, envp);
//
// If the execve() failed, we should exit and let the parent pick up
// our non-zero exit status.
//
exit (1);
break;
//
// Parent process: Break out of the switch to do our processing.
//
default:
break;
}
//
// Parent process: Wait for the child process to termiante.
//
if ((wait (&status)) == -1)
{
return 1;
}
//
// If the program exited normally with a zero exit status, return success!
//
if (WIFEXITED (status) && (WEXITSTATUS(status) == 0))
{
return 0;
}
//
// Otherwise, return failure.
//
return 1;
}

View File

@ -1,328 +0,0 @@
//===-- Timer.cpp - Interval Timing Support -------------------------------===//
//
// Interval Timing implementation.
//
//===----------------------------------------------------------------------===//
#include "Support/Timer.h"
#include "Support/CommandLine.h"
#include "Config/sys/resource.h"
#include "Config/sys/time.h"
#include "Config/unistd.h"
#include "Config/malloc.h"
#include "Config/stdio.h"
#include <iostream>
#include <algorithm>
#include <functional>
#include <fstream>
// getLibSupportInfoOutputFilename - This ugly hack is brought to you courtesy
// of constructor/destructor ordering being unspecified by C++. Basically the
// problem is that a Statistic<> object gets destroyed, which ends up calling
// 'GetLibSupportInfoOutputFile()' (below), which calls this function.
// LibSupportInfoOutputFilename used to be a global variable, but sometimes it
// would get destroyed before the Statistic, causing havoc to ensue. We "fix"
// this by creating the string the first time it is needed and never destroying
// it.
static std::string &getLibSupportInfoOutputFilename() {
static std::string *LibSupportInfoOutputFilename = new std::string();
return *LibSupportInfoOutputFilename;
}
namespace {
#ifdef HAVE_MALLINFO
cl::opt<bool>
TrackSpace("track-memory", cl::desc("Enable -time-passes memory "
"tracking (this may be slow)"),
cl::Hidden);
#endif
cl::opt<std::string, true>
InfoOutputFilename("info-output-file", cl::value_desc("filename"),
cl::desc("File to append -stats and -timer output to"),
cl::Hidden, cl::location(getLibSupportInfoOutputFilename()));
}
static TimerGroup *DefaultTimerGroup = 0;
static TimerGroup *getDefaultTimerGroup() {
if (DefaultTimerGroup) return DefaultTimerGroup;
return DefaultTimerGroup = new TimerGroup("Miscellaneous Ungrouped Timers");
}
Timer::Timer(const std::string &N)
: Elapsed(0), UserTime(0), SystemTime(0), MemUsed(0), PeakMem(0), Name(N),
Started(false), TG(getDefaultTimerGroup()) {
TG->addTimer();
}
Timer::Timer(const std::string &N, TimerGroup &tg)
: Elapsed(0), UserTime(0), SystemTime(0), MemUsed(0), PeakMem(0), Name(N),
Started(false), TG(&tg) {
TG->addTimer();
}
Timer::Timer(const Timer &T) {
TG = T.TG;
if (TG) TG->addTimer();
operator=(T);
}
// Copy ctor, initialize with no TG member.
Timer::Timer(bool, const Timer &T) {
TG = T.TG; // Avoid assertion in operator=
operator=(T); // Copy contents
TG = 0;
}
Timer::~Timer() {
if (TG) {
if (Started) {
Started = false;
TG->addTimerToPrint(*this);
}
TG->removeTimer();
}
}
static long getMemUsage() {
#ifdef HAVE_MALLINFO
if (TrackSpace) {
struct mallinfo MI = mallinfo();
return MI.uordblks/*+MI.hblkhd*/;
}
#endif
return 0;
}
struct TimeRecord {
double Elapsed, UserTime, SystemTime;
long MemUsed;
};
static TimeRecord getTimeRecord(bool Start) {
struct rusage RU;
struct timeval T;
long MemUsed = 0;
if (Start) {
MemUsed = getMemUsage();
if (getrusage(RUSAGE_SELF, &RU))
perror("getrusage call failed: -time-passes info incorrect!");
}
gettimeofday(&T, 0);
if (!Start) {
MemUsed = getMemUsage();
if (getrusage(RUSAGE_SELF, &RU))
perror("getrusage call failed: -time-passes info incorrect!");
}
TimeRecord Result;
Result.Elapsed = T.tv_sec + T.tv_usec/1000000.0;
Result.UserTime = RU.ru_utime.tv_sec + RU.ru_utime.tv_usec/1000000.0;
Result.SystemTime = RU.ru_stime.tv_sec + RU.ru_stime.tv_usec/1000000.0;
Result.MemUsed = MemUsed;
return Result;
}
static std::vector<Timer*> ActiveTimers;
void Timer::startTimer() {
Started = true;
TimeRecord TR = getTimeRecord(true);
Elapsed -= TR.Elapsed;
UserTime -= TR.UserTime;
SystemTime -= TR.SystemTime;
MemUsed -= TR.MemUsed;
PeakMemBase = TR.MemUsed;
ActiveTimers.push_back(this);
}
void Timer::stopTimer() {
TimeRecord TR = getTimeRecord(false);
Elapsed += TR.Elapsed;
UserTime += TR.UserTime;
SystemTime += TR.SystemTime;
MemUsed += TR.MemUsed;
if (ActiveTimers.back() == this) {
ActiveTimers.pop_back();
} else {
std::vector<Timer*>::iterator I =
std::find(ActiveTimers.begin(), ActiveTimers.end(), this);
assert(I != ActiveTimers.end() && "stop but no startTimer?");
ActiveTimers.erase(I);
}
}
void Timer::sum(const Timer &T) {
Elapsed += T.Elapsed;
UserTime += T.UserTime;
SystemTime += T.SystemTime;
MemUsed += T.MemUsed;
PeakMem += T.PeakMem;
}
/// addPeakMemoryMeasurement - This method should be called whenever memory
/// usage needs to be checked. It adds a peak memory measurement to the
/// currently active timers, which will be printed when the timer group prints
///
void Timer::addPeakMemoryMeasurement() {
long MemUsed = getMemUsage();
for (std::vector<Timer*>::iterator I = ActiveTimers.begin(),
E = ActiveTimers.end(); I != E; ++I)
(*I)->PeakMem = std::max((*I)->PeakMem, MemUsed-(*I)->PeakMemBase);
}
//===----------------------------------------------------------------------===//
// TimerGroup Implementation
//===----------------------------------------------------------------------===//
// printAlignedFP - Simulate the printf "%A.Bf" format, where A is the
// TotalWidth size, and B is the AfterDec size.
//
static void printAlignedFP(double Val, unsigned AfterDec, unsigned TotalWidth,
std::ostream &OS) {
assert(TotalWidth >= AfterDec+1 && "Bad FP Format!");
OS.width(TotalWidth-AfterDec-1);
char OldFill = OS.fill();
OS.fill(' ');
OS << (int)Val; // Integer part;
OS << ".";
OS.width(AfterDec);
OS.fill('0');
unsigned ResultFieldSize = 1;
while (AfterDec--) ResultFieldSize *= 10;
OS << (int)(Val*ResultFieldSize) % ResultFieldSize;
OS.fill(OldFill);
}
static void printVal(double Val, double Total, std::ostream &OS) {
if (Total < 1e-7) // Avoid dividing by zero...
OS << " ----- ";
else {
OS << " ";
printAlignedFP(Val, 4, 7, OS);
OS << " (";
printAlignedFP(Val*100/Total, 1, 5, OS);
OS << "%)";
}
}
void Timer::print(const Timer &Total, std::ostream &OS) {
if (Total.UserTime)
printVal(UserTime, Total.UserTime, OS);
if (Total.SystemTime)
printVal(SystemTime, Total.SystemTime, OS);
if (Total.getProcessTime())
printVal(getProcessTime(), Total.getProcessTime(), OS);
printVal(Elapsed, Total.Elapsed, OS);
OS << " ";
if (Total.MemUsed) {
OS.width(9);
OS << MemUsed << " ";
}
if (Total.PeakMem) {
if (PeakMem) {
OS.width(9);
OS << PeakMem << " ";
} else
OS << " ";
}
OS << Name << "\n";
Started = false; // Once printed, don't print again
}
// GetLibSupportInfoOutputFile - Return a file stream to print our output on...
std::ostream *GetLibSupportInfoOutputFile() {
std::string &LibSupportInfoOutputFilename = getLibSupportInfoOutputFilename();
if (LibSupportInfoOutputFilename.empty())
return &std::cerr;
if (LibSupportInfoOutputFilename == "-")
return &std::cout;
std::ostream *Result = new std::ofstream(LibSupportInfoOutputFilename.c_str(),
std::ios::app);
if (!Result->good()) {
std::cerr << "Error opening info-output-file '"
<< LibSupportInfoOutputFilename << " for appending!\n";
delete Result;
return &std::cerr;
}
return Result;
}
void TimerGroup::removeTimer() {
if (--NumTimers == 0 && !TimersToPrint.empty()) { // Print timing report...
// Sort the timers in descending order by amount of time taken...
std::sort(TimersToPrint.begin(), TimersToPrint.end(),
std::greater<Timer>());
// Figure out how many spaces to indent TimerGroup name...
unsigned Padding = (80-Name.length())/2;
if (Padding > 80) Padding = 0; // Don't allow "negative" numbers
std::ostream *OutStream = GetLibSupportInfoOutputFile();
++NumTimers;
{ // Scope to contain Total timer... don't allow total timer to drop us to
// zero timers...
Timer Total("TOTAL");
for (unsigned i = 0, e = TimersToPrint.size(); i != e; ++i)
Total.sum(TimersToPrint[i]);
// Print out timing header...
*OutStream << "===" << std::string(73, '-') << "===\n"
<< std::string(Padding, ' ') << Name << "\n"
<< "===" << std::string(73, '-')
<< "===\n Total Execution Time: ";
printAlignedFP(Total.getProcessTime(), 4, 5, *OutStream);
*OutStream << " seconds (";
printAlignedFP(Total.getWallTime(), 4, 5, *OutStream);
*OutStream << " wall clock)\n\n";
if (Total.UserTime)
*OutStream << " ---User Time---";
if (Total.SystemTime)
*OutStream << " --System Time--";
if (Total.getProcessTime())
*OutStream << " --User+System--";
*OutStream << " ---Wall Time---";
if (Total.getMemUsed())
*OutStream << " ---Mem---";
if (Total.getPeakMem())
*OutStream << " -PeakMem-";
*OutStream << " --- Name ---\n";
// Loop through all of the timing data, printing it out...
for (unsigned i = 0, e = TimersToPrint.size(); i != e; ++i)
TimersToPrint[i].print(Total, *OutStream);
Total.print(Total, *OutStream);
*OutStream << std::endl; // Flush output
}
--NumTimers;
TimersToPrint.clear();
if (OutStream != &std::cerr && OutStream != &std::cout)
delete OutStream; // Close the file...
}
// Delete default timer group!
if (NumTimers == 0 && this == DefaultTimerGroup) {
delete DefaultTimerGroup;
DefaultTimerGroup = 0;
}
}

View File

@ -1,374 +0,0 @@
#include "Support/Debug.h"
#include "Support/FileUtilities.h"
#include "Support/ToolRunner.h"
//===---------------------------------------------------------------------===//
// LLI Implementation of AbstractIntepreter interface
//
class LLI : public AbstractInterpreter {
std::string LLIPath; // The path to the LLI executable
public:
LLI(const std::string &Path) : LLIPath(Path) { }
virtual int ExecuteProgram(const std::string &Bytecode,
const cl::list<std::string> &Args,
const std::string &InputFile,
const std::string &OutputFile,
const std::string &SharedLib = "");
};
int LLI::ExecuteProgram(const std::string &Bytecode,
const cl::list<std::string> &Args,
const std::string &InputFile,
const std::string &OutputFile,
const std::string &SharedLib) {
if (!SharedLib.empty()) {
std::cerr << "LLI currently does not support loading shared libraries.\n"
<< "Exiting.\n";
exit(1);
}
std::vector<const char*> LLIArgs;
LLIArgs.push_back(LLIPath.c_str());
LLIArgs.push_back("-abort-on-exception");
LLIArgs.push_back("-quiet");
LLIArgs.push_back("-force-interpreter=true");
LLIArgs.push_back(Bytecode.c_str());
// Add optional parameters to the running program from Argv
for (unsigned i=0, e = Args.size(); i != e; ++i)
LLIArgs.push_back(Args[i].c_str());
LLIArgs.push_back(0);
std::cout << "<lli>" << std::flush;
DEBUG(std::cerr << "\nAbout to run:\n\t";
for (unsigned i=0, e = LLIArgs.size(); i != e; ++i)
std::cerr << " " << LLIArgs[i];
std::cerr << "\n";
);
return RunProgramWithTimeout(LLIPath, &LLIArgs[0],
InputFile, OutputFile, OutputFile);
}
// LLI create method - Try to find the LLI executable
AbstractInterpreter *createLLItool(const std::string &ProgramPath,
std::string &Message) {
std::string LLIPath = FindExecutable("lli", ProgramPath);
if (!LLIPath.empty()) {
Message = "Found lli: " + LLIPath + "\n";
return new LLI(LLIPath);
}
Message = "Cannot find `lli' in executable directory or PATH!\n";
return 0;
}
//===----------------------------------------------------------------------===//
// LLC Implementation of AbstractIntepreter interface
//
int LLC::OutputAsm(const std::string &Bytecode,
std::string &OutputAsmFile) {
OutputAsmFile = getUniqueFilename(Bytecode+".llc.s");
const char *LLCArgs[] = {
LLCPath.c_str(),
"-o", OutputAsmFile.c_str(), // Output to the Asm file
"-f", // Overwrite as necessary...
Bytecode.c_str(), // This is the input bytecode
0
};
std::cout << "<llc>" << std::flush;
if (RunProgramWithTimeout(LLCPath, LLCArgs, "/dev/null", "/dev/null",
"/dev/null")) {
// If LLC failed on the bytecode, print error...
std::cerr << "Error: `llc' failed!\n";
removeFile(OutputAsmFile);
return 1;
}
return 0;
}
int LLC::ExecuteProgram(const std::string &Bytecode,
const cl::list<std::string> &Args,
const std::string &InputFile,
const std::string &OutputFile,
const std::string &SharedLib) {
std::string OutputAsmFile;
if (OutputAsm(Bytecode, OutputAsmFile)) {
std::cerr << "Could not generate asm code with `llc', exiting.\n";
exit(1);
}
// Assuming LLC worked, compile the result with GCC and run it.
int Result = gcc->ExecuteProgram(OutputAsmFile, Args, AsmFile,
InputFile, OutputFile, SharedLib);
removeFile(OutputAsmFile);
return Result;
}
/// createLLCtool - Try to find the LLC executable
///
LLC *createLLCtool(const std::string &ProgramPath, std::string &Message)
{
std::string LLCPath = FindExecutable("llc", ProgramPath);
if (LLCPath.empty()) {
Message = "Cannot find `llc' in executable directory or PATH!\n";
return 0;
}
Message = "Found llc: " + LLCPath + "\n";
GCC *gcc = createGCCtool(ProgramPath, Message);
if (!gcc) {
std::cerr << Message << "\n";
exit(1);
}
return new LLC(LLCPath, gcc);
}
//===---------------------------------------------------------------------===//
// JIT Implementation of AbstractIntepreter interface
//
class JIT : public AbstractInterpreter {
std::string LLIPath; // The path to the LLI executable
public:
JIT(const std::string &Path) : LLIPath(Path) { }
virtual int ExecuteProgram(const std::string &Bytecode,
const cl::list<std::string> &Args,
const std::string &InputFile,
const std::string &OutputFile,
const std::string &SharedLib = "");
};
int JIT::ExecuteProgram(const std::string &Bytecode,
const cl::list<std::string> &Args,
const std::string &InputFile,
const std::string &OutputFile,
const std::string &SharedLib) {
// Construct a vector of parameters, incorporating those from the command-line
std::vector<const char*> JITArgs;
JITArgs.push_back(LLIPath.c_str());
JITArgs.push_back("-quiet");
JITArgs.push_back("-force-interpreter=false");
if (!SharedLib.empty()) {
JITArgs.push_back("-load");
JITArgs.push_back(SharedLib.c_str());
}
JITArgs.push_back(Bytecode.c_str());
// Add optional parameters to the running program from Argv
for (unsigned i=0, e = Args.size(); i != e; ++i)
JITArgs.push_back(Args[i].c_str());
JITArgs.push_back(0);
std::cout << "<jit>" << std::flush;
DEBUG(std::cerr << "\nAbout to run:\n\t";
for (unsigned i=0, e = JITArgs.size(); i != e; ++i)
std::cerr << " " << JITArgs[i];
std::cerr << "\n";
);
DEBUG(std::cerr << "\nSending output to " << OutputFile << "\n");
return RunProgramWithTimeout(LLIPath, &JITArgs[0],
InputFile, OutputFile, OutputFile);
}
/// createJITtool - Try to find the LLI executable
///
AbstractInterpreter *createJITtool(const std::string &ProgramPath,
std::string &Message) {
std::string LLIPath = FindExecutable("lli", ProgramPath);
if (!LLIPath.empty()) {
Message = "Found lli: " + LLIPath + "\n";
return new JIT(LLIPath);
}
Message = "Cannot find `lli' in executable directory or PATH!\n";
return 0;
}
int CBE::OutputC(const std::string &Bytecode,
std::string &OutputCFile) {
OutputCFile = getUniqueFilename(Bytecode+".cbe.c");
const char *DisArgs[] = {
DISPath.c_str(),
"-o", OutputCFile.c_str(), // Output to the C file
"-c", // Output to C
"-f", // Overwrite as necessary...
Bytecode.c_str(), // This is the input bytecode
0
};
std::cout << "<cbe>" << std::flush;
if (RunProgramWithTimeout(DISPath, DisArgs, "/dev/null", "/dev/null",
"/dev/null")) {
// If dis failed on the bytecode, print error...
std::cerr << "Error: `llvm-dis -c' failed!\n";
return 1;
}
return 0;
}
int CBE::ExecuteProgram(const std::string &Bytecode,
const cl::list<std::string> &Args,
const std::string &InputFile,
const std::string &OutputFile,
const std::string &SharedLib) {
std::string OutputCFile;
if (OutputC(Bytecode, OutputCFile)) {
std::cerr << "Could not generate C code with `llvm-dis', exiting.\n";
exit(1);
}
int Result = gcc->ExecuteProgram(OutputCFile, Args, CFile,
InputFile, OutputFile, SharedLib);
removeFile(OutputCFile);
return Result;
}
/// createCBEtool - Try to find the 'dis' executable
///
CBE *createCBEtool(const std::string &ProgramPath, std::string &Message) {
std::string DISPath = FindExecutable("llvm-dis", ProgramPath);
if (DISPath.empty()) {
Message =
"Cannot find `llvm-dis' in executable directory or PATH!\n";
return 0;
}
Message = "Found llvm-dis: " + DISPath + "\n";
GCC *gcc = createGCCtool(ProgramPath, Message);
if (!gcc) {
std::cerr << Message << "\n";
exit(1);
}
return new CBE(DISPath, gcc);
}
//===---------------------------------------------------------------------===//
// GCC abstraction
//
// This is not a *real* AbstractInterpreter as it does not accept bytecode
// files, but only input acceptable to GCC, i.e. C, C++, and assembly files
//
int GCC::ExecuteProgram(const std::string &ProgramFile,
const cl::list<std::string> &Args,
FileType fileType,
const std::string &InputFile,
const std::string &OutputFile,
const std::string &SharedLib) {
std::string OutputBinary = getUniqueFilename(ProgramFile+".gcc.exe");
std::vector<const char*> GCCArgs;
GCCArgs.push_back(GCCPath.c_str());
if (!SharedLib.empty()) // Specify the shared library to link in...
GCCArgs.push_back(SharedLib.c_str());
GCCArgs.push_back("-x");
if (fileType == CFile) {
GCCArgs.push_back("c");
GCCArgs.push_back("-fno-strict-aliasing");
} else {
GCCArgs.push_back("assembler");
}
GCCArgs.push_back(ProgramFile.c_str()); // Specify the input filename...
GCCArgs.push_back("-o");
GCCArgs.push_back(OutputBinary.c_str()); // Output to the right file...
GCCArgs.push_back("-lm"); // Hard-code the math library...
GCCArgs.push_back("-O2"); // Optimize the program a bit...
GCCArgs.push_back(0); // NULL terminator
std::cout << "<gcc>" << std::flush;
if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], "/dev/null", "/dev/null",
"/dev/null")) {
ProcessFailure(&GCCArgs[0]);
exit(1);
}
std::vector<const char*> ProgramArgs;
ProgramArgs.push_back(OutputBinary.c_str());
// Add optional parameters to the running program from Argv
for (unsigned i=0, e = Args.size(); i != e; ++i)
ProgramArgs.push_back(Args[i].c_str());
ProgramArgs.push_back(0); // NULL terminator
// Now that we have a binary, run it!
std::cout << "<program>" << std::flush;
DEBUG(std::cerr << "\nAbout to run:\n\t";
for (unsigned i=0, e = ProgramArgs.size(); i != e; ++i)
std::cerr << " " << ProgramArgs[i];
std::cerr << "\n";
);
int ProgramResult = RunProgramWithTimeout(OutputBinary, &ProgramArgs[0],
InputFile, OutputFile, OutputFile);
removeFile(OutputBinary);
return ProgramResult;
}
int GCC::MakeSharedObject(const std::string &InputFile,
FileType fileType,
std::string &OutputFile) {
OutputFile = getUniqueFilename(InputFile+".so");
// Compile the C/asm file into a shared object
const char* GCCArgs[] = {
GCCPath.c_str(),
"-x", (fileType == AsmFile) ? "assembler" : "c",
"-fno-strict-aliasing",
InputFile.c_str(), // Specify the input filename...
#if defined(sparc) || defined(__sparc__) || defined(__sparcv9)
"-G", // Compile a shared library, `-G' for Sparc
#else
"-shared", // `-shared' for Linux/X86, maybe others
#endif
"-o", OutputFile.c_str(), // Output to the right filename...
"-O2", // Optimize the program a bit...
0
};
std::cout << "<gcc>" << std::flush;
if(RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", "/dev/null",
"/dev/null")) {
ProcessFailure(GCCArgs);
exit(1);
}
return 0;
}
void GCC::ProcessFailure(const char** GCCArgs) {
std::cerr << "\n*** Error: invocation of the C compiler failed!\n";
for (const char **Arg = GCCArgs; *Arg; ++Arg)
std::cerr << " " << *Arg;
std::cerr << "\n";
// Rerun the compiler, capturing any error messages to print them.
std::string ErrorFilename = getUniqueFilename("gcc.errors");
RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", ErrorFilename.c_str(),
ErrorFilename.c_str());
// Print out the error messages generated by GCC if possible...
std::ifstream ErrorFile(ErrorFilename.c_str());
if (ErrorFile) {
std::copy(std::istreambuf_iterator<char>(ErrorFile),
std::istreambuf_iterator<char>(),
std::ostreambuf_iterator<char>(std::cerr));
ErrorFile.close();
std::cerr << "\n";
}
removeFile(ErrorFilename);
}
/// createGCCtool - Try to find the `gcc' executable
///
GCC *createGCCtool(const std::string &ProgramPath, std::string &Message) {
std::string GCCPath = FindExecutable("gcc", ProgramPath);
if (GCCPath.empty()) {
Message = "Cannot find `gcc' in executable directory or PATH!\n";
return 0;
}
Message = "Found gcc: " + GCCPath + "\n";
return new GCC(GCCPath);
}

View File

@ -1,16 +0,0 @@
//===-- ValueHolder.cpp - Wrapper for Value implementation ----------------===//
//
// This class defines a simple subclass of User, which keeps a pointer to a
// Value, which automatically updates when Value::replaceAllUsesWith is called.
// This is useful when you have pointers to Value's in your pass, but the
// pointers get invalidated when some other portion of the algorithm is
// replacing Values with other Values.
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/ValueHolder.h"
#include "llvm/Type.h"
ValueHolder::ValueHolder(Value *V) : User(Type::TypeTy, Value::TypeVal) {
Operands.push_back(Use(V, this));
}

View File

@ -1,13 +0,0 @@
Copyright (C) 1991 Todd A. Proebsting
All Rights Reserved.
This software is in the public domain. You may use and copy this material
freely. This privilege extends to modifications, although any modified
version of this system given to a third party should clearly identify your
modifications as well as the original source.
The responsibility for the use of this material resides entirely with you.
We make no warranty of any kind concerning this material, nor do we make
any claim as to the suitability of BURG for any application. This software
is experimental in nature and there is no written or implied warranty. Use
it at your own risk.

View File

@ -1,84 +0,0 @@
# $Id$
#CFLAGS =
#CFLAGS = -O
#CFLAGS = -O -DNOLEX
CFLAGS = -g -DDEBUG
#CFLAGS = -g -DNOLEX -DDEBUG
SRCS = \
be.c \
burs.c \
closure.c \
delta.c \
fe.c \
item.c \
lex.c \
list.c \
main.c \
map.c \
nonterminal.c \
operator.c \
pattern.c \
plank.c \
queue.c \
rule.c \
string.c \
symtab.c \
table.c \
trim.c \
zalloc.c
BU_OBJS = \
burs.o \
closure.o \
delta.o \
item.o \
list.o \
map.o \
nonterminal.o \
operator.o \
pattern.o \
queue.o \
rule.o \
table.o \
trim.o \
zalloc.o
FE_OBJS = \
be.o \
fe.o \
lex.o \
main.o \
plank.o \
string.o \
symtab.o \
y.tab.o
all: test
burg: $(BU_OBJS) $(FE_OBJS)
$(CC) -o burg $(CFLAGS) $(BU_OBJS) $(FE_OBJS)
y.tab.c y.tab.h: gram.y
yacc -d gram.y
clean:
rm -f *.o y.tab.h y.tab.c core burg *.aux *.log *.dvi sample sample.c tmp
$(FE_OBJS): b.h
$(BU_OBJS): b.h
$(FE_OBJS): fe.h
lex.o: y.tab.h
doc.dvi: doc.tex
latex doc; latex doc
test: burg sample.gr
./burg -I <sample.gr >sample.c && cc $(CFLAGS) -o sample sample.c && ./sample
./burg -I sample.gr >tmp && cmp tmp sample.c
./burg -I <sample.gr -o tmp && cmp tmp sample.c
./burg -I sample.gr -o tmp && cmp tmp sample.c
./burg -I -O0 <sample.gr >tmp && cmp tmp sample.c
./burg -I -= <sample.gr >tmp && cmp tmp sample.c

View File

@ -1,50 +0,0 @@
\relax
\bibstyle{alpha}
\citation{aho-twig-toplas}
\citation{appel-87}
\citation{balachandran-complang}
\citation{kron-phd}
\citation{hoffmann-jacm}
\citation{hatcher-popl}
\citation{chase-popl}
\citation{pelegri-popl}
\citation{pelegri-phd}
\citation{wilhelm-tr}
\citation{henry-budp}
\citation{fraser-henry-spe-91}
\citation{proebsting-91}
\@writefile{toc}{\contentsline {section}{\numberline {1}Overview}{1}}
\@writefile{toc}{\contentsline {section}{\numberline {2}Input}{1}}
\@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces A Sample Tree Grammar}}{2}}
\newlabel{fig-tree-grammar}{{1}{2}}
\@writefile{lof}{\contentsline {figure}{\numberline {2}{\ignorespaces EBNF Grammar for Tree Grammars for {\sc Burg}\ }}{3}}
\newlabel{fig-grammar-grammar}{{2}{3}}
\@writefile{toc}{\contentsline {section}{\numberline {3}Output}{3}}
\citation{aho-johnson-dp-classic}
\citation{fraser-henry-spe-91}
\citation{henry-budp}
\citation{pelegri-phd}
\@writefile{toc}{\contentsline {section}{\numberline {4}Debugging}{6}}
\@writefile{toc}{\contentsline {section}{\numberline {5}Running {\sc Burg}\ }{6}}
\newlabel{sec-man-page}{{5}{6}}
\citation{pelegri-popl}
\citation{henry-budp}
\citation{balachandran-complang}
\citation{proebsting-91}
\@writefile{lof}{\contentsline {figure}{\numberline {3}{\ignorespaces A Diverging Tree Grammar}}{7}}
\newlabel{fig-diverge-grammar}{{3}{7}}
\@writefile{toc}{\contentsline {section}{\numberline {6}Acknowledgements}{7}}
\bibcite{aho-twig-toplas}{AGT89}
\bibcite{aho-johnson-dp-classic}{AJ76}
\bibcite{appel-87}{App87}
\bibcite{balachandran-complang}{BDB90}
\bibcite{wilhelm-tr}{BMW87}
\bibcite{chase-popl}{Cha87}
\bibcite{fraser-henry-spe-91}{FH91}
\bibcite{hatcher-popl}{HC86}
\bibcite{henry-budp}{Hen89}
\bibcite{hoffmann-jacm}{HO82}
\bibcite{kron-phd}{Kro75}
\bibcite{pelegri-phd}{PL87}
\bibcite{pelegri-popl}{PLG88}
\bibcite{proebsting-91}{Pro91}

Binary file not shown.

View File

@ -1,157 +0,0 @@
This is TeX, Version 3.14159 (Web2C 7.3.2) (format=latex 2000.8.30) 4 JUN 2001 13:20
**doc
(doc.tex
LaTeX2e <2000/06/01>
(/usr/dcs/software/supported/encap/TeX/share/texmf/tex/latex/base/latex209.def
File: latex209.def 1998/05/13 v0.52 Standard LaTeX file
Entering LaTeX 2.09 COMPATIBILITY MODE
*************************************************************
!!WARNING!! !!WARNING!! !!WARNING!! !!WARNING!!
This mode attempts to provide an emulation of the LaTeX 2.09
author environment so that OLD documents can be successfully
processed. It should NOT be used for NEW documents!
New documents should use Standard LaTeX conventions and start
with the \documentclass command.
Compatibility mode is UNLIKELY TO WORK with LaTeX 2.09 style
files that change any internal macros, especially not with
those that change the FONT SELECTION or OUTPUT ROUTINES.
Therefore such style files MUST BE UPDATED to use
Current Standard LaTeX: LaTeX2e.
If you suspect that you may be using such a style file, which
is probably very, very old by now, then you should attempt to
get it updated by sending a copy of this error message to the
author of that file.
*************************************************************
\footheight=\dimen102
\@maxsep=\dimen103
\@dblmaxsep=\dimen104
\@cla=\count79
\@clb=\count80
\mscount=\count81
(/usr/dcs/software/supported/encap/TeX/share/texmf/tex/latex/base/tracefnt.sty
Package: tracefnt 1997/05/29 v3.0j Standard LaTeX package (font tracing)
\tracingfonts=\count82
LaTeX Info: Redefining \selectfont on input line 96.
)
\symbold=\mathgroup4
\symsans=\mathgroup5
\symtypewriter=\mathgroup6
\symitalic=\mathgroup7
\symsmallcaps=\mathgroup8
\symslanted=\mathgroup9
LaTeX Font Info: Redeclaring math alphabet \mathbf on input line 288.
LaTeX Font Info: Redeclaring math alphabet \mathsf on input line 289.
LaTeX Font Info: Redeclaring math alphabet \mathtt on input line 290.
LaTeX Font Info: Redeclaring math alphabet \mathit on input line 296.
LaTeX Info: Redefining \em on input line 306.
(/usr/dcs/software/supported/encap/TeX/share/texmf/tex/latex/base/latexsym.sty
Package: latexsym 1998/08/17 v2.2e Standard LaTeX package (lasy symbols)
\symlasy=\mathgroup10
LaTeX Font Info: Overwriting symbol font `lasy' in version `bold'
(Font) U/lasy/m/n --> U/lasy/b/n on input line 42.
)
LaTeX Font Info: Redeclaring math delimiter \lgroup on input line 370.
LaTeX Font Info: Redeclaring math delimiter \rgroup on input line 372.
LaTeX Font Info: Redeclaring math delimiter \bracevert on input line 374.
(/usr/dcs/software/supported/encap/TeX/share/texmf/tex/latex/config/latex209.cf
g
(/usr/dcs/software/supported/encap/TeX/share/texmf/tex/latex/tools/rawfonts.sty
Compatibility mode: package `' requested, but `rawfonts' provided.
Package: rawfonts 1994/05/08 Low-level LaTeX 2.09 font compatibility
(/usr/dcs/software/supported/encap/TeX/share/texmf/tex/latex/tools/somedefs.sty
Package: somedefs 1994/06/01 Toolkit for optional definitions
)
LaTeX Font Info: Try loading font information for U+lasy on input line 44.
(/usr/dcs/software/supported/encap/TeX/share/texmf/tex/latex/base/ulasy.fd
File: ulasy.fd 1998/08/17 v2.2eLaTeX symbol font definitions
)))) (/usr/dcs/software/supported/encap/TeX/share/texmf/tex/latex/base/article.
cls
Document Class: article 2000/05/19 v1.4b Standard LaTeX document class
(/usr/dcs/software/supported/encap/TeX/share/texmf/tex/latex/base/size11.clo
File: size11.clo 2000/05/19 v1.4b Standard LaTeX file (size option)
)
\c@part=\count83
\c@section=\count84
\c@subsection=\count85
\c@subsubsection=\count86
\c@paragraph=\count87
\c@subparagraph=\count88
\c@figure=\count89
\c@table=\count90
\abovecaptionskip=\skip41
\belowcaptionskip=\skip42
Compatibility mode: definition of \rm ignored.
Compatibility mode: definition of \sf ignored.
Compatibility mode: definition of \tt ignored.
Compatibility mode: definition of \bf ignored.
Compatibility mode: definition of \it ignored.
Compatibility mode: definition of \sl ignored.
Compatibility mode: definition of \sc ignored.
LaTeX Info: Redefining \cal on input line 501.
LaTeX Info: Redefining \mit on input line 502.
\bibindent=\dimen105
)
(/usr/dcs/software/supported/encap/TeX/share/texmf/tex/latex/pstex/fullpage.sty
) (doc.aux)
\openout1 = `doc.aux'.
LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 2.
LaTeX Font Info: ... okay on input line 2.
LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 2.
LaTeX Font Info: ... okay on input line 2.
LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 2.
LaTeX Font Info: ... okay on input line 2.
LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 2.
LaTeX Font Info: ... okay on input line 2.
LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 2.
LaTeX Font Info: ... okay on input line 2.
LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 2.
LaTeX Font Info: ... okay on input line 2.
LaTeX Font Info: External font `cmex10' loaded for size
(Font) <12> on input line 33.
LaTeX Font Info: External font `cmex10' loaded for size
(Font) <8> on input line 33.
LaTeX Font Info: External font `cmex10' loaded for size
(Font) <6> on input line 33.
LaTeX Font Info: Try loading font information for OMS+cmtt on input line 100
.
LaTeX Font Info: No file OMScmtt.fd. on input line 100.
LaTeX Font Warning: Font shape `OMS/cmtt/m/n' undefined
(Font) using `OMS/cmsy/m/n' instead
(Font) for symbol `textbraceleft' on input line 100.
[1
]
LaTeX Font Info: External font `cmex10' loaded for size
(Font) <10.95> on input line 150.
[2] [3] [4] [5] [6]
Overfull \hbox (1.38191pt too wide) in paragraph at lines 480--484
[]\OT1/cmr/m/n/10.95 Emit code for \OT1/cmtt/m/n/10.95 burm[]arity\OT1/cmr/m/n/
10.95 , \OT1/cmtt/m/n/10.95 burm[]child\OT1/cmr/m/n/10.95 , \OT1/cmtt/m/n/10.95
burm[]cost\OT1/cmr/m/n/10.95 , \OT1/cmtt/m/n/10.95 burm[]ntname\OT1/cmr/m/n/10
.95 , \OT1/cmtt/m/n/10.95 burm[]op[]label\OT1/cmr/m/n/10.95 , \OT1/cmtt/m/n/10.
95 burm[]opname\OT1/cmr/m/n/10.95 ,
[]
[7] [8] [9] (doc.aux)
LaTeX Font Warning: Some font shapes were not available, defaults substituted.
)
Here is how much of TeX's memory you used:
543 strings out of 12968
6147 string characters out of 289029
446019 words of memory out of 1453895
3433 multiletter control sequences out of 10000+10000
23403 words of font info for 87 fonts, out of 400000 for 2000
14 hyphenation exceptions out of 1000
21i,6n,20p,308b,283s stack positions out of 300i,100n,500p,50000b,4000s
Output written on doc.dvi (9 pages, 29856 bytes).

View File

@ -1,596 +0,0 @@
\documentstyle[11pt,fullpage]{article}
\begin{document}
\def\AddSpace#1{\ifcat#1a\ \fi#1} % if next is a letter, add a space
\def\YACC#1{{\sc Yacc}\AddSpace#1}
\def\TWIG#1{{\sc Twig}\AddSpace#1}
\def\PROG#1{{\sc Burg}\AddSpace#1}
\def\PARSER#1{{\sc Burm}\AddSpace#1}
\def\CODEGEN#1{{\sc Codegen}\AddSpace#1}
\title{{\sc Burg} --- Fast Optimal Instruction Selection and Tree Parsing}
\author{
Christopher W. Fraser \\
AT\&T Bell Laboratories \\
600 Mountain Avenue 2C-464 \\
Murray Hill, NJ 07974-0636 \\
{\tt cwf@research.att.com}
\and
Robert R. Henry \\
Tera Computer Company \\
400 N. 34th St., Suite 300 \\
Seattle, WA 98103-8600 \\
{\tt rrh@tera.com}
\and
Todd A. Proebsting \\
Dept. of Computer Sciences \\
University of Wisconsin \\
Madison, WI 53706 \\
{\tt todd@cs.wisc.edu}
}
\date{December 1991}
\maketitle
\bibliographystyle{alpha}
\newcommand\term[1]{{\it #1}}
\newcommand\secref[1]{\S\ref{#1}}
\newcommand\figref[1]{Figure~\ref{#1}}
%
% rationale table making
%
{\catcode`\^^M=13 \gdef\Obeycr{\catcode`\^^M=13 \def^^M{\\}}%
\gdef\Restorecr{\catcode`\^^M=5 }} %
%
% for printing out options
%
\newcommand\option[1]{% #1=option character
{\tt -#1}%
}
\newcommand\var[1]{%
{\tt #1}%
}
\section{Overview}
\PROG is a program that generates a fast tree parser using BURS
(Bottom-Up Rewrite System) technology. It accepts a cost-augmented
tree grammar and emits a C program that discovers in linear time an
optimal parse of trees in the language described by the grammar. \PROG
has been used to construct fast optimal instruction selectors for use
in code generation. \PROG addresses many of the problems addressed by
{\sc Twig}~\cite{aho-twig-toplas,appel-87}, but it is somewhat less flexible and
much faster. \PROG is available via anonymous \var{ftp} from
\var{kaese.cs.wisc.edu}. The compressed \var{shar} file
\var{pub/burg.shar.Z} holds the complete distribution.
This document describes only that fraction of the BURS model that is
required to use \PROG. Readers interested in more detail might start
with Reference~\cite{balachandran-complang}. Other relevant documents
include References~\cite{kron-phd,hoffmann-jacm,hatcher-popl,chase-popl,pelegri-popl,pelegri-phd,wilhelm-tr,henry-budp,fraser-henry-spe-91,proebsting-91}.
\section{Input}
\PROG accepts a tree grammar and emits a BURS tree parser.
\figref{fig-tree-grammar} shows a sample grammar that implements a very
simple instruction selector.
\begin{figure}
\begin{verbatim}
%{
#define NODEPTR_TYPE treepointer
#define OP_LABEL(p) ((p)->op)
#define LEFT_CHILD(p) ((p)->left)
#define RIGHT_CHILD(p) ((p)->right)
#define STATE_LABEL(p) ((p)->state_label)
#define PANIC printf
%}
%start reg
%term Assign=1 Constant=2 Fetch=3 Four=4 Mul=5 Plus=6
%%
con: Constant = 1 (0);
con: Four = 2 (0);
addr: con = 3 (0);
addr: Plus(con,reg) = 4 (0);
addr: Plus(con,Mul(Four,reg)) = 5 (0);
reg: Fetch(addr) = 6 (1);
reg: Assign(addr,reg) = 7 (1);
\end{verbatim}
\caption{A Sample Tree Grammar\label{fig-tree-grammar}}
\end{figure}
\PROG grammars are structurally similar to \YACC's. Comments follow C
conventions. Text between ``\var{\%\{}'' and ``\var{\%\}}'' is called
the \term{configuration section}; there may be several such segments.
All are concatenated and copied verbatim into the head of the generated
parser, which is called \PARSER. Text after the second ``\var{\%\%}'',
if any, is also copied verbatim into \PARSER, at the end.
The configuration section configures \PARSER for the trees being parsed
and the client's environment. This section must define
\var{NODEPTR\_TYPE} to be a visible typedef symbol for a pointer to a
node in the subject tree. \PARSER invokes \var{OP\_LABEL(p)},
\var{LEFT\_CHILD(p)}, and \var{RIGHT\_CHILD(p)} to read the operator
and children from the node pointed to by \var{p}. It invokes
\var{PANIC} when it detects an error. If the configuration section
defines these operations as macros, they are implemented in-line;
otherwise, they must be implemented as functions. The section on
diagnostics elaborates on \var{PANIC}.
\PARSER computes and stores a single integral \term{state} in each node
of the subject tree. The configuration section must define a macro
\var{STATE\_LABEL(p)} to access the state field of the node pointed to
by \var{p}. A macro is required because \PROG uses it as an lvalue. A
C \var{short} is usually the right choice; typical code generation
grammars require 100--1000 distinct state labels.
The tree grammar follows the configuration section.
\figref{fig-grammar-grammar} gives an EBNF grammar for \PROG tree
grammars.
\begin{figure}
\begin{verbatim}
grammar: {dcl} '%%' {rule}
dcl: '%start' Nonterminal
dcl: '%term' { Identifier '=' Integer }
rule: Nonterminal ':' tree '=' Integer cost ';'
cost: /* empty */
cost: '(' Integer { ',' Integer } ')'
tree: Term '(' tree ',' tree ')'
tree: Term '(' tree ')'
tree: Term
tree: Nonterminal
\end{verbatim}
\caption{EBNF Grammar for Tree Grammars for \PROG\ \label{fig-grammar-grammar}}
\end{figure}
Comments, the text between ``\var{\%\{}'' and ``\var{\%\}}'', and the
text after the optional second ``\var{\%\%}'' are treated lexically, so
the figure omits them. In the EBNF grammar, quoted text must appear
literally, \var{Nonterminal} and \var{Integer} are self-explanatory,
and \var{Term} denotes an identifier previously declared as a
terminal. {\tt\{$X$\}} denotes zero or more instances of $X$.
Text before the first ``\var{\%\%}'' declares the start symbol and the
terminals or operators in subject trees. All terminals must be
declared; each line of such declarations begins with \var{\%term}.
Each terminal has fixed arity, which \PROG infers from the rules using that terminal.
\PROG restricts terminals to have at most two children. Each terminal
is declared with a positive, unique, integral \term{external symbol
number} after a ``\var{=}''. \var{OP\_LABEL(p)} must return the valid
external symbol number for \var{p}. Ideally, external symbol numbers
form a dense enumeration. Non-terminals are not declared, but the
start symbol may be declared with a line that begins with
\var{\%start}.
Text after the first ``\var{\%\%}'' declares the rules. A tree grammar
is like a context-free grammar: it has rules, non-terminals,
terminals, and a special start non-terminal. The right-hand side of a
rule, called the \term{pattern}, is a tree. Tree patterns appear in
prefix parenthesized form. Every non-terminal denotes a tree. A chain
rule is a rule whose pattern is another non-terminal. If no start
symbol is declared, \PROG uses the non-terminal defined by the first
rule. \PROG needs a single start symbol; grammars for which it is
natural to use multiple start symbols must be augmented with an
artificial start symbol that derives, with zero cost, the grammar's
natural start symbols. \PARSER will automatically select one
that costs least for any given tree.
\PROG accepts no embedded semantic actions like \YACC's, because no one
format suited all intended applications. Instead, each rule has a
positive, unique, integral \term{external rule number}, after the
pattern and preceded by a ``\var{=}''. Ideally, external rule numbers
form a dense enumeration. \PARSER uses these numbers to report the
matching rule to a user-supplied routine, which must implement any
desired semantic action; see below. Humans may select these integers
by hand, but \PROG is intended as a \term{server} for building BURS
tree parsers. Thus some \PROG clients will consume a richer
description and translate it into \PROG's simpler input.
Rules end with a vector of non-negative, integer costs, in parentheses
and separated by commas. If the cost vector is omitted, then all
elements are assumed to be zero. \PROG retains only the first four
elements of the list. The cost of a derivation is the sum of the costs
for all rules applied in the derivation. Arithmetic on cost vectors
treats each member of the vector independently. The tree parser finds
the cheapest parse of the subject tree. It breaks ties arbitrarily.
By default, \PROG uses only the \term{principal cost} of each cost
vector, which defaults to the first element, but options described
below provide alternatives.
\section{Output}
\PARSER traverses the subject tree twice. The first pass or
\term{labeller} runs bottom-up and left-to-right, visiting each node
exactly once. Each node is labeled with a state, a single number that
encodes all full and partial optimal pattern matches viable at that
node. The second pass or \term{reducer} traverses the subject tree
top-down. The reducer accepts a tree node's state label and a
\term{goal} non-terminal --- initially the root's state label and the
start symbol --- which combine to determine the rule to be applied at
that node. By construction, the rule has the given goal non-terminal
as its left-hand side. The rule's pattern identifies the subject
subtrees and goal non-terminals for all recursive visits. Here, a
``subtree'' is not necessarily an immediate child of the current node.
Patterns with interior operators cause the reducer to skip the
corresponding subject nodes, so the reducer may proceed directly to
grandchildren, great-grandchildren, and so on. On the other hand,
chain rules cause the reducer to revisit the current subject node, with
a new goal
non-terminal, so \term{x} is also regarded as a subtree of \term{x}.
As the reducer visits (and possibly revisits) each node, user-supplied
code implements semantic action side effects and controls the order in
which subtrees are visited. The labeller is self-contained, but the
reducer combines code from \PROG with code from the user, so \PARSER
does not stand alone.
The \PARSER that is generated by \PROG provides primitives for
labelling and reducing trees. These mechanisms are a compromise
between expressibility, abstraction, simplicity, flexibility and
efficiency. Clients may combine primitives into labellers and reducers
that can traverse trees in arbitrary ways, and they may call semantic
routines when and how they wish during traversal. Also, \PROG
generates a few higher level routines that implement common
combinations of primitives, and it generates mechanisms that help debug
the tree parse.
\PROG generates the labeller as a function named \var{burm\_label} with
the signature
\begin{verbatim}
extern int burm_label(NODEPTR_TYPE p);
\end{verbatim}
It labels the entire subject tree pointed to by \var{p} and returns the
root's state label. State zero labels unmatched trees. The trees may
be corrupt or merely inconsistent with the grammar.
The simpler \var{burm\_state} is \var{burm\_label} without the
code to traverse the tree and to read and write its fields. It may be
used to integrate labelling into user-supplied traversal code. A
typical signature is
\begin{verbatim}
extern int burm_state(int op, int leftstate, int rightstate);
\end{verbatim}
It accepts an external symbol number for a node and the labels for the
node's left and right children. It returns the state label to assign
to that node. For unary operators, the last argument is ignored; for
leaves, the last two arguments are ignored. In general, \PROG
generates a \var{burm\_state} that accepts the maximum number of child
states required by the input grammar. For example, if the grammar
includes no binary operators, then \var{burm\_state} will have the
signature
\begin{verbatim}
extern int burm_state(int op, int leftstate);
\end{verbatim}
This feature is included to permit future expansion to operators with
more than two children.
The user must write the reducer, but \PARSER writes code and data that
help. Primary is
\begin{verbatim}
extern int burm_rule(int state, int goalnt);
\end{verbatim}
which accepts a tree's state label and a goal non-terminal and returns the
external rule number of a rule. The rule will have matched the tree
and have the goal non-terminal on the left-hand side; \var{burm\_rule}
returns zero when the tree labelled with the given state did not match
the goal non-terminal. For the initial, root-level call, \var{goalnt}
must be one, and \PARSER exports an array that identifies the values
for nested calls:
\begin{verbatim}
extern short *burm_nts[] = { ... };
\end{verbatim}
is an array indexed by external rule numbers. Each element points to a
zero-terminated vector of short integers, which encode the goal
non-terminals for that rule's pattern, left-to-right. The user needs
only these two externals to write a complete reducer, but a third
external simplifies some applications:
\begin{verbatim}
extern NODEPTR_TYPE *burm_kids(NODEPTR_TYPE p, int eruleno, NODEPTR_TYPE kids[]);
\end{verbatim}
accepts the address of a tree \var{p}, an external rule number, and an
empty vector of pointers to trees. The procedure assumes that \var{p}
matched the given rule, and it fills in the vector with the subtrees (in
the sense described above) of \var{p} that must be reduced recursively.
\var{kids} is returned. It is not zero-terminated.
The simple user code below labels and then fully reduces a subject tree;
the reducer prints the tree cover. \var{burm\_string} is defined below.
\begin{verbatim}
parse(NODEPTR_TYPE p) {
burm_label(p); /* label the tree */
reduce(p, 1, 0); /* and reduce it */
}
reduce(NODEPTR_TYPE p, int goalnt, int indent) {
int eruleno = burm_rule(STATE_LABEL(p), goalnt); /* matching rule number */
short *nts = burm_nts[eruleno]; /* subtree goal non-terminals */
NODEPTR_TYPE kids[10]; /* subtree pointers */
int i;
for (i = 0; i < indent; i++)
printf("."); /* print indented ... */
printf("%s\n", burm_string[eruleno]); /* ... text of rule */
burm_kids(p, eruleno, kids); /* initialize subtree pointers */
for (i = 0; nts[i]; i++) /* traverse subtrees left-to-right */
reduce(kids[i], nts[i], indent+1); /* and print them recursively */
}
\end{verbatim}
The reducer may recursively traverse subtrees in any order, and it may
interleave arbitrary semantic actions with recursive traversals.
Multiple reducers may be written, to implement multi-pass algorithms
or independent single-pass algorithms.
For each non-terminal $x$, \PROG emits a preprocessor directive to
equate \var{burm\_}$x$\var{\_NT} with $x$'s integral encoding. It also
defines a macro \var{burm\_}$x$\var{\_rule(a)} that is equivalent to
\var{burm\_rule(a,}$x$\var{)}. For the grammar in
\figref{fig-tree-grammar}, \PROG emits
\begin{verbatim}
#define burm_reg_NT 1
#define burm_con_NT 2
#define burm_addr_NT 3
#define burm_reg_rule(a) ...
#define burm_con_rule(a) ...
#define burm_addr_rule(a) ...
\end{verbatim}
Such symbols are visible only to the code after the second
``\var{\%\%}''. If the symbols \var{burm\_}$x$\var{\_NT} are needed
elsewhere, extract them from the \PARSER source.
The \option{I} option directs \PROG to emit an encoding of the input
that may help the user produce diagnostics. The vectors
\begin{verbatim}
extern char *burm_opname[];
extern char burm_arity[];
\end{verbatim}
hold the name and number of children, respectively, for each terminal.
They are indexed by the terminal's external symbol number. The vectors
\begin{verbatim}
extern char *burm_string[];
extern short burm_cost[][4];
\end{verbatim}
hold the text and cost vector for each rule. They are indexed by the
external rule number. The zero-terminated vector
\begin{verbatim}
extern char *burm_ntname[];
\end{verbatim}
is indexed by \var{burm\_}$x$\var{\_NT} and holds the name of
non-terminal $x$. Finally, the procedures
\begin{verbatim}
extern int burm_op_label(NODEPTR_TYPE p);
extern int burm_state_label(NODEPTR_TYPE p);
extern NODEPTR_TYPE burm_child(NODEPTR_TYPE p, int index);
\end{verbatim}
are callable versions of the configuration macros.
\var{burm\_child(p,0)} implements \var{LEFT\_CHILD(p)}, and
\var{burm\_child(p,1)} implements \var{RIGHT\_CHILD(p)}. A sample use
is the grammar-independent expression
\var{burm\_opname[burm\_op\_label(p)]}, which yields the textual name
for the operator in the tree node pointed to by \var{p}.
A complete tree parser can be assembled from just \var{burm\_state},
\var{burm\_rule}, and \var{burm\_nts}, which use none of the
configuration section except \var{PANIC}. The generated routines that
use the rest of the configuration section are compiled only if the
configuration section defines \var{STATE\_LABEL}, so they can be
omitted if the user prefers to hide the tree structure from \PARSER.
This course may be wise if, say, the tree structure is defined in a
large header file with symbols that might collide with \PARSER's.
\PARSER selects an optimal parse without dynamic programming at compile
time~\cite{aho-johnson-dp-classic}. Instead, \PROG does the dynamic
programming at compile-compile time, as it builds \PARSER.
Consequently, \PARSER parses quickly. Similar labellers have taken as
few as 15 instructions per node, and reducers as few as 35 per node
visited~\cite{fraser-henry-spe-91}.
\section{Debugging}
\PARSER invokes \var{PANIC} when an error prevents it from proceeding.
\var{PANIC} has the same signature as \var{printf}. It should pass its
arguments to \var{printf} if diagnostics are desired and then either
abort (say via \var{exit}) or recover (say via \var{longjmp}). If it
returns, \PARSER aborts. Some errors are not caught.
\PROG assumes a robust preprocessor, so it omits full consistency
checking and error recovery. \PROG constructs a set of states using a
closure algorithm like that used in LR table construction. \PROG
considers all possible trees generated by the tree grammar and
summarizes infinite sets of trees with finite sets. The summary
records the cost of those trees but actually manipulates the
differences in costs between viable alternatives using a dynamic
programming algorithm. Reference~\cite{henry-budp} elaborates.
Some grammars derive trees whose optimal parses depend on arbitrarily
distant data. When this happens, \PROG and the tree grammar
\term{cost diverge}, and \PROG attempts to build an infinite
set of states; it first thrashes and ultimately exhausts
memory and exits. For example, the tree grammar in
\figref{fig-diverge-grammar}
\begin{figure}
\begin{verbatim}
%term Const=17 RedFetch=20 GreenFetch=21 Plus=22
%%
reg: GreenFetch(green_reg) = 10 (0);
reg: RedFetch(red_reg) = 11 (0);
green_reg: Const = 20 (0);
green_reg: Plus(green_reg,green_reg) = 21 (1);
red_reg: Const = 30 (0);
red_reg: Plus(red_reg,red_reg) = 31 (2);
\end{verbatim}
\caption{A Diverging Tree Grammar\label{fig-diverge-grammar}}
\end{figure}
diverges, since non-terminals \var{green\_reg} and \var{red\_reg}
derive identical infinite trees with different costs. If the cost of
rule 31 is changed to 1, then the grammar does not diverge.
Practical tree grammars describing instruction selection do not
cost-diverge because infinite trees are derived from non-terminals
that model temporary registers. Machines can move data between
different types of registers for a small bounded cost, and the rules
for these instructions prevent divergence. For example, if
\figref{fig-diverge-grammar} included rules to move data between red
and green registers, the grammar would not diverge. If a bonafide
machine grammar appears to make \PROG loop, try a host with more
memory. To apply \PROG to problems other than instruction selection,
be prepared to consult the literature on
cost-divergence~\cite{pelegri-phd}.
\section{Running \PROG\ }\label{sec-man-page}
\PROG reads a tree grammar and writes a \PARSER in C. \PARSER can be
compiled by itself or included in another file. When suitably named
with the \option{p} option, disjoint instances of \PARSER should link
together without name conflicts. The command:
\begin{flushleft}
\var{burg} [ {\it arguments} ] [ {\it file} ]
\end{flushleft}
invokes \PROG. If a {\it file} is named, \PROG expects its grammar
there; otherwise it reads the standard input. The options include:
\def\Empty{}
%
\newcommand\odescr[2]{% #1=option character, #2=optional argument
\gdef\Arg2{#2}%
\item[\option{#1}\ifx\Arg2\Empty\else{{\it #2}}\fi]
}
\begin{description}
%
\odescr{c}{} $N$
Abort if any relative cost exceeds $N$, which keeps \PROG from looping on
diverging grammars. Several
references~\cite{pelegri-popl,henry-budp,balachandran-complang,proebsting-91}
explain relative costs.
%
\odescr{d}{}
Report a few statistics and flag unused rules and terminals.
%
\odescr{o}{} {\it file}
Write parser into {\it file}. Otherwise it writes to the standard output.
%
\odescr{p}{} {\it prefix}
Start exported names with {\it prefix}. The default is \var{burm}.
%
\odescr{t}{}
Generates smaller tables faster, but all goal non-terminals passed to
\var{burm\_rule} must come from an appropriate \var{burm\_nts}. Using
\var{burm\_}$x$\var{\_NT} instead may give unpredictable results.
%
\odescr{I}{}
Emit code for \var{burm\_arity}, \var{burm\_child}, \var{burm\_cost},
\var{burm\_ntname}, \var{burm\_op\_label}, \var{burm\_opname},
\var{burm\_state\_label}, and \var{burm\_string}.
%
\odescr{O}{} $N$
Change the principal cost to $N$. Elements of each cost vector are
numbered from zero.
%
\odescr{=}{}
Compare costs lexicographically, using all costs in the given order.
This option slows \PROG and may produce a larger parser. Increases
range from small to astronomical.
\end{description}
\section{Acknowledgements}
The first \PROG was adapted by the second author from his \CODEGEN
package, which was developed at the University of Washington with
partial support from NSF Grant CCR-88-01806. It was unbundled from
\CODEGEN with the support of Tera Computer. The current \PROG was
written by the third author with the support of NSF grant
CCR-8908355. The interface, documentation, and testing involved
all three authors.
Comments from a large group at the 1991 Dagstuhl Seminar on Code
Generation improved \PROG's interface. Robert Giegerich and Susan
Graham organized the workshop, and the International Conference and
Research Center for Computer Science, Schloss Dagstuhl, provided an
ideal environment for such collaboration. Beta-testers included Helmut
Emmelmann, Dave Hanson, John Hauser, Hugh Redelmeier, and Bill Waite.
\begin{thebibliography}{BMW87}
\bibitem[AGT89]{aho-twig-toplas}
Alfred~V. Aho, Mahadevan Ganapathi, and Steven W.~K. Tjiang.
\newblock Code generation using tree matching and dynamic programming.
\newblock {\em ACM Transactions on Programming Languages and Systems},
11(4):491--516, October 1989.
\bibitem[AJ76]{aho-johnson-dp-classic}
Alfred~V. Aho and Steven~C. Johnson.
\newblock Optimal code generation for expression trees.
\newblock {\em Journal of the ACM}, 23(3):458--501, July 1976.
\bibitem[App87]{appel-87}
Andrew~W. Appel.
\newblock Concise specification of locally optimal code generators.
\newblock Technical report CS-TR-080-87, Princeton University, 1987.
\bibitem[BDB90]{balachandran-complang}
A.~Balachandran, D.~M. Dhamdhere, and S.~Biswas.
\newblock Efficient retargetable code generation using bottom-up tree pattern
matching.
\newblock {\em Computer Languages}, 15(3):127--140, 1990.
\bibitem[BMW87]{wilhelm-tr}
J\"{u}rgen B\"{o}rstler, Ulrich M\"{o}nche, and Reinhard Wilhelm.
\newblock Table compression for tree automata.
\newblock Technical Report Aachener Informatik-Berichte No. 87-12, RWTH Aachen,
Fachgruppe Informatik, Aachen, Fed. Rep. of Germany, 1987.
\bibitem[Cha87]{chase-popl}
David~R. Chase.
\newblock An improvement to bottom up tree pattern matching.
\newblock {\em Fourteenth Annual ACM Symposium on Principles of Programming
Languages}, pages 168--177, January 1987.
\bibitem[FH91]{fraser-henry-spe-91}
Christopher~W. Fraser and Robert~R. Henry.
\newblock Hard-coding bottom-up code generation tables to save time and space.
\newblock {\em Software---Practice\&Experience}, 21(1):1--12, January 1991.
\bibitem[HC86]{hatcher-popl}
Philip~J. Hatcher and Thomas~W. Christopher.
\newblock High-quality code generation via bottom-up tree pattern matching.
\newblock {\em Thirteenth Annual ACM Symposium on Principles of Programming
Languages}, pages 119--130, January 1986.
\bibitem[Hen89]{henry-budp}
Robert~R. Henry.
\newblock Encoding optimal pattern selection in a table-driven bottom-up
tree-pattern matcher.
\newblock Technical Report 89-02-04, University of Washington Computer Science
Department, Seattle, WA, February 1989.
\bibitem[HO82]{hoffmann-jacm}
Christoph Hoffmann and Michael~J. O'Donnell.
\newblock Pattern matching in trees.
\newblock {\em Journal of the ACM}, 29(1):68--95, January 1982.
\bibitem[Kro75]{kron-phd}
H.~H. Kron.
\newblock {\em Tree Templates and Subtree Transformational Grammars}.
\newblock PhD thesis, UC Santa Cruz, December 1975.
\bibitem[PL87]{pelegri-phd}
Eduardo Pelegri-Llopart.
\newblock {\em Tree Transformations in Compiler Systems}.
\newblock PhD thesis, UC Berkeley, December 1987.
\bibitem[PLG88]{pelegri-popl}
Eduardo Pelegri-Llopart and Susan~L. Graham.
\newblock Optimal code generation for expression trees: An application of
{BURS} theory.
\newblock {\em Fifteenth Annual ACM Symposium on Principles of Programming
Languages}, pages 294--308, January 1988.
\bibitem[Pro91]{proebsting-91}
Todd~A. Proebsting.
\newblock Simple and efficient {BURS} table generation.
\newblock Technical report, Department of Computer Sciences, University of
Wisconsin, 1991.
\end{thebibliography}
\end{document}

View File

@ -1,10 +0,0 @@
8/20/02 -- Vikram Adve
be.c: Replaced "char*" with "const char*" to avoid compiler warnings.
9/9/03 -- John Criswell
b.h be.c fe.h gram.y lex.c main.c map.c nontermainl.c plan.c zalloc.c:
A cursory look through our logs and comments indicates that these are
the only modified files. No feature enhancements have been made;
rather, all changes either fix minor programming errors, get rid of
warnings, ANSI-ify the code, or integrate Burg into our build system.

View File

@ -1,28 +0,0 @@
LEVEL = ../../..
TOOLNAME = burg
ExtraSource = gram.tab.c
include $(LEVEL)/Makefile.common
gram.tab.c gram.tab.h:: gram.yc
$(VERB) $(BISON) -o gram.tab.c -d $<
$(SourceDir)/lex.c: gram.tab.h
clean::
rm -rf gram.tab.h gram.tab.c core* *.aux *.log *.dvi sample sample.c tmp
#$(BUILD_OBJ_DIR)/Release/lex.o $(BUILD_OBJ_DIR)/Profile/lex.o $(BUILD_OBJ_DIR)/Debug/lex.o: gram.tab.h
doc.dvi: doc.tex
latex doc; latex doc
test:: $(TOOLEXENAME_G) sample.gr
$(TOOLEXENAME_G) -I <sample.gr >sample.c && $(CC) $(CFLAGS) -o sample sample.c && ./sample
$(TOOLEXENAME_G) -I sample.gr >tmp && cmp tmp sample.c
$(TOOLEXENAME_G) -I <sample.gr -o tmp && cmp tmp sample.c
$(TOOLEXENAME_G) -I sample.gr -o tmp && cmp tmp sample.c
$(TOOLEXENAME_G) -I -O0 <sample.gr >tmp && cmp tmp sample.c
$(TOOLEXENAME_G) -I -= <sample.gr >tmp && cmp tmp sample.c
$(RM) -f tmp sample.c

View File

@ -1,14 +0,0 @@
To format the documentation, type "make doc.dvi" and print the result.
The length of the cost vectors is fixed at 4 for reasons that are
primarily historical. To change it, edit the definition of DELTAWIDTH
in b.h.
Burg is compiled without optimization by default to avoid problems
with initial installation. To improve burg's performance, add '-O' to
CFLAGS in the Makefile and rebuild burg with a high quality optimizing
compiler.
To be added to the Burg mailing list, send your preferred electronic
mail address to cwf@research.att.com.

View File

@ -1,311 +0,0 @@
/* $Id$ */
#define MAX_ARITY 2
typedef int ItemSetNum;
typedef int OperatorNum;
typedef int NonTerminalNum;
typedef int RuleNum;
typedef int ArityNum;
typedef int ERuleNum;
extern NonTerminalNum last_user_nonterminal;
extern NonTerminalNum max_nonterminal;
extern RuleNum max_rule;
extern ERuleNum max_erule_num;
extern int max_arity;
#ifdef __STDC__
#define ARGS(x) x
#else
#define ARGS(x) ()
#endif
#ifndef NOLEX
#define DELTAWIDTH 4
typedef short DeltaCost[DELTAWIDTH];
typedef short *DeltaPtr;
extern void ASSIGNCOST ARGS((DeltaPtr, DeltaPtr));
extern void ADDCOST ARGS((DeltaPtr, DeltaPtr));
extern void MINUSCOST ARGS((DeltaPtr, DeltaPtr));
extern void ZEROCOST ARGS((DeltaPtr));
extern int LESSCOST ARGS((DeltaPtr, DeltaPtr));
extern int EQUALCOST ARGS((DeltaPtr, DeltaPtr));
#define PRINCIPLECOST(x) (x[0])
#else
#define DELTAWIDTH 1
typedef int DeltaCost;
typedef int DeltaPtr;
#define ASSIGNCOST(l, r) ((l) = (r))
#define ADDCOST(l, r) ((l) += (r))
#define MINUSCOST(l, r) ((l) -= (r))
#define ZEROCOST(x) ((x) = 0)
#define LESSCOST(l, r) ((l) < (r))
#define EQUALCOST(l, r) ((l) == (r))
#define PRINCIPLECOST(x) (x)
#endif /* NOLEX */
#define NODIVERGE(c,state,nt,base) if (prevent_divergence > 0) CHECKDIVERGE(c,state,nt,base);
struct list {
void *x;
struct list *next;
};
typedef struct list *List;
struct intlist {
int x;
struct intlist *next;
};
typedef struct intlist *IntList;
struct operator {
char *name;
unsigned int ref:1;
OperatorNum num;
ItemSetNum baseNum;
ItemSetNum stateCount;
ArityNum arity;
struct table *table;
};
typedef struct operator *Operator;
struct nonterminal {
char *name;
NonTerminalNum num;
ItemSetNum baseNum;
ItemSetNum ruleCount;
struct plankMap *pmap;
struct rule *sampleRule; /* diagnostic---gives "a" rule that with this lhs */
};
typedef struct nonterminal *NonTerminal;
struct pattern {
NonTerminal normalizer;
Operator op; /* NULL if NonTerm -> NonTerm */
NonTerminal children[MAX_ARITY];
};
typedef struct pattern *Pattern;
struct rule {
DeltaCost delta;
ERuleNum erulenum;
RuleNum num;
RuleNum newNum;
NonTerminal lhs;
Pattern pat;
unsigned int used:1;
};
typedef struct rule *Rule;
struct item {
DeltaCost delta;
Rule rule;
};
typedef struct item Item;
typedef short *Relevant; /* relevant non-terminals */
typedef Item *ItemArray;
struct item_set { /* indexed by NonTerminal */
ItemSetNum num;
ItemSetNum newNum;
Operator op;
struct item_set *kids[2];
struct item_set *representative;
Relevant relevant;
ItemArray virgin;
ItemArray closed;
};
typedef struct item_set *Item_Set;
#define DIM_MAP_SIZE (1 << 8)
#define GLOBAL_MAP_SIZE (1 << 15)
struct mapping { /* should be a hash table for TS -> int */
List *hash;
int hash_size;
int max_size;
ItemSetNum count;
Item_Set *set; /* map: int <-> Item_Set */
};
typedef struct mapping *Mapping;
struct index_map {
ItemSetNum max_size;
Item_Set *class;
};
typedef struct index_map Index_Map;
struct dimension {
Relevant relevant;
Index_Map index_map;
Mapping map;
ItemSetNum max_size;
struct plankMap *pmap;
};
typedef struct dimension *Dimension;
struct table {
Operator op;
List rules;
Relevant relevant;
Dimension dimen[MAX_ARITY]; /* 1 for each dimension */
Item_Set *transition; /* maps local indices to global
itemsets */
};
typedef struct table *Table;
struct relation {
Rule rule;
DeltaCost chain;
NonTerminalNum nextchain;
DeltaCost sibling;
int sibFlag;
int sibComputed;
};
typedef struct relation *Relation;
struct queue {
List head;
List tail;
};
typedef struct queue *Queue;
struct plank {
char *name;
List fields;
int width;
};
typedef struct plank *Plank;
struct except {
short index;
short value;
};
typedef struct except *Exception;
struct plankMap {
List exceptions;
int offset;
struct stateMap *values;
};
typedef struct plankMap *PlankMap;
struct stateMap {
char *fieldname;
Plank plank;
int width;
short *value;
};
typedef struct stateMap *StateMap;
struct stateMapTable {
List maps;
};
extern void CHECKDIVERGE ARGS((DeltaPtr, Item_Set, int, int));
extern void zero ARGS((Item_Set));
extern ItemArray newItemArray ARGS((void));
extern ItemArray itemArrayCopy ARGS((ItemArray));
extern Item_Set newItem_Set ARGS((Relevant));
extern void freeItem_Set ARGS((Item_Set));
extern Mapping newMapping ARGS((int));
extern NonTerminal newNonTerminal ARGS((char *));
extern int nonTerminalName ARGS((char *, int));
extern Operator newOperator ARGS((char *, OperatorNum, ArityNum));
extern Pattern newPattern ARGS((Operator));
extern Rule newRule ARGS((DeltaPtr, ERuleNum, NonTerminal, Pattern));
extern List newList ARGS((void *, List));
extern IntList newIntList ARGS((int, IntList));
extern int length ARGS((List));
extern List appendList ARGS((void *, List));
extern Table newTable ARGS((Operator));
extern Queue newQ ARGS((void));
extern void addQ ARGS((Queue, Item_Set));
extern Item_Set popQ ARGS((Queue));
extern int equivSet ARGS((Item_Set, Item_Set));
extern Item_Set decode ARGS((Mapping, ItemSetNum));
extern Item_Set encode ARGS((Mapping, Item_Set, int *));
extern void build ARGS((void));
extern Item_Set *transLval ARGS((Table, int, int));
typedef void * (*ListFn) ARGS((void *));
extern void foreachList ARGS((ListFn, List));
extern void reveachList ARGS((ListFn, List));
extern void addToTable ARGS((Table, Item_Set));
extern void closure ARGS((Item_Set));
extern void trim ARGS((Item_Set));
extern void findChainRules ARGS((void));
extern void findAllPairs ARGS((void));
extern void addRelevant ARGS((Relevant, NonTerminalNum));
extern void *zalloc ARGS((unsigned int));
extern void zfree ARGS((void *));
extern NonTerminal start;
extern List rules;
extern List chainrules;
extern List operators;
extern List leaves;
extern List nonterminals;
extern List grammarNts;
extern Queue globalQ;
extern Mapping globalMap;
extern int exceptionTolerance;
extern int prevent_divergence;
extern int principleCost;
extern int lexical;
extern struct rule stub_rule;
extern Relation *allpairs;
extern Item_Set *sortedStates;
extern Item_Set errorState;
extern void dumpRelevant ARGS((Relevant));
extern void dumpOperator ARGS((Operator, int));
extern void dumpOperator_s ARGS((Operator));
extern void dumpOperator_l ARGS((Operator));
extern void dumpNonTerminal ARGS((NonTerminal));
extern void dumpRule ARGS((Rule));
extern void dumpRuleList ARGS((List));
extern void dumpItem ARGS((Item *));
extern void dumpItem_Set ARGS((Item_Set));
extern void dumpMapping ARGS((Mapping));
extern void dumpQ ARGS((Queue));
extern void dumpIndex_Map ARGS((Index_Map *));
extern void dumpDimension ARGS((Dimension));
extern void dumpPattern ARGS((Pattern));
extern void dumpTable ARGS((Table, int));
extern void dumpTransition ARGS((Table));
extern void dumpCost ARGS((DeltaCost));
extern void dumpAllPairs ARGS((void));
extern void dumpRelation ARGS((Relation));
extern void dumpSortedStates ARGS((void));
extern void dumpSortedRules ARGS((void));
extern int debugTrim;
#ifdef DEBUG
#define debug(a,b) if (a) b
#else
#define debug(a,b)
#endif
extern int debugTables;
#define TABLE_INCR 8
#define STATES_INCR 64
#ifdef NDEBUG
#define assert(c) ((void) 0)
#else
#define assert(c) ((void) ((c) || fatal(__FILE__,__LINE__)))
#endif
extern void doStart ARGS((char *));
extern void exit ARGS((int));
extern int fatal ARGS((const char *, int));
extern void yyerror ARGS((const char *));
extern void yyerror1 ARGS((const char *));

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -1,71 +0,0 @@
char rcsid_burs[] = "$Id$";
#include "b.h"
Item_Set errorState;
static void doLeaf ARGS((Operator));
static void
doLeaf(leaf) Operator leaf;
{
int new;
List pl;
Item_Set ts;
Item_Set tmp;
assert(leaf->arity == 0);
ts = newItem_Set(leaf->table->relevant);
for (pl = rules; pl; pl = pl->next) {
Rule p = (Rule) pl->x;
if (p->pat->op == leaf) {
if (!ts->virgin[p->lhs->num].rule || p->delta < ts->virgin[p->lhs->num].delta) {
ts->virgin[p->lhs->num].rule = p;
ASSIGNCOST(ts->virgin[p->lhs->num].delta, p->delta);
ts->op = leaf;
}
}
}
trim(ts);
zero(ts);
tmp = encode(globalMap, ts, &new);
if (new) {
closure(ts);
leaf->table->transition[0] = ts;
addQ(globalQ, ts);
} else {
leaf->table->transition[0] = tmp;
freeItem_Set(ts);
}
}
void
build()
{
int new;
List ol;
Item_Set ts;
globalQ = newQ();
globalMap = newMapping(GLOBAL_MAP_SIZE);
ts = newItem_Set(0);
errorState = encode(globalMap, ts, &new);
ts->closed = ts->virgin;
addQ(globalQ, ts);
foreachList((ListFn) doLeaf, leaves);
debug(debugTables, printf("---initial set of states ---\n"));
debug(debugTables, dumpMapping(globalMap));
debug(debugTables, foreachList((ListFn) dumpItem_Set, globalQ->head));
for (ts = popQ(globalQ); ts; ts = popQ(globalQ)) {
for (ol = operators; ol; ol = ol->next) {
Operator op = (Operator) ol->x;
addToTable(op->table, ts);
}
}
}

View File

@ -1,95 +0,0 @@
char rcsid_closure[] = "$Id$";
#include <stdio.h>
#include "b.h"
int prevent_divergence = 0;
List chainrules;
void
findChainRules()
{
List pl;
assert(!chainrules);
for (pl = rules; pl; pl = pl->next) {
Rule p = (Rule) pl->x;
if (!p->pat->op) {
chainrules = newList(p, chainrules);
} else {
p->pat->op->table->rules = newList(p, p->pat->op->table->rules);
addRelevant(p->pat->op->table->relevant, p->lhs->num);
}
}
}
void
zero(t) Item_Set t;
{
int i;
DeltaCost base;
int exists;
int base_nt;
assert(!t->closed);
ZEROCOST(base);
exists = 0;
for (i = 0; i < max_nonterminal; i++) {
if (t->virgin[i].rule) {
if (exists) {
if (LESSCOST(t->virgin[i].delta, base)) {
ASSIGNCOST(base, t->virgin[i].delta);
base_nt = i;
}
} else {
ASSIGNCOST(base, t->virgin[i].delta);
exists = 1;
base_nt = i;
}
}
}
if (!exists) {
return;
}
for (i = 0; i < max_nonterminal; i++) {
if (t->virgin[i].rule) {
MINUSCOST(t->virgin[i].delta, base);
}
NODIVERGE(t->virgin[i].delta, t, i, base_nt);
}
}
void
closure(t) Item_Set t;
{
int changes;
List pl;
assert(!t->closed);
t->closed = itemArrayCopy(t->virgin);
changes = 1;
while (changes) {
changes = 0;
for (pl = chainrules; pl; pl = pl->next) {
Rule p = (Rule) pl->x;
register Item *rhs_item = &t->closed[p->pat->children[0]->num];
if (rhs_item->rule) { /* rhs is active */
DeltaCost dc;
register Item *lhs_item = &t->closed[p->lhs->num];
ASSIGNCOST(dc, rhs_item->delta);
ADDCOST(dc, p->delta);
if (LESSCOST(dc, lhs_item->delta) || !lhs_item->rule) {
ASSIGNCOST(lhs_item->delta, dc);
lhs_item->rule = p;
changes = 1;
}
}
}
}
}

View File

@ -1,143 +0,0 @@
char rcsid_delta[] = "$Id$";
#include <stdio.h>
#include "b.h"
#include "fe.h"
int principleCost = 0;
int lexical = 0;
#ifndef NOLEX
void
ASSIGNCOST(l, r) DeltaPtr l; DeltaPtr r;
{
int i;
if (lexical) {
for (i = 0; i < DELTAWIDTH; i++) {
l[i] = r[i];
}
} else {
l[0] = r[0];
}
}
void
ADDCOST(l, r) DeltaPtr l; DeltaPtr r;
{
int i;
if (lexical) {
for (i = 0; i < DELTAWIDTH; i++) {
l[i] += r[i];
}
} else {
l[0] += r[0];
}
}
void
MINUSCOST(l, r) DeltaPtr l; DeltaPtr r;
{
int i;
if (lexical) {
for (i = 0; i < DELTAWIDTH; i++) {
l[i] -= r[i];
}
} else {
l[0] -= r[0];
}
}
void
ZEROCOST(x) DeltaPtr x;
{
int i;
if (lexical) {
for (i = 0; i < DELTAWIDTH; i++) {
x[i] = 0;
}
} else {
x[0] = 0;
}
}
int
LESSCOST(l, r) DeltaPtr l; DeltaPtr r;
{
int i;
if (lexical) {
for (i = 0; i < DELTAWIDTH; i++) {
if (l[i] < r[i]) {
return 1;
} else if (l[i] > r[i]) {
return 0;
}
}
return 0;
} else {
return l[0] < r[0];
}
}
int
EQUALCOST(l, r) DeltaPtr l; DeltaPtr r;
{
int i;
if (lexical) {
for (i = 0; i < DELTAWIDTH; i++) {
if (l[i] != r[i]) {
return 0;
}
}
return 1;
} else {
return l[0] == r[0];
}
}
#endif /* NOLEX */
void
CHECKDIVERGE(c, its, nt, base) DeltaPtr c; Item_Set its; int nt; int base;
{
int i;
if (prevent_divergence <= 0) {
return;
}
if (lexical) {
#ifndef NOLEX
for (i = 0; i < DELTAWIDTH; i++) {
if (c[i] > prevent_divergence) {
char ntname[100];
char basename[100];
nonTerminalName(ntname, nt);
nonTerminalName(basename, base);
fprintf(stderr, "ERROR: The grammar appears to diverge\n");
fprintf(stderr, "\tRelative Costs: %s(0), %s(%d)\n", basename, ntname, c[i]);
fprintf(stderr, "\tOffending Operator: %s\n", its->op->name);
fprintf(stderr, "\tOffending Tree: ");
printRepresentative(stderr, its);
fprintf(stderr, "\n");
exit(1);
}
}
#endif /*NOLEX*/
} else if (PRINCIPLECOST(c) > prevent_divergence) {
char ntname[100];
char basename[100];
nonTerminalName(ntname, nt);
nonTerminalName(basename, base);
fprintf(stderr, "ERROR: The grammar appears to diverge\n");
fprintf(stderr, "\tRelative Costs: %s(0), %s(%d)\n", basename, ntname, PRINCIPLECOST(c));
fprintf(stderr, "\tOffending Operator: %s\n", its->op->name);
fprintf(stderr, "\tOffending Tree: ");
printRepresentative(stderr, its);
fprintf(stderr, "\n");
exit(1);
}
}

View File

@ -1,403 +0,0 @@
char rcsid_fe[] = "$Id$";
#include <stdio.h>
#include <string.h>
#include "b.h"
#include "fe.h"
int grammarflag;
static int arity;
List ruleASTs;
List grammarNts;
static void doBinding ARGS((Binding));
static void doDecl ARGS((Arity));
static NonTerminal lookup ARGS((Pattern));
static NonTerminal normalize ARGS((PatternAST, NonTerminal, Pattern *));
static void doEnterNonTerm ARGS((RuleAST));
static void doRule ARGS((RuleAST));
static void doTable ARGS((Operator));
static void
doBinding(b) Binding b;
{
int new;
Symbol s;
s = enter(b->name, &new);
if (!new) {
fprintf(stderr, "Non-unique name: %s\n", b->name);
exit(1);
}
s->tag = OPERATOR;
s->u.op = newOperator(b->name, b->opnum, arity);
if (arity == 0) {
leaves = newList(s->u.op, leaves);
}
}
static void
doDecl(a) Arity a;
{
if (!a) {
return;
}
arity = a->arity;
foreachList((ListFn) doBinding, a->bindings);
}
static List xpatterns;
static int tcount;
static NonTerminal
lookup(p) Pattern p;
{
char buf[10];
char *s;
List l;
NonTerminal n;
DeltaCost dummy;
for (l = xpatterns; l; l = l->next) {
Pattern x = (Pattern) l->x;
if (x->op == p->op
&& x->children[0] == p->children[0]
&& x->children[1] == p->children[1]) {
return x->normalizer;
}
}
sprintf(buf, "n%%%d", tcount++);
s = (char *) zalloc(strlen(buf)+1);
strcpy(s, buf);
n = newNonTerminal(s);
p->normalizer = n;
xpatterns = newList(p, xpatterns);
ZEROCOST(dummy);
(void) newRule(dummy, 0, n, p);
return n;
}
static NonTerminal
normalize(ast, nt, patt) PatternAST ast; NonTerminal nt; Pattern *patt;
{
Symbol s;
int new;
Pattern dummy;
s = enter(ast->op, &new);
ast->sym = s;
if (new) {
fprintf(stderr, "Illegal use of %s --- undefined symbol\n", s->name);
exit(1);
return 0; /* shut up compilers */
} else if (s->tag == NONTERMINAL) {
if (ast->children) {
fprintf(stderr, "Illegal use of %s, a non-terminal, as a terminal\n", s->name);
exit(1);
}
*patt = newPattern(0);
(*patt)->children[0] = s->u.nt;
return s->u.nt;
} else {
s->u.op->ref = 1;
*patt = newPattern(s->u.op);
if (s->u.op->arity == -1) {
if (!ast->children) {
s->u.op->arity = 0;
leaves = newList(s->u.op, leaves);
} else if (!ast->children->next) {
s->u.op->arity = 1;
} else if (!ast->children->next->next) {
s->u.op->arity = 2;
} else {
fprintf(stderr, "ERROR: Too many children (max = 2) for \"%s\"\n", s->name);
exit(1);
}
if (s->u.op->arity > max_arity) {
max_arity = s->u.op->arity;
}
}
switch (s->u.op->arity) {
default:
assert(0);
break;
case 0:
if (ast->children) {
fprintf(stderr, "ERROR: Incorrect number of children for leaf operator, \"%s\"\n", s->name);
exit(1);
}
break;
case 1:
if (!ast->children || ast->children->next) {
fprintf(stderr, "ERROR: Incorrect number of children for unary operator, \"%s\"\n", s->name);
exit(1);
}
(*patt)->children[0] = normalize((PatternAST) ast->children->x, 0, &dummy);
break;
case 2:
if (!ast->children || !ast->children->next) {
fprintf(stderr, "ERROR: Incorrect number of children for binary operator, \"%s\"\n", s->name);
exit(1);
}
(*patt)->children[0] = normalize((PatternAST) ast->children->x, 0, &dummy);
(*patt)->children[1] = normalize((PatternAST) ast->children->next->x, 0, &dummy);
break;
}
if (nt) {
(*patt)->normalizer = nt;
return nt;
} else {
return lookup(*patt);
}
}
}
static void
doEnterNonTerm(ast) RuleAST ast;
{
int new;
Symbol s;
DeltaCost delta;
int i;
IntList p;
s = enter(ast->lhs, &new);
if (new) {
s->u.nt = newNonTerminal(s->name);
s->tag = NONTERMINAL;
} else {
if (s->tag != NONTERMINAL) {
fprintf(stderr, "Illegal use of %s as a non-terminal\n", s->name);
exit(1);
}
}
ZEROCOST(delta);
for (p = ast->cost, i = 0; p; p = p->next, i++) {
int x = p->x;
#ifndef NOLEX
if (lexical) {
if (i < DELTAWIDTH) {
delta[i] = x;
}
} else
#endif /* NOLEX */
{
if (i == principleCost) {
PRINCIPLECOST(delta) = x;
}
}
}
ast->rule = newRule(delta, ast->erulenum, s->u.nt, 0);
}
static void
doRule(ast) RuleAST ast;
{
Pattern pat;
(void) normalize(ast->pat, ast->rule->lhs, &pat);
ast->rule->pat = pat;
}
static void
doTable(op) Operator op;
{
op->table = newTable(op);
}
void
doSpec(decls, rules) List decls; List rules;
{
foreachList((ListFn) doDecl, decls);
debug(debugTables, foreachList((ListFn) dumpOperator_l, operators));
ruleASTs = rules;
reveachList((ListFn) doEnterNonTerm, rules);
last_user_nonterminal = max_nonterminal;
reveachList((ListFn) doRule, rules);
debug(debugTables, foreachList((ListFn) dumpRule, rules));
foreachList((ListFn) doTable, operators);
}
void
doStart(name) char *name;
{
Symbol s;
int new;
if (start) {
yyerror1("Redeclaration of start symbol to be ");
fprintf(stderr, "\"%s\"\n", name);
exit(1);
}
s = enter(name, &new);
if (new) {
s->u.nt = newNonTerminal(s->name);
s->tag = NONTERMINAL;
} else {
if (s->tag != NONTERMINAL) {
fprintf(stderr, "Illegal use of %s as a non-terminal\n", s->name);
exit(1);
}
}
}
void
doGrammarNts()
{
List l;
int new;
for (l = grammarNts; l; l = l->next) {
char *n = (char*) l->x;
Symbol s;
s = enter(n, &new);
if (new) {
fprintf(stderr, "ERROR: %%gram, unused non-terminal: \"%s\"\n", n);
exit(1);
}
if (s->tag != NONTERMINAL) {
fprintf(stderr, "ERROR: %%gram, Not a non-terminal: \"%s\"\n", n);
exit(1);
}
l->x = s;
}
}
void
doGram(nts) List nts;
{
if (grammarNts) {
yyerror1("Redeclaration of %%gram\n");
exit(1);
}
grammarNts = nts;
}
Arity
newArity(ar, b) int ar; List b;
{
Arity a = (Arity) zalloc(sizeof(struct arity));
a->arity = ar;
a->bindings = b;
return a;
}
Binding
newBinding(name, opnum) char *name; int opnum;
{
Binding b = (Binding) zalloc(sizeof(struct binding));
if (opnum == 0) {
yyerror1("ERROR: Non-positive external symbol number, ");
fprintf(stderr, "%d", opnum);
exit(1);
}
b->name = name;
b->opnum = opnum;
return b;
}
PatternAST
newPatternAST(op, children) char *op; List children;
{
PatternAST p = (PatternAST) zalloc(sizeof(struct patternAST));
p->op = op;
p->children = children;
return p;
}
int max_ruleAST;
RuleAST
newRuleAST(lhs, pat, erulenum, cost) char *lhs; PatternAST pat; int erulenum; IntList cost;
{
RuleAST p = (RuleAST) zalloc(sizeof(struct ruleAST));
p->lhs = lhs;
p->pat = pat;
if (erulenum <= 0) {
yyerror1("External Rulenumber ");
fprintf(stderr, "(%d) <= 0\n", erulenum);
exit(1);
}
p->erulenum = erulenum;
p->cost = cost;
max_ruleAST++;
return p;
}
void
dumpBinding(b) Binding b;
{
printf("%s=%d ", b->name, b->opnum);
}
void
dumpArity(a) Arity a;
{
List l;
printf("Arity(%d) ", a->arity);
for (l = a->bindings; l; l = l->next) {
Binding b = (Binding) l->x;
dumpBinding(b);
}
printf("\n");
}
void
dumpPatternAST(p) PatternAST p;
{
List l;
printf("%s", p->op);
if (p->children) {
printf("(");
for (l = p->children; l; l = l->next) {
PatternAST past = (PatternAST) l->x;
dumpPatternAST(past);
if (l->next) {
printf(", ");
}
}
printf(")");
}
}
void
dumpRuleAST(p) RuleAST p;
{
printf("%s : ", p->lhs);
dumpPatternAST(p->pat);
printf(" = %d (%ld)\n", p->erulenum, (long) p->cost);
}
void
dumpDecls(decls) List decls;
{
List l;
for (l = decls; l; l = l->next) {
Arity a = (Arity) l->x;
dumpArity(a);
}
}
void
dumpRules(rules) List rules;
{
List l;
for (l = rules; l; l = l->next) {
RuleAST p = (RuleAST) l->x;
dumpRuleAST(p);
}
}

View File

@ -1,132 +0,0 @@
/* $Id$ */
struct binding {
char *name;
int opnum;
};
typedef struct binding *Binding;
struct arity {
int arity;
List bindings;
};
typedef struct arity *Arity;
struct patternAST {
struct symbol *sym;
char *op;
List children;
};
typedef struct patternAST *PatternAST;
struct ruleAST {
char *lhs;
PatternAST pat;
int erulenum;
IntList cost;
struct rule *rule;
struct strTableElement *kids;
struct strTableElement *nts;
};
typedef struct ruleAST *RuleAST;
typedef enum {
UNKNOWN,
OPERATOR,
NONTERMINAL
} TagType;
struct symbol {
char *name;
TagType tag;
union {
NonTerminal nt;
Operator op;
} u;
};
typedef struct symbol *Symbol;
struct strTableElement {
char *str;
IntList erulenos;
char *ename;
};
typedef struct strTableElement *StrTableElement;
struct strTable {
List elems;
};
typedef struct strTable *StrTable;
extern void doGrammarNts ARGS((void));
void makeRuleDescArray ARGS((void));
void makeDeltaCostArray ARGS((void));
void makeStateStringArray ARGS((void));
extern StrTable newStrTable ARGS((void));
extern StrTableElement addString ARGS((StrTable, char *, int, int *));
extern void doSpec ARGS((List, List));
extern Arity newArity ARGS((int, List));
extern Binding newBinding ARGS((char *, int));
extern PatternAST newPatternAST ARGS((char *, List));
extern RuleAST newRuleAST ARGS((char *, PatternAST, int, IntList));
extern Symbol enter ARGS((char *, int *));
extern Symbol newSymbol ARGS((char *));
extern void makeDebug ARGS((void));
extern void makeSimple ARGS((void));
extern void makePlanks ARGS((void));
extern void makeOpLabel ARGS((void));
extern void makeChild ARGS((void));
extern void makeOperators ARGS((void));
extern void makeLabel ARGS((void));
extern void makeString ARGS((void));
extern void makeString ARGS((void));
extern void makeReduce ARGS((void));
extern void makeRuleTable ARGS((void));
extern void makeTables ARGS((void));
extern void makeTreecost ARGS((void));
extern void makePrint ARGS((void));
extern void makeRule ARGS((void));
extern void makeNts ARGS((void));
extern void makeKids ARGS((void));
extern void startBurm ARGS((void));
extern void startOptional ARGS((void));
extern void makePlankLabel ARGS((void));
extern void makeStateLabel ARGS((void));
extern void makeStringArray ARGS((void));
extern void makeNonterminalArray ARGS((void));
extern void makeCostArray ARGS((void));
extern void makeLHSmap ARGS((void));
extern void makeClosureArray ARGS((void));
extern void makeOperatorVector ARGS((void));
extern void endOptional ARGS((void));
extern void reportDiagnostics ARGS((void));
extern void makeNonterminals ARGS((void));
extern int opsOfArity ARGS((int));
extern void yypurge ARGS((void));
extern void yyfinished ARGS((void));
extern void printRepresentative ARGS((FILE *, Item_Set));
extern void dumpRules ARGS((List));
extern void dumpDecls ARGS((List));
extern void dumpRuleAST ARGS((RuleAST));
extern void dumpPatternAST ARGS((PatternAST));
extern void dumpArity ARGS((Arity));
extern void dumpBinding ARGS((Binding));
extern void dumpStrTable ARGS((StrTable));
extern int yylex ARGS((void));
extern int yyparse ARGS((void));
extern int max_ruleAST;
extern List ruleASTs;
extern FILE *outfile;
extern const char *prefix;
extern int trimflag;
extern int speedflag;
extern int grammarflag;

View File

@ -1,91 +0,0 @@
%{
char rcsid_gram[] = "$Id$";
#include <stdio.h>
#include "b.h"
#include "fe.h"
int doGram(List);
%}
%union {
int y_int;
char *y_string;
Arity y_arity;
Binding y_binding;
PatternAST y_patternAST;
RuleAST y_ruleAST;
List y_list;
IntList y_intlist;
}
%start full
%term ERROR
%term K_TERM
%term K_GRAM
%term K_START
%term K_PPERCENT
%term INT
%term ID
%token <y_string> ID
%token <y_int> INT
%type <y_arity> decl
%type <y_binding> binding
%type <y_intlist> cost costtail
%type <y_ruleAST> rule
%type <y_patternAST> pattern
%type <y_list> decls rules bindinglist grammarlist
%%
full : spec
| spec K_PPERCENT
{ yyfinished(); }
;
spec : decls K_PPERCENT rules
{ doSpec($1, $3); }
;
decls : /* lambda */ { $$ = 0; }
| decls decl { $$ = newList($2, $1); }
;
decl : K_TERM bindinglist { $$ = newArity(-1, $2); }
| K_GRAM grammarlist { $$ = 0; doGram($2); }
| K_START ID { $$ = 0; doStart($2); } /* kludge */
;
grammarlist : /* lambda */ { $$ = 0; }
| grammarlist ID { $$ = newList($2, $1); }
;
bindinglist : /* lambda */ { $$ = 0; }
| bindinglist binding { $$ = newList($2, $1); }
;
binding : ID '=' INT { $$ = newBinding($1, $3); }
;
rules : /* lambda */ { $$ = 0; }
| rules rule { $$ = newList($2, $1); }
;
rule : ID ':' pattern '=' INT cost ';' { $$ = newRuleAST($1, $3, $5, $6); }
;
pattern : ID { $$ = newPatternAST($1, 0); }
| ID '(' pattern ')' { $$ = newPatternAST($1, newList($3,0)); }
| ID '(' pattern ',' pattern ')' { $$ = newPatternAST($1, newList($3, newList($5, 0))); }
;
cost : /* lambda */ { $$ = 0; }
| '(' INT costtail ')' { $$ = newIntList($2, $3); }
;
costtail : /* lambda */ { $$ = 0; }
| ',' INT costtail { $$ = newIntList($2, $3); }
| INT costtail { $$ = newIntList($1, $2); }
;

View File

@ -1,133 +0,0 @@
char rcsid_item[] = "$Id$";
#include "b.h"
#include <stdio.h>
#include <string.h>
#include "fe.h"
static Item_Set fptr;
ItemArray
newItemArray()
{
ItemArray ia;
ia = (ItemArray) zalloc(max_nonterminal *sizeof(*ia));
return ia;
}
ItemArray
itemArrayCopy(src) ItemArray src;
{
ItemArray dst;
dst = newItemArray();
memcpy(dst, src, max_nonterminal * sizeof(*dst));
return dst;
}
Item_Set
newItem_Set(relevant) Relevant relevant;
{
Item_Set ts;
if (fptr) {
ts = fptr;
fptr = 0;
memset(ts->virgin, 0, max_nonterminal * sizeof(struct item));
if (ts->closed) {
zfree(ts->closed);
ts->closed = 0;
}
ts->num = 0;
ts->op = 0;
} else {
ts = (Item_Set) zalloc(sizeof(struct item_set));
ts->virgin = newItemArray();
}
ts->relevant = relevant;
return ts;
}
void
freeItem_Set(ts) Item_Set ts;
{
assert(!fptr);
fptr = ts;
}
int
equivSet(a, b) Item_Set a; Item_Set b;
{
register Relevant r;
register int nt;
register Item *aa = a->virgin;
register Item *ba = b->virgin;
/*
return !bcmp(a->virgin, b->virgin, max_nonterminal * sizeof(Item));
*/
r = a->relevant ? a->relevant : b->relevant;
assert(r);
if (a->op && b->op && a->op != b->op) {
return 0;
}
for (; (nt = *r) != 0; r++) {
if (aa[nt].rule != ba[nt].rule || !EQUALCOST(aa[nt].delta, ba[nt].delta)) {
return 0;
}
}
return 1;
}
void
printRepresentative(f, s) FILE *f; Item_Set s;
{
if (!s) {
return;
}
fprintf(f, "%s", s->op->name);
switch (s->op->arity) {
case 1:
fprintf(f, "(");
printRepresentative(f, s->kids[0]);
fprintf(f, ")");
break;
case 2:
fprintf(f, "(");
printRepresentative(f, s->kids[0]);
fprintf(f, ", ");
printRepresentative(f, s->kids[1]);
fprintf(f, ")");
break;
}
}
void
dumpItem(t) Item *t;
{
printf("[%s #%d]", t->rule->lhs->name, t->rule->num);
dumpCost(t->delta);
}
void
dumpItem_Set(ts) Item_Set ts;
{
int i;
printf("Item_Set #%d: [", ts->num);
for (i = 1; i < max_nonterminal; i++) {
if (ts->virgin[i].rule) {
printf(" %d", i);
dumpCost(ts->virgin[i].delta);
}
}
printf(" ]\n");
}
void
dumpCost(dc) DeltaCost dc;
{
printf("(%ld)", (long) dc);
}

View File

@ -1,259 +0,0 @@
char rcsid_lex[] = "$Id$";
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "b.h"
#include "fe.h"
#include "gram.tab.h"
static char buf[BUFSIZ];
static int yyline = 1;
typedef int (*ReadFn) ARGS((void));
static char *StrCopy ARGS((char *));
static int code_get ARGS((void));
static int simple_get ARGS((void));
static void ReadCharString ARGS((ReadFn, int));
static void ReadCodeBlock ARGS((void));
static void ReadOldComment ARGS((ReadFn));
static char *
StrCopy(s) char *s;
{
char *t = (char *)zalloc(strlen(s) + 1);
strcpy(t,s);
return t;
}
static int
simple_get()
{
int ch;
if ((ch = getchar()) == '\n') {
yyline++;
}
return ch;
}
static int
code_get()
{
int ch;
if ((ch = getchar()) == '\n') {
yyline++;
}
if (ch != EOF) {
fputc(ch, outfile);
}
return ch;
}
void
yypurge()
{
while (code_get() != EOF) ;
}
static void
ReadCharString(rdfn, which) ReadFn rdfn; int which;
{
int ch;
int backslash = 0;
int firstline = yyline;
while ((ch = rdfn()) != EOF) {
if (ch == which && !backslash) {
return;
}
if (ch == '\\' && !backslash) {
backslash = 1;
} else {
backslash = 0;
}
}
yyerror1("Unexpected EOF in string on line ");
fprintf(stderr, "%d\n", firstline);
exit(1);
}
static void
ReadOldComment(rdfn) ReadFn rdfn;
{
/* will not work for comments delimiter in string */
int ch;
int starred = 0;
int firstline = yyline;
while ((ch = rdfn()) != EOF) {
if (ch == '*') {
starred = 1;
} else if (ch == '/' && starred) {
return;
} else {
starred = 0;
}
}
yyerror1("Unexpected EOF in comment on line ");
fprintf(stderr, "%d\n", firstline);
exit(1);
}
static void
ReadCodeBlock()
{
int ch;
int firstline = yyline;
while ((ch = getchar()) != EOF) {
if (ch == '%') {
ch = getchar();
if (ch != '}') {
yyerror("bad %%");
}
return;
}
fputc(ch, outfile);
if (ch == '\n') {
yyline++;
}
if (ch == '"' || ch == '\'') {
ReadCharString(code_get, ch);
} else if (ch == '/') {
ch = getchar();
if (ch == '*') {
fputc(ch, outfile);
ReadOldComment(code_get);
continue;
} else {
ungetc(ch, stdin);
}
}
}
yyerror1("Unclosed block of C code started on line ");
fprintf(stderr, "%d\n", firstline);
exit(1);
}
static int done;
void
yyfinished()
{
done = 1;
}
int
yylex()
{
int ch;
char *ptr = buf;
if (done) return 0;
while ((ch = getchar()) != EOF) {
switch (ch) {
case ' ':
case '\f':
case '\t':
continue;
case '\n':
yyline++;
continue;
case '(':
case ')':
case ',':
case ':':
case ';':
case '=':
return(ch);
case '/':
ch = getchar();
if (ch == '*') {
ReadOldComment(simple_get);
continue;
} else {
ungetc(ch, stdin);
yyerror("illegal char /");
continue;
}
case '%':
ch = getchar();
switch (ch) {
case '%':
return (K_PPERCENT);
case '{':
ReadCodeBlock();
continue;
case 's':
case 'g':
case 't':
do {
if (ptr >= &buf[BUFSIZ]) {
yyerror("ID too long");
return(ERROR);
} else {
*ptr++ = ch;
}
ch = getchar();
} while (isalpha(ch) || isdigit(ch) || ch == '_');
ungetc(ch, stdin);
*ptr = '\0';
if (!strcmp(buf, "term")) return K_TERM;
if (!strcmp(buf, "start")) return K_START;
if (!strcmp(buf, "gram")) return K_GRAM;
yyerror("illegal character after %%");
continue;
default:
yyerror("illegal character after %%");
continue;
}
default:
if (isalpha(ch) ) {
do {
if (ptr >= &buf[BUFSIZ]) {
yyerror("ID too long");
return(ERROR);
} else {
*ptr++ = ch;
}
ch = getchar();
} while (isalpha(ch) || isdigit(ch) || ch == '_');
ungetc(ch, stdin);
*ptr = '\0';
yylval.y_string = StrCopy(buf);
return(ID);
}
if (isdigit(ch)) {
int val=0;
do {
val *= 10;
val += (ch - '0');
ch = getchar();
} while (isdigit(ch));
ungetc(ch, stdin);
yylval.y_int = val;
return(INT);
}
yyerror1("illegal char ");
fprintf(stderr, "(\\%03o)\n", ch);
exit(1);
}
}
return(0);
}
void yyerror1(const char *str)
{
fprintf(stderr, "line %d: %s", yyline, str);
}
void
yyerror(const char *str)
{
yyerror1(str);
fprintf(stderr, "\n");
exit(1);
}

View File

@ -1,75 +0,0 @@
char rcsid_list[] = "$Id$";
#include "b.h"
IntList
newIntList(x, next) int x; IntList next;
{
IntList l;
l = (IntList) zalloc(sizeof(*l));
assert(l);
l->x = x;
l->next = next;
return l;
}
List
newList(x, next) void *x; List next;
{
List l;
l = (List) zalloc(sizeof(*l));
assert(l);
l->x = x;
l->next = next;
return l;
}
List
appendList(x, l) void *x; List l;
{
List last;
List p;
last = 0;
for (p = l; p; p = p->next) {
last = p;
}
if (last) {
last->next = newList(x, 0);
return l;
} else {
return newList(x, 0);
}
}
void
foreachList(f, l) ListFn f; List l;
{
for (; l; l = l->next) {
(*f)(l->x);
}
}
void
reveachList(f, l) ListFn f; List l;
{
if (l) {
reveachList(f, l->next);
(*f)(l->x);
}
}
int
length(l) List l;
{
int c = 0;
for(; l; l = l->next) {
c++;
}
return c;
}

View File

@ -1,182 +0,0 @@
char rcsid_main[] = "$Id$";
#include <math.h>
#include <stdio.h>
#include "b.h"
#include "fe.h"
int debugTables = 0;
static int simpleTables = 0;
static int internals = 0;
static int diagnostics = 0;
static char *inFileName;
static char *outFileName;
static char version[] = "BURG, Version 1.0";
extern int main ARGS((int argc, char **argv));
int
main(argc, argv) int argc; char **argv;
{
int i;
extern int atoi ARGS((char *));
for (i = 1; argv[i]; i++) {
char **needStr = 0;
int *needInt = 0;
if (argv[i][0] == '-') {
switch (argv[i][1]) {
case 'V':
fprintf(stderr, "%s\n", version);
break;
case 'p':
needStr = (char**)&prefix;
break;
case 'o':
needStr = &outFileName;
break;
case 'I':
internals = 1;
break;
case 'T':
simpleTables = 1;
break;
case '=':
#ifdef NOLEX
fprintf(stderr, "'%s' was not compiled to support lexicographic ordering\n", argv[0]);
#else
lexical = 1;
#endif /* NOLEX */
break;
case 'O':
needInt = &principleCost;
break;
case 'c':
needInt = &prevent_divergence;
break;
case 'e':
needInt = &exceptionTolerance;
break;
case 'd':
diagnostics = 1;
break;
case 'S':
speedflag = 1;
break;
case 't':
trimflag = 1;
break;
case 'G':
grammarflag = 1;
break;
default:
fprintf(stderr, "Bad option (%s)\n", argv[i]);
exit(1);
}
} else {
if (inFileName) {
fprintf(stderr, "Unexpected Filename (%s) after (%s)\n", argv[i], inFileName);
exit(1);
}
inFileName = argv[i];
}
if (needInt || needStr) {
char *v;
char *opt = argv[i];
if (argv[i][2]) {
v = &argv[i][2];
} else {
v = argv[++i];
if (!v) {
fprintf(stderr, "Expection argument after %s\n", opt);
exit(1);
}
}
if (needInt) {
*needInt = atoi(v);
} else if (needStr) {
*needStr = v;
}
}
}
if (inFileName) {
if(freopen(inFileName, "r", stdin)==NULL) {
fprintf(stderr, "Failed opening (%s)", inFileName);
exit(1);
}
}
if (outFileName) {
if ((outfile = fopen(outFileName, "w")) == NULL) {
fprintf(stderr, "Failed opening (%s)", outFileName);
exit(1);
}
} else {
outfile = stdout;
}
yyparse();
if (!rules) {
fprintf(stderr, "ERROR: No rules present\n");
exit(1);
}
findChainRules();
findAllPairs();
doGrammarNts();
build();
debug(debugTables, foreachList((ListFn) dumpOperator_l, operators));
debug(debugTables, printf("---final set of states ---\n"));
debug(debugTables, dumpMapping(globalMap));
startBurm();
makeNts();
if (simpleTables) {
makeSimple();
} else {
makePlanks();
}
startOptional();
makeLabel();
makeKids();
if (internals) {
makeChild();
makeOpLabel();
makeStateLabel();
}
endOptional();
makeOperatorVector();
makeNonterminals();
if (internals) {
makeOperators();
makeStringArray();
makeRuleDescArray();
makeCostArray();
makeDeltaCostArray();
makeStateStringArray();
makeNonterminalArray();
/*
makeLHSmap();
*/
}
makeClosureArray();
if (diagnostics) {
reportDiagnostics();
}
yypurge();
exit(0);
}

View File

@ -1,135 +0,0 @@
char rcsid_map[] = "$Id$";
#include <stdio.h>
#include <string.h>
#include "b.h"
#include "fe.h"
Mapping globalMap;
static void growMapping ARGS((Mapping));
static int hash ARGS((Item_Set, int));
Mapping
newMapping(size) int size;
{
Mapping m;
m = (Mapping) zalloc(sizeof(struct mapping));
assert(m);
m->count = 0;
m->hash = (List*) zalloc(size * sizeof(List));
m->hash_size = size;
m->max_size = STATES_INCR;
m->set = (Item_Set*) zalloc(m->max_size * sizeof(Item_Set));
assert(m->set);
return m;
}
static void
growMapping(m) Mapping m;
{
Item_Set *tmp;
m->max_size += STATES_INCR;
tmp = (Item_Set*) zalloc(m->max_size * sizeof(Item_Set));
memcpy(tmp, m->set, m->count * sizeof(Item_Set));
zfree(m->set);
m->set = tmp;
}
static int
hash(ts, mod) Item_Set ts; int mod;
{
register Item *p = ts->virgin;
register int v;
register Relevant r = ts->relevant;
register int nt;
if (!ts->op) {
return 0;
}
v = 0;
for (; (nt = *r) != 0; r++) {
v ^= ((long)p[nt].rule) + (PRINCIPLECOST(p[nt].delta)<<4);
}
v >>= 4;
v &= (mod-1);
return v;
}
Item_Set
encode(m, ts, new) Mapping m; Item_Set ts; int *new;
{
int h;
List l;
assert(m);
assert(ts);
assert(m->count <= m->max_size);
if (grammarNts && errorState && m == globalMap) {
List l;
int found;
found = 0;
for (l = grammarNts; l; l = l->next) {
Symbol s;
s = (Symbol) l->x;
if (ts->virgin[s->u.nt->num].rule) {
found = 1;
break;
}
}
if (!found) {
*new = 0;
return errorState;
}
}
*new = 0;
h = hash(ts, m->hash_size);
for (l = m->hash[h]; l; l = l->next) {
Item_Set s = (Item_Set) l->x;
if (ts->op == s->op && equivSet(ts, s)) {
ts->num = s->num;
return s;
}
}
if (m->count >= m->max_size) {
growMapping(m);
}
assert(m->count < m->max_size);
m->set[m->count] = ts;
ts->num = m->count++;
*new = 1;
m->hash[h] = newList(ts, m->hash[h]);
return ts;
}
Item_Set
decode(m, t) Mapping m; ItemSetNum t;
{
assert(m);
assert(t);
assert(m->count < m->max_size);
assert(t < m->count);
return m->set[t];
}
void
dumpMapping(m) Mapping m;
{
int i;
printf("BEGIN Mapping: Size=%d\n", m->count);
for (i = 0; i < m->count; i++) {
dumpItem_Set(m->set[i]);
}
printf("END Mapping\n");
}

View File

@ -1,49 +0,0 @@
char rcsid_nonterminal[] = "$Id$";
#include "b.h"
#include <stdio.h>
#include <string.h>
NonTerminal start;
NonTerminalNum max_nonterminal = 1;
NonTerminalNum last_user_nonterminal;
List nonterminals;
NonTerminal
newNonTerminal(name) char *name;
{
NonTerminal nt;
nt = (NonTerminal) zalloc(sizeof(struct nonterminal));
assert(nt);
if (max_nonterminal == 1) {
start = nt;
}
nt->name = name;
nt->num = max_nonterminal++;
nonterminals = newList(nt, nonterminals);
return nt;
}
int
nonTerminalName(buf, i) char *buf; int i;
{
List l;
for (l = nonterminals; l; l = l->next) {
NonTerminal nt = (NonTerminal) l->x;
if (nt->num == i) {
strcpy(buf, nt->name);
return 1;
}
}
strcpy(buf, "(Unknown NonTerminal)");
return 0;
}
void
dumpNonTerminal(n) NonTerminal n;
{
printf("%s(%d)", n->name, n->num);
}

View File

@ -1,48 +0,0 @@
char rcsid_operator[] = "$Id$";
#include "b.h"
#include <stdio.h>
int max_arity = -1;
List operators;
List leaves;
Operator
newOperator(name, num, arity) char *name; OperatorNum num; ArityNum arity;
{
Operator op;
assert(arity <= MAX_ARITY);
op = (Operator) zalloc(sizeof(struct operator));
assert(op);
op->name = name;
op->num = num;
op->arity = arity;
operators = newList(op, operators);
return op;
}
void
dumpOperator_s(op) Operator op;
{
printf("Op: %s(%d)=%d\n", op->name, op->arity, op->num);
}
void
dumpOperator(op, full) Operator op; int full;
{
dumpOperator_s(op);
if (full) {
dumpTable(op->table, 0);
}
}
void
dumpOperator_l(op) Operator op;
{
dumpOperator(op, 1);
}

View File

@ -1,38 +0,0 @@
char rcsid_pattern[] = "$Id$";
#include <stdio.h>
#include "b.h"
Pattern
newPattern(op) Operator op;
{
Pattern p;
p = (Pattern) zalloc(sizeof(struct pattern));
p->op = op;
return p;
}
void
dumpPattern(p) Pattern p;
{
int i;
if (!p) {
printf("[no-pattern]");
return;
}
if (p->op) {
printf("%s", p->op->name);
if (p->op->arity > 0) {
printf("(");
for (i = 0; i < p->op->arity; i++) {
printf("%s ", p->children[i]->name);
}
printf(")");
}
} else {
printf("%s", p->children[0]->name);
}
}

View File

@ -1,921 +0,0 @@
char rcsid_plank[] = "$Id$";
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "b.h"
#include "fe.h"
#define ERROR_VAL 0
int speedflag = 0;
Item_Set *sortedStates;
static struct stateMapTable smt;
int exceptionTolerance = 0;
static int plankSize = 32;
static Plank newPlank ARGS((void));
static PlankMap newPlankMap ARGS((int));
static StateMap newStateMap ARGS((void));
static Exception newException ARGS((int, int));
static void enterStateMap ARGS((PlankMap, short *, int, int *));
static List assemblePlanks ARGS((void));
static void assignRules ARGS((RuleAST));
static int stateCompare ARGS((Item_Set *, Item_Set *));
static int ruleCompare ARGS((RuleAST *, RuleAST *));
static void renumber ARGS((void));
static short * newVector ARGS((void));
static int width ARGS((int));
static PlankMap mapToPmap ARGS((Dimension));
static void doDimPmaps ARGS((Operator));
static void doNonTermPmaps ARGS((NonTerminal));
static void makePmaps ARGS((void));
static void outPlank ARGS((Plank));
static void purgePlanks ARGS((List));
static void inToEx ARGS((void));
static void makePlankRuleMacros ARGS((void));
static void makePlankRule ARGS((void));
static void exceptionSwitch ARGS((List, const char *, const char *, const char *, int, const char *));
static void doPlankLabel ARGS((Operator));
static void doPlankLabelSafely ARGS((Operator));
static void doPlankLabelMacrosSafely ARGS((Operator));
static void makePlankState ARGS((void));
static Plank
newPlank()
{
Plank p;
char buf[50];
static int num = 0;
p = (Plank) zalloc(sizeof(struct plank));
sprintf(buf, "%s_plank_%d", prefix, num++);
p->name = (char *) zalloc(strlen(buf)+1);
strcpy(p->name, buf);
return p;
}
static PlankMap
newPlankMap(offset) int offset;
{
PlankMap im;
im = (PlankMap) zalloc(sizeof(struct plankMap));
im->offset = offset;
return im;
}
static StateMap
newStateMap()
{
char buf[50];
static int num = 0;
StateMap sm;
sm = (StateMap) zalloc(sizeof(struct stateMap));
sprintf(buf, "f%d", num++);
sm->fieldname = (char *) zalloc(strlen(buf)+1);
strcpy(sm->fieldname, buf);
return sm;
}
static Exception
newException(index, value) int index; int value;
{
Exception e;
e = (Exception) zalloc(sizeof(struct except));
e->index = index;
e->value = value;
return e;
}
static void
enterStateMap(im, v, width, new) PlankMap im; short * v; int width; int *new;
{
int i;
StateMap sm;
List l;
int size;
assert(im);
assert(v);
assert(width > 0);
size = globalMap->count;
for (l = smt.maps; l; l = l->next) {
int ecount;
sm = (StateMap) l->x;
ecount = 0;
for (i = 0; i < size; i++) {
if (v[i] != -1 && sm->value[i] != -1 && v[i] != sm->value[i]) {
if (++ecount > exceptionTolerance) {
goto again;
}
}
}
for (i = 0; i < size; i++) {
assert(v[i] >= 0);
assert(sm->value[i] >= 0);
if (v[i] == -1) {
continue;
}
if (sm->value[i] == -1) {
sm->value[i] = v[i];
} else if (v[i] != sm->value[i]) {
im->exceptions = newList(newException(i,v[i]), im->exceptions);
}
}
im->values = sm;
if (width > sm->width) {
sm->width = width;
}
*new = 0;
return;
again: ;
}
sm = newStateMap();
im->values = sm;
sm->value = v;
sm->width = width;
*new = 1;
smt.maps = newList(sm, smt.maps);
}
static List
assemblePlanks()
{
List planks = 0;
Plank pl;
List p;
List s;
for (s = smt.maps; s; s = s->next) {
StateMap sm = (StateMap) s->x;
for (p = planks; p; p = p->next) {
pl = (Plank) p->x;
if (sm->width <= plankSize - pl->width) {
pl->width += sm->width;
pl->fields = newList(sm, pl->fields);
sm->plank = pl;
goto next;
}
}
pl = newPlank();
pl->width = sm->width;
pl->fields = newList(sm, 0);
sm->plank = pl;
planks = appendList(pl, planks);
next: ;
}
return planks;
}
RuleAST *sortedRules;
static int count;
static void
assignRules(ast) RuleAST ast;
{
sortedRules[count++] = ast;
}
static int
stateCompare(s, t) Item_Set *s; Item_Set *t;
{
return strcmp((*s)->op->name, (*t)->op->name);
}
static int
ruleCompare(s, t) RuleAST *s; RuleAST *t;
{
return strcmp((*s)->lhs, (*t)->lhs);
}
void
dumpSortedStates()
{
int i;
printf("dump Sorted States: ");
for (i = 0; i < globalMap->count; i++) {
printf("%d ", sortedStates[i]->num);
}
printf("\n");
}
void
dumpSortedRules()
{
int i;
printf("dump Sorted Rules: ");
for (i = 0; i < max_ruleAST; i++) {
printf("%d ", sortedRules[i]->rule->erulenum);
}
printf("\n");
}
static void
renumber()
{
int i;
Operator previousOp;
NonTerminal previousLHS;
int base_counter;
sortedStates = (Item_Set*) zalloc(globalMap->count * sizeof(Item_Set));
for (i = 1; i < globalMap->count; i++) {
sortedStates[i-1] = globalMap->set[i];
}
qsort(sortedStates, globalMap->count-1, sizeof(Item_Set), (int(*)(const void *, const void *))stateCompare);
previousOp = 0;
for (i = 0; i < globalMap->count-1; i++) {
sortedStates[i]->newNum = i;
sortedStates[i]->op->stateCount++;
if (previousOp != sortedStates[i]->op) {
sortedStates[i]->op->baseNum = i;
previousOp = sortedStates[i]->op;
}
}
sortedRules = (RuleAST*) zalloc(max_ruleAST * sizeof(RuleAST));
count = 0;
foreachList((ListFn) assignRules, ruleASTs);
qsort(sortedRules, max_ruleAST, sizeof(RuleAST), (int(*)(const void *, const void *))ruleCompare);
previousLHS = 0;
base_counter = 0;
for (i = 0; i < max_ruleAST; i++) {
if (previousLHS != sortedRules[i]->rule->lhs) {
sortedRules[i]->rule->lhs->baseNum = base_counter;
previousLHS = sortedRules[i]->rule->lhs;
base_counter++; /* make space for 0 */
}
sortedRules[i]->rule->newNum = base_counter;
sortedRules[i]->rule->lhs->ruleCount++;
sortedRules[i]->rule->lhs->sampleRule = sortedRules[i]->rule; /* kludge for diagnostics */
base_counter++;
}
}
static short *
newVector()
{
short *p;
p = (short *) zalloc(globalMap->count* sizeof(short));
return p;
}
static int
width(v) int v;
{
int c;
for (c = 0; v; v >>= 1) {
c++;
}
return c;
}
static PlankMap
mapToPmap(d) Dimension d;
{
PlankMap im;
short *v;
int i;
int new;
if (d->map->count == 1) {
return 0;
}
assert(d->map->count > 1);
im = newPlankMap(0);
v = newVector();
for (i = 0; i < globalMap->count-1; i++) {
int index = d->map->set[d->index_map.class[sortedStates[i]->num]->num]->num;
assert(index >= 0);
v[i+1] = index;
}
v[0] = 0;
enterStateMap(im, v, width(d->map->count), &new);
if (!new) {
zfree(v);
}
return im;
}
static void
doDimPmaps(op) Operator op;
{
int i, j;
Dimension d;
short *v;
PlankMap im;
int new;
if (!op->table->rules) {
return;
}
switch (op->arity) {
case 0:
break;
case 1:
d = op->table->dimen[0];
if (d->map->count > 1) {
v = newVector();
im = newPlankMap(op->baseNum);
for (i = 0; i < globalMap->count-1; i++) {
int index = d->map->set[d->index_map.class[sortedStates[i]->num]->num]->num;
if (index) {
Item_Set *ts = transLval(op->table, index, 0);
v[i+1] = (*ts)->newNum - op->baseNum+1;
assert(v[i+1] >= 0);
}
}
enterStateMap(im, v, width(d->map->count-1), &new);
if (!new) {
zfree(v);
}
d->pmap = im;
}
break;
case 2:
if (op->table->dimen[0]->map->count == 1 && op->table->dimen[1]->map->count == 1) {
op->table->dimen[0]->pmap = 0;
op->table->dimen[1]->pmap = 0;
} else if (op->table->dimen[0]->map->count == 1) {
v = newVector();
im = newPlankMap(op->baseNum);
d = op->table->dimen[1];
for (i = 0; i < globalMap->count-1; i++) {
int index = d->map->set[d->index_map.class[sortedStates[i]->num]->num]->num;
if (index) {
Item_Set *ts = transLval(op->table, 1, index);
v[i+1] = (*ts)->newNum - op->baseNum+1;
assert(v[i+1] >= 0);
}
}
enterStateMap(im, v, width(d->map->count-1), &new);
if (!new) {
zfree(v);
}
d->pmap = im;
} else if (op->table->dimen[1]->map->count == 1) {
v = newVector();
im = newPlankMap(op->baseNum);
d = op->table->dimen[0];
for (i = 0; i < globalMap->count-1; i++) {
int index = d->map->set[d->index_map.class[sortedStates[i]->num]->num]->num;
if (index) {
Item_Set *ts = transLval(op->table, index, 1);
v[i +1] = (*ts)->newNum - op->baseNum +1;
assert(v[i +1] >= 0);
}
}
enterStateMap(im, v, width(d->map->count-1), &new);
if (!new) {
zfree(v);
}
d->pmap = im;
} else {
op->table->dimen[0]->pmap = mapToPmap(op->table->dimen[0]);
op->table->dimen[1]->pmap = mapToPmap(op->table->dimen[1]);
/* output table */
fprintf(outfile, "static unsigned %s %s_%s_transition[%d][%d] = {",
op->stateCount <= 255 ? "char" : "short",
prefix,
op->name,
op->table->dimen[0]->map->count,
op->table->dimen[1]->map->count);
for (i = 0; i < op->table->dimen[0]->map->count; i++) {
if (i > 0) {
fprintf(outfile, ",");
}
fprintf(outfile, "\n{");
for (j = 0; j < op->table->dimen[1]->map->count; j++) {
Item_Set *ts = transLval(op->table, i, j);
short diff;
if (j > 0) {
fprintf(outfile, ",");
if (j % 10 == 0) {
fprintf(outfile, "\t/* row %d, cols %d-%d*/\n",
i,
j-10,
j-1);
}
}
if ((*ts)->num > 0) {
diff = (*ts)->newNum - op->baseNum +1;
} else {
diff = 0;
}
fprintf(outfile, "%5d", diff);
}
fprintf(outfile, "}\t/* row %d */", i);
}
fprintf(outfile, "\n};\n");
}
break;
default:
assert(0);
}
}
static NonTerminal *ntVector;
static void
doNonTermPmaps(n) NonTerminal n;
{
short *v;
PlankMap im;
int new;
int i;
ntVector[n->num] = n;
if (n->num >= last_user_nonterminal) {
return;
}
if (n->ruleCount <= 0) {
return;
}
im = newPlankMap(n->baseNum);
v = newVector();
for (i = 0; i < globalMap->count-1; i++) {
Rule r = globalMap->set[sortedStates[i]->num]->closed[n->num].rule;
if (r) {
r->used = 1;
v[i+1] = r->newNum - n->baseNum /*safely*/;
assert(v[i+1] >= 0);
}
}
enterStateMap(im, v, width(n->ruleCount+1), &new);
if (!new) {
zfree(v);
}
n->pmap = im;
}
static void
makePmaps()
{
foreachList((ListFn) doDimPmaps, operators);
ntVector = (NonTerminal*) zalloc((max_nonterminal) * sizeof(NonTerminal));
foreachList((ListFn) doNonTermPmaps, nonterminals);
}
static void
outPlank(p) Plank p;
{
List f;
int i;
fprintf(outfile, "static struct {\n");
for (f = p->fields; f; f = f->next) {
StateMap sm = (StateMap) f->x;
fprintf(outfile, "\tunsigned int %s:%d;\n", sm->fieldname, sm->width);
}
fprintf(outfile, "} %s[] = {\n", p->name);
for (i = 0; i < globalMap->count; i++) {
fprintf(outfile, "\t{");
for (f = p->fields; f; f = f->next) {
StateMap sm = (StateMap) f->x;
fprintf(outfile, "%4d,", sm->value[i] == -1 ? ERROR_VAL : sm->value[i]);
}
fprintf(outfile, "},\t/* row %d */\n", i);
}
fprintf(outfile, "};\n");
}
static void
purgePlanks(planks) List planks;
{
List p;
for (p = planks; p; p = p->next) {
Plank x = (Plank) p->x;
outPlank(x);
}
}
static void
inToEx()
{
int i;
int counter;
fprintf(outfile, "static short %s_eruleMap[] = {\n", prefix);
counter = 0;
for (i = 0; i < max_ruleAST; i++) {
if (counter > 0) {
fprintf(outfile, ",");
if (counter % 10 == 0) {
fprintf(outfile, "\t/* %d-%d */\n", counter-10, counter-1);
}
}
if (counter < sortedRules[i]->rule->newNum) {
assert(counter == sortedRules[i]->rule->newNum-1);
fprintf(outfile, "%5d", 0);
counter++;
if (counter > 0) {
fprintf(outfile, ",");
if (counter % 10 == 0) {
fprintf(outfile, "\t/* %d-%d */\n", counter-10, counter-1);
}
}
}
fprintf(outfile, "%5d", sortedRules[i]->rule->erulenum);
counter++;
}
fprintf(outfile, "\n};\n");
}
static void
makePlankRuleMacros()
{
int i;
for (i = 1; i < last_user_nonterminal; i++) {
List es;
PlankMap im = ntVector[i]->pmap;
fprintf(outfile, "#define %s_%s_rule(state)\t", prefix, ntVector[i]->name);
if (im) {
fprintf(outfile, "%s_eruleMap[", prefix);
for (es = im->exceptions; es; es = es->next) {
Exception e = (Exception) es->x;
fprintf(outfile, "((state) == %d ? %d :",
e->index, e->value);
}
fprintf(outfile, "%s[state].%s",
im->values->plank->name,
im->values->fieldname);
for (es = im->exceptions; es; es = es->next) {
fprintf(outfile, ")");
}
fprintf(outfile, " +%d]", im->offset);
} else {
/* nonterminal never appears on LHS. */
assert(ntVector[i] == start);
fprintf(outfile, "0");
}
fprintf(outfile, "\n");
}
fprintf(outfile, "\n");
}
static void
makePlankRule()
{
int i;
makePlankRuleMacros();
fprintf(outfile, "#ifdef __STDC__\n");
fprintf(outfile, "int %s_rule(int state, int goalnt) {\n", prefix);
fprintf(outfile, "#else\n");
fprintf(outfile, "int %s_rule(state, goalnt) int state; int goalnt; {\n", prefix);
fprintf(outfile, "#endif\n");
fprintf(outfile,
"\t%s_assert(state >= 0 && state < %d, %s_PANIC(\"Bad state %%d passed to %s_rule\\n\", state));\n",
prefix, globalMap->count, prefix, prefix);
fprintf(outfile, "\tswitch(goalnt) {\n");
for (i = 1; i < last_user_nonterminal; i++) {
fprintf(outfile, "\tcase %d:\n", i);
fprintf(outfile, "\t\treturn %s_%s_rule(state);\n", prefix, ntVector[i]->name);
}
fprintf(outfile, "\tdefault:\n");
fprintf(outfile, "\t\t%s_PANIC(\"Unknown nonterminal %%d in %s_rule;\\n\", goalnt);\n", prefix, prefix);
fprintf(outfile, "\t\tabort();\n");
fprintf(outfile, "\t\treturn 0;\n");
fprintf(outfile, "\t}\n");
fprintf(outfile, "}\n");
}
static void
exceptionSwitch(es, sw, pre, post, offset, def) List es; const char *sw; const char *pre; const char *post; int offset; const char *def;
{
if (es) {
fprintf(outfile, "\t\tswitch (%s) {\n", sw);
for (; es; es = es->next) {
Exception e = (Exception) es->x;
fprintf(outfile, "\t\tcase %d: %s %d; %s\n", e->index, pre, e->value+offset, post);
}
if (def) {
fprintf(outfile, "\t\tdefault: %s;\n", def);
}
fprintf(outfile, "\t\t}\n");
} else {
if (def) {
fprintf(outfile, "\t\t%s;\n", def);
}
}
}
static void
doPlankLabel(op) Operator op;
{
PlankMap im0;
PlankMap im1;
char buf[100];
fprintf(outfile, "\tcase %d:\n", op->num);
switch (op->arity) {
case 0:
fprintf(outfile, "\t\treturn %d;\n", op->table->transition[0]->newNum);
break;
case 1:
im0 = op->table->dimen[0]->pmap;
if (im0) {
exceptionSwitch(im0->exceptions, "l", "return ", "", im0->offset, 0);
fprintf(outfile, "\t\treturn %s[l].%s + %d;\n",
im0->values->plank->name, im0->values->fieldname, im0->offset);
} else {
Item_Set *ts = transLval(op->table, 1, 0);
if (*ts) {
fprintf(outfile, "\t\treturn %d;\n", (*ts)->newNum);
} else {
fprintf(outfile, "\t\treturn %d;\n", ERROR_VAL);
}
}
break;
case 2:
im0 = op->table->dimen[0]->pmap;
im1 = op->table->dimen[1]->pmap;
if (!im0 && !im1) {
Item_Set *ts = transLval(op->table, 1, 1);
if (*ts) {
fprintf(outfile, "\t\treturn %d;\n", (*ts)->newNum);
} else {
fprintf(outfile, "\t\treturn %d;\n", ERROR_VAL);
}
} else if (!im0) {
exceptionSwitch(im1->exceptions, "r", "return ", "", im1->offset, 0);
fprintf(outfile, "\t\treturn %s[r].%s + %d;\n",
im1->values->plank->name, im1->values->fieldname, im1->offset);
} else if (!im1) {
exceptionSwitch(im0->exceptions, "l", "return ", "", im0->offset, 0);
fprintf(outfile, "\t\treturn %s[l].%s + %d;\n",
im0->values->plank->name, im0->values->fieldname, im0->offset);
} else {
assert(im0->offset == 0);
assert(im1->offset == 0);
sprintf(buf, "l = %s[l].%s",
im0->values->plank->name, im0->values->fieldname);
exceptionSwitch(im0->exceptions, "l", "l =", "break;", 0, buf);
sprintf(buf, "r = %s[r].%s",
im1->values->plank->name, im1->values->fieldname);
exceptionSwitch(im1->exceptions, "r", "r =", "break;", 0, buf);
fprintf(outfile, "\t\treturn %s_%s_transition[l][r] + %d;\n",
prefix,
op->name,
op->baseNum);
}
break;
default:
assert(0);
}
}
static void
doPlankLabelMacrosSafely(op) Operator op;
{
PlankMap im0;
PlankMap im1;
switch (op->arity) {
case -1:
fprintf(outfile, "#define %s_%s_state\t0\n", prefix, op->name);
break;
case 0:
fprintf(outfile, "#define %s_%s_state", prefix, op->name);
fprintf(outfile, "\t%d\n", op->table->transition[0]->newNum+1);
break;
case 1:
fprintf(outfile, "#define %s_%s_state(l)", prefix, op->name);
im0 = op->table->dimen[0]->pmap;
if (im0) {
if (im0->exceptions) {
List es = im0->exceptions;
assert(0);
fprintf(outfile, "\t\tswitch (l) {\n");
for (; es; es = es->next) {
Exception e = (Exception) es->x;
fprintf(outfile, "\t\tcase %d: return %d;\n", e->index, e->value ? e->value+im0->offset : 0);
}
fprintf(outfile, "\t\t}\n");
}
if (speedflag) {
fprintf(outfile, "\t( %s[l].%s + %d )\n",
im0->values->plank->name, im0->values->fieldname,
im0->offset);
} else {
fprintf(outfile, "\t( (%s_TEMP = %s[l].%s) ? %s_TEMP + %d : 0 )\n",
prefix,
im0->values->plank->name, im0->values->fieldname,
prefix,
im0->offset);
}
} else {
Item_Set *ts = transLval(op->table, 1, 0);
if (*ts) {
fprintf(outfile, "\t%d\n", (*ts)->newNum+1);
} else {
fprintf(outfile, "\t%d\n", 0);
}
}
break;
case 2:
fprintf(outfile, "#define %s_%s_state(l,r)", prefix, op->name);
im0 = op->table->dimen[0]->pmap;
im1 = op->table->dimen[1]->pmap;
if (!im0 && !im1) {
Item_Set *ts = transLval(op->table, 1, 1);
assert(0);
if (*ts) {
fprintf(outfile, "\t\treturn %d;\n", (*ts)->newNum+1);
} else {
fprintf(outfile, "\t\treturn %d;\n", 0);
}
} else if (!im0) {
assert(0);
if (im1->exceptions) {
List es = im1->exceptions;
fprintf(outfile, "\t\tswitch (r) {\n");
for (; es; es = es->next) {
Exception e = (Exception) es->x;
fprintf(outfile, "\t\tcase %d: return %d;\n", e->index, e->value ? e->value+im1->offset : 0);
}
fprintf(outfile, "\t\t}\n");
}
fprintf(outfile, "\t\tstate = %s[r].%s; offset = %d;\n",
im1->values->plank->name, im1->values->fieldname, im1->offset);
fprintf(outfile, "\t\tbreak;\n");
} else if (!im1) {
assert(0);
if (im0->exceptions) {
List es = im0->exceptions;
fprintf(outfile, "\t\tswitch (l) {\n");
for (; es; es = es->next) {
Exception e = (Exception) es->x;
fprintf(outfile, "\t\tcase %d: return %d;\n", e->index, e->value ? e->value+im0->offset : 0);
}
fprintf(outfile, "\t\t}\n");
}
fprintf(outfile, "\t\tstate = %s[l].%s; offset = %d;\n",
im0->values->plank->name, im0->values->fieldname, im0->offset);
fprintf(outfile, "\t\tbreak;\n");
} else {
assert(im0->offset == 0);
assert(im1->offset == 0);
/*
sprintf(buf, "l = %s[l].%s",
im0->values->plank->name, im0->values->fieldname);
exceptionSwitch(im0->exceptions, "l", "l =", "break;", 0, buf);
sprintf(buf, "r = %s[r].%s",
im1->values->plank->name, im1->values->fieldname);
exceptionSwitch(im1->exceptions, "r", "r =", "break;", 0, buf);
fprintf(outfile, "\t\tstate = %s_%s_transition[l][r]; offset = %d;\n",
prefix,
op->name,
op->baseNum);
fprintf(outfile, "\t\tbreak;\n");
*/
if (speedflag) {
fprintf(outfile, "\t( %s_%s_transition[%s[l].%s][%s[r].%s] + %d)\n",
prefix,
op->name,
im0->values->plank->name, im0->values->fieldname,
im1->values->plank->name, im1->values->fieldname,
op->baseNum);
} else {
fprintf(outfile, "\t( (%s_TEMP = %s_%s_transition[%s[l].%s][%s[r].%s]) ? ",
prefix,
prefix,
op->name,
im0->values->plank->name, im0->values->fieldname,
im1->values->plank->name, im1->values->fieldname);
fprintf(outfile, "%s_TEMP + %d : 0 )\n",
prefix,
op->baseNum);
}
}
break;
default:
assert(0);
}
}
static void
doPlankLabelSafely(op) Operator op;
{
fprintf(outfile, "\tcase %d:\n", op->num);
switch (op->arity) {
case -1:
fprintf(outfile, "\t\treturn 0;\n");
break;
case 0:
fprintf(outfile, "\t\treturn %s_%s_state;\n", prefix, op->name);
break;
case 1:
fprintf(outfile, "\t\treturn %s_%s_state(l);\n", prefix, op->name);
break;
case 2:
fprintf(outfile, "\t\treturn %s_%s_state(l,r);\n", prefix, op->name);
break;
default:
assert(0);
}
}
static void
makePlankState()
{
fprintf(outfile, "\n");
fprintf(outfile, "int %s_TEMP;\n", prefix);
foreachList((ListFn) doPlankLabelMacrosSafely, operators);
fprintf(outfile, "\n");
fprintf(outfile, "#ifdef __STDC__\n");
switch (max_arity) {
case -1:
fprintf(stderr, "ERROR: no terminals in grammar.\n");
exit(1);
case 0:
fprintf(outfile, "int %s_state(int op) {\n", prefix);
fprintf(outfile, "#else\n");
fprintf(outfile, "int %s_state(op) int op; {\n", prefix);
break;
case 1:
fprintf(outfile, "int %s_state(int op, int l) {\n", prefix);
fprintf(outfile, "#else\n");
fprintf(outfile, "int %s_state(op, l) int op; int l; {\n", prefix);
break;
case 2:
fprintf(outfile, "int %s_state(int op, int l, int r) {\n", prefix);
fprintf(outfile, "#else\n");
fprintf(outfile, "int %s_state(op, l, r) int op; int l; int r; {\n", prefix);
break;
default:
assert(0);
}
fprintf(outfile, "#endif\n");
fprintf(outfile, "\tregister int %s_TEMP;\n", prefix);
fprintf(outfile, "#ifndef NDEBUG\n");
fprintf(outfile, "\tswitch (op) {\n");
opsOfArity(2);
if (max_arity >= 2) {
fprintf(outfile,
"\t\t%s_assert(r >= 0 && r < %d, %s_PANIC(\"Bad state %%d passed to %s_state\\n\", r));\n",
prefix, globalMap->count, prefix, prefix);
fprintf(outfile, "\t\t/*FALLTHROUGH*/\n");
}
opsOfArity(1);
if (max_arity > 1) {
fprintf(outfile,
"\t\t%s_assert(l >= 0 && l < %d, %s_PANIC(\"Bad state %%d passed to %s_state\\n\", l));\n",
prefix, globalMap->count, prefix, prefix);
fprintf(outfile, "\t\t/*FALLTHROUGH*/\n");
}
opsOfArity(0);
fprintf(outfile, "\t\tbreak;\n");
fprintf(outfile, "\t}\n");
fprintf(outfile, "#endif\n");
fprintf(outfile, "\tswitch (op) {\n");
fprintf(outfile,"\tdefault: %s_PANIC(\"Unknown op %%d in %s_state\\n\", op); abort(); return 0;\n",
prefix, prefix);
foreachList((ListFn) doPlankLabelSafely, operators);
fprintf(outfile, "\t}\n");
fprintf(outfile, "}\n");
}
void
makePlanks()
{
List planks;
renumber();
makePmaps();
planks = assemblePlanks();
purgePlanks(planks);
inToEx();
makePlankRule();
makePlankState();
}

View File

@ -1,64 +0,0 @@
char rcsid_queue[] = "$Id$";
#include "b.h"
#include <stdio.h>
Queue globalQ;
Queue
newQ()
{
Queue q;
q = (Queue) zalloc(sizeof(struct queue));
assert(q);
q->head = 0;
q->tail = 0;
return q;
}
void
addQ(q, ts) Queue q; Item_Set ts;
{
List qe;
assert(q);
assert(ts);
qe = newList(ts, 0);
if (q->head) {
assert(q->tail);
q->tail->next = qe;
q->tail = qe;
} else {
q->head = q->tail = qe;
}
}
Item_Set
popQ(q) Queue q;
{
List qe;
Item_Set ts;
assert(q);
if (q->head) {
qe = q->head;
q->head = q->head->next;
ts = (Item_Set) qe->x;
zfree(qe);
return ts;
} else {
return 0;
}
}
void
dumpQ(q) Queue q;
{
printf("Begin Queue\n");
foreachList((ListFn)dumpItem_Set, q->head);
printf("End Queue\n");
}

View File

@ -1,49 +0,0 @@
char rcsid_rule[] = "$Id$";
#include "b.h"
#include <stdio.h>
RuleNum max_rule;
int max_erule_num;
struct rule stub_rule;
List rules;
Rule
newRule(delta, erulenum, lhs, pat) DeltaPtr delta; ERuleNum erulenum; NonTerminal lhs; Pattern pat;
{
Rule p;
p = (Rule) zalloc(sizeof(struct rule));
assert(p);
ASSIGNCOST(p->delta, delta);
p->erulenum = erulenum;
if (erulenum > max_erule_num) {
max_erule_num = erulenum;
}
p->num = max_rule++;
p->lhs = lhs;
p->pat = pat;
rules = newList(p, rules);
return p;
}
void
dumpRule(p) Rule p;
{
dumpNonTerminal(p->lhs);
printf(" : ");
dumpPattern(p->pat);
printf(" ");
dumpCost(p->delta);
printf("\n");
}
void
dumpRuleList(l) List l;
{
foreachList((ListFn)dumpRule, l);
}

View File

@ -1,150 +0,0 @@
%{
#include <stdio.h>
typedef struct node *NODEPTR_TYPE;
struct node {
int op, state_label;
NODEPTR_TYPE left, right;
};
#define OP_LABEL(p) ((p)->op)
#define STATE_LABEL(p) ((p)->state_label)
#define LEFT_CHILD(p) ((p)->left)
#define RIGHT_CHILD(p) ((p)->right)
#define PANIC printf
%}
%start reg
%term Assign=1 Constant=2 Fetch=3 Four=4 Mul=5 Plus=6
%%
con: Constant = 1 (0);
con: Four = 2 (0);
addr: con = 3 (0);
addr: Plus(con,reg) = 4 (0);
addr: Plus(con,Mul(Four,reg)) = 5 (0);
reg: Fetch(addr) = 6 (1);
reg: Assign(addr,reg) = 7 (1);
%%
#define Assign 1
#define Constant 2
#define Fetch 3
#define Four 4
#define Mul 5
#define Plus 6
#ifdef __STDC__
#define ARGS(x) x
#else
#define ARGS(x) ()
#endif
NODEPTR_TYPE buildtree ARGS((int, NODEPTR_TYPE, NODEPTR_TYPE));
void printcover ARGS((NODEPTR_TYPE, int, int));
void printtree ARGS((NODEPTR_TYPE));
int treecost ARGS((NODEPTR_TYPE, int, int));
void printMatches ARGS((NODEPTR_TYPE));
int main ARGS((void));
NODEPTR_TYPE buildtree(op, left, right) int op; NODEPTR_TYPE left; NODEPTR_TYPE right; {
NODEPTR_TYPE p;
extern void *malloc ARGS((unsigned));
p = (NODEPTR_TYPE) malloc(sizeof *p);
p->op = op;
p->left = left;
p->right = right;
return p;
}
void printcover(p, goalnt, indent) NODEPTR_TYPE p; int goalnt; int indent; {
int eruleno = burm_rule(STATE_LABEL(p), goalnt);
short *nts = burm_nts[eruleno];
NODEPTR_TYPE kids[10];
int i;
if (eruleno == 0) {
printf("no cover\n");
return;
}
for (i = 0; i < indent; i++)
printf(".");
printf("%s\n", burm_string[eruleno]);
burm_kids(p, eruleno, kids);
for (i = 0; nts[i]; i++)
printcover(kids[i], nts[i], indent+1);
}
void printtree(p) NODEPTR_TYPE p; {
int op = burm_op_label(p);
printf("%s", burm_opname[op]);
switch (burm_arity[op]) {
case 0:
break;
case 1:
printf("(");
printtree(burm_child(p, 0));
printf(")");
break;
case 2:
printf("(");
printtree(burm_child(p, 0));
printf(", ");
printtree(burm_child(p, 1));
printf(")");
break;
}
}
int treecost(p, goalnt, costindex) NODEPTR_TYPE p; int goalnt; int costindex; {
int eruleno = burm_rule(STATE_LABEL(p), goalnt);
int cost = burm_cost[eruleno][costindex], i;
short *nts = burm_nts[eruleno];
NODEPTR_TYPE kids[10];
burm_kids(p, eruleno, kids);
for (i = 0; nts[i]; i++)
cost += treecost(kids[i], nts[i], costindex);
return cost;
}
void printMatches(p) NODEPTR_TYPE p; {
int nt;
int eruleno;
printf("Node 0x%lx= ", (unsigned long)p);
printtree(p);
printf(" matched rules:\n");
for (nt = 1; burm_ntname[nt] != (char*)NULL; nt++)
if ((eruleno = burm_rule(STATE_LABEL(p), nt)) != 0)
printf("\t%s\n", burm_string[eruleno]);
}
main() {
NODEPTR_TYPE p;
p = buildtree(Assign,
buildtree(Constant, 0, 0),
buildtree(Fetch,
buildtree(Plus,
buildtree(Constant, 0, 0),
buildtree(Mul,
buildtree(Four, 0, 0),
buildtree(Fetch, buildtree(Constant, 0, 0), 0)
)
),
0
)
);
printtree(p);
printf("\n\n");
burm_label(p);
printcover(p, 1, 0);
printf("\nCover cost == %d\n\n", treecost(p, 1, 0));
printMatches(p);
return 0;
}

View File

@ -1,65 +0,0 @@
char rcsid_string[] = "$Id$";
#include <stdio.h>
#include <string.h>
#include "b.h"
#include "fe.h"
static StrTableElement newStrTableElement ARGS((void));
StrTable
newStrTable()
{
return (StrTable) zalloc(sizeof(struct strTable));
}
static StrTableElement
newStrTableElement()
{
return (StrTableElement) zalloc(sizeof(struct strTableElement));
}
void
dumpStrTable(t) StrTable t;
{
List e;
IntList r;
printf("Begin StrTable\n");
for (e = t->elems; e; e = e->next) {
StrTableElement el = (StrTableElement) e->x;
printf("%s: ", el->str);
for (r = el->erulenos; r; r = r->next) {
int i = r->x;
printf("(%d)", i);
}
printf("\n");
}
printf("End StrTable\n");
}
StrTableElement
addString(t, s, eruleno, new) StrTable t; char *s; int eruleno; int *new;
{
List l;
StrTableElement ste;
assert(t);
for (l = t->elems; l; l = l->next) {
StrTableElement e = (StrTableElement) l->x;
assert(e);
if (!strcmp(s, e->str)) {
e->erulenos = newIntList(eruleno, e->erulenos);
*new = 0;
return e;
}
}
ste = newStrTableElement();
ste->erulenos = newIntList(eruleno, 0);
ste->str = (char *) zalloc(strlen(s) + 1);
strcpy(ste->str, s);
t->elems = newList(ste, t->elems);
*new = 1;
return ste;
}

View File

@ -1,38 +0,0 @@
char rcsid_symtab[] = "$Id$";
#include <stdio.h>
#include <string.h>
#include "b.h"
#include "fe.h"
static List symtab;
Symbol
newSymbol(name) char *name;
{
Symbol s;
s = (Symbol) zalloc(sizeof(struct symbol));
assert(s);
s->name = name;
return s;
}
Symbol
enter(name, new) char *name; int *new;
{
List l;
Symbol s;
*new = 0;
for (l = symtab; l; l = l->next) {
s = (Symbol) l->x;
if (!strcmp(name, s->name)) {
return s;
}
}
*new = 1;
s = newSymbol(name);
symtab = newList(s, symtab);
return s;
}

View File

@ -1,552 +0,0 @@
char rcsid_table[] = "$Id$";
#include "b.h"
#include <string.h>
#include <stdio.h>
static void growIndex_Map ARGS((Index_Map *));
static Relevant newRelevant ARGS((void));
static Dimension newDimension ARGS((Operator, int));
static void GT_1 ARGS((Table));
static void GT_2_0 ARGS((Table));
static void GT_2_1 ARGS((Table));
static void growTransition ARGS((Table, int));
static Item_Set restrict ARGS((Dimension, Item_Set));
static void addHP_1 ARGS((Table, Item_Set));
static void addHP_2_0 ARGS((Table, Item_Set));
static void addHP_2_1 ARGS((Table, Item_Set));
static void addHyperPlane ARGS((Table, int, Item_Set));
static void
growIndex_Map(r) Index_Map *r;
{
Index_Map new;
new.max_size = r->max_size + STATES_INCR;
new.class = (Item_Set*) zalloc(new.max_size * sizeof(Item_Set));
assert(new.class);
memcpy(new.class, r->class, r->max_size * sizeof(Item_Set));
zfree(r->class);
*r = new;
}
static Relevant
newRelevant()
{
Relevant r = (Relevant) zalloc(max_nonterminal * sizeof(*r));
return r;
}
void
addRelevant(r, nt) Relevant r; NonTerminalNum nt;
{
int i;
for (i = 0; r[i]; i++) {
if (r[i] == nt) {
break;
}
}
if (!r[i]) {
r[i] = nt;
}
}
static Dimension
newDimension(op, index) Operator op; ArityNum index;
{
Dimension d;
List pl;
Relevant r;
assert(op);
assert(index >= 0 && index < op->arity);
d = (Dimension) zalloc(sizeof(struct dimension));
assert(d);
r = d->relevant = newRelevant();
for (pl = rules; pl; pl = pl->next) {
Rule pr = (Rule) pl->x;
if (pr->pat->op == op) {
addRelevant(r, pr->pat->children[index]->num);
}
}
d->index_map.max_size = STATES_INCR;
d->index_map.class = (Item_Set*)
zalloc(d->index_map.max_size * sizeof(Item_Set));
d->map = newMapping(DIM_MAP_SIZE);
d->max_size = TABLE_INCR;
return d;
}
Table
newTable(op) Operator op;
{
Table t;
int i, size;
assert(op);
t = (Table) zalloc(sizeof(struct table));
assert(t);
t->op = op;
for (i = 0; i < op->arity; i++) {
t->dimen[i] = newDimension(op, i);
}
size = 1;
for (i = 0; i < op->arity; i++) {
size *= t->dimen[i]->max_size;
}
t->transition = (Item_Set*) zalloc(size * sizeof(Item_Set));
t->relevant = newRelevant();
assert(t->transition);
return t;
}
static void
GT_1(t) Table t;
{
Item_Set *ts;
ItemSetNum oldsize = t->dimen[0]->max_size;
ItemSetNum newsize = t->dimen[0]->max_size + TABLE_INCR;
t->dimen[0]->max_size = newsize;
ts = (Item_Set*) zalloc(newsize * sizeof(Item_Set));
assert(ts);
memcpy(ts, t->transition, oldsize * sizeof(Item_Set));
zfree(t->transition);
t->transition = ts;
}
static void
GT_2_0(t) Table t;
{
Item_Set *ts;
ItemSetNum oldsize = t->dimen[0]->max_size;
ItemSetNum newsize = t->dimen[0]->max_size + TABLE_INCR;
int size;
t->dimen[0]->max_size = newsize;
size = newsize * t->dimen[1]->max_size;
ts = (Item_Set*) zalloc(size * sizeof(Item_Set));
assert(ts);
memcpy(ts, t->transition, oldsize*t->dimen[1]->max_size * sizeof(Item_Set));
zfree(t->transition);
t->transition = ts;
}
static void
GT_2_1(t) Table t;
{
Item_Set *ts;
ItemSetNum oldsize = t->dimen[1]->max_size;
ItemSetNum newsize = t->dimen[1]->max_size + TABLE_INCR;
int size;
Item_Set *from;
Item_Set *to;
int i1, i2;
t->dimen[1]->max_size = newsize;
size = newsize * t->dimen[0]->max_size;
ts = (Item_Set*) zalloc(size * sizeof(Item_Set));
assert(ts);
from = t->transition;
to = ts;
for (i1 = 0; i1 < t->dimen[0]->max_size; i1++) {
for (i2 = 0; i2 < oldsize; i2++) {
to[i2] = from[i2];
}
to += newsize;
from += oldsize;
}
zfree(t->transition);
t->transition = ts;
}
static void
growTransition(t, dim) Table t; ArityNum dim;
{
assert(t);
assert(t->op);
assert(dim < t->op->arity);
switch (t->op->arity) {
default:
assert(0);
break;
case 1:
GT_1(t);
return;
case 2:
switch (dim) {
default:
assert(0);
break;
case 0:
GT_2_0(t);
return;
case 1:
GT_2_1(t);
return;
}
}
}
static Item_Set
restrict(d, ts) Dimension d; Item_Set ts;
{
DeltaCost base;
Item_Set r;
int found;
register Relevant r_ptr = d->relevant;
register Item *ts_current = ts->closed;
register Item *r_current;
register int i;
register int nt;
ZEROCOST(base);
found = 0;
r = newItem_Set(d->relevant);
r_current = r->virgin;
for (i = 0; (nt = r_ptr[i]) != 0; i++) {
if (ts_current[nt].rule) {
r_current[nt].rule = &stub_rule;
if (!found) {
found = 1;
ASSIGNCOST(base, ts_current[nt].delta);
} else {
if (LESSCOST(ts_current[nt].delta, base)) {
ASSIGNCOST(base, ts_current[nt].delta);
}
}
}
}
/* zero align */
for (i = 0; (nt = r_ptr[i]) != 0; i++) {
if (r_current[nt].rule) {
ASSIGNCOST(r_current[nt].delta, ts_current[nt].delta);
MINUSCOST(r_current[nt].delta, base);
}
}
assert(!r->closed);
r->representative = ts;
return r;
}
static void
addHP_1(t, ts) Table t; Item_Set ts;
{
List pl;
Item_Set e;
Item_Set tmp;
int new;
e = newItem_Set(t->relevant);
assert(e);
e->kids[0] = ts->representative;
for (pl = t->rules; pl; pl = pl->next) {
Rule p = (Rule) pl->x;
if (t->op == p->pat->op && ts->virgin[p->pat->children[0]->num].rule) {
DeltaCost dc;
ASSIGNCOST(dc, ts->virgin[p->pat->children[0]->num].delta);
ADDCOST(dc, p->delta);
if (!e->virgin[p->lhs->num].rule || LESSCOST(dc, e->virgin[p->lhs->num].delta)) {
e->virgin[p->lhs->num].rule = p;
ASSIGNCOST(e->virgin[p->lhs->num].delta, dc);
e->op = t->op;
}
}
}
trim(e);
zero(e);
tmp = encode(globalMap, e, &new);
assert(ts->num < t->dimen[0]->map->max_size);
t->transition[ts->num] = tmp;
if (new) {
closure(e);
addQ(globalQ, tmp);
} else {
freeItem_Set(e);
}
}
static void
addHP_2_0(t, ts) Table t; Item_Set ts;
{
List pl;
register Item_Set e;
Item_Set tmp;
int new;
int i2;
assert(t->dimen[1]->map->count <= t->dimen[1]->map->max_size);
for (i2 = 0; i2 < t->dimen[1]->map->count; i2++) {
e = newItem_Set(t->relevant);
assert(e);
e->kids[0] = ts->representative;
e->kids[1] = t->dimen[1]->map->set[i2]->representative;
for (pl = t->rules; pl; pl = pl->next) {
register Rule p = (Rule) pl->x;
if (t->op == p->pat->op
&& ts->virgin[p->pat->children[0]->num].rule
&& t->dimen[1]->map->set[i2]->virgin[p->pat->children[1]->num].rule){
DeltaCost dc;
ASSIGNCOST(dc, p->delta);
ADDCOST(dc, ts->virgin[p->pat->children[0]->num].delta);
ADDCOST(dc, t->dimen[1]->map->set[i2]->virgin[p->pat->children[1]->num].delta);
if (!e->virgin[p->lhs->num].rule || LESSCOST(dc, e->virgin[p->lhs->num].delta)) {
e->virgin[p->lhs->num].rule = p;
ASSIGNCOST(e->virgin[p->lhs->num].delta, dc);
e->op = t->op;
}
}
}
trim(e);
zero(e);
tmp = encode(globalMap, e, &new);
assert(ts->num < t->dimen[0]->map->max_size);
t->transition[ts->num * t->dimen[1]->max_size + i2] = tmp;
if (new) {
closure(e);
addQ(globalQ, tmp);
} else {
freeItem_Set(e);
}
}
}
static void
addHP_2_1(t, ts) Table t; Item_Set ts;
{
List pl;
register Item_Set e;
Item_Set tmp;
int new;
int i1;
assert(t->dimen[0]->map->count <= t->dimen[0]->map->max_size);
for (i1 = 0; i1 < t->dimen[0]->map->count; i1++) {
e = newItem_Set(t->relevant);
assert(e);
e->kids[0] = t->dimen[0]->map->set[i1]->representative;
e->kids[1] = ts->representative;
for (pl = t->rules; pl; pl = pl->next) {
register Rule p = (Rule) pl->x;
if (t->op == p->pat->op
&& ts->virgin[p->pat->children[1]->num].rule
&& t->dimen[0]->map->set[i1]->virgin[p->pat->children[0]->num].rule){
DeltaCost dc;
ASSIGNCOST(dc, p->delta );
ADDCOST(dc, ts->virgin[p->pat->children[1]->num].delta);
ADDCOST(dc, t->dimen[0]->map->set[i1]->virgin[p->pat->children[0]->num].delta);
if (!e->virgin[p->lhs->num].rule || LESSCOST(dc, e->virgin[p->lhs->num].delta)) {
e->virgin[p->lhs->num].rule = p;
ASSIGNCOST(e->virgin[p->lhs->num].delta, dc);
e->op = t->op;
}
}
}
trim(e);
zero(e);
tmp = encode(globalMap, e, &new);
assert(ts->num < t->dimen[1]->map->max_size);
t->transition[i1 * t->dimen[1]->max_size + ts->num] = tmp;
if (new) {
closure(e);
addQ(globalQ, tmp);
} else {
freeItem_Set(e);
}
}
}
static void
addHyperPlane(t, i, ts) Table t; ArityNum i; Item_Set ts;
{
switch (t->op->arity) {
default:
assert(0);
break;
case 1:
addHP_1(t, ts);
return;
case 2:
switch (i) {
default:
assert(0);
break;
case 0:
addHP_2_0(t, ts);
return;
case 1:
addHP_2_1(t, ts);
return;
}
}
}
void
addToTable(t, ts) Table t; Item_Set ts;
{
ArityNum i;
assert(t);
assert(ts);
assert(t->op);
for (i = 0; i < t->op->arity; i++) {
Item_Set r;
Item_Set tmp;
int new;
r = restrict(t->dimen[i], ts);
tmp = encode(t->dimen[i]->map, r, &new);
if (t->dimen[i]->index_map.max_size <= ts->num) {
growIndex_Map(&t->dimen[i]->index_map);
}
assert(ts->num < t->dimen[i]->index_map.max_size);
t->dimen[i]->index_map.class[ts->num] = tmp;
if (new) {
if (t->dimen[i]->max_size <= r->num) {
growTransition(t, i);
}
addHyperPlane(t, i, r);
} else {
freeItem_Set(r);
}
}
}
Item_Set *
transLval(t, row, col) Table t; int row; int col;
{
switch (t->op->arity) {
case 0:
assert(row == 0);
assert(col == 0);
return t->transition;
case 1:
assert(col == 0);
return t->transition + row;
case 2:
return t->transition + row * t->dimen[1]->max_size + col;
default:
assert(0);
}
return 0;
}
void
dumpRelevant(r) Relevant r;
{
for (; *r; r++) {
printf("%4d", *r);
}
}
void
dumpIndex_Map(r) Index_Map *r;
{
int i;
printf("BEGIN Index_Map: MaxSize (%d)\n", r->max_size);
for (i = 0; i < globalMap->count; i++) {
printf("\t#%d: -> %d\n", i, r->class[i]->num);
}
printf("END Index_Map:\n");
}
void
dumpDimension(d) Dimension d;
{
printf("BEGIN Dimension:\n");
printf("Relevant: ");
dumpRelevant(d->relevant);
printf("\n");
dumpIndex_Map(&d->index_map);
dumpMapping(d->map);
printf("MaxSize of dimension = %d\n", d->max_size);
printf("END Dimension\n");
}
void
dumpTable(t, full) Table t; int full;
{
int i;
if (!t) {
printf("NO Table yet.\n");
return;
}
printf("BEGIN Table:\n");
if (full) {
dumpOperator(t->op, 0);
}
for (i = 0; i < t->op->arity; i++) {
printf("BEGIN dimension(%d)\n", i);
dumpDimension(t->dimen[i]);
printf("END dimension(%d)\n", i);
}
dumpTransition(t);
printf("END Table:\n");
}
void
dumpTransition(t) Table t;
{
int i,j;
switch (t->op->arity) {
case 0:
printf("{ %d }", t->transition[0]->num);
break;
case 1:
printf("{");
for (i = 0; i < t->dimen[0]->map->count; i++) {
if (i > 0) {
printf(",");
}
printf("%5d", t->transition[i]->num);
}
printf("}");
break;
case 2:
printf("{");
for (i = 0; i < t->dimen[0]->map->count; i++) {
if (i > 0) {
printf(",");
}
printf("\n");
printf("{");
for (j = 0; j < t->dimen[1]->map->count; j++) {
Item_Set *ts = transLval(t, i, j);
if (j > 0) {
printf(",");
}
printf("%5d", (*ts)->num);
}
printf("}");
}
printf("\n}\n");
break;
default:
assert(0);
}
}

View File

@ -1,412 +0,0 @@
char rcsid_trim[] = "$Id$";
#include <stdio.h>
#include "b.h"
#include "fe.h"
Relation *allpairs;
int trimflag = 0;
int debugTrim = 0;
static void siblings ARGS((int, int));
static void findAllNexts ARGS((void));
static Relation *newAllPairs ARGS((void));
static void
siblings(i, j) int i; int j;
{
int k;
List pl;
DeltaCost Max;
int foundmax;
allpairs[i][j].sibComputed = 1;
if (i == 1) {
return; /* never trim start symbol */
}
if (i==j) {
return;
}
ZEROCOST(Max);
foundmax = 0;
for (k = 1; k < max_nonterminal; k++) {
DeltaCost tmp;
if (k==i || k==j) {
continue;
}
if (!allpairs[k][i].rule) {
continue;
}
if (!allpairs[k][j].rule) {
return;
}
ASSIGNCOST(tmp, allpairs[k][j].chain);
MINUSCOST(tmp, allpairs[k][i].chain);
if (foundmax) {
if (LESSCOST(Max, tmp)) {
ASSIGNCOST(Max, tmp);
}
} else {
foundmax = 1;
ASSIGNCOST(Max, tmp);
}
}
for (pl = rules; pl; pl = pl->next) {
Rule p = (Rule) pl->x;
Operator op = p->pat->op;
List oprule;
DeltaCost Min;
int foundmin;
if (!op) {
continue;
}
switch (op->arity) {
case 0:
continue;
case 1:
if (!allpairs[p->pat->children[0]->num ][ i].rule) {
continue;
}
foundmin = 0;
for (oprule = op->table->rules; oprule; oprule = oprule->next) {
Rule s = (Rule) oprule->x;
DeltaPtr Cx;
DeltaPtr Csj;
DeltaPtr Cpi;
DeltaCost tmp;
if (!allpairs[p->lhs->num ][ s->lhs->num].rule
|| !allpairs[s->pat->children[0]->num ][ j].rule) {
continue;
}
Cx = allpairs[p->lhs->num ][ s->lhs->num].chain;
Csj= allpairs[s->pat->children[0]->num ][ j].chain;
Cpi= allpairs[p->pat->children[0]->num ][ i].chain;
ASSIGNCOST(tmp, Cx);
ADDCOST(tmp, s->delta);
ADDCOST(tmp, Csj);
MINUSCOST(tmp, Cpi);
MINUSCOST(tmp, p->delta);
if (foundmin) {
if (LESSCOST(tmp, Min)) {
ASSIGNCOST(Min, tmp);
}
} else {
foundmin = 1;
ASSIGNCOST(Min, tmp);
}
}
if (!foundmin) {
return;
}
if (foundmax) {
if (LESSCOST(Max, Min)) {
ASSIGNCOST(Max, Min);
}
} else {
foundmax = 1;
ASSIGNCOST(Max, Min);
}
break;
case 2:
/* do first dimension */
if (allpairs[p->pat->children[0]->num ][ i].rule) {
foundmin = 0;
for (oprule = op->table->rules; oprule; oprule = oprule->next) {
Rule s = (Rule) oprule->x;
DeltaPtr Cx;
DeltaPtr Cb;
DeltaPtr Csj;
DeltaPtr Cpi;
DeltaCost tmp;
if (allpairs[p->lhs->num ][ s->lhs->num].rule
&& allpairs[s->pat->children[0]->num ][ j].rule
&& allpairs[s->pat->children[1]->num ][ p->pat->children[1]->num].rule) {
Cx = allpairs[p->lhs->num ][ s->lhs->num].chain;
Csj= allpairs[s->pat->children[0]->num ][ j].chain;
Cpi= allpairs[p->pat->children[0]->num ][ i].chain;
Cb = allpairs[s->pat->children[1]->num ][ p->pat->children[1]->num].chain;
ASSIGNCOST(tmp, Cx);
ADDCOST(tmp, s->delta);
ADDCOST(tmp, Csj);
ADDCOST(tmp, Cb);
MINUSCOST(tmp, Cpi);
MINUSCOST(tmp, p->delta);
if (foundmin) {
if (LESSCOST(tmp, Min)) {
ASSIGNCOST(Min, tmp);
}
} else {
foundmin = 1;
ASSIGNCOST(Min, tmp);
}
}
}
if (!foundmin) {
return;
}
if (foundmax) {
if (LESSCOST(Max, Min)) {
ASSIGNCOST(Max, Min);
}
} else {
foundmax = 1;
ASSIGNCOST(Max, Min);
}
}
/* do second dimension */
if (allpairs[p->pat->children[1]->num ][ i].rule) {
foundmin = 0;
for (oprule = op->table->rules; oprule; oprule = oprule->next) {
Rule s = (Rule) oprule->x;
DeltaPtr Cx;
DeltaPtr Cb;
DeltaPtr Csj;
DeltaPtr Cpi;
DeltaCost tmp;
if (allpairs[p->lhs->num ][ s->lhs->num].rule
&& allpairs[s->pat->children[1]->num ][ j].rule
&& allpairs[s->pat->children[0]->num ][ p->pat->children[0]->num].rule) {
Cx = allpairs[p->lhs->num ][ s->lhs->num].chain;
Csj= allpairs[s->pat->children[1]->num ][ j].chain;
Cpi= allpairs[p->pat->children[1]->num ][ i].chain;
Cb = allpairs[s->pat->children[0]->num ][ p->pat->children[0]->num].chain;
ASSIGNCOST(tmp, Cx);
ADDCOST(tmp, s->delta);
ADDCOST(tmp, Csj);
ADDCOST(tmp, Cb);
MINUSCOST(tmp, Cpi);
MINUSCOST(tmp, p->delta);
if (foundmin) {
if (LESSCOST(tmp, Min)) {
ASSIGNCOST(Min, tmp);
}
} else {
foundmin = 1;
ASSIGNCOST(Min, tmp);
}
}
}
if (!foundmin) {
return;
}
if (foundmax) {
if (LESSCOST(Max, Min)) {
ASSIGNCOST(Max, Min);
}
} else {
foundmax = 1;
ASSIGNCOST(Max, Min);
}
}
break;
default:
assert(0);
}
}
allpairs[i ][ j].sibFlag = foundmax;
ASSIGNCOST(allpairs[i ][ j].sibling, Max);
}
static void
findAllNexts()
{
int i,j;
int last;
for (i = 1; i < max_nonterminal; i++) {
last = 0;
for (j = 1; j < max_nonterminal; j++) {
if (allpairs[i ][j].rule) {
allpairs[i ][ last].nextchain = j;
last = j;
}
}
}
/*
for (i = 1; i < max_nonterminal; i++) {
last = 0;
for (j = 1; j < max_nonterminal; j++) {
if (allpairs[i ][j].sibFlag) {
allpairs[i ][ last].nextsibling = j;
last = j;
}
}
}
*/
}
static Relation *
newAllPairs()
{
int i;
Relation *rv;
rv = (Relation*) zalloc(max_nonterminal * sizeof(Relation));
for (i = 0; i < max_nonterminal; i++) {
rv[i] = (Relation) zalloc(max_nonterminal * sizeof(struct relation));
}
return rv;
}
void
findAllPairs()
{
List pl;
int changes;
int j;
allpairs = newAllPairs();
for (pl = chainrules; pl; pl = pl->next) {
Rule p = (Rule) pl->x;
NonTerminalNum rhs = p->pat->children[0]->num;
NonTerminalNum lhs = p->lhs->num;
Relation r = &allpairs[lhs ][ rhs];
if (LESSCOST(p->delta, r->chain)) {
ASSIGNCOST(r->chain, p->delta);
r->rule = p;
}
}
for (j = 1; j < max_nonterminal; j++) {
Relation r = &allpairs[j ][ j];
ZEROCOST(r->chain);
r->rule = &stub_rule;
}
changes = 1;
while (changes) {
changes = 0;
for (pl = chainrules; pl; pl = pl->next) {
Rule p = (Rule) pl->x;
NonTerminalNum rhs = p->pat->children[0]->num;
NonTerminalNum lhs = p->lhs->num;
int i;
for (i = 1; i < max_nonterminal; i++) {
Relation r = &allpairs[rhs ][ i];
Relation s = &allpairs[lhs ][ i];
DeltaCost dc;
if (!r->rule) {
continue;
}
ASSIGNCOST(dc, p->delta);
ADDCOST(dc, r->chain);
if (!s->rule || LESSCOST(dc, s->chain)) {
s->rule = p;
ASSIGNCOST(s->chain, dc);
changes = 1;
}
}
}
}
findAllNexts();
}
void
trim(t) Item_Set t;
{
int m,n;
static short *vec = 0;
int last;
assert(!t->closed);
debug(debugTrim, printf("Begin Trim\n"));
debug(debugTrim, dumpItem_Set(t));
last = 0;
if (!vec) {
vec = (short*) zalloc(max_nonterminal * sizeof(*vec));
}
for (m = 1; m < max_nonterminal; m++) {
if (t->virgin[m].rule) {
vec[last++] = m;
}
}
for (m = 0; m < last; m++) {
DeltaCost tmp;
int j;
int i;
i = vec[m];
for (j = allpairs[i ][ 0].nextchain; j; j = allpairs[i ][ j].nextchain) {
if (i == j) {
continue;
}
if (!t->virgin[j].rule) {
continue;
}
ASSIGNCOST(tmp, t->virgin[j].delta);
ADDCOST(tmp, allpairs[i ][ j].chain);
if (!LESSCOST(t->virgin[i].delta, tmp)) {
t->virgin[i].rule = 0;
ZEROCOST(t->virgin[i].delta);
debug(debugTrim, printf("Trimmed Chain (%d,%d)\n", i,j));
goto outer;
}
}
if (!trimflag) {
continue;
}
for (n = 0; n < last; n++) {
j = vec[n];
if (i == j) {
continue;
}
if (!t->virgin[j].rule) {
continue;
}
if (!allpairs[i][j].sibComputed) {
siblings(i,j);
}
if (!allpairs[i][j].sibFlag) {
continue;
}
ASSIGNCOST(tmp, t->virgin[j].delta);
ADDCOST(tmp, allpairs[i ][ j].sibling);
if (!LESSCOST(t->virgin[i].delta, tmp)) {
t->virgin[i].rule = 0;
ZEROCOST(t->virgin[i].delta);
goto outer;
}
}
outer: ;
}
debug(debugTrim, dumpItem_Set(t));
debug(debugTrim, printf("End Trim\n"));
}
void
dumpRelation(r) Relation r;
{
printf("{ %d %ld %d %ld }", r->rule->erulenum, (long) r->chain, r->sibFlag, (long) r->sibling);
}
void
dumpAllPairs()
{
int i,j;
printf("Dumping AllPairs\n");
for (i = 1; i < max_nonterminal; i++) {
for (j = 1; j < max_nonterminal; j++) {
dumpRelation(&allpairs[i ][j]);
}
printf("\n");
}
}

View File

@ -1,35 +0,0 @@
char rcsid_zalloc[] = "$Id$";
#include <stdio.h>
#include <string.h>
#include "b.h"
extern void exit ARGS((int));
extern void free ARGS((void *));
extern void *malloc ARGS((unsigned));
int
fatal(const char *name, int line)
{
fprintf(stderr, "assertion failed: file %s, line %d\n", name, line);
exit(1);
return 0;
}
void *
zalloc(size) unsigned int size;
{
void *t = (void *) malloc(size);
if (!t) {
fprintf(stderr, "Malloc failed---PROGRAM ABORTED\n");
exit(1);
}
memset(t, 0, size);
return t;
}
void
zfree(p) void *p;
{
free(p);
}

View File

@ -1,6 +0,0 @@
LEVEL = ../..
DIRS = Burg TableGen
include $(LEVEL)/Makefile.common

View File

@ -1,217 +0,0 @@
//===- CodeEmitterGen.cpp - Code Emitter Generator ------------------------===//
//
// FIXME: Document.
//
//===----------------------------------------------------------------------===//
#include "CodeEmitterGen.h"
#include "Record.h"
#include "Support/Debug.h"
void CodeEmitterGen::run(std::ostream &o) {
std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction");
EmitSourceFileHeader("Machine Code Emitter", o);
std::string Namespace = "V9::";
std::string ClassName = "SparcV9CodeEmitter::";
//const std::string &Namespace = Inst->getValue("Namespace")->getName();
o << "unsigned " << ClassName
<< "getBinaryCodeForInstr(MachineInstr &MI) {\n"
<< " unsigned Value = 0;\n"
<< " DEBUG(std::cerr << MI);\n"
<< " switch (MI.getOpcode()) {\n";
for (std::vector<Record*>::iterator I = Insts.begin(), E = Insts.end();
I != E; ++I) {
Record *R = *I;
o << " case " << Namespace << R->getName() << ": {\n"
<< " DEBUG(std::cerr << \"Emitting " << R->getName() << "\\n\");\n";
BitsInit *BI = R->getValueAsBitsInit("Inst");
unsigned Value = 0;
const std::vector<RecordVal> &Vals = R->getValues();
DEBUG(o << " // prefilling: ");
// Start by filling in fixed values...
for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i) {
if (BitInit *B = dynamic_cast<BitInit*>(BI->getBit(e-i-1))) {
Value |= B->getValue() << (e-i-1);
DEBUG(o << B->getValue());
} else {
DEBUG(o << "0");
}
}
DEBUG(o << "\n");
DEBUG(o << " // " << *R->getValue("Inst") << "\n");
o << " Value = " << Value << "U;\n\n";
// Loop over all of the fields in the instruction determining which are the
// operands to the instruction.
//
unsigned op = 0;
std::map<std::string, unsigned> OpOrder;
std::map<std::string, bool> OpContinuous;
for (unsigned i = 0, e = Vals.size(); i != e; ++i) {
if (!Vals[i].getPrefix() && !Vals[i].getValue()->isComplete()) {
// Is the operand continuous? If so, we can just mask and OR it in
// instead of doing it bit-by-bit, saving a lot in runtime cost.
const BitsInit *InstInit = BI;
int beginBitInVar = -1, endBitInVar = -1;
int beginBitInInst = -1, endBitInInst = -1;
bool continuous = true;
for (int bit = InstInit->getNumBits()-1; bit >= 0; --bit) {
if (VarBitInit *VBI =
dynamic_cast<VarBitInit*>(InstInit->getBit(bit))) {
TypedInit *TI = VBI->getVariable();
if (VarInit *VI = dynamic_cast<VarInit*>(TI)) {
// only process the current variable
if (VI->getName() != Vals[i].getName())
continue;
if (beginBitInVar == -1)
beginBitInVar = VBI->getBitNum();
if (endBitInVar == -1)
endBitInVar = VBI->getBitNum();
else {
if (endBitInVar == (int)VBI->getBitNum() + 1)
endBitInVar = VBI->getBitNum();
else {
continuous = false;
break;
}
}
if (beginBitInInst == -1)
beginBitInInst = bit;
if (endBitInInst == -1)
endBitInInst = bit;
else {
if (endBitInInst == bit + 1)
endBitInInst = bit;
else {
continuous = false;
break;
}
}
// maintain same distance between bits in field and bits in
// instruction. if the relative distances stay the same
// throughout,
if (beginBitInVar - (int)VBI->getBitNum() !=
beginBitInInst - bit) {
continuous = false;
break;
}
}
}
}
// If we have found no bit in "Inst" which comes from this field, then
// this is not an operand!!
if (beginBitInInst != -1) {
o << " // op" << op << ": " << Vals[i].getName() << "\n"
<< " int64_t op" << op
<<" = getMachineOpValue(MI, MI.getOperand("<<op<<"));\n";
//<< " MachineOperand &op" << op <<" = MI.getOperand("<<op<<");\n";
OpOrder[Vals[i].getName()] = op++;
DEBUG(o << " // Var: begin = " << beginBitInVar
<< ", end = " << endBitInVar
<< "; Inst: begin = " << beginBitInInst
<< ", end = " << endBitInInst << "\n");
if (continuous) {
DEBUG(o << " // continuous: op" << OpOrder[Vals[i].getName()]
<< "\n");
// Mask off the right bits
// Low mask (ie. shift, if necessary)
assert(endBitInVar >= 0 && "Negative shift amount in masking!");
if (endBitInVar != 0) {
o << " op" << OpOrder[Vals[i].getName()]
<< " >>= " << endBitInVar << ";\n";
beginBitInVar -= endBitInVar;
endBitInVar = 0;
}
// High mask
o << " op" << OpOrder[Vals[i].getName()]
<< " &= (1<<" << beginBitInVar+1 << ") - 1;\n";
// Shift the value to the correct place (according to place in inst)
assert(endBitInInst >= 0 && "Negative shift amount in inst position!");
if (endBitInInst != 0)
o << " op" << OpOrder[Vals[i].getName()]
<< " <<= " << endBitInInst << ";\n";
// Just OR in the result
o << " Value |= op" << OpOrder[Vals[i].getName()] << ";\n";
}
// otherwise, will be taken care of in the loop below using this
// value:
OpContinuous[Vals[i].getName()] = continuous;
}
}
}
for (unsigned f = 0, e = Vals.size(); f != e; ++f) {
if (Vals[f].getPrefix()) {
BitsInit *FieldInitializer = (BitsInit*)Vals[f].getValue();
// Scan through the field looking for bit initializers of the current
// variable...
for (int i = FieldInitializer->getNumBits()-1; i >= 0; --i) {
if (BitInit *BI = dynamic_cast<BitInit*>(FieldInitializer->getBit(i)))
{
DEBUG(o << " // bit init: f: " << f << ", i: " << i << "\n");
} else if (UnsetInit *UI =
dynamic_cast<UnsetInit*>(FieldInitializer->getBit(i))) {
DEBUG(o << " // unset init: f: " << f << ", i: " << i << "\n");
} else if (VarBitInit *VBI =
dynamic_cast<VarBitInit*>(FieldInitializer->getBit(i))) {
TypedInit *TI = VBI->getVariable();
if (VarInit *VI = dynamic_cast<VarInit*>(TI)) {
// If the bits of the field are laid out consecutively in the
// instruction, then instead of separately ORing in bits, just
// mask and shift the entire field for efficiency.
if (OpContinuous[VI->getName()]) {
// already taken care of in the loop above, thus there is no
// need to individually OR in the bits
// for debugging, output the regular version anyway, commented
DEBUG(o << " // Value |= getValueBit(op"
<< OpOrder[VI->getName()] << ", " << VBI->getBitNum()
<< ")" << " << " << i << ";\n");
} else {
o << " Value |= getValueBit(op" << OpOrder[VI->getName()]
<< ", " << VBI->getBitNum()
<< ")" << " << " << i << ";\n";
}
} else if (FieldInit *FI = dynamic_cast<FieldInit*>(TI)) {
// FIXME: implement this!
o << "FIELD INIT not implemented yet!\n";
} else {
o << "Error: UNIMPLEMENTED\n";
}
}
}
}
}
o << " break;\n"
<< " }\n";
}
o << " default:\n"
<< " std::cerr << \"Not supported instr: \" << MI << \"\\n\";\n"
<< " abort();\n"
<< " }\n"
<< " return Value;\n"
<< "}\n";
}

View File

@ -1,24 +0,0 @@
//===- CodeEmitterGen.h - Code Emitter Generator ----------------*- C++ -*-===//
//
// FIXME: document
//
//===----------------------------------------------------------------------===//
#ifndef CODEMITTERGEN_H
#define CODEMITTERGEN_H
#include "TableGenBackend.h"
class CodeEmitterGen : public TableGenBackend {
RecordKeeper &Records;
public:
CodeEmitterGen(RecordKeeper &R) : Records(R) {}
// run - Output the code emitter
void run(std::ostream &o);
private:
void emitMachineOpEmitter(std::ostream &o, const std::string &Namespace);
void emitGetValueBit(std::ostream &o, const std::string &Namespace);
};
#endif

View File

@ -1,89 +0,0 @@
//===- CodeGenWrappers.cpp - Code Generation Class Wrappers -----*- C++ -*-===//
//
// These classes wrap target description classes used by the various code
// generation TableGen backends. This makes it easier to access the data and
// provides a single place that needs to check it for validity. All of these
// classes throw exceptions on error conditions.
//
//===----------------------------------------------------------------------===//
#include "CodeGenWrappers.h"
#include "Record.h"
/// getValueType - Return the MCV::ValueType that the specified TableGen record
/// corresponds to.
MVT::ValueType getValueType(Record *Rec) {
return (MVT::ValueType)Rec->getValueAsInt("Value");
}
std::string getName(MVT::ValueType T) {
switch (T) {
case MVT::Other: return "UNKNOWN";
case MVT::i1: return "i1";
case MVT::i8: return "i8";
case MVT::i16: return "i16";
case MVT::i32: return "i32";
case MVT::i64: return "i64";
case MVT::i128: return "i128";
case MVT::f32: return "f32";
case MVT::f64: return "f64";
case MVT::f80: return "f80";
case MVT::f128: return "f128";
case MVT::isVoid:return "void";
default: assert(0 && "ILLEGAL VALUE TYPE!"); return "";
}
}
std::string getEnumName(MVT::ValueType T) {
switch (T) {
case MVT::Other: return "Other";
case MVT::i1: return "i1";
case MVT::i8: return "i8";
case MVT::i16: return "i16";
case MVT::i32: return "i32";
case MVT::i64: return "i64";
case MVT::i128: return "i128";
case MVT::f32: return "f32";
case MVT::f64: return "f64";
case MVT::f80: return "f80";
case MVT::f128: return "f128";
case MVT::isVoid:return "isVoid";
default: assert(0 && "ILLEGAL VALUE TYPE!"); return "";
}
}
std::ostream &operator<<(std::ostream &OS, MVT::ValueType T) {
return OS << getName(T);
}
/// getTarget - Return the current instance of the Target class.
///
CodeGenTarget::CodeGenTarget() {
std::vector<Record*> Targets = Records.getAllDerivedDefinitions("Target");
if (Targets.size() != 1)
throw std::string("ERROR: Multiple subclasses of Target defined!");
TargetRec = Targets[0];
// Read in all of the CalleeSavedRegisters...
ListInit *LI = TargetRec->getValueAsListInit("CalleeSavedRegisters");
for (unsigned i = 0, e = LI->getSize(); i != e; ++i)
if (DefInit *DI = dynamic_cast<DefInit*>(LI->getElement(i)))
CalleeSavedRegisters.push_back(DI->getDef());
else
throw "Target: " + TargetRec->getName() +
" expected register definition in CalleeSavedRegisters list!";
PointerType = getValueType(TargetRec->getValueAsDef("PointerType"));
}
const std::string &CodeGenTarget::getName() const {
return TargetRec->getName();
}
Record *CodeGenTarget::getInstructionSet() const {
return TargetRec->getValueAsDef("InstructionSet");
}

View File

@ -1,56 +0,0 @@
//===- CodeGenWrappers.h - Code Generation Class Wrappers -------*- C++ -*-===//
//
// These classes wrap target description classes used by the various code
// generation TableGen backends. This makes it easier to access the data and
// provides a single place that needs to check it for validity. All of these
// classes throw exceptions on error conditions.
//
//===----------------------------------------------------------------------===//
#ifndef CODEGENWRAPPERS_H
#define CODEGENWRAPPERS_H
#include "llvm/CodeGen/ValueTypes.h"
#include <iosfwd>
#include <string>
#include <vector>
class Record;
class RecordKeeper;
/// getValueType - Return the MVT::ValueType that the specified TableGen record
/// corresponds to.
MVT::ValueType getValueType(Record *Rec);
std::ostream &operator<<(std::ostream &OS, MVT::ValueType T);
std::string getName(MVT::ValueType T);
std::string getEnumName(MVT::ValueType T);
/// CodeGenTarget - This class corresponds to the Target class in the .td files.
///
class CodeGenTarget {
Record *TargetRec;
std::vector<Record*> CalleeSavedRegisters;
MVT::ValueType PointerType;
public:
CodeGenTarget();
Record *getTargetRecord() const { return TargetRec; }
const std::string &getName() const;
const std::vector<Record*> &getCalleeSavedRegisters() const {
return CalleeSavedRegisters;
}
MVT::ValueType getPointerType() const { return PointerType; }
// getInstructionSet - Return the InstructionSet object...
Record *getInstructionSet() const;
// getInstructionSet - Return the CodeGenInstructionSet object for this
// target, lazily reading it from the record keeper as needed.
// CodeGenInstructionSet *getInstructionSet -
};
#endif

View File

@ -1,222 +0,0 @@
/*===-- FileLexer.l - Scanner for TableGen Files ----------------*- C++ -*-===//
//
// This file defines a simple flex scanner for TableGen files. This is pretty
// straight-forward, except for the magic to handle file inclusion.
//
//===----------------------------------------------------------------------===*/
%option prefix="File"
%option yylineno
%option nostdinit
%option never-interactive
%option batch
%option nodefault
%option 8bit
%option outfile="Lexer.cpp"
%option ecs
%option noreject
%option noyymore
%x comment
%{
#include "Record.h"
typedef std::pair<Record*, std::vector<Init*>*> SubClassRefTy;
#include "FileParser.h"
// Global variable recording the location of the include directory
std::string IncludeDirectory;
// ParseInt - This has to handle the special case of binary numbers 0b0101
static int ParseInt(const char *Str) {
if (Str[0] == '0' && Str[1] == 'b')
return strtol(Str+2, 0, 2);
return strtol(Str, 0, 0);
}
static int CommentDepth = 0;
struct IncludeRec {
std::string Filename;
FILE *File;
unsigned LineNo;
YY_BUFFER_STATE Buffer;
IncludeRec(const std::string &FN, FILE *F)
: Filename(FN), File(F), LineNo(0){
}
};
static std::vector<IncludeRec> IncludeStack;
std::ostream &err() {
if (IncludeStack.empty())
return std::cerr << "At end of input: ";
for (unsigned i = 0, e = IncludeStack.size()-1; i != e; ++i)
std::cerr << "Included from " << IncludeStack[i].Filename << ":"
<< IncludeStack[i].LineNo << ":\n";
return std::cerr << "Parsing " << IncludeStack.back().Filename << ":"
<< Filelineno << ": ";
}
int Fileparse();
//
// Function: ParseFile()
//
// Description:
// This function begins the parsing of the specified tablegen file.
//
// Inputs:
// Filename - A string containing the name of the file to parse.
// IncludeDir - A string containing the directory from which include
// files can be found.
//
void ParseFile(const std::string &Filename, const std::string & IncludeDir) {
FILE *F = stdin;
if (Filename != "-") {
F = fopen(Filename.c_str(), "r");
if (F == 0) {
std::cerr << "Could not open input file '" + Filename + "'!\n";
exit (1);
}
IncludeStack.push_back(IncludeRec(Filename, F));
} else {
IncludeStack.push_back(IncludeRec("<stdin>", stdin));
}
//
// Record the location of the include directory so that the lexer can find
// it later.
//
IncludeDirectory = IncludeDir;
Filein = F;
Filelineno = 1;
Fileparse();
Filein = stdin;
}
// HandleInclude - This function is called when an include directive is
// encountered in the input stream...
static void HandleInclude(const char *Buffer) {
unsigned Length = yyleng;
assert(Buffer[Length-1] == '"');
Buffer += strlen("include ");
Length -= strlen("include ");
while (*Buffer != '"') {
++Buffer;
--Length;
}
assert(Length >= 2 && "Double quotes not found?");
std::string Filename(Buffer+1, Buffer+Length-1);
//std::cerr << "Filename = '" << Filename << "'\n";
// Save the line number and lex buffer of the includer...
IncludeStack.back().LineNo = Filelineno;
IncludeStack.back().Buffer = YY_CURRENT_BUFFER;
// Open the new input file...
yyin = fopen(Filename.c_str(), "r");
if (yyin == 0) {
//
// If we couldn't find the file in the current directory, look for it in
// the include directories.
//
// NOTE:
// Right now, there is only one directory. We need to eventually add
// support for more.
//
Filename = IncludeDirectory + "/" + Filename;
yyin = fopen(Filename.c_str(), "r");
if (yyin == 0) {
err() << "Could not find include file '" << Filename << "'!\n";
abort();
}
}
// Add the file to our include stack...
IncludeStack.push_back(IncludeRec(Filename, yyin));
Filelineno = 1; // Reset line numbering...
//yyrestart(yyin); // Start lexing the new file...
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
}
// yywrap - This is called when the lexer runs out of input in one of the files.
// Switch back to an includer if an includee has run out of input.
//
extern "C"
int yywrap() {
if (IncludeStack.back().File != stdin)
fclose(IncludeStack.back().File);
IncludeStack.pop_back();
if (IncludeStack.empty()) return 1; // Top-level file is done.
// Otherwise, we need to switch back to a file which included the current one.
Filelineno = IncludeStack.back().LineNo; // Restore current line number
yy_switch_to_buffer(IncludeStack.back().Buffer);
return 0;
}
%}
Comment \/\/.*
Identifier [a-zA-Z_][0-9a-zA-Z_]*
Integer [-+]?[0-9]+|0x[0-9a-fA-F]+|0b[01]+
CodeFragment \[\{([^}]+|\}[^\]])*\}\]
StringVal \"[^"]*\"
IncludeStr include[ \t\n]+\"[^"]*\"
%%
{Comment} { /* Ignore comments */ }
{IncludeStr} { HandleInclude(yytext); }
{CodeFragment} { Filelval.StrVal = new std::string(yytext+2, yytext+yyleng-2);
return CODEFRAGMENT; }
int { return INT; }
bit { return BIT; }
bits { return BITS; }
string { return STRING; }
list { return LIST; }
code { return CODE; }
dag { return DAG; }
class { return CLASS; }
def { return DEF; }
field { return FIELD; }
let { return LET; }
in { return IN; }
{Identifier} { Filelval.StrVal = new std::string(yytext, yytext+yyleng);
return ID; }
${Identifier} { Filelval.StrVal = new std::string(yytext+1, yytext+yyleng);
return VARNAME; }
{StringVal} { Filelval.StrVal = new std::string(yytext+1, yytext+yyleng-1);
return STRVAL; }
{Integer} { Filelval.IntVal = ParseInt(Filetext); return INTVAL; }
[ \t\n]+ { /* Ignore whitespace */ }
"/*" { BEGIN(comment); CommentDepth++; }
<comment>[^*/]* /* eat anything that's not a '*' or '/' */
<comment>"*"+[^*/]* /* eat up '*'s not followed by '/'s */
<comment>"/*" { ++CommentDepth; }
<comment>"/"+[^*]* /* eat up /'s not followed by *'s */
<comment>"*"+"/" { if (!--CommentDepth) { BEGIN(INITIAL); } }
<comment><<EOF>> { err() << "Unterminated comment!\n"; abort(); }
. { return Filetext[0]; }
%%

View File

@ -1,510 +0,0 @@
//===-- FileParser.y - Parser for TableGen files ----------------*- C++ -*-===//
//
// This file implements the bison parser for Table Generator files...
//
//===------------------------------------------------------------------------=//
%{
#include "Record.h"
#include "Support/StringExtras.h"
#include <algorithm>
#include <cstdio>
#define YYERROR_VERBOSE 1
int yyerror(const char *ErrorMsg);
int yylex();
extern int Filelineno;
static Record *CurRec = 0;
typedef std::pair<Record*, std::vector<Init*>*> SubClassRefTy;
struct LetRecord {
std::string Name;
std::vector<unsigned> Bits;
Init *Value;
bool HasBits;
LetRecord(const std::string &N, std::vector<unsigned> *B, Init *V)
: Name(N), Value(V), HasBits(B != 0) {
if (HasBits) Bits = *B;
}
};
static std::vector<std::vector<LetRecord> > LetStack;
extern std::ostream &err();
static void addValue(const RecordVal &RV) {
if (RecordVal *ERV = CurRec->getValue(RV.getName())) {
// The value already exists in the class, treat this as a set...
if (ERV->setValue(RV.getValue())) {
err() << "New definition of '" << RV.getName() << "' of type '"
<< *RV.getType() << "' is incompatible with previous "
<< "definition of type '" << *ERV->getType() << "'!\n";
abort();
}
} else {
CurRec->addValue(RV);
}
}
static void addSuperClass(Record *SC) {
if (CurRec->isSubClassOf(SC)) {
err() << "Already subclass of '" << SC->getName() << "'!\n";
abort();
}
CurRec->addSuperClass(SC);
}
static void setValue(const std::string &ValName,
std::vector<unsigned> *BitList, Init *V) {
if (!V) return ;
RecordVal *RV = CurRec->getValue(ValName);
if (RV == 0) {
err() << "Value '" << ValName << "' unknown!\n";
abort();
}
// If we are assigning to a subset of the bits in the value... then we must be
// assigning to a field of BitsRecTy, which must have a BitsInit
// initializer...
//
if (BitList) {
BitsInit *CurVal = dynamic_cast<BitsInit*>(RV->getValue());
if (CurVal == 0) {
err() << "Value '" << ValName << "' is not a bits type!\n";
abort();
}
// Convert the incoming value to a bits type of the appropriate size...
Init *BI = V->convertInitializerTo(new BitsRecTy(BitList->size()));
if (BI == 0) {
V->convertInitializerTo(new BitsRecTy(BitList->size()));
err() << "Initializer '" << *V << "' not compatible with bit range!\n";
abort();
}
// We should have a BitsInit type now...
assert(dynamic_cast<BitsInit*>(BI) != 0 || &(std::cerr << *BI) == 0);
BitsInit *BInit = (BitsInit*)BI;
BitsInit *NewVal = new BitsInit(CurVal->getNumBits());
// Loop over bits, assigning values as appropriate...
for (unsigned i = 0, e = BitList->size(); i != e; ++i) {
unsigned Bit = (*BitList)[i];
if (NewVal->getBit(Bit)) {
err() << "Cannot set bit #" << Bit << " of value '" << ValName
<< "' more than once!\n";
abort();
}
NewVal->setBit(Bit, BInit->getBit(i));
}
for (unsigned i = 0, e = CurVal->getNumBits(); i != e; ++i)
if (NewVal->getBit(i) == 0)
NewVal->setBit(i, CurVal->getBit(i));
V = NewVal;
}
if (RV->setValue(V)) {
err() << "Value '" << ValName << "' of type '" << *RV->getType()
<< "' is incompatible with initializer '" << *V << "'!\n";
abort();
}
}
static void addSubClass(Record *SC, const std::vector<Init*> &TemplateArgs) {
// Add all of the values in the subclass into the current class...
const std::vector<RecordVal> &Vals = SC->getValues();
for (unsigned i = 0, e = Vals.size(); i != e; ++i)
addValue(Vals[i]);
const std::vector<std::string> &TArgs = SC->getTemplateArgs();
// Ensure that an appropriate number of template arguments are specified...
if (TArgs.size() < TemplateArgs.size()) {
err() << "ERROR: More template args specified than expected!\n";
abort();
} else { // This class expects template arguments...
// Loop over all of the template arguments, setting them to the specified
// value or leaving them as the default as necessary.
for (unsigned i = 0, e = TArgs.size(); i != e; ++i) {
if (i < TemplateArgs.size()) { // A value is specified for this temp-arg?
// Set it now.
setValue(TArgs[i], 0, TemplateArgs[i]);
} else if (!CurRec->getValue(TArgs[i])->getValue()->isComplete()) {
err() << "ERROR: Value not specified for template argument #"
<< i << " (" << TArgs[i] << ") of subclass '" << SC->getName()
<< "'!\n";
abort();
}
}
}
// Since everything went well, we can now set the "superclass" list for the
// current record.
const std::vector<Record*> &SCs = SC->getSuperClasses();
for (unsigned i = 0, e = SCs.size(); i != e; ++i)
addSuperClass(SCs[i]);
addSuperClass(SC);
}
%}
%union {
std::string *StrVal;
int IntVal;
RecTy *Ty;
Init *Initializer;
std::vector<Init*> *FieldList;
std::vector<unsigned>*BitList;
Record *Rec;
SubClassRefTy *SubClassRef;
std::vector<SubClassRefTy> *SubClassList;
std::vector<std::pair<Init*, std::string> > *DagValueList;
};
%token INT BIT STRING BITS LIST CODE DAG CLASS DEF FIELD LET IN
%token <IntVal> INTVAL
%token <StrVal> ID VARNAME STRVAL CODEFRAGMENT
%type <Ty> Type
%type <Rec> ClassInst DefInst Object ObjectBody ClassID
%type <SubClassRef> SubClassRef
%type <SubClassList> ClassList ClassListNE
%type <IntVal> OptPrefix
%type <Initializer> Value OptValue
%type <DagValueList> DagArgList DagArgListNE
%type <FieldList> ValueList ValueListNE
%type <BitList> BitList OptBitList RBitList
%type <StrVal> Declaration OptID OptVarName
%start File
%%
ClassID : ID {
$$ = Records.getClass(*$1);
if ($$ == 0) {
err() << "Couldn't find class '" << *$1 << "'!\n";
abort();
}
delete $1;
};
// TableGen types...
Type : STRING { // string type
$$ = new StringRecTy();
} | BIT { // bit type
$$ = new BitRecTy();
} | BITS '<' INTVAL '>' { // bits<x> type
$$ = new BitsRecTy($3);
} | INT { // int type
$$ = new IntRecTy();
} | LIST '<' Type '>' { // list<x> type
$$ = new ListRecTy($3);
} | CODE { // code type
$$ = new CodeRecTy();
} | DAG { // dag type
$$ = new DagRecTy();
} | ClassID { // Record Type
$$ = new RecordRecTy($1);
};
OptPrefix : /*empty*/ { $$ = 0; } | FIELD { $$ = 1; };
OptValue : /*empty*/ { $$ = 0; } | '=' Value { $$ = $2; };
Value : INTVAL {
$$ = new IntInit($1);
} | STRVAL {
$$ = new StringInit(*$1);
delete $1;
} | CODEFRAGMENT {
$$ = new CodeInit(*$1);
delete $1;
} | '?' {
$$ = new UnsetInit();
} | '{' ValueList '}' {
BitsInit *Init = new BitsInit($2->size());
for (unsigned i = 0, e = $2->size(); i != e; ++i) {
struct Init *Bit = (*$2)[i]->convertInitializerTo(new BitRecTy());
if (Bit == 0) {
err() << "Element #" << i << " (" << *(*$2)[i]
<< ") is not convertable to a bit!\n";
abort();
}
Init->setBit($2->size()-i-1, Bit);
}
$$ = Init;
delete $2;
} | ID {
if (const RecordVal *RV = (CurRec ? CurRec->getValue(*$1) : 0)) {
$$ = new VarInit(*$1, RV->getType());
} else if (Record *D = Records.getDef(*$1)) {
$$ = new DefInit(D);
} else {
err() << "Variable not defined: '" << *$1 << "'!\n";
abort();
}
delete $1;
} | Value '{' BitList '}' {
$$ = $1->convertInitializerBitRange(*$3);
if ($$ == 0) {
err() << "Invalid bit range for value '" << *$1 << "'!\n";
abort();
}
delete $3;
} | '[' ValueList ']' {
$$ = new ListInit(*$2);
delete $2;
} | Value '.' ID {
if (!$1->getFieldType(*$3)) {
err() << "Cannot access field '" << *$3 << "' of value '" << *$1 << "!\n";
abort();
}
$$ = new FieldInit($1, *$3);
delete $3;
} | '(' ID DagArgList ')' {
Record *D = Records.getDef(*$2);
if (D == 0) {
err() << "Invalid def '" << *$2 << "'!\n";
abort();
}
$$ = new DagInit(D, *$3);
delete $2; delete $3;
};
OptVarName : /* empty */ {
$$ = new std::string();
}
| ':' VARNAME {
$$ = $2;
};
DagArgListNE : Value OptVarName {
$$ = new std::vector<std::pair<Init*, std::string> >();
$$->push_back(std::make_pair($1, *$2));
delete $2;
}
| DagArgListNE ',' Value OptVarName {
$1->push_back(std::make_pair($3, *$4));
delete $4;
$$ = $1;
};
DagArgList : /*empty*/ {
$$ = new std::vector<std::pair<Init*, std::string> >();
}
| DagArgListNE { $$ = $1; };
RBitList : INTVAL {
$$ = new std::vector<unsigned>();
$$->push_back($1);
} | INTVAL '-' INTVAL {
if ($1 < $3 || $1 < 0 || $3 < 0) {
err() << "Invalid bit range: " << $1 << "-" << $3 << "!\n";
abort();
}
$$ = new std::vector<unsigned>();
for (int i = $1; i >= $3; --i)
$$->push_back(i);
} | INTVAL INTVAL {
$2 = -$2;
if ($1 < $2 || $1 < 0 || $2 < 0) {
err() << "Invalid bit range: " << $1 << "-" << $2 << "!\n";
abort();
}
$$ = new std::vector<unsigned>();
for (int i = $1; i >= $2; --i)
$$->push_back(i);
} | RBitList ',' INTVAL {
($$=$1)->push_back($3);
} | RBitList ',' INTVAL '-' INTVAL {
if ($3 < $5 || $3 < 0 || $5 < 0) {
err() << "Invalid bit range: " << $3 << "-" << $5 << "!\n";
abort();
}
$$ = $1;
for (int i = $3; i >= $5; --i)
$$->push_back(i);
} | RBitList ',' INTVAL INTVAL {
$4 = -$4;
if ($3 < $4 || $3 < 0 || $4 < 0) {
err() << "Invalid bit range: " << $3 << "-" << $4 << "!\n";
abort();
}
$$ = $1;
for (int i = $3; i >= $4; --i)
$$->push_back(i);
};
BitList : RBitList { $$ = $1; std::reverse($1->begin(), $1->end()); };
OptBitList : /*empty*/ { $$ = 0; } | '{' BitList '}' { $$ = $2; };
ValueList : /*empty*/ {
$$ = new std::vector<Init*>();
} | ValueListNE {
$$ = $1;
};
ValueListNE : Value {
$$ = new std::vector<Init*>();
$$->push_back($1);
} | ValueListNE ',' Value {
($$ = $1)->push_back($3);
};
Declaration : OptPrefix Type ID OptValue {
addValue(RecordVal(*$3, $2, $1));
setValue(*$3, 0, $4);
$$ = $3;
};
BodyItem : Declaration ';' {
delete $1;
} | LET ID OptBitList '=' Value ';' {
setValue(*$2, $3, $5);
delete $2;
delete $3;
};
BodyList : /*empty*/ | BodyList BodyItem;
Body : ';' | '{' BodyList '}';
SubClassRef : ClassID {
$$ = new SubClassRefTy($1, new std::vector<Init*>());
} | ClassID '<' ValueListNE '>' {
$$ = new SubClassRefTy($1, $3);
};
ClassListNE : SubClassRef {
$$ = new std::vector<SubClassRefTy>();
$$->push_back(*$1);
delete $1;
}
| ClassListNE ',' SubClassRef {
($$=$1)->push_back(*$3);
delete $3;
};
ClassList : /*empty */ {
$$ = new std::vector<SubClassRefTy>();
}
| ':' ClassListNE {
$$ = $2;
};
DeclListNE : Declaration {
CurRec->addTemplateArg(*$1);
delete $1;
} | DeclListNE ',' Declaration {
CurRec->addTemplateArg(*$3);
delete $3;
};
TemplateArgList : '<' DeclListNE '>' {};
OptTemplateArgList : /*empty*/ | TemplateArgList;
OptID : ID { $$ = $1; } | /*empty*/ { $$ = new std::string(); };
ObjectBody : OptID {
static unsigned AnonCounter = 0;
if ($1->empty())
*$1 = "anonymous."+utostr(AnonCounter++);
CurRec = new Record(*$1);
delete $1;
} OptTemplateArgList ClassList {
for (unsigned i = 0, e = $4->size(); i != e; ++i) {
addSubClass((*$4)[i].first, *(*$4)[i].second);
// Delete the template arg values for the class
delete (*$4)[i].second;
}
// Process any variables on the set stack...
for (unsigned i = 0, e = LetStack.size(); i != e; ++i)
for (unsigned j = 0, e = LetStack[i].size(); j != e; ++j)
setValue(LetStack[i][j].Name,
LetStack[i][j].HasBits ? &LetStack[i][j].Bits : 0,
LetStack[i][j].Value);
} Body {
CurRec->resolveReferences();
// Now that all of the references have been resolved, we can delete template
// arguments for superclasses, so they don't pollute our record, and so that
// their names won't conflict with later uses of the name...
for (unsigned i = 0, e = $4->size(); i != e; ++i) {
Record *SuperClass = (*$4)[i].first;
for (unsigned i = 0, e = SuperClass->getTemplateArgs().size(); i != e; ++i)
CurRec->removeValue(SuperClass->getTemplateArgs()[i]);
}
delete $4; // Delete the class list...
$$ = CurRec;
CurRec = 0;
};
ClassInst : CLASS ObjectBody {
if (Records.getClass($2->getName())) {
err() << "Class '" << $2->getName() << "' already defined!\n";
abort();
}
Records.addClass($$ = $2);
};
DefInst : DEF ObjectBody {
if (!$2->getTemplateArgs().empty()) {
err() << "Def '" << $2->getName()
<< "' is not permitted to have template arguments!\n";
abort();
}
// If ObjectBody has template arguments, it's an error.
if (Records.getDef($2->getName())) {
err() << "Def '" << $2->getName() << "' already defined!\n";
abort();
}
Records.addDef($$ = $2);
};
Object : ClassInst | DefInst;
LETItem : ID OptBitList '=' Value {
LetStack.back().push_back(LetRecord(*$1, $2, $4));
delete $1; delete $2;
};
LETList : LETItem | LETList ',' LETItem;
// LETCommand - A 'LET' statement start...
LETCommand : LET { LetStack.push_back(std::vector<LetRecord>()); } LETList IN;
// Support Set commands wrapping objects... both with and without braces.
Object : LETCommand '{' ObjectList '}' {
LetStack.pop_back();
}
| LETCommand Object {
LetStack.pop_back();
};
ObjectList : Object {} | ObjectList Object {};
File : ObjectList {};
%%
int yyerror(const char *ErrorMsg) {
err() << "Error parsing: " << ErrorMsg << "\n";
abort();
}

View File

@ -1,160 +0,0 @@
//===- InstrInfoEmitter.cpp - Generate a Instruction Set Desc. ------------===//
//
// This tablegen backend is responsible for emitting a description of the target
// instruction set for the code generator.
//
//===----------------------------------------------------------------------===//
#include "InstrInfoEmitter.h"
#include "CodeGenWrappers.h"
#include "Record.h"
// runEnums - Print out enum values for all of the instructions.
void InstrInfoEmitter::runEnums(std::ostream &OS) {
std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction");
if (Insts.size() == 0)
throw std::string("No 'Instruction' subclasses defined!");
std::string Namespace = Insts[0]->getValueAsString("Namespace");
EmitSourceFileHeader("Target Instruction Enum Values", OS);
if (!Namespace.empty())
OS << "namespace " << Namespace << " {\n";
OS << " enum {\n";
CodeGenTarget Target;
// We must emit the PHI opcode first...
Record *InstrInfo = Target.getInstructionSet();
Record *PHI = InstrInfo->getValueAsDef("PHIInst");
OS << " " << PHI->getName() << ", \t// 0 (fixed for all targets)\n";
// Print out the rest of the instructions now...
for (unsigned i = 0, e = Insts.size(); i != e; ++i)
if (Insts[i] != PHI)
OS << " " << Insts[i]->getName() << ", \t// " << i+1 << "\n";
OS << " };\n";
if (!Namespace.empty())
OS << "}\n";
}
void InstrInfoEmitter::printDefList(ListInit *LI, const std::string &Name,
std::ostream &OS) const {
OS << "static const unsigned " << Name << "[] = { ";
for (unsigned j = 0, e = LI->getSize(); j != e; ++j)
if (DefInit *DI = dynamic_cast<DefInit*>(LI->getElement(j)))
OS << getQualifiedName(DI->getDef()) << ", ";
else
throw "Illegal value in '" + Name + "' list!";
OS << "0 };\n";
}
// run - Emit the main instruction description records for the target...
void InstrInfoEmitter::run(std::ostream &OS) {
EmitSourceFileHeader("Target Instruction Descriptors", OS);
CodeGenTarget Target;
const std::string &TargetName = Target.getName();
Record *InstrInfo = Target.getInstructionSet();
Record *PHI = InstrInfo->getValueAsDef("PHIInst");
std::vector<Record*> Instructions =
Records.getAllDerivedDefinitions("Instruction");
// Emit all of the instruction's implicit uses and defs...
for (unsigned i = 0, e = Instructions.size(); i != e; ++i) {
Record *Inst = Instructions[i];
ListInit *LI = Inst->getValueAsListInit("Uses");
if (LI->getSize()) printDefList(LI, Inst->getName()+"ImpUses", OS);
LI = Inst->getValueAsListInit("Defs");
if (LI->getSize()) printDefList(LI, Inst->getName()+"ImpDefs", OS);
}
OS << "\nstatic const TargetInstrDescriptor " << TargetName
<< "Insts[] = {\n";
emitRecord(PHI, 0, InstrInfo, OS);
for (unsigned i = 0, e = Instructions.size(); i != e; ++i)
if (Instructions[i] != PHI)
emitRecord(Instructions[i], i+1, InstrInfo, OS);
OS << "};\n";
}
void InstrInfoEmitter::emitRecord(Record *R, unsigned Num, Record *InstrInfo,
std::ostream &OS) {
OS << " { \"" << R->getValueAsString("Name")
<< "\",\t-1, -1, 0, false, 0, 0, 0, 0";
// Emit all of the target indepedent flags...
if (R->getValueAsBit("isReturn")) OS << "|M_RET_FLAG";
if (R->getValueAsBit("isBranch")) OS << "|M_BRANCH_FLAG";
if (R->getValueAsBit("isCall" )) OS << "|M_CALL_FLAG";
if (R->getValueAsBit("isTwoAddress")) OS << "|M_2_ADDR_FLAG";
if (R->getValueAsBit("isTerminator")) OS << "|M_TERMINATOR_FLAG";
OS << ", 0";
// Emit all of the target-specific flags...
ListInit *LI = InstrInfo->getValueAsListInit("TSFlagsFields");
ListInit *Shift = InstrInfo->getValueAsListInit("TSFlagsShifts");
if (LI->getSize() != Shift->getSize())
throw "Lengths of " + InstrInfo->getName() +
":(TargetInfoFields, TargetInfoPositions) must be equal!";
for (unsigned i = 0, e = LI->getSize(); i != e; ++i)
emitShiftedValue(R, dynamic_cast<StringInit*>(LI->getElement(i)),
dynamic_cast<IntInit*>(Shift->getElement(i)), OS);
OS << ", ";
// Emit the implicit uses and defs lists...
LI = R->getValueAsListInit("Uses");
if (!LI->getSize())
OS << "0, ";
else
OS << R->getName() << "ImpUses, ";
LI = R->getValueAsListInit("Defs");
if (!LI->getSize())
OS << "0 ";
else
OS << R->getName() << "ImpDefs ";
OS << " }, // Inst #" << Num << " = " << R->getName() << "\n";
}
void InstrInfoEmitter::emitShiftedValue(Record *R, StringInit *Val,
IntInit *ShiftInt, std::ostream &OS) {
if (Val == 0 || ShiftInt == 0)
throw std::string("Illegal value or shift amount in TargetInfo*!");
RecordVal *RV = R->getValue(Val->getValue());
int Shift = ShiftInt->getValue();
if (RV == 0 || RV->getValue() == 0)
throw R->getName() + " doesn't have a field named '" + Val->getValue()+"'!";
Init *Value = RV->getValue();
if (BitInit *BI = dynamic_cast<BitInit*>(Value)) {
if (BI->getValue()) OS << "|(1<<" << Shift << ")";
return;
} else if (BitsInit *BI = dynamic_cast<BitsInit*>(Value)) {
// Convert the Bits to an integer to print...
Init *I = BI->convertInitializerTo(new IntRecTy());
if (I)
if (IntInit *II = dynamic_cast<IntInit*>(I)) {
if (II->getValue())
OS << "|(" << II->getValue() << "<<" << Shift << ")";
return;
}
} else if (IntInit *II = dynamic_cast<IntInit*>(Value)) {
if (II->getValue()) OS << "|(" << II->getValue() << "<<" << Shift << ")";
return;
}
std::cerr << "Unhandled initializer: " << *Val << "\n";
throw "In record '" + R->getName() + "' for TSFlag emission.";
}

View File

@ -1,34 +0,0 @@
//===- InstrInfoEmitter.h - Generate a Instruction Set Desc. ----*- C++ -*-===//
//
// This tablegen backend is responsible for emitting a description of the target
// instruction set for the code generator.
//
//===----------------------------------------------------------------------===//
#ifndef INSTRINFO_EMITTER_H
#define INSTRINFO_EMITTER_H
#include "TableGenBackend.h"
class StringInit;
class IntInit;
class ListInit;
class InstrInfoEmitter : public TableGenBackend {
RecordKeeper &Records;
public:
InstrInfoEmitter(RecordKeeper &R) : Records(R) {}
// run - Output the instruction set description, returning true on failure.
void run(std::ostream &OS);
// runEnums - Print out enum values for all of the instructions.
void runEnums(std::ostream &OS);
private:
void printDefList(ListInit *LI, const std::string &Name,
std::ostream &OS) const;
void emitRecord(Record *R, unsigned Num, Record *InstrInfo, std::ostream &OS);
void emitShiftedValue(Record *R, StringInit *Val, IntInit *Shift,
std::ostream &OS);
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,387 +0,0 @@
//===- InstrInfoEmitter.h - Generate a Instruction Set Desc. ----*- C++ -*-===//
//
// This tablegen backend is responsible for emitting a description of the target
// instruction set for the code generator.
//
//===----------------------------------------------------------------------===//
#ifndef INSTRSELECTOR_EMITTER_H
#define INSTRSELECTOR_EMITTER_H
#include "TableGenBackend.h"
#include "CodeGenWrappers.h"
#include <vector>
#include <map>
#include <cassert>
class DagInit;
class Init;
class InstrSelectorEmitter;
/// NodeType - Represents Information parsed from the DagNode entries.
///
struct NodeType {
enum ArgResultTypes {
Any, // No constraint on type
Val, // A non-void type
Arg0, // Value matches the type of Arg0
Arg1, // Value matches the type of Arg1
Ptr, // Tree node is the type of the target pointer
I8, // Always bool
Void, // Tree node always returns void
};
ArgResultTypes ResultType;
std::vector<ArgResultTypes> ArgTypes;
NodeType(ArgResultTypes RT, std::vector<ArgResultTypes> &AT) : ResultType(RT){
AT.swap(ArgTypes);
}
NodeType() : ResultType(Val) {}
NodeType(const NodeType &N) : ResultType(N.ResultType), ArgTypes(N.ArgTypes){}
static ArgResultTypes Translate(Record *R);
};
/// TreePatternNode - Represent a node of the tree patterns.
///
class TreePatternNode {
/// Operator - The operation that this node represents... this is null if this
/// is a leaf.
Record *Operator;
/// Type - The inferred value type...
///
MVT::ValueType Type;
/// Children - If this is not a leaf (Operator != 0), this is the subtrees
/// that we contain.
std::vector<std::pair<TreePatternNode*, std::string> > Children;
/// Value - If this node is a leaf, this indicates what the thing is.
///
Init *Value;
public:
TreePatternNode(Record *o, const std::vector<std::pair<TreePatternNode*,
std::string> > &c)
: Operator(o), Type(MVT::Other), Children(c), Value(0) {}
TreePatternNode(Init *V) : Operator(0), Type(MVT::Other), Value(V) {}
Record *getOperator() const {
assert(Operator && "This is a leaf node!");
return Operator;
}
MVT::ValueType getType() const { return Type; }
void setType(MVT::ValueType T) { Type = T; }
bool isLeaf() const { return Operator == 0; }
unsigned getNumChildren() const { return Children.size(); }
TreePatternNode *getChild(unsigned c) const {
assert(Operator != 0 && "This is a leaf node!");
assert(c < Children.size() && "Child access out of range!");
return Children[c].first;
}
const std::string &getChildName(unsigned c) const {
assert(Operator != 0 && "This is a leaf node!");
assert(c < Children.size() && "Child access out of range!");
return Children[c].second;
}
Init *getValue() const {
assert(Operator == 0 && "This is not a leaf node!");
return Value;
}
/// getValueRecord - Returns the value of this tree node as a record. For now
/// we only allow DefInit's as our leaf values, so this is used.
Record *getValueRecord() const;
/// clone - Make a copy of this tree and all of its children.
///
TreePatternNode *clone() const;
void dump() const;
/// InstantiateNonterminals - If this pattern refers to any nonterminals which
/// are not themselves completely resolved, clone the nonterminal and resolve
/// it with the using context we provide.
void InstantiateNonterminals(InstrSelectorEmitter &ISE);
/// UpdateNodeType - Set the node type of N to VT if VT contains information.
/// If N already contains a conflicting type, then throw an exception. This
/// returns true if any information was updated.
///
bool updateNodeType(MVT::ValueType VT, const std::string &RecName);
};
std::ostream &operator<<(std::ostream &OS, const TreePatternNode &N);
/// Pattern - Represent a pattern of one form or another. Currently, three
/// types of patterns are possible: Instruction's, Nonterminals, and Expanders.
///
struct Pattern {
enum PatternType {
Nonterminal, Instruction, Expander
};
private:
/// PTy - The type of pattern this is.
///
PatternType PTy;
/// Tree - The tree pattern which corresponds to this pattern. Note that if
/// there was a (set) node on the outside level that it has been stripped off.
///
TreePatternNode *Tree;
/// Result - If this is an instruction or expander pattern, this is the
/// register result, specified with a (set) in the pattern.
///
std::string ResultName; // The name of the result value...
TreePatternNode *ResultNode; // The leaf node for the result register...
/// TheRecord - The actual TableGen record corresponding to this pattern.
///
Record *TheRecord;
/// Resolved - This is true of the pattern is useful in practice. In
/// particular, some non-terminals will have non-resolvable types. When a
/// user of the non-terminal is later found, they will have inferred a type
/// for the result of the non-terminal, which cause a clone of an unresolved
/// nonterminal to be made which is "resolved".
///
bool Resolved;
/// Args - This is a list of all of the arguments to this pattern, which are
/// the non-void leaf nodes in this pattern.
std::vector<std::pair<TreePatternNode*, std::string> > Args;
/// ISE - the instruction selector emitter coordinating this madness.
///
InstrSelectorEmitter &ISE;
public:
/// Pattern constructor - Parse the specified DagInitializer into the current
/// record.
Pattern(PatternType pty, DagInit *RawPat, Record *TheRec,
InstrSelectorEmitter &ise);
/// Pattern - Constructor used for cloning nonterminal patterns
Pattern(TreePatternNode *tree, Record *rec, bool res,
InstrSelectorEmitter &ise)
: PTy(Nonterminal), Tree(tree), ResultNode(0), TheRecord(rec),
Resolved(res), ISE(ise) {
calculateArgs(Tree, "");
}
/// getPatternType - Return what flavor of Record this pattern originated from
///
PatternType getPatternType() const { return PTy; }
/// getTree - Return the tree pattern which corresponds to this pattern.
///
TreePatternNode *getTree() const { return Tree; }
Record *getResult() const {
return ResultNode ? ResultNode->getValueRecord() : 0;
}
const std::string &getResultName() const { return ResultName; }
TreePatternNode *getResultNode() const { return ResultNode; }
/// getRecord - Return the actual TableGen record corresponding to this
/// pattern.
///
Record *getRecord() const { return TheRecord; }
unsigned getNumArgs() const { return Args.size(); }
TreePatternNode *getArg(unsigned i) const {
assert(i < Args.size() && "Argument reference out of range!");
return Args[i].first;
}
Record *getArgRec(unsigned i) const {
return getArg(i)->getValueRecord();
}
Init *getArgVal(unsigned i) const {
return getArg(i)->getValue();
}
const std::string &getArgName(unsigned i) const {
assert(i < Args.size() && "Argument reference out of range!");
return Args[i].second;
}
bool isResolved() const { return Resolved; }
/// InferAllTypes - Runs the type inference engine on the current pattern,
/// stopping when nothing can be inferred, then updating the Resolved field.
void InferAllTypes();
/// InstantiateNonterminals - If this pattern refers to any nonterminals which
/// are not themselves completely resolved, clone the nonterminal and resolve
/// it with the using context we provide.
void InstantiateNonterminals() {
Tree->InstantiateNonterminals(ISE);
}
/// clone - This method is used to make an exact copy of the current pattern,
/// then change the "TheRecord" instance variable to the specified record.
///
Pattern *clone(Record *R) const;
/// error - Throw an exception, prefixing it with information about this
/// pattern.
void error(const std::string &Msg) const;
/// getSlotName - If this is a leaf node, return the slot name that the
/// operand will update.
std::string getSlotName() const;
static std::string getSlotName(Record *R);
void dump() const;
private:
void calculateArgs(TreePatternNode *N, const std::string &Name);
MVT::ValueType getIntrinsicType(Record *R) const;
TreePatternNode *ParseTreePattern(DagInit *DI);
bool InferTypes(TreePatternNode *N, bool &MadeChange);
};
std::ostream &operator<<(std::ostream &OS, const Pattern &P);
/// PatternOrganizer - This class represents all of the patterns which are
/// useful for the instruction selector, neatly catagorized in a hierarchical
/// structure.
struct PatternOrganizer {
/// PatternsForNode - The list of patterns which can produce a value of a
/// particular slot type, given a particular root node in the tree. All of
/// the patterns in this vector produce the same value type and have the same
/// root DAG node.
typedef std::vector<Pattern*> PatternsForNode;
/// NodesForSlot - This map keeps track of all of the root DAG nodes which can
/// lead to the production of a value for this slot. All of the patterns in
/// this data structure produces values of the same slot.
typedef std::map<Record*, PatternsForNode> NodesForSlot;
/// AllPatterns - This data structure contains all patterns in the instruction
/// selector.
std::map<std::string, NodesForSlot> AllPatterns;
// Forwarding functions...
typedef std::map<std::string, NodesForSlot>::iterator iterator;
iterator begin() { return AllPatterns.begin(); }
iterator end() { return AllPatterns.end(); }
/// addPattern - Add the specified pattern to the appropriate location in the
/// collection.
void addPattern(Pattern *P);
};
/// InstrSelectorEmitter - The top-level class which coordinates construction
/// and emission of the instruction selector.
///
class InstrSelectorEmitter : public TableGenBackend {
RecordKeeper &Records;
CodeGenTarget Target;
std::map<Record*, NodeType> NodeTypes;
/// Patterns - a list of all of the patterns defined by the target description
///
std::map<Record*, Pattern*> Patterns;
/// InstantiatedNTs - A data structure to keep track of which nonterminals
/// have been instantiated already...
///
std::map<std::pair<Pattern*,MVT::ValueType>, Record*> InstantiatedNTs;
/// ComputableValues - This map indicates which patterns can be used to
/// generate a value that is used by the selector. The keys of this map
/// implicitly define the values that are used by the selector.
///
PatternOrganizer ComputableValues;
public:
InstrSelectorEmitter(RecordKeeper &R) : Records(R) {}
// run - Output the instruction set description, returning true on failure.
void run(std::ostream &OS);
const CodeGenTarget &getTarget() const { return Target; }
std::map<Record*, NodeType> &getNodeTypes() { return NodeTypes; }
const NodeType &getNodeType(Record *R) const {
std::map<Record*, NodeType>::const_iterator I = NodeTypes.find(R);
assert(I != NodeTypes.end() && "Unknown node type!");
return I->second;
}
/// getPattern - return the pattern corresponding to the specified record, or
/// null if there is none.
Pattern *getPattern(Record *R) const {
std::map<Record*, Pattern*>::const_iterator I = Patterns.find(R);
return I != Patterns.end() ? I->second : 0;
}
/// ReadNonterminal - This method parses the specified record as a
/// nonterminal, but only if it hasn't been read in already.
Pattern *ReadNonterminal(Record *R);
/// InstantiateNonterminal - This method takes the nonterminal specified by
/// NT, which should not be completely resolved, clones it, applies ResultTy
/// to its root, then runs the type inference stuff on it. This should
/// produce a newly resolved nonterminal, which we make a record for and
/// return. To be extra fancy and efficient, this only makes one clone for
/// each type it is instantiated with.
Record *InstantiateNonterminal(Pattern *NT, MVT::ValueType ResultTy);
private:
// ReadNodeTypes - Read in all of the node types in the current RecordKeeper,
// turning them into the more accessible NodeTypes data structure.
void ReadNodeTypes();
// ReadNonTerminals - Read in all nonterminals and incorporate them into our
// pattern database.
void ReadNonterminals();
// ReadInstructionPatterns - Read in all subclasses of Instruction, and
// process those with a useful Pattern field.
void ReadInstructionPatterns();
// ReadExpanderPatterns - Read in all of the expanded patterns.
void ReadExpanderPatterns();
// InstantiateNonterminals - Instantiate any unresolved nonterminals with
// information from the context that they are used in.
void InstantiateNonterminals();
// CalculateComputableValues - Fill in the ComputableValues map through
// analysis of the patterns we are playing with.
void CalculateComputableValues();
// EmitMatchCosters - Given a list of patterns, which all have the same root
// pattern operator, emit an efficient decision tree to decide which one to
// pick. This is structured this way to avoid reevaluations of non-obvious
// subexpressions.
void EmitMatchCosters(std::ostream &OS,
const std::vector<std::pair<Pattern*, TreePatternNode*> > &Patterns,
const std::string &VarPrefix, unsigned Indent);
/// PrintExpanderOperand - Print out Arg as part of the instruction emission
/// process for the expander pattern P. This argument may be referencing some
/// values defined in P, or may just be physical register references or
/// something like that. If PrintArg is true, we are printing out arguments
/// to the BuildMI call. If it is false, we are printing the result register
/// name.
void PrintExpanderOperand(Init *Arg, const std::string &NameVar,
TreePatternNode *ArgDecl, Pattern *P,
bool PrintArg, std::ostream &OS);
};
#endif

View File

@ -1,18 +0,0 @@
LEVEL = ../../..
TOOLNAME = tblgen
USEDLIBS = support.a
.PRECIOUS: FileLexer.cpp FileParser.cpp
include $(LEVEL)/Makefile.common
#
# Make the source file depend on the header file. In this way, dependencies
# (which depend on the source file) won't get generated until bison is done
# generating the C source and header files for the parser.
#
FileLexer.cpp: FileParser.h
clean::
-rm -f FileParser.cpp FileParser.h FileLexer.cpp CommandLine.cpp
-rm -f FileParser.output

View File

@ -1,676 +0,0 @@
//===- Record.cpp - Record implementation ---------------------------------===//
//
//
//===----------------------------------------------------------------------===//
#include "Record.h"
//===----------------------------------------------------------------------===//
// Type implementations
//===----------------------------------------------------------------------===//
void RecTy::dump() const { print(std::cerr); }
Init *BitRecTy::convertValue(BitsInit *BI) {
if (BI->getNumBits() != 1) return 0; // Only accept if just one bit!
return BI->getBit(0);
}
bool BitRecTy::baseClassOf(const BitsRecTy *RHS) const {
return RHS->getNumBits() == 1;
}
Init *BitRecTy::convertValue(IntInit *II) {
int Val = II->getValue();
if (Val != 0 && Val != 1) return 0; // Only accept 0 or 1 for a bit!
return new BitInit(Val != 0);
}
Init *BitRecTy::convertValue(TypedInit *VI) {
if (dynamic_cast<BitRecTy*>(VI->getType()))
return VI; // Accept variable if it is already of bit type!
return 0;
}
Init *BitsRecTy::convertValue(UnsetInit *UI) {
BitsInit *Ret = new BitsInit(Size);
for (unsigned i = 0; i != Size; ++i)
Ret->setBit(i, new UnsetInit());
return Ret;
}
Init *BitsRecTy::convertValue(BitInit *UI) {
if (Size != 1) return 0; // Can only convert single bit...
BitsInit *Ret = new BitsInit(1);
Ret->setBit(0, UI);
return Ret;
}
// convertValue from Int initializer to bits type: Split the integer up into the
// appropriate bits...
//
Init *BitsRecTy::convertValue(IntInit *II) {
int Value = II->getValue();
// Make sure this bitfield is large enough to hold the integer value...
if (Value >= 0) {
if (Value & ~((1 << Size)-1))
return 0;
} else {
if ((Value >> Size) != -1 || ((Value & (1 << Size-1)) == 0))
return 0;
}
BitsInit *Ret = new BitsInit(Size);
for (unsigned i = 0; i != Size; ++i)
Ret->setBit(i, new BitInit(Value & (1 << i)));
return Ret;
}
Init *BitsRecTy::convertValue(BitsInit *BI) {
// If the number of bits is right, return it. Otherwise we need to expand or
// truncate...
if (BI->getNumBits() == Size) return BI;
return 0;
}
Init *BitsRecTy::convertValue(TypedInit *VI) {
if (BitsRecTy *BRT = dynamic_cast<BitsRecTy*>(VI->getType()))
if (BRT->Size == Size) {
BitsInit *Ret = new BitsInit(Size);
for (unsigned i = 0; i != Size; ++i)
Ret->setBit(i, new VarBitInit(VI, i));
return Ret;
}
if (Size == 1 && dynamic_cast<BitRecTy*>(VI->getType())) {
BitsInit *Ret = new BitsInit(1);
Ret->setBit(0, VI);
return Ret;
}
return 0;
}
Init *IntRecTy::convertValue(BitInit *BI) {
return new IntInit(BI->getValue());
}
Init *IntRecTy::convertValue(BitsInit *BI) {
int Result = 0;
for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i)
if (BitInit *Bit = dynamic_cast<BitInit*>(BI->getBit(i))) {
Result |= Bit->getValue() << i;
} else {
return 0;
}
return new IntInit(Result);
}
Init *IntRecTy::convertValue(TypedInit *TI) {
if (TI->getType()->typeIsConvertibleTo(this))
return TI; // Accept variable if already of the right type!
return 0;
}
Init *StringRecTy::convertValue(TypedInit *TI) {
if (dynamic_cast<StringRecTy*>(TI->getType()))
return TI; // Accept variable if already of the right type!
return 0;
}
void ListRecTy::print(std::ostream &OS) const {
OS << "list<" << *Ty << ">";
}
Init *ListRecTy::convertValue(ListInit *LI) {
std::vector<Init*> Elements;
// Verify that all of the elements of the list are subclasses of the
// appropriate class!
for (unsigned i = 0, e = LI->getSize(); i != e; ++i)
if (Init *CI = LI->getElement(i)->convertInitializerTo(Ty))
Elements.push_back(CI);
else
return 0;
return new ListInit(Elements);
}
Init *ListRecTy::convertValue(TypedInit *TI) {
// Ensure that TI is compatible with our class.
if (ListRecTy *LRT = dynamic_cast<ListRecTy*>(TI->getType()))
if (LRT->getElementType()->typeIsConvertibleTo(getElementType()))
return TI;
return 0;
}
Init *CodeRecTy::convertValue(TypedInit *TI) {
if (TI->getType()->typeIsConvertibleTo(this))
return TI;
return 0;
}
Init *DagRecTy::convertValue(TypedInit *TI) {
if (TI->getType()->typeIsConvertibleTo(this))
return TI;
return 0;
}
void RecordRecTy::print(std::ostream &OS) const {
OS << Rec->getName();
}
Init *RecordRecTy::convertValue(DefInit *DI) {
// Ensure that DI is a subclass of Rec.
if (!DI->getDef()->isSubClassOf(Rec))
return 0;
return DI;
}
Init *RecordRecTy::convertValue(TypedInit *TI) {
// Ensure that TI is compatible with Rec.
if (RecordRecTy *RRT = dynamic_cast<RecordRecTy*>(TI->getType()))
if (RRT->getRecord()->isSubClassOf(getRecord()) ||
RRT->getRecord() == getRecord())
return TI;
return 0;
}
bool RecordRecTy::baseClassOf(const RecordRecTy *RHS) const {
return Rec == RHS->getRecord() || RHS->getRecord()->isSubClassOf(Rec);
}
//===----------------------------------------------------------------------===//
// Initializer implementations
//===----------------------------------------------------------------------===//
void Init::dump() const { return print(std::cerr); }
Init *BitsInit::convertInitializerBitRange(const std::vector<unsigned> &Bits) {
BitsInit *BI = new BitsInit(Bits.size());
for (unsigned i = 0, e = Bits.size(); i != e; ++i) {
if (Bits[i] >= getNumBits()) {
delete BI;
return 0;
}
BI->setBit(i, getBit(Bits[i]));
}
return BI;
}
void BitsInit::print(std::ostream &OS) const {
//if (!printInHex(OS)) return;
//if (!printAsVariable(OS)) return;
//if (!printAsUnset(OS)) return;
OS << "{ ";
for (unsigned i = 0, e = getNumBits(); i != e; ++i) {
if (i) OS << ", ";
if (Init *Bit = getBit(e-i-1))
Bit->print(OS);
else
OS << "*";
}
OS << " }";
}
bool BitsInit::printInHex(std::ostream &OS) const {
// First, attempt to convert the value into an integer value...
int Result = 0;
for (unsigned i = 0, e = getNumBits(); i != e; ++i)
if (BitInit *Bit = dynamic_cast<BitInit*>(getBit(i))) {
Result |= Bit->getValue() << i;
} else {
return true;
}
OS << "0x" << std::hex << Result << std::dec;
return false;
}
bool BitsInit::printAsVariable(std::ostream &OS) const {
// Get the variable that we may be set equal to...
assert(getNumBits() != 0);
VarBitInit *FirstBit = dynamic_cast<VarBitInit*>(getBit(0));
if (FirstBit == 0) return true;
TypedInit *Var = FirstBit->getVariable();
// Check to make sure the types are compatible.
BitsRecTy *Ty = dynamic_cast<BitsRecTy*>(FirstBit->getVariable()->getType());
if (Ty == 0) return true;
if (Ty->getNumBits() != getNumBits()) return true; // Incompatible types!
// Check to make sure all bits are referring to the right bits in the variable
for (unsigned i = 0, e = getNumBits(); i != e; ++i) {
VarBitInit *Bit = dynamic_cast<VarBitInit*>(getBit(i));
if (Bit == 0 || Bit->getVariable() != Var || Bit->getBitNum() != i)
return true;
}
Var->print(OS);
return false;
}
bool BitsInit::printAsUnset(std::ostream &OS) const {
for (unsigned i = 0, e = getNumBits(); i != e; ++i)
if (!dynamic_cast<UnsetInit*>(getBit(i)))
return true;
OS << "?";
return false;
}
// resolveReferences - If there are any field references that refer to fields
// that have been filled in, we can propagate the values now.
//
Init *BitsInit::resolveReferences(Record &R) {
bool Changed = false;
BitsInit *New = new BitsInit(getNumBits());
for (unsigned i = 0, e = Bits.size(); i != e; ++i) {
Init *B;
Init *CurBit = getBit(i);
do {
B = CurBit;
CurBit = CurBit->resolveReferences(R);
Changed |= B != CurBit;
} while (B != CurBit);
New->setBit(i, CurBit);
}
if (Changed)
return New;
delete New;
return this;
}
Init *IntInit::convertInitializerBitRange(const std::vector<unsigned> &Bits) {
BitsInit *BI = new BitsInit(Bits.size());
for (unsigned i = 0, e = Bits.size(); i != e; ++i) {
if (Bits[i] >= 32) {
delete BI;
return 0;
}
BI->setBit(i, new BitInit(Value & (1 << Bits[i])));
}
return BI;
}
void ListInit::print(std::ostream &OS) const {
OS << "[";
for (unsigned i = 0, e = Values.size(); i != e; ++i) {
if (i) OS << ", ";
OS << *Values[i];
}
OS << "]";
}
Init *VarInit::convertInitializerBitRange(const std::vector<unsigned> &Bits) {
BitsRecTy *T = dynamic_cast<BitsRecTy*>(getType());
if (T == 0) return 0; // Cannot subscript a non-bits variable...
unsigned NumBits = T->getNumBits();
BitsInit *BI = new BitsInit(Bits.size());
for (unsigned i = 0, e = Bits.size(); i != e; ++i) {
if (Bits[i] >= NumBits) {
delete BI;
return 0;
}
BI->setBit(i, new VarBitInit(this, Bits[i]));
}
return BI;
}
Init *VarInit::resolveBitReference(Record &R, unsigned Bit) {
if (R.isTemplateArg(getName()))
return this;
RecordVal *RV = R.getValue(getName());
assert(RV && "Reference to a non-existant variable?");
assert(dynamic_cast<BitsInit*>(RV->getValue()));
BitsInit *BI = (BitsInit*)RV->getValue();
assert(Bit < BI->getNumBits() && "Bit reference out of range!");
Init *B = BI->getBit(Bit);
if (!dynamic_cast<UnsetInit*>(B)) // If the bit is not set...
return B; // Replace the VarBitInit with it.
return this;
}
RecTy *VarInit::getFieldType(const std::string &FieldName) const {
if (RecordRecTy *RTy = dynamic_cast<RecordRecTy*>(getType()))
if (const RecordVal *RV = RTy->getRecord()->getValue(FieldName))
return RV->getType();
return 0;
}
Init *VarInit::getFieldInit(Record &R, const std::string &FieldName) const {
if (RecordRecTy *RTy = dynamic_cast<RecordRecTy*>(getType()))
if (const RecordVal *RV = R.getValue(VarName))
if (Init *I = RV->getValue()->getFieldInit(R, FieldName))
return I;
else
return 0;
return 0;
}
/// resolveReferences - This method is used by classes that refer to other
/// variables which may not be defined at the time they expression is formed.
/// If a value is set for the variable later, this method will be called on
/// users of the value to allow the value to propagate out.
///
Init *VarInit::resolveReferences(Record &R) {
if (RecordVal *Val = R.getValue(VarName))
if (!dynamic_cast<UnsetInit*>(Val->getValue()))
return Val->getValue();
return this;
}
Init *VarBitInit::resolveReferences(Record &R) {
Init *I = getVariable()->resolveBitReference(R, getBitNum());
if (I != getVariable())
return I;
return this;
}
RecTy *DefInit::getFieldType(const std::string &FieldName) const {
if (const RecordVal *RV = Def->getValue(FieldName))
return RV->getType();
return 0;
}
Init *DefInit::getFieldInit(Record &R, const std::string &FieldName) const {
return Def->getValue(FieldName)->getValue();
}
void DefInit::print(std::ostream &OS) const {
OS << Def->getName();
}
Init *FieldInit::convertInitializerBitRange(const std::vector<unsigned> &Bits) {
BitsRecTy *T = dynamic_cast<BitsRecTy*>(getType());
if (T == 0) return 0; // Cannot subscript a non-bits field...
unsigned NumBits = T->getNumBits();
BitsInit *BI = new BitsInit(Bits.size());
for (unsigned i = 0, e = Bits.size(); i != e; ++i) {
if (Bits[i] >= NumBits) {
delete BI;
return 0;
}
BI->setBit(i, new VarBitInit(this, Bits[i]));
}
return BI;
}
Init *FieldInit::resolveBitReference(Record &R, unsigned Bit) {
Init *BitsVal = Rec->getFieldInit(R, FieldName);
if (BitsVal)
if (BitsInit *BI = dynamic_cast<BitsInit*>(BitsVal)) {
assert(Bit < BI->getNumBits() && "Bit reference out of range!");
Init *B = BI->getBit(Bit);
if (dynamic_cast<BitInit*>(B)) // If the bit is set...
return B; // Replace the VarBitInit with it.
}
return this;
}
Init *FieldInit::resolveReferences(Record &R) {
Init *BitsVal = Rec->getFieldInit(R, FieldName);
if (BitsVal) {
Init *BVR = BitsVal->resolveReferences(R);
return BVR->isComplete() ? BVR : this;
}
return this;
}
void DagInit::print(std::ostream &OS) const {
OS << "(" << NodeTypeDef->getName();
if (Args.size()) {
OS << " " << *Args[0];
if (!ArgNames[0].empty()) OS << ":$" << ArgNames[0];
for (unsigned i = 1, e = Args.size(); i != e; ++i) {
OS << ", " << *Args[i];
if (!ArgNames[i].empty()) OS << ":$" << ArgNames[i];
}
}
OS << ")";
}
//===----------------------------------------------------------------------===//
// Other implementations
//===----------------------------------------------------------------------===//
RecordVal::RecordVal(const std::string &N, RecTy *T, unsigned P)
: Name(N), Ty(T), Prefix(P) {
Value = Ty->convertValue(new UnsetInit());
assert(Value && "Cannot create unset value for current type!");
}
void RecordVal::dump() const { std::cerr << *this; }
void RecordVal::print(std::ostream &OS, bool PrintSem) const {
if (getPrefix()) OS << "field ";
OS << *getType() << " " << getName();
if (getValue()) {
OS << " = " << *getValue();
}
if (PrintSem) OS << ";\n";
}
// resolveReferences - If there are any field references that refer to fields
// that have been filled in, we can propagate the values now.
//
void Record::resolveReferences() {
for (unsigned i = 0, e = Values.size(); i != e; ++i)
Values[i].setValue(Values[i].getValue()->resolveReferences(*this));
}
void Record::dump() const { std::cerr << *this; }
std::ostream &operator<<(std::ostream &OS, const Record &R) {
OS << R.getName();
const std::vector<std::string> &TArgs = R.getTemplateArgs();
if (!TArgs.empty()) {
OS << "<";
for (unsigned i = 0, e = TArgs.size(); i != e; ++i) {
if (i) OS << ", ";
const RecordVal *RV = R.getValue(TArgs[i]);
assert(RV && "Template argument record not found??");
RV->print(OS, false);
}
OS << ">";
}
OS << " {";
const std::vector<Record*> &SC = R.getSuperClasses();
if (!SC.empty()) {
OS << "\t//";
for (unsigned i = 0, e = SC.size(); i != e; ++i)
OS << " " << SC[i]->getName();
}
OS << "\n";
const std::vector<RecordVal> &Vals = R.getValues();
for (unsigned i = 0, e = Vals.size(); i != e; ++i)
if (Vals[i].getPrefix() && !R.isTemplateArg(Vals[i].getName()))
OS << Vals[i];
for (unsigned i = 0, e = Vals.size(); i != e; ++i)
if (!Vals[i].getPrefix() && !R.isTemplateArg(Vals[i].getName()))
OS << Vals[i];
return OS << "}\n";
}
/// getValueInit - Return the initializer for a value with the specified name,
/// or throw an exception if the field does not exist.
///
Init *Record::getValueInit(const std::string &FieldName) const {
const RecordVal *R = getValue(FieldName);
if (R == 0 || R->getValue() == 0)
throw "Record '" + getName() + "' does not have a field named '" +
FieldName + "!\n";
return R->getValue();
}
/// getValueAsString - This method looks up the specified field and returns its
/// value as a string, throwing an exception if the field does not exist or if
/// the value is not a string.
///
std::string Record::getValueAsString(const std::string &FieldName) const {
const RecordVal *R = getValue(FieldName);
if (R == 0 || R->getValue() == 0)
throw "Record '" + getName() + "' does not have a field named '" +
FieldName + "!\n";
if (const StringInit *SI = dynamic_cast<const StringInit*>(R->getValue()))
return SI->getValue();
throw "Record '" + getName() + "', field '" + FieldName +
"' does not have a string initializer!";
}
/// getValueAsBitsInit - This method looks up the specified field and returns
/// its value as a BitsInit, throwing an exception if the field does not exist
/// or if the value is not the right type.
///
BitsInit *Record::getValueAsBitsInit(const std::string &FieldName) const {
const RecordVal *R = getValue(FieldName);
if (R == 0 || R->getValue() == 0)
throw "Record '" + getName() + "' does not have a field named '" +
FieldName + "!\n";
if (BitsInit *BI = dynamic_cast<BitsInit*>(R->getValue()))
return BI;
throw "Record '" + getName() + "', field '" + FieldName +
"' does not have a BitsInit initializer!";
}
/// getValueAsListInit - This method looks up the specified field and returns
/// its value as a ListInit, throwing an exception if the field does not exist
/// or if the value is not the right type.
///
ListInit *Record::getValueAsListInit(const std::string &FieldName) const {
const RecordVal *R = getValue(FieldName);
if (R == 0 || R->getValue() == 0)
throw "Record '" + getName() + "' does not have a field named '" +
FieldName + "!\n";
if (ListInit *LI = dynamic_cast<ListInit*>(R->getValue()))
return LI;
throw "Record '" + getName() + "', field '" + FieldName +
"' does not have a list initializer!";
}
/// getValueAsInt - This method looks up the specified field and returns its
/// value as an int, throwing an exception if the field does not exist or if
/// the value is not the right type.
///
int Record::getValueAsInt(const std::string &FieldName) const {
const RecordVal *R = getValue(FieldName);
if (R == 0 || R->getValue() == 0)
throw "Record '" + getName() + "' does not have a field named '" +
FieldName + "!\n";
if (IntInit *II = dynamic_cast<IntInit*>(R->getValue()))
return II->getValue();
throw "Record '" + getName() + "', field '" + FieldName +
"' does not have a list initializer!";
}
/// getValueAsDef - This method looks up the specified field and returns its
/// value as a Record, throwing an exception if the field does not exist or if
/// the value is not the right type.
///
Record *Record::getValueAsDef(const std::string &FieldName) const {
const RecordVal *R = getValue(FieldName);
if (R == 0 || R->getValue() == 0)
throw "Record '" + getName() + "' does not have a field named '" +
FieldName + "!\n";
if (DefInit *DI = dynamic_cast<DefInit*>(R->getValue()))
return DI->getDef();
throw "Record '" + getName() + "', field '" + FieldName +
"' does not have a list initializer!";
}
/// getValueAsBit - This method looks up the specified field and returns its
/// value as a bit, throwing an exception if the field does not exist or if
/// the value is not the right type.
///
bool Record::getValueAsBit(const std::string &FieldName) const {
const RecordVal *R = getValue(FieldName);
if (R == 0 || R->getValue() == 0)
throw "Record '" + getName() + "' does not have a field named '" +
FieldName + "!\n";
if (BitInit *BI = dynamic_cast<BitInit*>(R->getValue()))
return BI->getValue();
throw "Record '" + getName() + "', field '" + FieldName +
"' does not have a bit initializer!";
}
/// getValueAsDag - This method looks up the specified field and returns its
/// value as an Dag, throwing an exception if the field does not exist or if
/// the value is not the right type.
///
DagInit *Record::getValueAsDag(const std::string &FieldName) const {
const RecordVal *R = getValue(FieldName);
if (R == 0 || R->getValue() == 0)
throw "Record '" + getName() + "' does not have a field named '" +
FieldName + "!\n";
if (DagInit *DI = dynamic_cast<DagInit*>(R->getValue()))
return DI;
throw "Record '" + getName() + "', field '" + FieldName +
"' does not have a dag initializer!";
}
void RecordKeeper::dump() const { std::cerr << *this; }
std::ostream &operator<<(std::ostream &OS, const RecordKeeper &RK) {
OS << "------------- Classes -----------------\n";
const std::map<std::string, Record*> &Classes = RK.getClasses();
for (std::map<std::string, Record*>::const_iterator I = Classes.begin(),
E = Classes.end(); I != E; ++I)
OS << "class " << *I->second;
OS << "------------- Defs -----------------\n";
const std::map<std::string, Record*> &Defs = RK.getDefs();
for (std::map<std::string, Record*>::const_iterator I = Defs.begin(),
E = Defs.end(); I != E; ++I)
OS << "def " << *I->second;
return OS;
}
/// getAllDerivedDefinitions - This method returns all concrete definitions
/// that derive from the specified class name. If a class with the specified
/// name does not exist, an error is printed and true is returned.
std::vector<Record*>
RecordKeeper::getAllDerivedDefinitions(const std::string &ClassName) const {
Record *Class = Records.getClass(ClassName);
if (!Class)
throw "ERROR: Couldn't find the '" + ClassName + "' class!\n";
std::vector<Record*> Defs;
for (std::map<std::string, Record*>::const_iterator I = getDefs().begin(),
E = getDefs().end(); I != E; ++I)
if (I->second->isSubClassOf(Class))
Defs.push_back(I->second);
return Defs;
}

View File

@ -1,849 +0,0 @@
//===- Record.h - Classes to represent Table Records ------------*- C++ -*-===//
//
// This file defines the main TableGen data structures, including the TableGen
// types, values, and high-level data structures.
//
//===----------------------------------------------------------------------===//
#ifndef RECORD_H
#define RECORD_H
#include <string>
#include <vector>
#include <map>
#include <iostream>
#include <cassert>
// RecTy subclasses...
class BitRecTy;
class BitsRecTy;
class IntRecTy;
class StringRecTy;
class ListRecTy;
class CodeRecTy;
class DagRecTy;
class RecordRecTy;
// Init subclasses...
class Init;
class UnsetInit;
class BitInit;
class BitsInit;
class IntInit;
class StringInit;
class CodeInit;
class ListInit;
class DefInit;
class DagInit;
class TypedInit;
class VarInit;
class FieldInit;
class VarBitInit;
// Other classes...
class Record;
//===----------------------------------------------------------------------===//
// Type Classes
//===----------------------------------------------------------------------===//
struct RecTy {
virtual ~RecTy() {}
virtual void print(std::ostream &OS) const = 0;
void dump() const;
/// typeIsConvertibleTo - Return true if all values of 'this' type can be
/// converted to the specified type.
virtual bool typeIsConvertibleTo(const RecTy *RHS) const = 0;
public: // These methods should only be called from subclasses of Init
virtual Init *convertValue( UnsetInit *UI) { return 0; }
virtual Init *convertValue( BitInit *BI) { return 0; }
virtual Init *convertValue( BitsInit *BI) { return 0; }
virtual Init *convertValue( IntInit *II) { return 0; }
virtual Init *convertValue(StringInit *SI) { return 0; }
virtual Init *convertValue( ListInit *LI) { return 0; }
virtual Init *convertValue( CodeInit *CI) { return 0; }
virtual Init *convertValue(VarBitInit *VB) { return 0; }
virtual Init *convertValue( DefInit *DI) { return 0; }
virtual Init *convertValue( DagInit *DI) { return 0; }
virtual Init *convertValue( TypedInit *TI) { return 0; }
virtual Init *convertValue( VarInit *VI) {
return convertValue((TypedInit*)VI);
}
virtual Init *convertValue( FieldInit *FI) {
return convertValue((TypedInit*)FI);
}
public: // These methods should only be called by subclasses of RecTy.
// baseClassOf - These virtual methods should be overloaded to return true iff
// all values of type 'RHS' can be converted to the 'this' type.
virtual bool baseClassOf(const BitRecTy *RHS) const { return false; }
virtual bool baseClassOf(const BitsRecTy *RHS) const { return false; }
virtual bool baseClassOf(const IntRecTy *RHS) const { return false; }
virtual bool baseClassOf(const StringRecTy *RHS) const { return false; }
virtual bool baseClassOf(const ListRecTy *RHS) const { return false; }
virtual bool baseClassOf(const CodeRecTy *RHS) const { return false; }
virtual bool baseClassOf(const DagRecTy *RHS) const { return false; }
virtual bool baseClassOf(const RecordRecTy *RHS) const { return false; }
};
inline std::ostream &operator<<(std::ostream &OS, const RecTy &Ty) {
Ty.print(OS);
return OS;
}
/// BitRecTy - 'bit' - Represent a single bit
///
struct BitRecTy : public RecTy {
Init *convertValue(UnsetInit *UI) { return (Init*)UI; }
Init *convertValue(BitInit *BI) { return (Init*)BI; }
Init *convertValue(BitsInit *BI);
Init *convertValue(IntInit *II);
Init *convertValue(TypedInit *VI);
Init *convertValue(VarBitInit *VB) { return (Init*)VB; }
void print(std::ostream &OS) const { OS << "bit"; }
bool typeIsConvertibleTo(const RecTy *RHS) const {
return RHS->baseClassOf(this);
}
virtual bool baseClassOf(const BitRecTy *RHS) const { return true; }
virtual bool baseClassOf(const BitsRecTy *RHS) const;
virtual bool baseClassOf(const IntRecTy *RHS) const { return true; }
};
/// BitsRecTy - 'bits<n>' - Represent a fixed number of bits
///
class BitsRecTy : public RecTy {
unsigned Size;
public:
BitsRecTy(unsigned Sz) : Size(Sz) {}
unsigned getNumBits() const { return Size; }
Init *convertValue(UnsetInit *UI);
Init *convertValue(BitInit *UI);
Init *convertValue(BitsInit *BI);
Init *convertValue(IntInit *II);
Init *convertValue(TypedInit *VI);
void print(std::ostream &OS) const { OS << "bits<" << Size << ">"; }
bool typeIsConvertibleTo(const RecTy *RHS) const {
return RHS->baseClassOf(this);
}
virtual bool baseClassOf(const BitRecTy *RHS) const { return Size == 1; }
virtual bool baseClassOf(const IntRecTy *RHS) const { return true; }
virtual bool baseClassOf(const BitsRecTy *RHS) const {
return RHS->Size == Size;
}
};
/// IntRecTy - 'int' - Represent an integer value of no particular size
///
struct IntRecTy : public RecTy {
Init *convertValue(UnsetInit *UI) { return (Init*)UI; }
Init *convertValue(IntInit *II) { return (Init*)II; }
Init *convertValue(BitInit *BI);
Init *convertValue(BitsInit *BI);
Init *convertValue(TypedInit *TI);
void print(std::ostream &OS) const { OS << "int"; }
bool typeIsConvertibleTo(const RecTy *RHS) const {
return RHS->baseClassOf(this);
}
virtual bool baseClassOf(const BitRecTy *RHS) const { return true; }
virtual bool baseClassOf(const IntRecTy *RHS) const { return true; }
virtual bool baseClassOf(const BitsRecTy *RHS) const { return true; }
};
/// StringRecTy - 'string' - Represent an string value
///
struct StringRecTy : public RecTy {
Init *convertValue(UnsetInit *UI) { return (Init*)UI; }
Init *convertValue(StringInit *SI) { return (Init*)SI; }
Init *convertValue(TypedInit *TI);
void print(std::ostream &OS) const { OS << "string"; }
bool typeIsConvertibleTo(const RecTy *RHS) const {
return RHS->baseClassOf(this);
}
virtual bool baseClassOf(const StringRecTy *RHS) const { return true; }
};
/// ListRecTy - 'list<Ty>' - Represent a list of values, all of which must be of
/// the specified type.
///
class ListRecTy : public RecTy {
RecTy *Ty;
public:
ListRecTy(RecTy *T) : Ty(T) {}
RecTy *getElementType() const { return Ty; }
Init *convertValue(UnsetInit *UI) { return (Init*)UI; }
Init *convertValue(ListInit *LI);
Init *convertValue(TypedInit *TI);
void print(std::ostream &OS) const;
bool typeIsConvertibleTo(const RecTy *RHS) const {
return RHS->baseClassOf(this);
}
virtual bool baseClassOf(const ListRecTy *RHS) const {
return RHS->getElementType()->typeIsConvertibleTo(Ty);
}
};
/// CodeRecTy - 'code' - Represent an code fragment, function or method.
///
struct CodeRecTy : public RecTy {
Init *convertValue(UnsetInit *UI) { return (Init*)UI; }
Init *convertValue( CodeInit *CI) { return (Init*)CI; }
Init *convertValue(TypedInit *TI);
void print(std::ostream &OS) const { OS << "code"; }
bool typeIsConvertibleTo(const RecTy *RHS) const {
return RHS->baseClassOf(this);
}
virtual bool baseClassOf(const CodeRecTy *RHS) const { return true; }
};
/// DagRecTy - 'dag' - Represent a dag fragment
///
struct DagRecTy : public RecTy {
Init *convertValue(UnsetInit *UI) { return (Init*)UI; }
Init *convertValue( DagInit *CI) { return (Init*)CI; }
Init *convertValue(TypedInit *TI);
void print(std::ostream &OS) const { OS << "dag"; }
bool typeIsConvertibleTo(const RecTy *RHS) const {
return RHS->baseClassOf(this);
}
virtual bool baseClassOf(const DagRecTy *RHS) const { return true; }
};
/// RecordRecTy - '<classname>' - Represent an instance of a class, such as:
/// (R32 X = EAX).
///
class RecordRecTy : public RecTy {
Record *Rec;
public:
RecordRecTy(Record *R) : Rec(R) {}
Record *getRecord() const { return Rec; }
Init *convertValue(UnsetInit *UI) { return (Init*)UI; }
Init *convertValue( DefInit *DI);
Init *convertValue(TypedInit *VI);
void print(std::ostream &OS) const;
bool typeIsConvertibleTo(const RecTy *RHS) const {
return RHS->baseClassOf(this);
}
virtual bool baseClassOf(const RecordRecTy *RHS) const;
};
//===----------------------------------------------------------------------===//
// Initializer Classes
//===----------------------------------------------------------------------===//
struct Init {
virtual ~Init() {}
/// isComplete - This virtual method should be overridden by values that may
/// not be completely specified yet.
virtual bool isComplete() const { return true; }
/// print - Print out this value.
virtual void print(std::ostream &OS) const = 0;
/// dump - Debugging method that may be called through a debugger, just
/// invokes print on cerr.
void dump() const;
/// convertInitializerTo - This virtual function is a simple call-back
/// function that should be overridden to call the appropriate
/// RecTy::convertValue method.
///
virtual Init *convertInitializerTo(RecTy *Ty) = 0;
/// convertInitializerBitRange - This method is used to implement the bitrange
/// selection operator. Given an initializer, it selects the specified bits
/// out, returning them as a new init of bits type. If it is not legal to use
/// the bit subscript operator on this initializer, return null.
///
virtual Init *convertInitializerBitRange(const std::vector<unsigned> &Bits) {
return 0;
}
/// getFieldType - This method is used to implement the FieldInit class.
/// Implementors of this method should return the type of the named field if
/// they are of record type.
///
virtual RecTy *getFieldType(const std::string &FieldName) const { return 0; }
/// getFieldInit - This method complements getFieldType to return the
/// initializer for the specified field. If getFieldType returns non-null
/// this method should return non-null, otherwise it returns null.
///
virtual Init *getFieldInit(Record &R, const std::string &FieldName) const {
return 0;
}
/// resolveReferences - This method is used by classes that refer to other
/// variables which may not be defined at the time they expression is formed.
/// If a value is set for the variable later, this method will be called on
/// users of the value to allow the value to propagate out.
///
virtual Init *resolveReferences(Record &R) { return this; }
};
inline std::ostream &operator<<(std::ostream &OS, const Init &I) {
I.print(OS); return OS;
}
/// UnsetInit - ? - Represents an uninitialized value
///
struct UnsetInit : public Init {
virtual Init *convertInitializerTo(RecTy *Ty) {
return Ty->convertValue(this);
}
virtual bool isComplete() const { return false; }
virtual void print(std::ostream &OS) const { OS << "?"; }
};
/// BitInit - true/false - Represent a concrete initializer for a bit.
///
class BitInit : public Init {
bool Value;
public:
BitInit(bool V) : Value(V) {}
bool getValue() const { return Value; }
virtual Init *convertInitializerTo(RecTy *Ty) {
return Ty->convertValue(this);
}
virtual void print(std::ostream &OS) const { OS << (Value ? "1" : "0"); }
};
/// BitsInit - { a, b, c } - Represents an initializer for a BitsRecTy value.
/// It contains a vector of bits, whose size is determined by the type.
///
class BitsInit : public Init {
std::vector<Init*> Bits;
public:
BitsInit(unsigned Size) : Bits(Size) {}
unsigned getNumBits() const { return Bits.size(); }
Init *getBit(unsigned Bit) const {
assert(Bit < Bits.size() && "Bit index out of range!");
return Bits[Bit];
}
void setBit(unsigned Bit, Init *V) {
assert(Bit < Bits.size() && "Bit index out of range!");
assert(Bits[Bit] == 0 && "Bit already set!");
Bits[Bit] = V;
}
virtual Init *convertInitializerTo(RecTy *Ty) {
return Ty->convertValue(this);
}
virtual Init *convertInitializerBitRange(const std::vector<unsigned> &Bits);
virtual bool isComplete() const {
for (unsigned i = 0; i != getNumBits(); ++i)
if (!getBit(i)->isComplete()) return false;
return true;
}
virtual void print(std::ostream &OS) const;
virtual Init *resolveReferences(Record &R);
// printXX - Print this bitstream with the specified format, returning true if
// it is not possible.
bool printInHex(std::ostream &OS) const;
bool printAsVariable(std::ostream &OS) const;
bool printAsUnset(std::ostream &OS) const;
};
/// IntInit - 7 - Represent an initalization by a literal integer value.
///
class IntInit : public Init {
int Value;
public:
IntInit(int V) : Value(V) {}
int getValue() const { return Value; }
virtual Init *convertInitializerTo(RecTy *Ty) {
return Ty->convertValue(this);
}
virtual Init *convertInitializerBitRange(const std::vector<unsigned> &Bits);
virtual void print(std::ostream &OS) const { OS << Value; }
};
/// StringInit - "foo" - Represent an initialization by a string value.
///
class StringInit : public Init {
std::string Value;
public:
StringInit(const std::string &V) : Value(V) {}
const std::string &getValue() const { return Value; }
virtual Init *convertInitializerTo(RecTy *Ty) {
return Ty->convertValue(this);
}
virtual void print(std::ostream &OS) const { OS << "\"" << Value << "\""; }
};
/// CodeInit - "[{...}]" - Represent a code fragment.
///
class CodeInit : public Init {
std::string Value;
public:
CodeInit(const std::string &V) : Value(V) {}
const std::string getValue() const { return Value; }
virtual Init *convertInitializerTo(RecTy *Ty) {
return Ty->convertValue(this);
}
virtual void print(std::ostream &OS) const { OS << "[{" << Value << "}]"; }
};
/// ListInit - [AL, AH, CL] - Represent a list of defs
///
class ListInit : public Init {
std::vector<Init*> Values;
public:
ListInit(std::vector<Init*> &Vs) {
Values.swap(Vs);
}
unsigned getSize() const { return Values.size(); }
Init *getElement(unsigned i) const {
assert(i < Values.size() && "List element index out of range!");
return Values[i];
}
virtual Init *convertInitializerTo(RecTy *Ty) {
return Ty->convertValue(this);
}
virtual void print(std::ostream &OS) const;
};
/// TypedInit - This is the common super-class of types that have a specific,
/// explicit, type.
///
class TypedInit : public Init {
RecTy *Ty;
public:
TypedInit(RecTy *T) : Ty(T) {}
RecTy *getType() const { return Ty; }
/// resolveBitReference - This method is used to implement
/// VarBitInit::resolveReferences. If the bit is able to be resolved, we
/// simply return the resolved value, otherwise we return this.
///
virtual Init *resolveBitReference(Record &R, unsigned Bit) = 0;
};
/// VarInit - 'Opcode' - Represent a reference to an entire variable object.
///
class VarInit : public TypedInit {
std::string VarName;
public:
VarInit(const std::string &VN, RecTy *T) : TypedInit(T), VarName(VN) {}
virtual Init *convertInitializerTo(RecTy *Ty) {
return Ty->convertValue(this);
}
const std::string &getName() const { return VarName; }
virtual Init *convertInitializerBitRange(const std::vector<unsigned> &Bits);
virtual Init *resolveBitReference(Record &R, unsigned Bit);
virtual RecTy *getFieldType(const std::string &FieldName) const;
virtual Init *getFieldInit(Record &R, const std::string &FieldName) const;
/// resolveReferences - This method is used by classes that refer to other
/// variables which may not be defined at the time they expression is formed.
/// If a value is set for the variable later, this method will be called on
/// users of the value to allow the value to propagate out.
///
virtual Init *resolveReferences(Record &R);
virtual void print(std::ostream &OS) const { OS << VarName; }
};
/// VarBitInit - Opcode{0} - Represent access to one bit of a variable or field.
///
class VarBitInit : public Init {
TypedInit *TI;
unsigned Bit;
public:
VarBitInit(TypedInit *T, unsigned B) : TI(T), Bit(B) {
assert(T->getType() && dynamic_cast<BitsRecTy*>(T->getType()) &&
((BitsRecTy*)T->getType())->getNumBits() > B &&
"Illegal VarBitInit expression!");
}
virtual Init *convertInitializerTo(RecTy *Ty) {
return Ty->convertValue(this);
}
TypedInit *getVariable() const { return TI; }
unsigned getBitNum() const { return Bit; }
virtual void print(std::ostream &OS) const {
TI->print(OS); OS << "{" << Bit << "}";
}
virtual Init *resolveReferences(Record &R);
};
/// DefInit - AL - Represent a reference to a 'def' in the description
///
class DefInit : public Init {
Record *Def;
public:
DefInit(Record *D) : Def(D) {}
virtual Init *convertInitializerTo(RecTy *Ty) {
return Ty->convertValue(this);
}
Record *getDef() const { return Def; }
//virtual Init *convertInitializerBitRange(const std::vector<unsigned> &Bits);
virtual RecTy *getFieldType(const std::string &FieldName) const;
virtual Init *getFieldInit(Record &R, const std::string &FieldName) const;
virtual void print(std::ostream &OS) const;
};
/// FieldInit - X.Y - Represent a reference to a subfield of a variable
///
class FieldInit : public TypedInit {
Init *Rec; // Record we are referring to
std::string FieldName; // Field we are accessing
public:
FieldInit(Init *R, const std::string &FN)
: TypedInit(R->getFieldType(FN)), Rec(R), FieldName(FN) {
assert(getType() && "FieldInit with non-record type!");
}
virtual Init *convertInitializerTo(RecTy *Ty) {
return Ty->convertValue(this);
}
virtual Init *convertInitializerBitRange(const std::vector<unsigned> &Bits);
virtual Init *resolveBitReference(Record &R, unsigned Bit);
virtual Init *resolveReferences(Record &R);
virtual void print(std::ostream &OS) const {
Rec->print(OS); OS << "." << FieldName;
}
};
/// DagInit - (def a, b) - Represent a DAG tree value. DAG inits are required
/// to have Records for their first value, after that, any legal Init is
/// possible.
///
class DagInit : public Init {
Record *NodeTypeDef;
std::vector<Init*> Args;
std::vector<std::string> ArgNames;
public:
DagInit(Record *D, const std::vector<std::pair<Init*, std::string> > &args)
: NodeTypeDef(D) {
Args.reserve(args.size());
ArgNames.reserve(args.size());
for (unsigned i = 0, e = args.size(); i != e; ++i) {
Args.push_back(args[i].first);
ArgNames.push_back(args[i].second);
}
}
virtual Init *convertInitializerTo(RecTy *Ty) {
return Ty->convertValue(this);
}
Record *getNodeType() const { return NodeTypeDef; }
unsigned getNumArgs() const { return Args.size(); }
Init *getArg(unsigned Num) const {
assert(Num < Args.size() && "Arg number out of range!");
return Args[Num];
}
const std::string &getArgName(unsigned Num) const {
assert(Num < ArgNames.size() && "Arg number out of range!");
return ArgNames[Num];
}
void setArg(unsigned Num, Init *I) {
assert(Num < Args.size() && "Arg number out of range!");
Args[Num] = I;
}
virtual void print(std::ostream &OS) const;
};
//===----------------------------------------------------------------------===//
// High-Level Classes
//===----------------------------------------------------------------------===//
class RecordVal {
std::string Name;
RecTy *Ty;
unsigned Prefix;
Init *Value;
public:
RecordVal(const std::string &N, RecTy *T, unsigned P);
const std::string &getName() const { return Name; }
unsigned getPrefix() const { return Prefix; }
RecTy *getType() const { return Ty; }
Init *getValue() const { return Value; }
bool setValue(Init *V) {
if (V) {
Value = V->convertInitializerTo(Ty);
return Value == 0;
}
Value = 0;
return false;
}
void dump() const;
void print(std::ostream &OS, bool PrintSem = true) const;
};
inline std::ostream &operator<<(std::ostream &OS, const RecordVal &RV) {
RV.print(OS << " ");
return OS;
}
struct Record {
const std::string Name;
std::vector<std::string> TemplateArgs;
std::vector<RecordVal> Values;
std::vector<Record*> SuperClasses;
public:
Record(const std::string &N) : Name(N) {}
~Record() {}
const std::string &getName() const { return Name; }
const std::vector<std::string> &getTemplateArgs() const {
return TemplateArgs;
}
const std::vector<RecordVal> &getValues() const { return Values; }
const std::vector<Record*> &getSuperClasses() const { return SuperClasses; }
bool isTemplateArg(const std::string &Name) const {
for (unsigned i = 0, e = TemplateArgs.size(); i != e; ++i)
if (TemplateArgs[i] == Name) return true;
return false;
}
const RecordVal *getValue(const std::string &Name) const {
for (unsigned i = 0, e = Values.size(); i != e; ++i)
if (Values[i].getName() == Name) return &Values[i];
return 0;
}
RecordVal *getValue(const std::string &Name) {
for (unsigned i = 0, e = Values.size(); i != e; ++i)
if (Values[i].getName() == Name) return &Values[i];
return 0;
}
void addTemplateArg(const std::string &Name) {
assert(!isTemplateArg(Name) && "Template arg already defined!");
TemplateArgs.push_back(Name);
}
void addValue(const RecordVal &RV) {
assert(getValue(RV.getName()) == 0 && "Value already added!");
Values.push_back(RV);
}
void removeValue(const std::string &Name) {
assert(getValue(Name) && "Cannot remove an entry that does not exist!");
for (unsigned i = 0, e = Values.size(); i != e; ++i)
if (Values[i].getName() == Name) {
Values.erase(Values.begin()+i);
return;
}
assert(0 && "Name does not exist in record!");
}
bool isSubClassOf(Record *R) const {
for (unsigned i = 0, e = SuperClasses.size(); i != e; ++i)
if (SuperClasses[i] == R)
return true;
return false;
}
bool isSubClassOf(const std::string &Name) const {
for (unsigned i = 0, e = SuperClasses.size(); i != e; ++i)
if (SuperClasses[i]->getName() == Name)
return true;
return false;
}
void addSuperClass(Record *R) {
assert(!isSubClassOf(R) && "Already subclassing record!");
SuperClasses.push_back(R);
}
// resolveReferences - If there are any field references that refer to fields
// that have been filled in, we can propagate the values now.
//
void resolveReferences();
void dump() const;
//===--------------------------------------------------------------------===//
// High-level methods useful to tablegen back-ends
//
/// getValueInit - Return the initializer for a value with the specified name,
/// or throw an exception if the field does not exist.
///
Init *getValueInit(const std::string &FieldName) const;
/// getValueAsString - This method looks up the specified field and returns
/// its value as a string, throwing an exception if the field does not exist
/// or if the value is not a string.
///
std::string getValueAsString(const std::string &FieldName) const;
/// getValueAsBitsInit - This method looks up the specified field and returns
/// its value as a BitsInit, throwing an exception if the field does not exist
/// or if the value is not the right type.
///
BitsInit *getValueAsBitsInit(const std::string &FieldName) const;
/// getValueAsListInit - This method looks up the specified field and returns
/// its value as a ListInit, throwing an exception if the field does not exist
/// or if the value is not the right type.
///
ListInit *getValueAsListInit(const std::string &FieldName) const;
/// getValueAsDef - This method looks up the specified field and returns its
/// value as a Record, throwing an exception if the field does not exist or if
/// the value is not the right type.
///
Record *getValueAsDef(const std::string &FieldName) const;
/// getValueAsBit - This method looks up the specified field and returns its
/// value as a bit, throwing an exception if the field does not exist or if
/// the value is not the right type.
///
bool getValueAsBit(const std::string &FieldName) const;
/// getValueAsInt - This method looks up the specified field and returns its
/// value as an int, throwing an exception if the field does not exist or if
/// the value is not the right type.
///
int getValueAsInt(const std::string &FieldName) const;
/// getValueAsDag - This method looks up the specified field and returns its
/// value as an Dag, throwing an exception if the field does not exist or if
/// the value is not the right type.
///
DagInit *getValueAsDag(const std::string &FieldName) const;
};
std::ostream &operator<<(std::ostream &OS, const Record &R);
class RecordKeeper {
std::map<std::string, Record*> Classes, Defs;
public:
~RecordKeeper() {
for (std::map<std::string, Record*>::iterator I = Classes.begin(),
E = Classes.end(); I != E; ++I)
delete I->second;
for (std::map<std::string, Record*>::iterator I = Defs.begin(),
E = Defs.end(); I != E; ++I)
delete I->second;
}
const std::map<std::string, Record*> &getClasses() const { return Classes; }
const std::map<std::string, Record*> &getDefs() const { return Defs; }
Record *getClass(const std::string &Name) const {
std::map<std::string, Record*>::const_iterator I = Classes.find(Name);
return I == Classes.end() ? 0 : I->second;
}
Record *getDef(const std::string &Name) const {
std::map<std::string, Record*>::const_iterator I = Defs.find(Name);
return I == Defs.end() ? 0 : I->second;
}
void addClass(Record *R) {
assert(getClass(R->getName()) == 0 && "Class already exists!");
Classes.insert(std::make_pair(R->getName(), R));
}
void addDef(Record *R) {
assert(getDef(R->getName()) == 0 && "Def already exists!");
Defs.insert(std::make_pair(R->getName(), R));
}
//===--------------------------------------------------------------------===//
// High-level helper methods, useful for tablegen backends...
/// getAllDerivedDefinitions - This method returns all concrete definitions
/// that derive from the specified class name. If a class with the specified
/// name does not exist, an exception is thrown.
std::vector<Record*>
getAllDerivedDefinitions(const std::string &ClassName) const;
void dump() const;
};
std::ostream &operator<<(std::ostream &OS, const RecordKeeper &RK);
extern RecordKeeper Records;
#endif

View File

@ -1,234 +0,0 @@
//===- RegisterInfoEmitter.cpp - Generate a Register File Desc. -*- C++ -*-===//
//
// This tablegen backend is responsible for emitting a description of a target
// register file for a code generator. It uses instances of the Register,
// RegisterAliases, and RegisterClass classes to gather this information.
//
//===----------------------------------------------------------------------===//
#include "RegisterInfoEmitter.h"
#include "CodeGenWrappers.h"
#include "Record.h"
#include "Support/StringExtras.h"
#include <set>
// runEnums - Print out enum values for all of the registers.
void RegisterInfoEmitter::runEnums(std::ostream &OS) {
std::vector<Record*> Registers = Records.getAllDerivedDefinitions("Register");
if (Registers.size() == 0)
throw std::string("No 'Register' subclasses defined!");
std::string Namespace = Registers[0]->getValueAsString("Namespace");
EmitSourceFileHeader("Target Register Enum Values", OS);
if (!Namespace.empty())
OS << "namespace " << Namespace << " {\n";
OS << " enum {\n NoRegister,\n";
for (unsigned i = 0, e = Registers.size(); i != e; ++i)
OS << " " << Registers[i]->getName() << ", \t// " << i+1 << "\n";
OS << " };\n";
if (!Namespace.empty())
OS << "}\n";
}
void RegisterInfoEmitter::runHeader(std::ostream &OS) {
EmitSourceFileHeader("Register Information Header Fragment", OS);
const std::string &TargetName = CodeGenTarget().getName();
std::string ClassName = TargetName + "GenRegisterInfo";
OS << "#include \"llvm/Target/MRegisterInfo.h\"\n\n";
OS << "struct " << ClassName << " : public MRegisterInfo {\n"
<< " " << ClassName
<< "(int CallFrameSetupOpcode = -1, int CallFrameDestroyOpcode = -1);\n"
<< " const unsigned* getCalleeSaveRegs() const;\n"
<< "};\n\n";
std::vector<Record*> RegisterClasses =
Records.getAllDerivedDefinitions("RegisterClass");
OS << "namespace " << TargetName << " { // Register classes\n";
for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i) {
if (RegisterClasses[i]->getValueAsBit("isDummyClass"))
continue; // Ignore dummies
const std::string &Name = RegisterClasses[i]->getName();
if (Name.size() < 9 || Name[9] != '.') // Ignore anonymous classes
OS << " extern TargetRegisterClass *" << Name << "RegisterClass;\n";
}
OS << "} // end of namespace " << TargetName << "\n\n";
}
// RegisterInfoEmitter::run - Main register file description emitter.
//
void RegisterInfoEmitter::run(std::ostream &OS) {
EmitSourceFileHeader("Register Information Source Fragment", OS);
// Start out by emitting each of the register classes... to do this, we build
// a set of registers which belong to a register class, this is to ensure that
// each register is only in a single register class.
//
std::vector<Record*> RegisterClasses =
Records.getAllDerivedDefinitions("RegisterClass");
std::vector<Record*> Registers = Records.getAllDerivedDefinitions("Register");
std::set<Record*> RegistersFound;
std::vector<std::string> RegClassNames;
// Loop over all of the register classes... emitting each one.
OS << "namespace { // Register classes...\n";
for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) {
Record *RC = RegisterClasses[rc];
if (RC->getValueAsBit("isDummyClass")) continue; // Ignore dummies
std::string Name = RC->getName();
if (Name.size() > 9 && Name[9] == '.') {
static unsigned AnonCounter = 0;
Name = "AnonRegClass_"+utostr(AnonCounter++);
}
RegClassNames.push_back(Name);
// Emit the register list now...
OS << " // " << Name << " Register Class...\n const unsigned " << Name
<< "[] = {\n ";
ListInit *RegList = RC->getValueAsListInit("MemberList");
for (unsigned i = 0, e = RegList->getSize(); i != e; ++i) {
DefInit *RegDef = dynamic_cast<DefInit*>(RegList->getElement(i));
if (!RegDef) throw "Register class member is not a record!";
Record *Reg = RegDef->getDef();
if (!Reg->isSubClassOf("Register"))
throw "Register Class member '" + Reg->getName() +
" does not derive from the Register class!";
if (RegistersFound.count(Reg))
throw "Register '" + Reg->getName() +
"' included in multiple register classes!";
RegistersFound.insert(Reg);
OS << getQualifiedName(Reg) << ", ";
}
OS << "\n };\n\n";
OS << " struct " << Name << "Class : public TargetRegisterClass {\n"
<< " " << Name << "Class() : TargetRegisterClass("
<< RC->getValueAsInt("Size")/8 << ", " << RC->getValueAsInt("Alignment")
<< ", " << Name << ", " << Name << " + " << RegList->getSize()
<< ") {}\n";
if (CodeInit *CI = dynamic_cast<CodeInit*>(RC->getValueInit("Methods")))
OS << CI->getValue();
else
throw "Expected 'code' fragment for 'Methods' value in register class '"+
RC->getName() + "'!";
OS << " } " << Name << "Instance;\n\n";
}
OS << " const TargetRegisterClass* const RegisterClasses[] = {\n";
for (unsigned i = 0, e = RegClassNames.size(); i != e; ++i)
OS << " &" << RegClassNames[i] << "Instance,\n";
OS << " };\n";
// Emit register class aliases...
std::vector<Record*> RegisterAliasesRecs =
Records.getAllDerivedDefinitions("RegisterAliases");
std::map<Record*, std::set<Record*> > RegisterAliases;
for (unsigned i = 0, e = RegisterAliasesRecs.size(); i != e; ++i) {
Record *AS = RegisterAliasesRecs[i];
Record *R = AS->getValueAsDef("Reg");
ListInit *LI = AS->getValueAsListInit("Aliases");
// Add information that R aliases all of the elements in the list... and
// that everything in the list aliases R.
for (unsigned j = 0, e = LI->getSize(); j != e; ++j) {
DefInit *Reg = dynamic_cast<DefInit*>(LI->getElement(j));
if (!Reg) throw "ERROR: Alias list element is not a def!";
if (RegisterAliases[R].count(Reg->getDef()))
std::cerr << "Warning: register alias between " << getQualifiedName(R)
<< " and " << getQualifiedName(Reg->getDef())
<< " specified multiple times!\n";
RegisterAliases[R].insert(Reg->getDef());
if (RegisterAliases[Reg->getDef()].count(R))
std::cerr << "Warning: register alias between " << getQualifiedName(R)
<< " and " << getQualifiedName(Reg->getDef())
<< " specified multiple times!\n";
RegisterAliases[Reg->getDef()].insert(R);
}
}
if (!RegisterAliases.empty())
OS << "\n\n // Register Alias Sets...\n";
// Loop over all of the registers which have aliases, emitting the alias list
// to memory.
for (std::map<Record*, std::set<Record*> >::iterator
I = RegisterAliases.begin(), E = RegisterAliases.end(); I != E; ++I) {
OS << " const unsigned " << I->first->getName() << "_AliasSet[] = { ";
for (std::set<Record*>::iterator ASI = I->second.begin(),
E = I->second.end(); ASI != E; ++ASI)
OS << getQualifiedName(*ASI) << ", ";
OS << "0 };\n";
}
OS << "\n const MRegisterDesc RegisterDescriptors[] = { // Descriptors\n";
OS << " { \"NOREG\",\t0,\t\t0,\t0 },\n";
// Now that register alias sets have been emitted, emit the register
// descriptors now.
for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
Record *Reg = Registers[i];
OS << " { \"";
if (!Reg->getValueAsString("Name").empty())
OS << Reg->getValueAsString("Name");
else
OS << Reg->getName();
OS << "\",\t";
if (RegisterAliases.count(Reg))
OS << Reg->getName() << "_AliasSet,\t";
else
OS << "0,\t\t";
OS << "0, 0 },\n";
}
OS << " };\n"; // End of register descriptors...
OS << "}\n\n"; // End of anonymous namespace...
CodeGenTarget Target;
OS << "namespace " << Target.getName() << " { // Register classes\n";
for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i) {
if (RegisterClasses[i]->getValueAsBit("isDummyClass"))
continue; // Ignore dummies
const std::string &Name = RegisterClasses[i]->getName();
if (Name.size() < 9 || Name[9] != '.') // Ignore anonymous classes
OS << " TargetRegisterClass *" << Name << "RegisterClass = &"
<< Name << "Instance;\n";
}
OS << "} // end of namespace " << Target.getName() << "\n\n";
std::string ClassName = Target.getName() + "GenRegisterInfo";
// Emit the constructor of the class...
OS << ClassName << "::" << ClassName
<< "(int CallFrameSetupOpcode, int CallFrameDestroyOpcode)\n"
<< " : MRegisterInfo(RegisterDescriptors, " << Registers.size()+1
<< ", RegisterClasses, RegisterClasses+" << RegClassNames.size() << ",\n "
<< " CallFrameSetupOpcode, CallFrameDestroyOpcode) {}\n\n";
// Emit the getCalleeSaveRegs method...
OS << "const unsigned* " << ClassName << "::getCalleeSaveRegs() const {\n"
<< " static const unsigned CalleeSaveRegs[] = {\n ";
const std::vector<Record*> &CSR = Target.getCalleeSavedRegisters();
for (unsigned i = 0, e = CSR.size(); i != e; ++i)
OS << getQualifiedName(CSR[i]) << ", ";
OS << " 0\n };\n return CalleeSaveRegs;\n}\n\n";
}

View File

@ -1,29 +0,0 @@
//===- RegisterInfoEmitter.h - Generate a Register File Desc. ---*- C++ -*-===//
//
// This tablegen backend is responsible for emitting a description of a target
// register file for a code generator. It uses instances of the Register,
// RegisterAliases, and RegisterClass classes to gather this information.
//
//===----------------------------------------------------------------------===//
#ifndef REGISTER_INFO_EMITTER_H
#define REGISTER_INFO_EMITTER_H
#include "TableGenBackend.h"
class RegisterInfoEmitter : public TableGenBackend {
RecordKeeper &Records;
public:
RegisterInfoEmitter(RecordKeeper &R) : Records(R) {}
// run - Output the register file description, returning true on failure.
void run(std::ostream &o);
// runHeader - Emit a header fragment for the register info emitter.
void runHeader(std::ostream &o);
// runEnums - Print out enum values for all of the registers.
void runEnums(std::ostream &o);
};
#endif

View File

@ -1,482 +0,0 @@
//===- TableGen.cpp - Top-Level TableGen implementation -------------------===//
//
// 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
// description in some predefined format. In practice, this is used by the LLVM
// code generators to automate generation of a code generator through a
// high-level description of the target.
//
//===----------------------------------------------------------------------===//
#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,
GenRegisterEnums, GenRegister, GenRegisterHeader,
GenInstrEnums, GenInstrs, GenInstrSelector,
PrintEnums,
Parse,
};
namespace {
cl::opt<ActionType>
Action(cl::desc("Action to perform:"),
cl::values(clEnumValN(PrintRecords, "print-records",
"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",
"Interpret machine code (testing only)"),
0));
cl::opt<std::string>
Class("class", cl::desc("Print Enum list for this class"),
cl::value_desc("class name"));
cl::opt<std::string>
OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"),
cl::init("-"));
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, const std::string & IncludeDir);
RecordKeeper Records;
static Init *getBit(Record *R, unsigned BitNo) {
const std::vector<RecordVal> &V = R->getValues();
for (unsigned i = 0, e = V.size(); i != e; ++i)
if (V[i].getPrefix()) {
assert(dynamic_cast<BitsInit*>(V[i].getValue()) &&
"Can only handle fields of bits<> type!");
BitsInit *I = (BitsInit*)V[i].getValue();
if (BitNo < I->getNumBits())
return I->getBit(BitNo);
BitNo -= I->getNumBits();
}
std::cerr << "Cannot find requested bit!\n";
abort();
return 0;
}
static unsigned getNumBits(Record *R) {
const std::vector<RecordVal> &V = R->getValues();
unsigned Num = 0;
for (unsigned i = 0, e = V.size(); i != e; ++i)
if (V[i].getPrefix()) {
assert(dynamic_cast<BitsInit*>(V[i].getValue()) &&
"Can only handle fields of bits<> type!");
Num += ((BitsInit*)V[i].getValue())->getNumBits();
}
return Num;
}
static bool BitsAreFixed(Record *I1, Record *I2, unsigned BitNo) {
return dynamic_cast<BitInit*>(getBit(I1, BitNo)) &&
dynamic_cast<BitInit*>(getBit(I2, BitNo));
}
static bool BitsAreEqual(Record *I1, Record *I2, unsigned BitNo) {
BitInit *Bit1 = dynamic_cast<BitInit*>(getBit(I1, BitNo));
BitInit *Bit2 = dynamic_cast<BitInit*>(getBit(I2, BitNo));
return Bit1 && Bit2 && Bit1->getValue() == Bit2->getValue();
}
static bool BitRangesEqual(Record *I1, Record *I2,
unsigned Start, unsigned End) {
for (unsigned i = Start; i != End; ++i)
if (!BitsAreEqual(I1, I2, i))
return false;
return true;
}
static unsigned getFirstFixedBit(Record *R, unsigned FirstFixedBit) {
// Look for the first bit of the pair that are required to be 0 or 1.
while (!dynamic_cast<BitInit*>(getBit(R, FirstFixedBit)))
++FirstFixedBit;
return FirstFixedBit;
}
static void FindInstDifferences(Record *I1, Record *I2,
unsigned FirstFixedBit, unsigned MaxBits,
unsigned &FirstVaryingBitOverall,
unsigned &LastFixedBitOverall) {
// Compare the first instruction to the rest of the instructions, looking for
// fields that differ.
//
unsigned FirstVaryingBit = FirstFixedBit;
while (FirstVaryingBit < MaxBits && BitsAreEqual(I1, I2, FirstVaryingBit))
++FirstVaryingBit;
unsigned LastFixedBit = FirstVaryingBit;
while (LastFixedBit < MaxBits && BitsAreFixed(I1, I2, LastFixedBit))
++LastFixedBit;
if (FirstVaryingBit < FirstVaryingBitOverall)
FirstVaryingBitOverall = FirstVaryingBit;
if (LastFixedBit < LastFixedBitOverall)
LastFixedBitOverall = LastFixedBit;
}
static bool getBitValue(Record *R, unsigned BitNo) {
Init *I = getBit(R, BitNo);
assert(dynamic_cast<BitInit*>(I) && "Bit should be fixed!");
return ((BitInit*)I)->getValue();
}
struct BitComparator {
unsigned BitBegin, BitEnd;
BitComparator(unsigned B, unsigned E) : BitBegin(B), BitEnd(E) {}
bool operator()(Record *R1, Record *R2) { // Return true if R1 is less than R2
for (unsigned i = BitBegin; i != BitEnd; ++i) {
bool V1 = getBitValue(R1, i), V2 = getBitValue(R2, i);
if (V1 < V2)
return true;
else if (V2 < V1)
return false;
}
return false;
}
};
static void PrintRange(std::vector<Record*>::iterator I,
std::vector<Record*>::iterator E) {
while (I != E) std::cerr << **I++;
}
static bool getMemoryBit(unsigned char *M, unsigned i) {
return (M[i/8] & (1 << (i&7))) != 0;
}
static unsigned getFirstFixedBitInSequence(std::vector<Record*>::iterator IB,
std::vector<Record*>::iterator IE,
unsigned StartBit) {
unsigned FirstFixedBit = 0;
for (std::vector<Record*>::iterator I = IB; I != IE; ++I)
FirstFixedBit = std::max(FirstFixedBit, getFirstFixedBit(*I, StartBit));
return FirstFixedBit;
}
// ParseMachineCode - Try to split the vector of instructions (which is
// 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,
unsigned char *M) {
assert(InstsB != InstsE && "Empty range?");
if (InstsB+1 == InstsE) {
// Only a single instruction, see if we match it...
Record *Inst = *InstsB;
for (unsigned i = 0, e = getNumBits(Inst); i != e; ++i)
if (BitInit *BI = dynamic_cast<BitInit*>(getBit(Inst, i)))
if (getMemoryBit(M, i) != BI->getValue())
throw std::string("Parse failed!\n");
return Inst;
}
unsigned MaxBits = ~0;
for (std::vector<Record*>::iterator I = InstsB; I != InstsE; ++I)
MaxBits = std::min(MaxBits, getNumBits(*I));
unsigned FirstFixedBit = getFirstFixedBitInSequence(InstsB, InstsE, 0);
unsigned FirstVaryingBit, LastFixedBit;
do {
FirstVaryingBit = ~0;
LastFixedBit = ~0;
for (std::vector<Record*>::iterator I = InstsB+1; I != InstsE; ++I)
FindInstDifferences(*InstsB, *I, FirstFixedBit, MaxBits,
FirstVaryingBit, LastFixedBit);
if (FirstVaryingBit == MaxBits) {
std::cerr << "ERROR: Could not find bit to distinguish between "
<< "the following entries!\n";
PrintRange(InstsB, InstsE);
}
#if 0
std::cerr << "FVB: " << FirstVaryingBit << " - " << LastFixedBit
<< ": " << InstsE-InstsB << "\n";
#endif
FirstFixedBit = getFirstFixedBitInSequence(InstsB, InstsE, FirstVaryingBit);
} while (FirstVaryingBit != FirstFixedBit);
//std::cerr << "\n\nXXXXXXXXXXXXXXXXX\n\n";
//PrintRange(InstsB, InstsE);
// Sort the Insts list so that the entries have all of the bits in the range
// [FirstVaryingBit,LastFixedBit) sorted. These bits are all guaranteed to be
// set to either 0 or 1 (BitInit values), which simplifies things.
//
std::sort(InstsB, InstsE, BitComparator(FirstVaryingBit, LastFixedBit));
// Once the list is sorted by these bits, split the bit list into smaller
// lists, and recurse on each one.
//
std::vector<Record*>::iterator RangeBegin = InstsB;
Record *Match = 0;
while (RangeBegin != InstsE) {
std::vector<Record*>::iterator RangeEnd = RangeBegin+1;
while (RangeEnd != InstsE &&
BitRangesEqual(*RangeBegin, *RangeEnd, FirstVaryingBit, LastFixedBit))
++RangeEnd;
// We just identified a range of equal instructions. If this range is the
// input range, we were not able to distinguish between the instructions in
// the set. Print an error and exit!
//
if (RangeBegin == InstsB && RangeEnd == InstsE) {
std::cerr << "Error: Could not distinguish among the following insts!:\n";
PrintRange(InstsB, InstsE);
abort();
}
#if 0
std::cerr << "FVB: " << FirstVaryingBit << " - " << LastFixedBit
<< ": [" << RangeEnd-RangeBegin << "] - ";
for (int i = LastFixedBit-1; i >= (int)FirstVaryingBit; --i)
std::cerr << (int)((BitInit*)getBit(*RangeBegin, i))->getValue() << " ";
std::cerr << "\n";
#endif
if (Record *R = ParseMachineCode(RangeBegin, RangeEnd, M)) {
if (Match) {
std::cerr << "Error: Multiple matches found:\n";
PrintRange(InstsB, InstsE);
}
assert(Match == 0 && "Multiple matches??");
Match = R;
}
RangeBegin = RangeEnd;
}
return Match;
}
static void PrintValue(Record *I, unsigned char *Ptr, const RecordVal &Val) {
assert(dynamic_cast<BitsInit*>(Val.getValue()) &&
"Can only handle undefined bits<> types!");
BitsInit *BI = (BitsInit*)Val.getValue();
assert(BI->getNumBits() <= 32 && "Can only handle fields up to 32 bits!");
unsigned Value = 0;
const std::vector<RecordVal> &Vals = I->getValues();
// Start by filling in fixed values...
for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i)
if (BitInit *B = dynamic_cast<BitInit*>(BI->getBit(i)))
Value |= B->getValue() << i;
// Loop over all of the fields in the instruction adding in any
// contributions to this value (due to bit references).
//
unsigned Offset = 0;
for (unsigned f = 0, e = Vals.size(); f != e; ++f)
if (Vals[f].getPrefix()) {
BitsInit *FieldInitializer = (BitsInit*)Vals[f].getValue();
if (&Vals[f] == &Val) {
// Read the bits directly now...
for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i)
Value |= getMemoryBit(Ptr, Offset+i) << i;
break;
}
// Scan through the field looking for bit initializers of the current
// variable...
for (unsigned i = 0, e = FieldInitializer->getNumBits(); i != e; ++i)
if (VarBitInit *VBI =
dynamic_cast<VarBitInit*>(FieldInitializer->getBit(i))) {
TypedInit *TI = VBI->getVariable();
if (VarInit *VI = dynamic_cast<VarInit*>(TI)) {
if (VI->getName() == Val.getName())
Value |= getMemoryBit(Ptr, Offset+i) << VBI->getBitNum();
} else if (FieldInit *FI = dynamic_cast<FieldInit*>(TI)) {
// FIXME: implement this!
std::cerr << "FIELD INIT not implemented yet!\n";
}
}
Offset += FieldInitializer->getNumBits();
}
std::cout << "0x" << std::hex << Value << std::dec;
}
static void PrintInstruction(Record *I, unsigned char *Ptr) {
std::cout << "Inst " << getNumBits(I)/8 << " bytes: "
<< "\t" << I->getName() << "\t" << *I->getValue("Name")->getValue()
<< "\t";
const std::vector<RecordVal> &Vals = I->getValues();
for (unsigned i = 0, e = Vals.size(); i != e; ++i)
if (!Vals[i].getValue()->isComplete()) {
std::cout << Vals[i].getName() << "=";
PrintValue(I, Ptr, Vals[i]);
std::cout << "\t";
}
std::cout << "\n";// << *I;
}
static void ParseMachineCode() {
// X86 code
unsigned char Buffer[] = {
0x55, // push EBP
0x89, 0xE5, // mov EBP, ESP
//0x83, 0xEC, 0x08, // sub ESP, 0x8
0xE8, 1, 2, 3, 4, // call +0x04030201
0x89, 0xEC, // mov ESP, EBP
0x5D, // pop EBP
0xC3, // ret
0x90, // nop
0xC9, // leave
0x89, 0xF6, // mov ESI, ESI
0x68, 1, 2, 3, 4, // push 0x04030201
0x5e, // pop ESI
0xFF, 0xD0, // call EAX
0xB8, 1, 2, 3, 4, // mov EAX, 0x04030201
0x85, 0xC0, // test EAX, EAX
0xF4, // hlt
};
#if 0
// SparcV9 code
unsigned char Buffer[] = { 0xbf, 0xe0, 0x20, 0x1f, 0x1, 0x0, 0x0, 0x1,
0x0, 0x0, 0x0, 0x0, 0xc1, 0x0, 0x20, 0x1, 0x1,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x1,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0xaf, 0xe8, 0x20, 0x17
};
#endif
std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction");
unsigned char *BuffPtr = Buffer;
while (1) {
Record *R = ParseMachineCode(Insts.begin(), Insts.end(), BuffPtr);
PrintInstruction(R, BuffPtr);
unsigned Bits = getNumBits(R);
assert((Bits & 7) == 0 && "Instruction is not an even number of bytes!");
BuffPtr += Bits/8;
}
}
int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv);
ParseFile(InputFilename, IncludeDir);
std::ostream *Out = &std::cout;
if (OutputFilename != "-") {
// 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 << ".tmp!\n";
return 1;
}
// Make sure the file gets removed if *gasp* tablegen crashes...
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 GenInstrEnums:
InstrInfoEmitter(Records).runEnums(*Out);
break;
case GenInstrs:
InstrInfoEmitter(Records).run(*Out);
break;
case GenInstrSelector:
InstrSelectorEmitter(Records).run(*Out);
break;
case PrintEnums:
std::vector<Record*> Recs = Records.getAllDerivedDefinitions(Class);
for (unsigned i = 0, e = Recs.size(); i != e; ++i)
*Out << Recs[i] << ", ";
*Out << "\n";
break;
}
} catch (const std::string &Error) {
std::cerr << Error << "\n";
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; // 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;
}

View File

@ -1,27 +0,0 @@
//===- TableGenBackend.cpp - Base class for TableGen Backends ---*- C++ -*-===//
//
// This file provides useful services for TableGen backends...
//
//===----------------------------------------------------------------------===//
#include "TableGenBackend.h"
#include "Record.h"
#include <iostream>
void TableGenBackend::EmitSourceFileHeader(const std::string &Desc,
std::ostream &OS) const {
OS << "//===- TableGen'erated file -------------------------------------*-"
" C++ -*-===//\n//\n// " << Desc << "\n//\n// Automatically generate"
"d file, do not edit!\n//\n//===------------------------------------"
"----------------------------------===//\n\n";
}
/// getQualifiedName - Return the name of the specified record, with a
/// namespace qualifier if the record contains one.
///
std::string TableGenBackend::getQualifiedName(Record *R) const {
std::string Namespace = R->getValueAsString("Namespace");
if (Namespace.empty()) return R->getName();
return Namespace + "::" + R->getName();
}

View File

@ -1,34 +0,0 @@
//===- TableGenBackend.h - Base class for TableGen Backends -----*- C++ -*-===//
//
// The TableGenBackend class is provided as a common interface for all TableGen
// backends. It provides useful services and an standardized interface.
//
//===----------------------------------------------------------------------===//
#ifndef TABLEGENBACKEND_H
#define TABLEGENBACKEND_H
#include <string>
#include <iosfwd>
class Record;
class RecordKeeper;
struct TableGenBackend {
virtual ~TableGenBackend() {}
// run - All TableGen backends should implement the run method, which should
// be the main entry point.
virtual void run(std::ostream &OS) = 0;
public: // Useful helper routines...
/// EmitSourceFileHeader - Output a LLVM style file header to the specified
/// ostream.
void EmitSourceFileHeader(const std::string &Desc, std::ostream &OS) const;
/// getQualifiedName - Return the name of the specified record, with a
/// namespace qualifier if the record contains one.
std::string getQualifiedName(Record *R) const;
};
#endif