mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-13 22:58:50 +00:00
Move support/lib into lib/Support
Move support/tools into utils llvm-svn: 8878
This commit is contained in:
parent
e522cdbdff
commit
ae8aec994f
@ -1,6 +0,0 @@
|
||||
LEVEL = ..
|
||||
|
||||
DIRS = lib tools
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
@ -1,6 +0,0 @@
|
||||
LEVEL = ../..
|
||||
|
||||
DIRS = Support
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
@ -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
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
LEVEL = ../../..
|
||||
LIBRARYNAME = support
|
||||
BUILD_ARCHIVE = 1
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
@ -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
|
||||
}
|
||||
|
@ -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"));
|
@ -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);
|
||||
}
|
@ -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...
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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));
|
||||
}
|
@ -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.
|
@ -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
|
@ -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.
@ -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).
|
@ -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}
|
||||
|
@ -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.
|
||||
|
@ -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
|
@ -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.
|
||||
|
@ -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.
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
@ -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); }
|
||||
;
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
@ -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");
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
@ -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");
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
LEVEL = ../..
|
||||
|
||||
DIRS = Burg TableGen
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
@ -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";
|
||||
}
|
@ -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
|
@ -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");
|
||||
}
|
@ -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
|
@ -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]; }
|
||||
|
||||
%%
|
@ -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();
|
||||
}
|
@ -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.";
|
||||
}
|
@ -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
@ -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
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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";
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
Loading…
Reference in New Issue
Block a user