aboutsummaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
authorDan Gohman <djg@cray.com>2007-07-18 16:29:46 +0000
committerDan Gohman <djg@cray.com>2007-07-18 16:29:46 +0000
commitf17a25c88b892d30c2b41ba7ecdfbdfb2b4be9cc (patch)
treeebb79ea1ee5e3bc1fdf38541a811a8b804f0679a /utils
downloadexternal_llvm-f17a25c88b892d30c2b41ba7ecdfbdfb2b4be9cc.tar.gz
external_llvm-f17a25c88b892d30c2b41ba7ecdfbdfb2b4be9cc.tar.bz2
external_llvm-f17a25c88b892d30c2b41ba7ecdfbdfb2b4be9cc.zip
It's not necessary to do rounding for alloca operations when the requested
alignment is equal to the stack alignment. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40004 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'utils')
-rwxr-xr-xutils/DSAclean.py32
-rw-r--r--utils/DSAextract.py111
-rwxr-xr-xutils/GenLibDeps.pl209
-rw-r--r--utils/Makefile21
-rw-r--r--utils/NLT.schema8
-rwxr-xr-xutils/NewNightlyTest.pl1156
-rw-r--r--utils/NightlyTest.gnuplot214
-rw-r--r--utils/NightlyTestTemplate.html244
-rw-r--r--utils/OldenDataRecover.pl37
-rw-r--r--utils/PerfectShuffle/Makefile14
-rw-r--r--utils/PerfectShuffle/PerfectShuffle.cpp497
-rwxr-xr-xutils/RegressionFinder.pl186
-rw-r--r--utils/TableGen/AsmWriterEmitter.cpp700
-rw-r--r--utils/TableGen/AsmWriterEmitter.h50
-rw-r--r--utils/TableGen/CallingConvEmitter.cpp139
-rw-r--r--utils/TableGen/CallingConvEmitter.h38
-rw-r--r--utils/TableGen/CodeEmitterGen.cpp228
-rw-r--r--utils/TableGen/CodeEmitterGen.h43
-rw-r--r--utils/TableGen/CodeGenInstruction.h146
-rw-r--r--utils/TableGen/CodeGenIntrinsics.h64
-rw-r--r--utils/TableGen/CodeGenRegisters.h59
-rw-r--r--utils/TableGen/CodeGenTarget.cpp655
-rw-r--r--utils/TableGen/CodeGenTarget.h180
-rw-r--r--utils/TableGen/DAGISelEmitter.cpp4001
-rw-r--r--utils/TableGen/DAGISelEmitter.h543
-rw-r--r--utils/TableGen/FileLexer.cpp.cvs1983
-rw-r--r--utils/TableGen/FileLexer.l240
-rw-r--r--utils/TableGen/FileLexer.l.cvs240
-rw-r--r--utils/TableGen/FileParser.cpp.cvs2863
-rw-r--r--utils/TableGen/FileParser.h.cvs120
-rw-r--r--utils/TableGen/FileParser.y806
-rw-r--r--utils/TableGen/FileParser.y.cvs806
-rw-r--r--utils/TableGen/InstrInfoEmitter.cpp365
-rw-r--r--utils/TableGen/InstrInfoEmitter.h59
-rw-r--r--utils/TableGen/IntrinsicEmitter.cpp389
-rw-r--r--utils/TableGen/IntrinsicEmitter.h57
-rw-r--r--utils/TableGen/Makefile29
-rw-r--r--utils/TableGen/Record.cpp955
-rw-r--r--utils/TableGen/Record.h1147
-rw-r--r--utils/TableGen/RegisterInfoEmitter.cpp568
-rw-r--r--utils/TableGen/RegisterInfoEmitter.h40
-rw-r--r--utils/TableGen/SubtargetEmitter.cpp523
-rw-r--r--utils/TableGen/SubtargetEmitter.h62
-rw-r--r--utils/TableGen/TableGen.cpp193
-rw-r--r--utils/TableGen/TableGenBackend.cpp34
-rw-r--r--utils/TableGen/TableGenBackend.h46
-rwxr-xr-xutils/cgiplotNLT.pl68
-rwxr-xr-xutils/check-each-file150
-rwxr-xr-xutils/codegen-diff135
-rwxr-xr-xutils/countloc.sh40
-rw-r--r--utils/emacs/README27
-rw-r--r--utils/emacs/emacs.el12
-rw-r--r--utils/emacs/llvm-mode.el127
-rw-r--r--utils/emacs/tablegen-mode.el133
-rwxr-xr-xutils/findmisopt178
-rwxr-xr-xutils/findoptdiff101
-rwxr-xr-xutils/findsym.pl33
-rw-r--r--utils/fpcmp/Makefile16
-rw-r--r--utils/fpcmp/fpcmp.cpp43
-rwxr-xr-xutils/getsrcs.sh34
-rw-r--r--utils/importNLT.pl86
-rwxr-xr-xutils/llvm-native-gcc249
-rwxr-xr-xutils/llvm-native-gxx249
-rwxr-xr-xutils/llvmdo198
-rwxr-xr-xutils/llvmgrep39
-rwxr-xr-xutils/makellvm144
-rwxr-xr-xutils/mkpatch37
-rw-r--r--utils/parseNLT.pl34
-rw-r--r--utils/plotNLT.pl53
-rwxr-xr-xutils/profile.pl75
-rwxr-xr-xutils/userloc.pl216
-rw-r--r--utils/vim/README43
-rw-r--r--utils/vim/llvm.vim61
-rw-r--r--utils/vim/tablegen.vim41
-rw-r--r--utils/vim/vimrc40
-rwxr-xr-xutils/webNLT.pl83
76 files changed, 23845 insertions, 0 deletions
diff --git a/utils/DSAclean.py b/utils/DSAclean.py
new file mode 100755
index 0000000000..6c43357019
--- /dev/null
+++ b/utils/DSAclean.py
@@ -0,0 +1,32 @@
+#! /usr/bin/python
+
+#changelog:
+#10/13/2005b: replaced the # in tmp(.#*)* with alphanumeric and _, this will then remove
+#nodes such as %tmp.1.i and %tmp._i.3
+#10/13/2005: exntended to remove variables of the form %tmp(.#)* rather than just
+#%tmp.#, i.e. it now will remove %tmp.12.3.15 etc, additionally fixed a spelling error in
+#the comments
+#10/12/2005: now it only removes nodes and edges for which the label is %tmp.# rather
+#than removing all lines for which the lable CONTAINS %tmp.#
+import re
+import sys
+if( len(sys.argv) < 3 ):
+ print 'usage is: ./DSAclean <dot_file_to_be_cleaned> <out_put_file>'
+ sys.exit(1)
+#get a file object
+input = open(sys.argv[1], 'r')
+output = open(sys.argv[2], 'w')
+#we'll get this one line at a time...while we could just put the whole thing in a string
+#it would kill old computers
+buffer = input.readline()
+while buffer != '':
+ if re.compile("label(\s*)=(\s*)\"\s%tmp(.\w*)*(\s*)\"").search(buffer):
+ #skip next line, write neither this line nor the next
+ buffer = input.readline()
+ else:
+ #this isn't a tmp Node, we can write it
+ output.write(buffer)
+ #prepare for the next iteration
+ buffer = input.readline()
+input.close()
+output.close()
diff --git a/utils/DSAextract.py b/utils/DSAextract.py
new file mode 100644
index 0000000000..134e9453fb
--- /dev/null
+++ b/utils/DSAextract.py
@@ -0,0 +1,111 @@
+#! /usr/bin/python
+
+#this is a script to extract given named nodes from a dot file, with
+#the associated edges. An edge is kept iff for edge x -> y
+# x and y are both nodes specified to be kept.
+
+#known issues: if a line contains '->' and is not an edge line
+#problems will occur. If node labels do not begin with
+#Node this also will not work. Since this is designed to work
+#on DSA dot output and not general dot files this is ok.
+#If you want to use this on other files rename the node labels
+#to Node[.*] with a script or something. This also relies on
+#the length of a node name being 13 characters (as it is in all
+#DSA dot output files)
+
+#Note that the name of the node can be any substring of the actual
+#name in the dot file. Thus if you say specify COLLAPSED
+#as a parameter this script will pull out all COLLAPSED
+#nodes in the file
+
+#Specifying escape characters in the name like \n also will not work,
+#as Python
+#will make it \\n, I'm not really sure how to fix this
+
+#currently the script prints the names it is searching for
+#to STDOUT, so you can check to see if they are what you intend
+
+import re
+import string
+import sys
+
+
+if len(sys.argv) < 3:
+ print 'usage is ./DSAextract <dot_file_to_modify> \
+ <output_file> [list of nodes to extract]'
+
+#open the input file
+input = open(sys.argv[1], 'r')
+
+#construct a set of node names
+node_name_set = set()
+for name in sys.argv[3:]:
+ node_name_set |= set([name])
+
+#construct a list of compiled regular expressions from the
+#node_name_set
+regexp_list = []
+for name in node_name_set:
+ regexp_list.append(re.compile(name))
+
+#used to see what kind of line we are on
+nodeexp = re.compile('Node')
+#used to check to see if the current line is an edge line
+arrowexp = re.compile('->')
+
+node_set = set()
+
+#read the file one line at a time
+buffer = input.readline()
+while buffer != '':
+ #filter out the unecessary checks on all the edge lines
+ if not arrowexp.search(buffer):
+ #check to see if this is a node we are looking for
+ for regexp in regexp_list:
+ #if this name is for the current node, add the dot variable name
+ #for the node (it will be Node(hex number)) to our set of nodes
+ if regexp.search(buffer):
+ node_set |= set([re.split('\s+',buffer,2)[1]])
+ break
+ buffer = input.readline()
+
+
+#test code
+#print '\n'
+
+print node_name_set
+
+#print node_set
+
+
+#open the output file
+output = open(sys.argv[2], 'w')
+#start the second pass over the file
+input = open(sys.argv[1], 'r')
+
+buffer = input.readline()
+while buffer != '':
+ #there are three types of lines we are looking for
+ #1) node lines, 2) edge lines 3) support lines (like page size, etc)
+
+ #is this an edge line?
+ #note that this is no completely robust, if a none edge line
+ #for some reason contains -> it will be missidentified
+ #hand edit the file if this happens
+ if arrowexp.search(buffer):
+ #check to make sure that both nodes are in the node list
+ #if they are print this to output
+ nodes = arrowexp.split(buffer)
+ nodes[0] = string.strip(nodes[0])
+ nodes[1] = string.strip(nodes[1])
+ if nodes[0][:13] in node_set and \
+ nodes[1][:13] in node_set:
+ output.write(buffer)
+ elif nodeexp.search(buffer): #this is a node line
+ node = re.split('\s+', buffer,2)[1]
+ if node in node_set:
+ output.write(buffer)
+ else: #this is a support line
+ output.write(buffer)
+ buffer = input.readline()
+
diff --git a/utils/GenLibDeps.pl b/utils/GenLibDeps.pl
new file mode 100755
index 0000000000..419d8f92d8
--- /dev/null
+++ b/utils/GenLibDeps.pl
@@ -0,0 +1,209 @@
+#!/usr/bin/perl -w
+#
+# Program: GenLibDeps.pl
+#
+# Synopsis: Generate HTML output that shows the dependencies between a set of
+# libraries. The output of this script should periodically replace
+# the similar content in the UsingLibraries.html document.
+#
+# Syntax: GenLibDeps.pl [-flat] <directory_with_libraries_in_it> [path_to_nm_binary]
+#
+
+# Parse arguments...
+my $FLAT = 0;
+my $WHY = 0;
+while (scalar(@ARGV) and ($_ = $ARGV[0], /^[-+]/)) {
+ shift;
+ last if /^--$/; # Stop processing arguments on --
+
+ # List command line options here...
+ if (/^-flat$/) { $FLAT = 1; next; }
+ if (/^-why/) { $WHY = 1; $FLAT = 1; next; }
+ print "Unknown option: $_ : ignoring!\n";
+}
+
+# Give first option a name.
+my $Directory = $ARGV[0];
+if (!defined($Directory) || ! -d "$Directory") {
+ die "First argument must specify the directory containing LLVM libs\n";
+}
+
+my $nmPath = $ARGV[1];
+
+# Find the "dot" program
+my $DotPath="";
+if (!$FLAT) {
+ chomp($DotPath = `which dot`);
+ die "Can't find 'dot'" if (! -x "$DotPath");
+}
+
+if (!defined($nmPath) || $nmPath eq "") {
+ chomp($nmPath=`which nm`);
+ die "Can't find 'nm'" if (! -x "$nmPath");
+}
+
+# Open the directory and read its contents, sorting by name and differentiating
+# by whether its a library (.a) or an object file (.o)
+opendir DIR,$Directory;
+my @files = readdir DIR;
+closedir DIR;
+@libs = grep(/libLLVM.*\.a$/,sort(@files));
+@objs = grep(/LLVM.*\.o$/,sort(@files));
+
+# Declare the hashes we will use to keep track of the library and object file
+# symbol definitions.
+my %libdefs;
+my %objdefs;
+
+# Gather definitions from the libraries
+foreach $lib (@libs ) {
+ open DEFS,
+ "$nmPath -g $Directory/$lib | grep ' [ABCDGRST] ' | sed -e 's/^[0-9A-Fa-f]* [ABCDGRST] //' | sort | uniq |";
+ while (<DEFS>) {
+ chomp($_);
+ $libdefs{$_} = $lib;
+ }
+ close DEFS;
+}
+
+# Gather definitions from the object files.
+foreach $obj (@objs ) {
+ open DEFS,
+ "$nmPath -g $Directory/$obj | grep ' [ABCDGRST] ' | sed -e 's/^[0-9A-Fa-f]* [ABCDGRST] //' | sort | uniq |";
+ while (<DEFS>) {
+ chomp($_);
+ $objdefs{$_} = $obj;
+ }
+ close DEFS;
+}
+
+# Generate one entry in the <dl> list. This generates the <dt> and <dd> elements
+# for one library or object file. The <dt> provides the name of the library or
+# object. The <dd> provides a list of the libraries/objects it depends on.
+sub gen_one_entry {
+ my $lib = $_[0];
+ my $lib_ns = $lib;
+ $lib_ns =~ s/(.*)\.[oa]/$1/;
+ if ($FLAT) {
+ print "$lib:";
+ if ($WHY) { print "\n"; }
+ } else {
+ print " <dt><b>$lib</b</dt><dd><ul>\n";
+ }
+ open UNDEFS,
+ "$nmPath -g -u $Directory/$lib | sed -e 's/^ *U //' | sort | uniq |";
+ my %DepLibs;
+ while (<UNDEFS>) {
+ chomp;
+ my $lib_printed = 0;
+ if (defined($libdefs{$_}) && $libdefs{$_} ne $lib) {
+ $DepLibs{$libdefs{$_}} = [] unless exists $DepLibs{$libdefs{$_}};
+ push(@{$DepLibs{$libdefs{$_}}}, $_);
+ } elsif (defined($objdefs{$_}) && $objdefs{$_} ne $lib) {
+ $libroot = $lib;
+ $libroot =~ s/lib(.*).a/$1/;
+ if ($objdefs{$_} ne "$libroot.o") {
+ $DepLibs{$objdefs{$_}} = [] unless exists $DepLibs{$objdefs{$_}};
+ push(@{$DepLibs{$objdefs{$_}}}, $_);
+ }
+ }
+ }
+ close UNDEFS;
+ for my $key (sort keys %DepLibs) {
+ if ($FLAT) {
+ print " $key";
+ if ($WHY) {
+ print "\n";
+ my @syms = @{$DepLibs{$key}};
+ foreach $sym (@syms) {
+ print " $sym\n";
+ }
+ }
+ } else {
+ print " <li>$key</li>\n";
+ }
+ $suffix = substr($key,length($key)-1,1);
+ $key =~ s/(.*)\.[oa]/$1/;
+ if ($suffix eq "a") {
+ if (!$FLAT) { print DOT "$lib_ns -> $key [ weight=0 ];\n" };
+ } else {
+ if (!$FLAT) { print DOT "$lib_ns -> $key [ weight=10];\n" };
+ }
+ }
+ if ($FLAT) {
+ if (!$WHY) {
+ print "\n";
+ }
+ } else {
+ print " </ul></dd>\n";
+ }
+}
+
+# Make sure we flush on write. This is slower but correct based on the way we
+# write I/O in gen_one_entry.
+$| = 1;
+
+# Print the definition list tag
+if (!$FLAT) {
+ print "<dl>\n";
+
+ open DOT, "| $DotPath -Tgif > libdeps.gif";
+
+ print DOT "digraph LibDeps {\n";
+ print DOT " size=\"40,15\"; \n";
+ print DOT " ratio=\"1.33333\"; \n";
+ print DOT " margin=\"0.25\"; \n";
+ print DOT " rankdir=\"LR\"; \n";
+ print DOT " mclimit=\"50.0\"; \n";
+ print DOT " ordering=\"out\"; \n";
+ print DOT " center=\"1\";\n";
+ print DOT "node [shape=\"box\",\n";
+ print DOT " color=\"#000088\",\n";
+ print DOT " fillcolor=\"#FFFACD\",\n";
+ print DOT " fontcolor=\"#3355BB\",\n";
+ print DOT " style=\"filled\",\n";
+ print DOT " fontname=\"sans\",\n";
+ print DOT " fontsize=\"24\"\n";
+ print DOT "];\n";
+ print DOT "edge [dir=\"forward\",style=\"solid\",color=\"#000088\"];\n";
+}
+
+# Print libraries first
+foreach $lib (@libs) {
+ gen_one_entry($lib);
+}
+
+if (!$FLAT) {
+ print DOT "}\n";
+ close DOT;
+ open DOT, "| $DotPath -Tgif > objdeps.gif";
+ print DOT "digraph ObjDeps {\n";
+ print DOT " size=\"8,10\";\n";
+ print DOT " margin=\"0.25\";\n";
+ print DOT " rankdir=\"LR\";\n";
+ print DOT " mclimit=\"50.0\";\n";
+ print DOT " ordering=\"out\";\n";
+ print DOT " center=\"1\";\n";
+ print DOT "node [shape=\"box\",\n";
+ print DOT " color=\"#000088\",\n";
+ print DOT " fillcolor=\"#FFFACD\",\n";
+ print DOT " fontcolor=\"#3355BB\",\n";
+ print DOT " fontname=\"sans\",\n";
+ print DOT " style=\"filled\",\n";
+ print DOT " fontsize=\"24\"\n";
+ print DOT "];\n";
+ print DOT "edge [dir=\"forward\",style=\"solid\",color=\"#000088\"];\n";
+}
+
+# Print objects second
+foreach $obj (@objs) {
+ gen_one_entry($obj);
+}
+
+if (!$FLAT) {
+ print DOT "}\n";
+ close DOT;
+
+# Print end tag of definition list element
+ print "</dl>\n";
+}
diff --git a/utils/Makefile b/utils/Makefile
new file mode 100644
index 0000000000..08d073b1f3
--- /dev/null
+++ b/utils/Makefile
@@ -0,0 +1,21 @@
+##===- utils/Makefile --------------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file was developed by the LLVM research group and is distributed under
+# the University of Illinois Open Source License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ..
+PARALLEL_DIRS := TableGen fpcmp PerfectShuffle
+
+EXTRA_DIST := cgiplotNLT.pl check-each-file codegen-diff countloc.sh cvsupdate \
+ DSAclean.py DSAextract.py emacs findsym.pl GenLibDeps.pl \
+ getsrcs.sh importNLT.pl llvmdo llvmgrep llvm-native-gcc \
+ llvm-native-gxx makellvm NightlyTest.gnuplot NightlyTest.pl \
+ NightlyTestTemplate.html NLT.schema OldenDataRecover.pl \
+ parseNLT.pl plotNLT.pl profile.pl RegressionFinder.pl userloc.pl \
+ webNLT.pl vim
+
+include $(LEVEL)/Makefile.common
diff --git a/utils/NLT.schema b/utils/NLT.schema
new file mode 100644
index 0000000000..4bcddbc9f7
--- /dev/null
+++ b/utils/NLT.schema
@@ -0,0 +1,8 @@
+CREATE TABLE `Tests` (
+ `NAME` varchar(255) NOT NULL default '',
+ `RUN` date NOT NULL default '0000-00-00',
+ `TEST` varchar(32) NOT NULL default '',
+ `VALUE` double NOT NULL default '0',
+ KEY `name_index` (`NAME`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+
diff --git a/utils/NewNightlyTest.pl b/utils/NewNightlyTest.pl
new file mode 100755
index 0000000000..2978f291f1
--- /dev/null
+++ b/utils/NewNightlyTest.pl
@@ -0,0 +1,1156 @@
+#!/usr/bin/perl
+use POSIX qw(strftime);
+use File::Copy;
+use Socket;
+
+#
+# Program: NewNightlyTest.pl
+#
+# Synopsis: Perform a series of tests which are designed to be run nightly.
+# This is used to keep track of the status of the LLVM tree, tracking
+# regressions and performance changes. Submits this information
+# to llvm.org where it is placed into the nightlytestresults database.
+#
+# Modified heavily by Patrick Jenkins, July 2006
+#
+# Syntax: NightlyTest.pl [OPTIONS] [CVSROOT BUILDDIR WEBDIR]
+# where
+# OPTIONS may include one or more of the following:
+# -nocheckout Do not create, checkout, update, or configure
+# the source tree.
+# -noremove Do not remove the BUILDDIR after it has been built.
+# -noremoveresults Do not remove the WEBDIR after it has been built.
+# -nobuild Do not build llvm. If tests are enabled perform them
+# on the llvm build specified in the build directory
+# -notest Do not even attempt to run the test programs. Implies
+# -norunningtests.
+# -norunningtests Do not run the Olden benchmark suite with
+# LARGE_PROBLEM_SIZE enabled.
+# -nodejagnu Do not run feature or regression tests
+# -parallel Run two parallel jobs with GNU Make.
+# -release Build an LLVM Release version
+# -release-asserts Build an LLVM ReleaseAsserts version
+# -enable-llcbeta Enable testing of beta features in llc.
+# -enable-lli Enable testing of lli (interpreter) features, default is off
+# -disable-llc Disable LLC tests in the nightly tester.
+# -disable-jit Disable JIT tests in the nightly tester.
+# -disable-cbe Disable C backend tests in the nightly tester.
+# -verbose Turn on some debug output
+# -debug Print information useful only to maintainers of this script.
+# -nice Checkout/Configure/Build with "nice" to reduce impact
+# on busy servers.
+# -f2c Next argument specifies path to F2C utility
+# -nickname The next argument specifieds the nickname this script
+# will submit to the nightlytest results repository.
+# -gccpath Path to gcc/g++ used to build LLVM
+# -cvstag Check out a specific CVS tag to build LLVM (useful for
+# testing release branches)
+# -usecvs Check code out from the (old) CVS Repository instead of from
+# the standard Subversion repository.
+# -target Specify the target triplet
+# -cflags Next argument specifies that C compilation options that
+# override the default.
+# -cxxflags Next argument specifies that C++ compilation options that
+# override the default.
+# -ldflags Next argument specifies that linker options that override
+# the default.
+# -compileflags Next argument specifies extra options passed to make when
+# building LLVM.
+# -use-gmake Use gmake instead of the default make command to build
+# llvm and run tests.
+#
+# ---------------- Options to configure llvm-test ----------------------------
+# -extraflags Next argument specifies extra options that are passed to
+# compile the tests.
+# -noexternals Do not run the external tests (for cases where povray
+# or SPEC are not installed)
+# -with-externals Specify a directory where the external tests are located.
+# -submit-server Specifies a server to submit the test results too. If this
+# option is not specified it defaults to
+# llvm.org. This is basically just the address of the
+# webserver
+# -submit-script Specifies which script to call on the submit server. If
+# this option is not specified it defaults to
+# /nightlytest/NightlyTestAccept.php. This is basically
+# everything after the www.yourserver.org.
+#
+# CVSROOT is the CVS repository from which the tree will be checked out,
+# specified either in the full :method:user@host:/dir syntax, or
+# just /dir if using a local repo.
+# BUILDDIR is the directory where sources for this test run will be checked out
+# AND objects for this test run will be built. This directory MUST NOT
+# exist before the script is run; it will be created by the cvs checkout
+# process and erased (unless -noremove is specified; see above.)
+# WEBDIR is the directory into which the test results web page will be written,
+# AND in which the "index.html" is assumed to be a symlink to the most recent
+# copy of the results. This directory will be created if it does not exist.
+# LLVMGCCDIR is the directory in which the LLVM GCC Front End is installed
+# to. This is the same as you would have for a normal LLVM build.
+#
+##############################################################
+#
+# Getting environment variables
+#
+##############################################################
+my $HOME = $ENV{'HOME'};
+my $SVNURL = $ENV{"SVNURL"};
+$SVNURL = 'https://llvm.org/svn/llvm-project' unless $SVNURL;
+my $CVSRootDir = $ENV{'CVSROOT'};
+$CVSRootDir = "/home/vadve/shared/PublicCVS" unless $CVSRootDir;
+my $BuildDir = $ENV{'BUILDDIR'};
+$BuildDir = "$HOME/buildtest" unless $BuildDir;
+my $WebDir = $ENV{'WEBDIR'};
+$WebDir = "$HOME/cvs/testresults-X86" unless $WebDir;
+
+##############################################################
+#
+# Calculate the date prefix...
+#
+##############################################################
+@TIME = localtime;
+my $DATE = sprintf "%4d-%02d-%02d", $TIME[5]+1900, $TIME[4]+1, $TIME[3];
+my $DateString = strftime "%B %d, %Y", localtime;
+my $TestStartTime = gmtime() . "GMT<br>" . localtime() . " (local)";
+
+##############################################################
+#
+# Parse arguments...
+#
+##############################################################
+$CONFIGUREARGS="";
+$nickname="";
+$NOTEST=0;
+$USESVN=1;
+$NORUNNINGTESTS=0;
+$MAKECMD="make";
+$SUBMITSERVER = "llvm.org";
+$SUBMITSCRIPT = "/nightlytest/NightlyTestAccept.php";
+
+while (scalar(@ARGV) and ($_ = $ARGV[0], /^[-+]/)) {
+ shift;
+ last if /^--$/; # Stop processing arguments on --
+
+ # List command line options here...
+ if (/^-nocheckout$/) { $NOCHECKOUT = 1; next; }
+ if (/^-nocvsstats$/) { $NOCVSSTATS = 1; next; }
+ if (/^-noremove$/) { $NOREMOVE = 1; next; }
+ if (/^-noremoveresults$/){ $NOREMOVERESULTS = 1; next; }
+ if (/^-notest$/) { $NOTEST = 1; $NORUNNINGTESTS = 1; next; }
+ if (/^-norunningtests$/) { $NORUNNINGTESTS = 1; next; }
+ if (/^-parallel$/) { $MAKEOPTS = "$MAKEOPTS -j2 -l3.0"; next; }
+ if (/^-release$/) { $MAKEOPTS = "$MAKEOPTS ENABLE_OPTIMIZED=1 ".
+ "OPTIMIZE_OPTION=-O2"; $BUILDTYPE="release"; next;}
+ if (/^-release-asserts$/){ $MAKEOPTS = "$MAKEOPTS ENABLE_OPTIMIZED=1 ".
+ "DISABLE-ASSERTIONS=1 ".
+ "OPTIMIZE_OPTION=-O2";
+ $BUILDTYPE="release-asserts"; next;}
+ if (/^-enable-llcbeta$/) { $PROGTESTOPTS .= " ENABLE_LLCBETA=1"; next; }
+ if (/^-enable-lli$/) { $PROGTESTOPTS .= " ENABLE_LLI=1";
+ $CONFIGUREARGS .= " --enable-lli"; next; }
+ if (/^-disable-llc$/) { $PROGTESTOPTS .= " DISABLE_LLC=1";
+ $CONFIGUREARGS .= " --disable-llc_diffs"; next; }
+ if (/^-disable-jit$/) { $PROGTESTOPTS .= " DISABLE_JIT=1";
+ $CONFIGUREARGS .= " --disable-jit"; next; }
+ if (/^-disable-cbe$/) { $PROGTESTOPTS .= " DISABLE_CBE=1"; next; }
+ if (/^-verbose$/) { $VERBOSE = 1; next; }
+ if (/^-debug$/) { $DEBUG = 1; next; }
+ if (/^-nice$/) { $NICE = "nice "; next; }
+ if (/^-f2c$/) { $CONFIGUREARGS .= " --with-f2c=$ARGV[0]";
+ shift; next; }
+ if (/^-with-externals$/) { $CONFIGUREARGS .= " --with-externals=$ARGV[0]";
+ shift; next; }
+ if (/^-submit-server/) { $SUBMITSERVER = "$ARGV[0]"; shift; next; }
+ if (/^-submit-script/) { $SUBMITSCRIPT = "$ARGV[0]"; shift; next; }
+ if (/^-nickname$/) { $nickname = "$ARGV[0]"; shift; next; }
+ if (/^-gccpath/) { $CONFIGUREARGS .=
+ " CC=$ARGV[0]/gcc CXX=$ARGV[0]/g++";
+ $GCCPATH=$ARGV[0]; shift; next; }
+ else { $GCCPATH=""; }
+ if (/^-cvstag/) { $CVSCOOPT .= " -r $ARGV[0]"; shift; next; }
+ else { $CVSCOOPT="";}
+ if (/^-usecvs/) { $USESVN = 0; }
+ if (/^-target/) { $CONFIGUREARGS .= " --target=$ARGV[0]";
+ shift; next; }
+ if (/^-cflags/) { $MAKEOPTS = "$MAKEOPTS C.Flags=\'$ARGV[0]\'";
+ shift; next; }
+ if (/^-cxxflags/) { $MAKEOPTS = "$MAKEOPTS CXX.Flags=\'$ARGV[0]\'";
+ shift; next; }
+ if (/^-ldflags/) { $MAKEOPTS = "$MAKEOPTS LD.Flags=\'$ARGV[0]\'";
+ shift; next; }
+ if (/^-compileflags/) { $MAKEOPTS = "$MAKEOPTS $ARGV[0]"; shift; next; }
+ if (/^-use-gmake/) { $MAKECMD = "gmake"; shift; next; }
+ if (/^-extraflags/) { $CONFIGUREARGS .=
+ " --with-extra-options=\'$ARGV[0]\'"; shift; next;}
+ if (/^-noexternals$/) { $NOEXTERNALS = 1; next; }
+ if (/^-nodejagnu$/) { $NODEJAGNU = 1; next; }
+ if (/^-nobuild$/) { $NOBUILD = 1; next; }
+ print "Unknown option: $_ : ignoring!\n";
+}
+
+if ($ENV{'LLVMGCCDIR'}) {
+ $CONFIGUREARGS .= " --with-llvmgccdir=" . $ENV{'LLVMGCCDIR'};
+ $LLVMGCCPATH = $ENV{'LLVMGCCDIR'};
+}
+else {
+ $LLVMGCCPATH = "";
+}
+
+if ($CONFIGUREARGS !~ /--disable-jit/) {
+ $CONFIGUREARGS .= " --enable-jit";
+}
+
+if (@ARGV != 0 and @ARGV != 3 and $VERBOSE) {
+ foreach $x (@ARGV) {
+ print "$x\n";
+ }
+ print "Must specify 0 or 3 options!";
+}
+
+if (@ARGV == 3) {
+ $CVSRootDir = $ARGV[0];
+ $BuildDir = $ARGV[1];
+ $WebDir = $ARGV[2];
+}
+
+if ($CVSRootDir eq "" or
+ $BuildDir eq "" or
+ $WebDir eq "") {
+ die("please specify a cvs root directory, a build directory, and a ".
+ "web directory");
+ }
+
+if ($nickname eq "") {
+ die ("Please invoke NewNightlyTest.pl with command line option " .
+ "\"-nickname <nickname>\"");
+}
+
+if ($BUILDTYPE ne "release" && $BUILDTYPE ne "release-asserts") {
+ $BUILDTYPE = "debug";
+}
+
+##############################################################
+#
+#define the file names we'll use
+#
+##############################################################
+my $Prefix = "$WebDir/$DATE";
+my $BuildLog = "$Prefix-Build-Log.txt";
+my $COLog = "$Prefix-CVS-Log.txt";
+my $OldenTestsLog = "$Prefix-Olden-tests.txt";
+my $SingleSourceLog = "$Prefix-SingleSource-ProgramTest.txt.gz";
+my $MultiSourceLog = "$Prefix-MultiSource-ProgramTest.txt.gz";
+my $ExternalLog = "$Prefix-External-ProgramTest.txt.gz";
+my $DejagnuLog = "$Prefix-Dejagnu-testrun.log";
+my $DejagnuSum = "$Prefix-Dejagnu-testrun.sum";
+my $DejagnuTestsLog = "$Prefix-DejagnuTests-Log.txt";
+if (! -d $WebDir) {
+ mkdir $WebDir, 0777;
+ if($VERBOSE){
+ warn "$WebDir did not exist; creating it.\n";
+ }
+}
+
+if ($VERBOSE) {
+ print "INITIALIZED\n";
+ if ($USESVN) {
+ print "SVN URL = $SVNURL\n";
+ } else {
+ print "CVS Root = $CVSRootDir\n";
+ }
+ print "COLog = $COLog\n";
+ print "BuildDir = $BuildDir\n";
+ print "WebDir = $WebDir\n";
+ print "Prefix = $Prefix\n";
+ print "BuildLog = $BuildLog\n";
+}
+
+##############################################################
+#
+# Helper functions
+#
+##############################################################
+sub GetDir {
+ my $Suffix = shift;
+ opendir DH, $WebDir;
+ my @Result = reverse sort grep !/$DATE/, grep /[-0-9]+$Suffix/, readdir DH;
+ closedir DH;
+ return @Result;
+}
+
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# DiffFiles - Diff the current version of the file against the last version of
+# the file, reporting things added and removed. This is used to report, for
+# example, added and removed warnings. This returns a pair (added, removed)
+#
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+sub DiffFiles {
+ my $Suffix = shift;
+ my @Others = GetDir $Suffix;
+ if (@Others == 0) { # No other files? We added all entries...
+ return (`cat $WebDir/$DATE$Suffix`, "");
+ }
+# Diff the files now...
+ my @Diffs = split "\n", `diff $WebDir/$DATE$Suffix $WebDir/$Others[0]`;
+ my $Added = join "\n", grep /^</, @Diffs;
+ my $Removed = join "\n", grep /^>/, @Diffs;
+ $Added =~ s/^< //gm;
+ $Removed =~ s/^> //gm;
+ return ($Added, $Removed);
+}
+
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+sub GetRegex { # (Regex with ()'s, value)
+ $_[1] =~ /$_[0]/m;
+ return $1
+ if (defined($1));
+ return "0";
+}
+
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+sub GetRegexNum {
+ my ($Regex, $Num, $Regex2, $File) = @_;
+ my @Items = split "\n", `grep '$Regex' $File`;
+ return GetRegex $Regex2, $Items[$Num];
+}
+
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+sub ChangeDir { # directory, logical name
+ my ($dir,$name) = @_;
+ chomp($dir);
+ if ( $VERBOSE ) { print "Changing To: $name ($dir)\n"; }
+ $result = chdir($dir);
+ if (!$result) {
+ print "ERROR!!! Cannot change directory to: $name ($dir) because $!";
+ return false;
+ }
+ return true;
+}
+
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+sub ReadFile {
+ if (open (FILE, $_[0])) {
+ undef $/;
+ my $Ret = <FILE>;
+ close FILE;
+ $/ = '\n';
+ return $Ret;
+ } else {
+ print "Could not open file '$_[0]' for reading!\n";
+ return "";
+ }
+}
+
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+sub WriteFile { # (filename, contents)
+ open (FILE, ">$_[0]") or die "Could not open file '$_[0]' for writing!\n";
+ print FILE $_[1];
+ close FILE;
+}
+
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+sub CopyFile { #filename, newfile
+ my ($file, $newfile) = @_;
+ chomp($file);
+ if ($VERBOSE) { print "Copying $file to $newfile\n"; }
+ copy($file, $newfile);
+}
+
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+sub AddRecord {
+ my ($Val, $Filename,$WebDir) = @_;
+ my @Records;
+ if (open FILE, "$WebDir/$Filename") {
+ @Records = grep !/$DATE/, split "\n", <FILE>;
+ close FILE;
+ }
+ push @Records, "$DATE: $Val";
+ WriteFile "$WebDir/$Filename", (join "\n", @Records) . "\n";
+}
+
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# FormatTime - Convert a time from 1m23.45 into 83.45
+#
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+sub FormatTime {
+ my $Time = shift;
+ if ($Time =~ m/([0-9]+)m([0-9.]+)/) {
+ $Time = sprintf("%7.4f", $1*60.0+$2);
+ }
+ return $Time;
+}
+
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# This function is meant to read in the dejagnu sum file and
+# return a string with only the results (i.e. PASS/FAIL/XPASS/
+# XFAIL).
+#
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+sub GetDejagnuTestResults { # (filename, log)
+ my ($filename, $DejagnuLog) = @_;
+ my @lines;
+ $/ = "\n"; #Make sure we're going line at a time.
+
+ if( $VERBOSE) { print "DEJAGNU TEST RESULTS:\n"; }
+
+ if (open SRCHFILE, $filename) {
+ # Process test results
+ while ( <SRCHFILE> ) {
+ if ( length($_) > 1 ) {
+ chomp($_);
+ if ( m/^(PASS|XPASS|FAIL|XFAIL): .*\/llvm\/test\/(.*)$/ ) {
+ push(@lines, "$1: test/$2");
+ }
+ }
+ }
+ }
+ close SRCHFILE;
+
+ my $content = join("\n", @lines);
+ return $content;
+}
+
+
+
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# This function acts as a mini web browswer submitting data
+# to our central server via the post method
+#
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+sub SendData{
+ $host = $_[0];
+ $file = $_[1];
+ $variables=$_[2];
+
+ $port=80;
+ $socketaddr= sockaddr_in $port, inet_aton $host or die "Bad hostname\n";
+ socket SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp') or
+ die "Bad socket\n";
+ connect SOCK, $socketaddr or die "Bad connection\n";
+ select((select(SOCK), $| = 1)[0]);
+
+ #creating content here
+ my $content;
+ foreach $key (keys (%$variables)){
+ $value = $variables->{$key};
+ $value =~ s/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg;
+ $content .= "$key=$value&";
+ }
+
+ $length = length($content);
+
+ my $send= "POST $file HTTP/1.0\n";
+ $send.= "Host: $host\n";
+ $send.= "Content-Type: application/x-www-form-urlencoded\n";
+ $send.= "Content-length: $length\n\n";
+ $send.= "$content";
+
+ print SOCK $send;
+ my $result;
+ while(<SOCK>){
+ $result .= $_;
+ }
+ close(SOCK);
+
+ my $sentdata="";
+ foreach $x (keys (%$variables)){
+ $value = $variables->{$x};
+ $sentdata.= "$x => $value\n";
+ }
+ WriteFile "$Prefix-sentdata.txt", $sentdata;
+
+
+ return $result;
+}
+
+##############################################################
+#
+# Getting Start timestamp
+#
+##############################################################
+$starttime = `date "+20%y-%m-%d %H:%M:%S"`;
+
+##############################################################
+#
+# Create the CVS repository directory
+#
+##############################################################
+if (!$NOCHECKOUT) {
+ if (-d $BuildDir) {
+ if (!$NOREMOVE) {
+ if ( $VERBOSE ) {
+ print "Build directory exists! Removing it\n";
+ }
+ system "rm -rf $BuildDir";
+ mkdir $BuildDir or die "Could not create checkout directory $BuildDir!";
+ } else {
+ if ( $VERBOSE ) {
+ print "Build directory exists!\n";
+ }
+ }
+ } else {
+ mkdir $BuildDir or die "Could not create checkout directory $BuildDir!";
+ }
+}
+ChangeDir( $BuildDir, "checkout directory" );
+
+
+##############################################################
+#
+# Check out the llvm tree, using either SVN or CVS
+#
+##############################################################
+if (!$NOCHECKOUT) {
+ if ( $VERBOSE ) { print "CHECKOUT STAGE:\n"; }
+ if ($USESVN) {
+ my $SVNCMD = "$NICE svn co $SVNURL";
+ if ($VERBOSE) {
+ print "( time -p $SVNCMD/llvm/trunk llvm; cd llvm/projects ; " .
+ "$SVNCMD/test-suite/trunk llvm-test ) > $COLog 2>&1\n";
+ }
+ system "( time -p $SVNCMD/llvm/trunk llvm; cd llvm/projects ; " .
+ "$SVNCMD/test-suite/trunk llvm-test ) > $COLog 2>&1\n";
+ } else {
+ my $CVSOPT = "";
+ $CVSOPT = "-z3" # Use compression if going over ssh.
+ if $CVSRootDir =~ /^:ext:/;
+ my $CVSCMD = "$NICE cvs $CVSOPT -d $CVSRootDir co -P $CVSCOOPT";
+ if ($VERBOSE) {
+ print "( time -p $CVSCMD llvm; cd llvm/projects ; " .
+ "$CVSCMD llvm-test ) > $COLog 2>&1\n";
+ }
+ system "( time -p $CVSCMD llvm; cd llvm/projects ; " .
+ "$CVSCMD llvm-test ) > $COLog 2>&1\n";
+ }
+}
+ChangeDir( $BuildDir , "Checkout directory") ;
+ChangeDir( "llvm" , "llvm source directory") ;
+
+##############################################################
+#
+# Get some static statistics about the current state of CVS
+#
+# This can probably be put on the server side
+#
+##############################################################
+my $CheckoutTime_Wall = GetRegex "([0-9.]+)", `grep '^real' $COLog`;
+my $CheckoutTime_User = GetRegex "([0-9.]+)", `grep '^user' $COLog`;
+my $CheckoutTime_Sys = GetRegex "([0-9.]+)", `grep '^sys' $COLog`;
+my $CheckoutTime_CPU = $CVSCheckoutTime_User + $CVSCheckoutTime_Sys;
+
+my $NumFilesInCVS = 0;
+my $NumDirsInCVS = 0;
+if ($USESVN) {
+ $NumFilesInCVS = `egrep '^A' $COLog | wc -l` + 0;
+ $NumDirsInCVS = `sed -e 's#/[^/]*$##' $COLog | sort | uniq | wc -l` + 0;
+} else {
+ $NumFilesInCVS = `egrep '^U' $COLog | wc -l` + 0;
+ $NumDirsInCVS = `egrep '^cvs (checkout|server|update):' $COLog | wc -l` + 0;
+}
+
+##############################################################
+#
+# Extract some information from the CVS history... use a hash so no duplicate
+# stuff is stored. This gets the history from the previous days worth
+# of cvs activity and parses it.
+#
+##############################################################
+
+# This just computes a reasonably accurate #of seconds since 2000. It doesn't
+# have to be perfect as its only used for comparing date ranges within a couple
+# of days.
+sub ConvertToSeconds {
+ my ($sec, $min, $hour, $day, $mon, $yr) = @_;
+ my $Result = ($yr - 2000) * 12;
+ $Result += $mon;
+ $Result *= 31;
+ $Result += $day;
+ $Result *= 24;
+ $Result += $hour;
+ $Result *= 60;
+ $Result += $min;
+ $Result *= 60;
+ $Result += $sec;
+ return $Result;
+}
+
+my (%AddedFiles, %ModifiedFiles, %RemovedFiles, %UsersCommitted, %UsersUpdated);
+
+if (!$NOCVSSTATS) {
+ if ($VERBOSE) { print "CHANGE HISTORY ANALYSIS STAGE\n"; }
+
+ if ($USESVN) {
+ @SVNHistory = split /<logentry/, `svn log --xml --verbose -r{$DATE}:HEAD`;
+ # Skip very first entry because it is the XML header cruft
+ shift @SVNHistory;
+ my $Now = time();
+ foreach $Record (@SVNHistory) {
+ my @Lines = split "\n", $Record;
+ my ($Author, $Date, $Revision);
+ # Get the date and see if its one we want to process.
+ my ($Year, $Month, $Day, $Hour, $Min, $Sec);
+ if ($Lines[3] =~ /<date>(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})/){
+ $Year = $1; $Month = $2; $Day = $3; $Hour = $4; $Min = $5; $Sec = $6;
+ }
+ my $Then = ConvertToSeconds($Sec, $Min, $Hour, $Day, $Month, $Year);
+ # Get the current date and compute when "yesterday" is.
+ my ($NSec, $NMin, $NHour, $NDay, $NMon, $NYear) = gmtime();
+ my $Now = ConvertToSeconds( $NSec, $NMin, $NHour, $NDay, $NMon, $NYear);
+ if (($Now - 24*60*60) > $Then) {
+ next;
+ }
+ if ($Lines[1] =~ / revision="([0-9]*)">/) {
+ $Revision = $1;
+ }
+ if ($Lines[2] =~ /<author>([^<]*)<\/author>/) {
+ $Author = $1;
+ }
+ $UsersCommitted{$Author} = 1;
+ $Date = $Year . "-" . $Month . "-" . $Day;
+ $Time = $Hour . ":" . $Min . ":" . $Sec;
+ print "Rev: $Revision, Author: $Author, Date: $Date, Time: $Time\n";
+ for ($i = 6; $i < $#Lines; $i += 2 ) {
+ if ($Lines[$i] =~ /^ action="(.)">([^<]*)</) {
+ if ($1 == "A") {
+ $AddedFiles{$2} = 1;
+ } elsif ($1 == 'D') {
+ $RemovedFiles{$2} = 1;
+ } elsif ($1 == 'M' || $1 == 'R' || $1 == 'C') {
+ $ModifiedFiles{$2} = 1;
+ } else {
+ print "UNMATCHABLE: $Lines[$i]\n";
+ }
+ }
+ }
+ }
+ } else {
+ @CVSHistory = split "\n", `cvs history -D '1 day ago' -a -xAMROCGUW`;
+#print join "\n", @CVSHistory; print "\n";
+
+ my $DateRE = '[-/:0-9 ]+\+[0-9]+';
+
+# Loop over every record from the CVS history, filling in the hashes.
+ foreach $File (@CVSHistory) {
+ my ($Type, $Date, $UID, $Rev, $Filename);
+ if ($File =~ /([AMRUGC]) ($DateRE) ([^ ]+) +([^ ]+) +([^ ]+) +([^ ]+)/) {
+ ($Type, $Date, $UID, $Rev, $Filename) = ($1, $2, $3, $4, "$6/$5");
+ } elsif ($File =~ /([W]) ($DateRE) ([^ ]+)/) {
+ ($Type, $Date, $UID, $Rev, $Filename) = ($1, $2, $3, "", "");
+ } elsif ($File =~ /([O]) ($DateRE) ([^ ]+) +([^ ]+)/) {
+ ($Type, $Date, $UID, $Rev, $Filename) = ($1, $2, $3, "", "$4/");
+ } else {
+ print "UNMATCHABLE: $File\n";
+ next;
+ }
+ # print "$File\nTy = $Type Date = '$Date' UID=$UID Rev=$Rev File = '$Filename'\n";
+
+ if ($Filename =~ /^llvm/) {
+ if ($Type eq 'M') { # Modified
+ $ModifiedFiles{$Filename} = 1;
+ $UsersCommitted{$UID} = 1;
+ } elsif ($Type eq 'A') { # Added
+ $AddedFiles{$Filename} = 1;
+ $UsersCommitted{$UID} = 1;
+ } elsif ($Type eq 'R') { # Removed
+ $RemovedFiles{$Filename} = 1;
+ $UsersCommitted{$UID} = 1;
+ } else {
+ $UsersUpdated{$UID} = 1;
+ }
+ }
+ }
+
+ my $TestError = 1;
+ } #$USESVN
+}#!NOCVSSTATS
+
+my $CVSAddedFiles = join "\n", sort keys %AddedFiles;
+my $CVSModifiedFiles = join "\n", sort keys %ModifiedFiles;
+my $CVSRemovedFiles = join "\n", sort keys %RemovedFiles;
+my $UserCommitList = join "\n", sort keys %UsersCommitted;
+my $UserUpdateList = join "\n", sort keys %UsersUpdated;
+
+##############################################################
+#
+# Build the entire tree, saving build messages to the build log
+#
+##############################################################
+if (!$NOCHECKOUT && !$NOBUILD) {
+ my $EXTRAFLAGS = "--enable-spec --with-objroot=.";
+ if ( $VERBOSE ) {
+ print "CONFIGURE STAGE:\n";
+ print "(time -p $NICE ./configure $CONFIGUREARGS $EXTRAFLAGS) " .
+ "> $BuildLog 2>&1\n";
+ }
+ system "(time -p $NICE ./configure $CONFIGUREARGS $EXTRAFLAGS) " .
+ "> $BuildLog 2>&1";
+ if ( $VERBOSE ) {
+ print "BUILD STAGE:\n";
+ print "(time -p $NICE $MAKECMD $MAKEOPTS) >> $BuildLog 2>&1\n";
+ }
+ # Build the entire tree, capturing the output into $BuildLog
+ system "(time -p $NICE $MAKECMD $MAKEOPTS) >> $BuildLog 2>&1";
+}
+
+##############################################################
+#
+# Get some statistics about the build...
+#
+##############################################################
+#this can de done on server
+#my @Linked = split '\n', `grep Linking $BuildLog`;
+#my $NumExecutables = scalar(grep(/executable/, @Linked));
+#my $NumLibraries = scalar(grep(!/executable/, @Linked));
+#my $NumObjects = `grep ']\: Compiling ' $BuildLog | wc -l` + 0;
+
+# Get the number of lines of source code. Must be here after the build is done
+# because countloc.sh uses the llvm-config script which must be built.
+my $LOC = `utils/countloc.sh -topdir $BuildDir/llvm`;
+
+# Get the time taken by the configure script
+my $ConfigTimeU = GetRegexNum "^user", 0, "([0-9.]+)", "$BuildLog";
+my $ConfigTimeS = GetRegexNum "^sys", 0, "([0-9.]+)", "$BuildLog";
+my $ConfigTime = $ConfigTimeU+$ConfigTimeS; # ConfigTime = User+System
+my $ConfigWallTime = GetRegexNum "^real", 0,"([0-9.]+)","$BuildLog";
+
+$ConfigTime=-1 unless $ConfigTime;
+$ConfigWallTime=-1 unless $ConfigWallTime;
+
+my $BuildTimeU = GetRegexNum "^user", 1, "([0-9.]+)", "$BuildLog";
+my $BuildTimeS = GetRegexNum "^sys", 1, "([0-9.]+)", "$BuildLog";
+my $BuildTime = $BuildTimeU+$BuildTimeS; # BuildTime = User+System
+my $BuildWallTime = GetRegexNum "^real", 1, "([0-9.]+)","$BuildLog";
+
+$BuildTime=-1 unless $BuildTime;
+$BuildWallTime=-1 unless $BuildWallTime;
+
+my $BuildError = 0, $BuildStatus = "OK";
+if ($NOBUILD) {
+ $BuildStatus = "Skipped by user";
+ $BuildError = 1;
+}
+elsif (`grep '^$MAKECMD\[^:]*: .*Error' $BuildLog | wc -l` + 0 ||
+ `grep '^$MAKECMD: \*\*\*.*Stop.' $BuildLog | wc -l`+0) {
+ $BuildStatus = "Error: compilation aborted";
+ $BuildError = 1;
+ if( $VERBOSE) { print "\n***ERROR BUILDING TREE\n\n"; }
+}
+if ($BuildError) { $NODEJAGNU=1; }
+
+my $a_file_sizes="";
+my $o_file_sizes="";
+if (!$BuildError) {
+ print "Organizing size of .o and .a files\n"
+ if ( $VERBOSE );
+ ChangeDir( "$BuildDir/llvm", "Build Directory" );
+ $afiles.= `find utils/ -iname '*.a' -ls`;
+ $afiles.= `find lib/ -iname '*.a' -ls`;
+ $afiles.= `find tools/ -iname '*.a' -ls`;
+ if($BUILDTYPE eq "release"){
+ $afiles.= `find Release/ -iname '*.a' -ls`;
+ } elsif($BUILDTYPE eq "release-asserts") {
+ $afiles.= `find Release-Asserts/ -iname '*.a' -ls`;
+ } else {
+ $afiles.= `find Debug/ -iname '*.a' -ls`;
+ }
+
+ $ofiles.= `find utils/ -iname '*.o' -ls`;
+ $ofiles.= `find lib/ -iname '*.o' -ls`;
+ $ofiles.= `find tools/ -iname '*.o' -ls`;
+ if($BUILDTYPE eq "release"){
+ $ofiles.= `find Release/ -iname '*.o' -ls`;
+ } elsif($BUILDTYPE eq "release-asserts") {
+ $ofiles.= `find Release-Asserts/ -iname '*.o' -ls`;
+ } else {
+ $ofiles.= `find Debug/ -iname '*.o' -ls`;
+ }
+
+ @AFILES = split "\n", $afiles;
+ $a_file_sizes="";
+ foreach $x (@AFILES){
+ $x =~ m/.+\s+.+\s+.+\s+.+\s+.+\s+.+\s+(.+)\s+.+\s+.+\s+.+\s+(.+)/;
+ $a_file_sizes.="$1 $2 $BUILDTYPE\n";
+ }
+ @OFILES = split "\n", $ofiles;
+ $o_file_sizes="";
+ foreach $x (@OFILES){
+ $x =~ m/.+\s+.+\s+.+\s+.+\s+.+\s+.+\s+(.+)\s+.+\s+.+\s+.+\s+(.+)/;
+ $o_file_sizes.="$1 $2 $BUILDTYPE\n";
+ }
+} else {
+ $a_file_sizes="No data due to a bad build.";
+ $o_file_sizes="No data due to a bad build.";
+}
+
+##############################################################
+#
+# Running dejagnu tests
+#
+##############################################################
+my $DejangnuTestResults=""; # String containing the results of the dejagnu
+my $dejagnu_output = "$DejagnuTestsLog";
+if (!$NODEJAGNU) {
+ if($VERBOSE) {
+ print "DEJAGNU FEATURE/REGRESSION TEST STAGE:\n";
+ print "(time -p $MAKECMD $MAKEOPTS check) > $dejagnu_output 2>&1\n";
+ }
+
+ #Run the feature and regression tests, results are put into testrun.sum
+ #Full log in testrun.log
+ system "(time -p $MAKECMD $MAKEOPTS check) > $dejagnu_output 2>&1";
+
+ #Copy the testrun.log and testrun.sum to our webdir
+ CopyFile("test/testrun.log", $DejagnuLog);
+ CopyFile("test/testrun.sum", $DejagnuSum);
+ #can be done on server
+ $DejagnuTestResults = GetDejagnuTestResults($DejagnuSum, $DejagnuLog);
+ $unexpfail_tests = $DejagnuTestResults;
+}
+
+#Extract time of dejagnu tests
+my $DejagnuTimeU = GetRegexNum "^user", 0, "([0-9.]+)", "$dejagnu_output";
+my $DejagnuTimeS = GetRegexNum "^sys", 0, "([0-9.]+)", "$dejagnu_output";
+$DejagnuTime = $DejagnuTimeU+$DejagnuTimeS; # DejagnuTime = User+System
+$DejagnuWallTime = GetRegexNum "^real", 0,"([0-9.]+)","$dejagnu_output";
+$DejagnuTestResults =
+ "Dejagnu skipped by user choice." unless $DejagnuTestResults;
+$DejagnuTime = "0.0" unless $DejagnuTime;
+$DejagnuWallTime = "0.0" unless $DejagnuWallTime;
+
+##############################################################
+#
+# Get warnings from the build
+#
+##############################################################
+if (!$NODEJAGNU) {
+ if ( $VERBOSE ) { print "BUILD INFORMATION COLLECTION STAGE\n"; }
+ my @Warn = split "\n", `egrep 'warning:|Entering dir' $BuildLog`;
+ my @Warnings;
+ my $CurDir = "";
+
+ foreach $Warning (@Warn) {
+ if ($Warning =~ m/Entering directory \`([^\`]+)\'/) {
+ $CurDir = $1; # Keep track of directory warning is in...
+ # Remove buildir prefix if included
+ if ($CurDir =~ m#$BuildDir/llvm/(.*)#) { $CurDir = $1; }
+ } else {
+ push @Warnings, "$CurDir/$Warning"; # Add directory to warning...
+ }
+ }
+ my $WarningsFile = join "\n", @Warnings;
+ $WarningsFile =~ s/:[0-9]+:/::/g;
+
+ # Emit the warnings file, so we can diff...
+ WriteFile "$WebDir/$DATE-Warnings.txt", $WarningsFile . "\n";
+ my ($WarningsAdded, $WarningsRemoved) = DiffFiles "-Warnings.txt";
+
+ # Output something to stdout if something has changed
+ #print "ADDED WARNINGS:\n$WarningsAdded\n\n" if (length $WarningsAdded);
+ #print "REMOVED WARNINGS:\n$WarningsRemoved\n\n" if (length $WarningsRemoved);
+
+ #my @TmpWarningsAdded = split "\n", $WarningsAdded; ~PJ on upgrade
+ #my @TmpWarningsRemoved = split "\n", $WarningsRemoved; ~PJ on upgrade
+
+} #endif !NODEGAGNU
+
+##############################################################
+#
+# If we built the tree successfully, run the nightly programs tests...
+#
+# A set of tests to run is passed in (i.e. "SingleSource" "MultiSource"
+# "External")
+#
+##############################################################
+sub TestDirectory {
+ my $SubDir = shift;
+ ChangeDir( "$BuildDir/llvm/projects/llvm-test/$SubDir",
+ "Programs Test Subdirectory" ) || return ("", "");
+
+ my $ProgramTestLog = "$Prefix-$SubDir-ProgramTest.txt";
+
+ # Run the programs tests... creating a report.nightly.csv file
+ if (!$NOTEST) {
+ if( $VERBOSE) {
+ print "$MAKECMD -k $MAKEOPTS $PROGTESTOPTS report.nightly.csv ".
+ "TEST=nightly > $ProgramTestLog 2>&1\n";
+ }
+ system "$MAKECMD -k $MAKEOPTS $PROGTESTOPTS report.nightly.csv ".
+ "TEST=nightly > $ProgramTestLog 2>&1";
+ $llcbeta_options=`$MAKECMD print-llcbeta-option`;
+ }
+
+ my $ProgramsTable;
+ if (`grep '^$MAKECMD\[^:]: .*Error' $ProgramTestLog | wc -l` + 0) {
+ $TestError = 1;
+ $ProgramsTable="Error running test $SubDir\n";
+ print "ERROR TESTING\n";
+ } elsif (`grep '^$MAKECMD\[^:]: .*No rule to make target' $ProgramTestLog | wc -l` + 0) {
+ $TestError = 1;
+ $ProgramsTable="Makefile error running tests $SubDir!\n";
+ print "ERROR TESTING\n";
+ } else {
+ $TestError = 0;
+ #
+ # Create a list of the tests which were run...
+ #
+ system "egrep 'TEST-(PASS|FAIL)' < $ProgramTestLog ".
+ "| sort > $Prefix-$SubDir-Tests.txt";
+ }
+ $ProgramsTable = ReadFile "report.nightly.csv";
+
+ ChangeDir( "../../..", "Programs Test Parent Directory" );
+ return ($ProgramsTable, $llcbeta_options);
+} #end sub TestDirectory
+
+##############################################################
+#
+# Calling sub TestDirectory
+#
+##############################################################
+if (!$BuildError) {
+ if ( $VERBOSE ) {
+ print "SingleSource TEST STAGE\n";
+ }
+ ($SingleSourceProgramsTable, $llcbeta_options) =
+ TestDirectory("SingleSource");
+ WriteFile "$Prefix-SingleSource-Performance.txt", $SingleSourceProgramsTable;
+ if ( $VERBOSE ) {
+ print "MultiSource TEST STAGE\n";
+ }
+ ($MultiSourceProgramsTable, $llcbeta_options) = TestDirectory("MultiSource");
+ WriteFile "$Prefix-MultiSource-Performance.txt", $MultiSourceProgramsTable;
+ if ( ! $NOEXTERNALS ) {
+ if ( $VERBOSE ) {
+ print "External TEST STAGE\n";
+ }
+ ($ExternalProgramsTable, $llcbeta_options) = TestDirectory("External");
+ WriteFile "$Prefix-External-Performance.txt", $ExternalProgramsTable;
+ system "cat $Prefix-SingleSource-Tests.txt " .
+ "$Prefix-MultiSource-Tests.txt ".
+ "$Prefix-External-Tests.txt | sort > $Prefix-Tests.txt";
+ system "cat $Prefix-SingleSource-Performance.txt " .
+ "$Prefix-MultiSource-Performance.txt ".
+ "$Prefix-External-Performance.txt | sort > $Prefix-Performance.txt";
+ } else {
+ $ExternalProgramsTable = "External TEST STAGE SKIPPED\n";
+ if ( $VERBOSE ) {
+ print "External TEST STAGE SKIPPED\n";
+ }
+ system "cat $Prefix-SingleSource-Tests.txt " .
+ "$Prefix-MultiSource-Tests.txt ".
+ " | sort > $Prefix-Tests.txt";
+ system "cat $Prefix-SingleSource-Performance.txt " .
+ "$Prefix-MultiSource-Performance.txt ".
+ " | sort > $Prefix-Performance.txt";
+ }
+
+ ##############################################################
+ #
+ #
+ # gathering tests added removed broken information here
+ #
+ #
+ ##############################################################
+ my $dejagnu_test_list = ReadFile "$Prefix-Tests.txt";
+ my @DEJAGNU = split "\n", $dejagnu_test_list;
+ my ($passes, $fails, $xfails) = "";
+
+ if(!$NODEJAGNU) {
+ for ($x=0; $x<@DEJAGNU; $x++) {
+ if ($DEJAGNU[$x] =~ m/^PASS:/) {
+ $passes.="$DEJAGNU[$x]\n";
+ }
+ elsif ($DEJAGNU[$x] =~ m/^FAIL:/) {
+ $fails.="$DEJAGNU[$x]\n";
+ }
+ elsif ($DEJAGNU[$x] =~ m/^XFAIL:/) {
+ $xfails.="$DEJAGNU[$x]\n";
+ }
+ }
+ }
+
+} #end if !$BuildError
+
+
+##############################################################
+#
+# If we built the tree successfully, runs of the Olden suite with
+# LARGE_PROBLEM_SIZE on so that we can get some "running" statistics.
+#
+##############################################################
+if (!$BuildError) {
+ if ( $VERBOSE ) { print "OLDEN TEST SUITE STAGE\n"; }
+ my ($NATTime, $CBETime, $LLCTime, $JITTime, $OptTime, $BytecodeSize,
+ $MachCodeSize) = ("","","","","","","");
+ if (!$NORUNNINGTESTS) {
+ ChangeDir( "$BuildDir/llvm/projects/llvm-test/MultiSource/Benchmarks/Olden",
+ "Olden Test Directory");
+
+ # Clean out previous results...
+ system "$NICE $MAKECMD $MAKEOPTS clean > /dev/null 2>&1";
+
+ # Run the nightly test in this directory, with LARGE_PROBLEM_SIZE and
+ # GET_STABLE_NUMBERS enabled!
+ if( $VERBOSE ) {
+ print "$MAKECMD -k $MAKEOPTS $PROGTESTOPTS report.nightly.csv.out " .
+ "TEST=nightly LARGE_PROBLEM_SIZE=1 GET_STABLE_NUMBERS=1 " .
+ "> /dev/null 2>&1\n";
+ }
+ system "$MAKECMD -k $MAKEOPTS $PROGTESTOPTS report.nightly.csv.out " .
+ "TEST=nightly LARGE_PROBLEM_SIZE=1 GET_STABLE_NUMBERS=1 " .
+ "> /dev/null 2>&1";
+ system "cp report.nightly.csv $OldenTestsLog";
+ }
+}
+
+##############################################################
+#
+# Getting end timestamp
+#
+##############################################################
+$endtime = `date "+20%y-%m-%d %H:%M:%S"`;
+
+
+##############################################################
+#
+# Place all the logs neatly into one humungous file
+#
+##############################################################
+if ( $VERBOSE ) { print "PREPARING LOGS TO BE SENT TO SERVER\n"; }
+
+$machine_data = "uname: ".`uname -a`.
+ "hardware: ".`uname -m`.
+ "os: ".`uname -sr`.
+ "name: ".`uname -n`.
+ "date: ".`date \"+20%y-%m-%d\"`.
+ "time: ".`date +\"%H:%M:%S\"`;
+
+my @CVS_DATA;
+my $cvs_data;
+@CVS_DATA = ReadFile "$COLog";
+$cvs_data = join("\n", @CVS_DATA);
+
+my @BUILD_DATA;
+my $build_data;
+@BUILD_DATA = ReadFile "$BuildLog";
+$build_data = join("\n", @BUILD_DATA);
+
+my (@DEJAGNU_LOG, @DEJAGNU_SUM, @DEJAGNULOG_FULL, @GCC_VERSION);
+my ($dejagnutests_log ,$dejagnutests_sum, $dejagnulog_full) = "";
+my ($gcc_version, $gcc_version_long) = "";
+
+$gcc_version_long="";
+if ($GCCPATH ne "") {
+ $gcc_version_long = `$GCCPATH/gcc --version`;
+} elsif ($ENV{"CC"}) {
+ $gcc_version_long = `$ENV{"CC"} --version`;
+} else {
+ $gcc_version_long = `gcc --version`;
+}
+@GCC_VERSION = split '\n', $gcc_version_long;
+$gcc_version = $GCC_VERSION[0];
+
+$llvmgcc_version_long="";
+if ($LLVMGCCPATH ne "") {
+ $llvmgcc_version_long = `$LLVMGCCPATH/llvm-gcc -v 2>&1`;
+} else {
+ $llvmgcc_version_long = `llvm-gcc -v 2>&1`;
+}
+@LLVMGCC_VERSION = split '\n', $llvmgcc_version_long;
+$llvmgcc_versionTarget = $LLVMGCC_VERSION[1];
+$llvmgcc_versionTarget =~ /Target: (.+)/;
+$targetTriple = $1;
+
+if(!$BuildError){
+ @DEJAGNU_LOG = ReadFile "$DejagnuLog";
+ @DEJAGNU_SUM = ReadFile "$DejagnuSum";
+ $dejagnutests_log = join("\n", @DEJAGNU_LOG);
+ $dejagnutests_sum = join("\n", @DEJAGNU_SUM);
+
+ @DEJAGNULOG_FULL = ReadFile "$DejagnuTestsLog";
+ $dejagnulog_full = join("\n", @DEJAGNULOG_FULL);
+}
+
+##############################################################
+#
+# Send data via a post request
+#
+##############################################################
+
+if ( $VERBOSE ) { print "SEND THE DATA VIA THE POST REQUEST\n"; }
+
+my %hash_of_data = (
+ 'machine_data' => $machine_data,
+ 'build_data' => $build_data,
+ 'gcc_version' => $gcc_version,
+ 'nickname' => $nickname,
+ 'dejagnutime_wall' => $DejagnuWallTime,
+ 'dejagnutime_cpu' => $DejagnuTime,
+ 'cvscheckouttime_wall' => $CheckoutTime_Wall,
+ 'cvscheckouttime_cpu' => $CheckoutTime_CPU,
+ 'configtime_wall' => $ConfigWallTime,
+ 'configtime_cpu'=> $ConfigTime,
+ 'buildtime_wall' => $BuildWallTime,
+ 'buildtime_cpu' => $BuildTime,
+ 'warnings' => $WarningsFile,
+ 'cvsusercommitlist' => $UserCommitList,
+ 'cvsuserupdatelist' => $UserUpdateList,
+ 'cvsaddedfiles' => $CVSAddedFiles,
+ 'cvsmodifiedfiles' => $CVSModifiedFiles,
+ 'cvsremovedfiles' => $CVSRemovedFiles,
+ 'lines_of_code' => $LOC,
+ 'cvs_file_count' => $NumFilesInCVS,
+ 'cvs_dir_count' => $NumDirsInCVS,
+ 'buildstatus' => $BuildStatus,
+ 'singlesource_programstable' => $SingleSourceProgramsTable,
+ 'multisource_programstable' => $MultiSourceProgramsTable,
+ 'externalsource_programstable' => $ExternalProgramsTable,
+ 'llcbeta_options' => $multisource_llcbeta_options,
+ 'warnings_removed' => $WarningsRemoved,
+ 'warnings_added' => $WarningsAdded,
+ 'passing_tests' => $passes,
+ 'expfail_tests' => $xfails,
+ 'unexpfail_tests' => $fails,
+ 'all_tests' => $dejagnu_test_list,
+ 'new_tests' => "",
+ 'removed_tests' => "",
+ 'dejagnutests_results' => $DejagnuTestResults,
+ 'dejagnutests_log' => $dejagnulog_full,
+ 'starttime' => $starttime,
+ 'endtime' => $endtime,
+ 'o_file_sizes' => $o_file_sizes,
+ 'a_file_sizes' => $a_file_sizes,
+ 'target_triple' => $targetTriple
+);
+
+$TESTING = 0;
+
+if ($TESTING) {
+ print "============================\n";
+ foreach $x(keys %hash_of_data){
+ print "$x => $hash_of_data{$x}\n";
+ }
+} else {
+ my $response = SendData $SUBMITSERVER,$SUBMITSCRIPT,\%hash_of_data;
+ if( $VERBOSE) { print "============================\n$response"; }
+}
+
+##############################################################
+#
+# Remove the cvs tree...
+#
+##############################################################
+system ( "$NICE rm -rf $BuildDir")
+ if (!$NOCHECKOUT and !$NOREMOVE);
+system ( "$NICE rm -rf $WebDir")
+ if (!$NOCHECKOUT and !$NOREMOVE and !$NOREMOVERESULTS);
diff --git a/utils/NightlyTest.gnuplot b/utils/NightlyTest.gnuplot
new file mode 100644
index 0000000000..514b72ab20
--- /dev/null
+++ b/utils/NightlyTest.gnuplot
@@ -0,0 +1,214 @@
+set terminal png
+
+##------- Plot small Date vs LOC ----
+set output "running_loc.png"
+set xlabel "Date"
+set ylabel "Lines of Code"
+set xdata time
+set timefmt "%Y-%m-%d-%H:%M:%S:"
+set format x "%b %d, %Y"
+
+set size .75,.75
+set xtics rotate
+set xlabel 0,-1
+plot "running_loc.txt" using 1:2 title '' with lines, \
+ "running_loc.txt" using 1:2 title "Date vs. Lines of Code" with lines
+
+##------- Plot large Date vs LOC ----
+set size 1.5,1.5
+set xtics norotate
+set xlabel 0,0
+set output "running_loc_large.png"
+plot "running_loc.txt" using 1:2 title '', \
+ "running_loc.txt" using 1:2 title "Date vs. Lines of Code" with lines
+
+
+# Delete all labels...
+set nolabel
+
+##------- Olden CBE performance ----
+
+set size .75,.75
+set xtics rotate
+set xlabel 0,-1
+set output "running_Olden_cbe_time.png"
+set ylabel "CBE compiled execution time (s)"
+plot "running_Olden_cbe_time.txt" u 1:2 t '' with lines, \
+ "running_Olden_cbe_time.txt" u 1:2 t "bh" with lines, \
+ "running_Olden_cbe_time.txt" u 1:3 t "em3d" with lines, \
+ "running_Olden_cbe_time.txt" u 1:4 t "mst" with lines, \
+ "running_Olden_cbe_time.txt" u 1:5 t "power" with lines, \
+ "running_Olden_cbe_time.txt" u 1:6 t "tsp" with lines, \
+ "running_Olden_cbe_time.txt" u 1:7 t "bisort" with lines, \
+ "running_Olden_cbe_time.txt" u 1:8 t "health" with lines, \
+ "running_Olden_cbe_time.txt" u 1:9 t "perimeter" with lines, \
+ "running_Olden_cbe_time.txt" u 1:10 t "treeadd" with lines, \
+ "running_Olden_cbe_time.txt" u 1:11 t "voronoi" \
+ with lines
+
+set size 1.5,1.5
+set xtics norotate
+set xlabel 0,0
+set output "running_Olden_cbe_time_large.png"
+plot "running_Olden_cbe_time.txt" u 1:2 t '' with lines, \
+ "running_Olden_cbe_time.txt" u 1:2 t "bh" with lines, \
+ "running_Olden_cbe_time.txt" u 1:3 t "em3d" with lines, \
+ "running_Olden_cbe_time.txt" u 1:4 t "mst" with lines, \
+ "running_Olden_cbe_time.txt" u 1:5 t "power" with lines, \
+ "running_Olden_cbe_time.txt" u 1:6 t "tsp" with lines, \
+ "running_Olden_cbe_time.txt" u 1:7 t "bisort" with lines, \
+ "running_Olden_cbe_time.txt" u 1:8 t "health" with lines, \
+ "running_Olden_cbe_time.txt" u 1:9 t "perimeter" with lines, \
+ "running_Olden_cbe_time.txt" u 1:10 t "treeadd" with lines, \
+ "running_Olden_cbe_time.txt" u 1:11 t "voronoi" \
+ with lines
+
+##------- Olden JIT performance ----
+
+set size .75,.75
+set xtics rotate
+set xlabel 0,-1
+set output "running_Olden_jit_time.png"
+set ylabel "JIT execution time (s)"
+plot "running_Olden_jit_time.txt" u 1:2 t '' with lines, \
+ "running_Olden_jit_time.txt" u 1:2 t "bh" with lines, \
+ "running_Olden_jit_time.txt" u 1:3 t "em3d" with lines, \
+ "running_Olden_jit_time.txt" u 1:4 t "mst" with lines, \
+ "running_Olden_jit_time.txt" u 1:5 t "power" with lines, \
+ "running_Olden_jit_time.txt" u 1:6 t "tsp" with lines, \
+ "running_Olden_jit_time.txt" u 1:7 t "bisort" with lines, \
+ "running_Olden_jit_time.txt" u 1:8 t "health" with lines, \
+ "running_Olden_jit_time.txt" u 1:9 t "perimeter" with lines, \
+ "running_Olden_jit_time.txt" u 1:10 t "treeadd" with lines, \
+ "running_Olden_jit_time.txt" u 1:11 t "voronoi" \
+ with lines
+
+set size 1.5,1.5
+set xtics norotate
+set xlabel 0,0
+set output "running_Olden_jit_time_large.png"
+plot "running_Olden_jit_time.txt" u 1:2 t '' with lines, \
+ "running_Olden_jit_time.txt" u 1:2 t "bh" with lines, \
+ "running_Olden_jit_time.txt" u 1:3 t "em3d" with lines, \
+ "running_Olden_jit_time.txt" u 1:4 t "mst" with lines, \
+ "running_Olden_jit_time.txt" u 1:5 t "power" with lines, \
+ "running_Olden_jit_time.txt" u 1:6 t "tsp" with lines, \
+ "running_Olden_jit_time.txt" u 1:7 t "bisort" with lines, \
+ "running_Olden_jit_time.txt" u 1:8 t "health" with lines, \
+ "running_Olden_jit_time.txt" u 1:9 t "perimeter" with lines, \
+ "running_Olden_jit_time.txt" u 1:10 t "treeadd" with lines, \
+ "running_Olden_jit_time.txt" u 1:11 t "voronoi" \
+ with lines
+
+##------- Olden LLC performance ----
+
+set size .75,.75
+set xtics rotate
+set xlabel 0,-1
+set output "running_Olden_llc_time.png"
+set ylabel "LLC compiled execution time (s)"
+plot "running_Olden_llc_time.txt" u 1:2 t '' with lines, \
+ "running_Olden_llc_time.txt" u 1:2 t "bh" with lines, \
+ "running_Olden_llc_time.txt" u 1:3 t "em3d" with lines, \
+ "running_Olden_llc_time.txt" u 1:4 t "mst" with lines, \
+ "running_Olden_llc_time.txt" u 1:5 t "power" with lines, \
+ "running_Olden_llc_time.txt" u 1:6 t "tsp" with lines, \
+ "running_Olden_llc_time.txt" u 1:7 t "bisort" with lines, \
+ "running_Olden_llc_time.txt" u 1:8 t "health" with lines, \
+ "running_Olden_llc_time.txt" u 1:9 t "perimeter" with lines, \
+ "running_Olden_llc_time.txt" u 1:10 t "treeadd" with lines, \
+ "running_Olden_llc_time.txt" u 1:11 t "voronoi" \
+ with lines
+
+set size 1.5,1.5
+set xtics norotate
+set xlabel 0,0
+set output "running_Olden_llc_time_large.png"
+plot "running_Olden_llc_time.txt" u 1:2 t '' with lines, \
+ "running_Olden_llc_time.txt" u 1:2 t "bh" with lines, \
+ "running_Olden_llc_time.txt" u 1:3 t "em3d" with lines, \
+ "running_Olden_llc_time.txt" u 1:4 t "mst" with lines, \
+ "running_Olden_llc_time.txt" u 1:5 t "power" with lines, \
+ "running_Olden_llc_time.txt" u 1:6 t "tsp" with lines, \
+ "running_Olden_llc_time.txt" u 1:7 t "bisort" with lines, \
+ "running_Olden_llc_time.txt" u 1:8 t "health" with lines, \
+ "running_Olden_llc_time.txt" u 1:9 t "perimeter" with lines, \
+ "running_Olden_llc_time.txt" u 1:10 t "treeadd" with lines, \
+ "running_Olden_llc_time.txt" u 1:11 t "voronoi" \
+ with lines
+
+
+##------- Olden optimizer time ----
+
+set size .75,.75
+set xtics rotate
+set xlabel 0,-1
+set output "running_Olden_opt_time.png"
+set ylabel "Time to run the optimizer (s)"
+plot "running_Olden_opt_time.txt" u 1:2 t '' with lines, \
+ "running_Olden_opt_time.txt" u 1:2 t "bh" with lines, \
+ "running_Olden_opt_time.txt" u 1:3 t "em3d" with lines, \
+ "running_Olden_opt_time.txt" u 1:4 t "mst" with lines, \
+ "running_Olden_opt_time.txt" u 1:5 t "power" with lines, \
+ "running_Olden_opt_time.txt" u 1:6 t "tsp" with lines, \
+ "running_Olden_opt_time.txt" u 1:7 t "bisort" with lines, \
+ "running_Olden_opt_time.txt" u 1:8 t "health" with lines, \
+ "running_Olden_opt_time.txt" u 1:9 t "perimeter" with lines, \
+ "running_Olden_opt_time.txt" u 1:10 t "treeadd" with lines, \
+ "running_Olden_opt_time.txt" u 1:11 t "voronoi" \
+ with lines
+
+set size 1.5,1.5
+set xtics norotate
+set xlabel 0,0
+set output "running_Olden_opt_time_large.png"
+plot "running_Olden_opt_time.txt" u 1:2 t '' with lines, \
+ "running_Olden_opt_time.txt" u 1:2 t "bh" with lines, \
+ "running_Olden_opt_time.txt" u 1:3 t "em3d" with lines, \
+ "running_Olden_opt_time.txt" u 1:4 t "mst" with lines, \
+ "running_Olden_opt_time.txt" u 1:5 t "power" with lines, \
+ "running_Olden_opt_time.txt" u 1:6 t "tsp" with lines, \
+ "running_Olden_opt_time.txt" u 1:7 t "bisort" with lines, \
+ "running_Olden_opt_time.txt" u 1:8 t "health" with lines, \
+ "running_Olden_opt_time.txt" u 1:9 t "perimeter" with lines, \
+ "running_Olden_opt_time.txt" u 1:10 t "treeadd" with lines, \
+ "running_Olden_opt_time.txt" u 1:11 t "voronoi" \
+ with lines
+
+
+##------- Bytecode size ----
+
+set size .75,.75
+set xtics rotate
+set xlabel 0,-1
+set output "running_Olden_bytecode.png"
+set ylabel "Program bytecode size (bytes)"
+plot "running_Olden_bytecode.txt" u 1:2 t '' with lines, \
+ "running_Olden_bytecode.txt" u 1:2 t "bh" with lines, \
+ "running_Olden_bytecode.txt" u 1:3 t "em3d" with lines, \
+ "running_Olden_bytecode.txt" u 1:4 t "mst" with lines, \
+ "running_Olden_bytecode.txt" u 1:5 t "power" with lines, \
+ "running_Olden_bytecode.txt" u 1:6 t "tsp" with lines, \
+ "running_Olden_bytecode.txt" u 1:7 t "bisort" with lines, \
+ "running_Olden_bytecode.txt" u 1:8 t "health" with lines, \
+ "running_Olden_bytecode.txt" u 1:9 t "perimeter" with lines, \
+ "running_Olden_bytecode.txt" u 1:10 t "treeadd" with lines, \
+ "running_Olden_bytecode.txt" u 1:11 t "voronoi" \
+ with lines
+
+set size 1.5,1.5
+set xtics norotate
+set xlabel 0,0
+set output "running_Olden_bytecode_large.png"
+plot "running_Olden_bytecode.txt" u 1:2 t '' with lines, \
+ "running_Olden_bytecode.txt" u 1:2 t "bh" with lines, \
+ "running_Olden_bytecode.txt" u 1:3 t "em3d" with lines, \
+ "running_Olden_bytecode.txt" u 1:4 t "mst" with lines, \
+ "running_Olden_bytecode.txt" u 1:5 t "power" with lines, \
+ "running_Olden_bytecode.txt" u 1:6 t "tsp" with lines, \
+ "running_Olden_bytecode.txt" u 1:7 t "bisort" with lines, \
+ "running_Olden_bytecode.txt" u 1:8 t "health" with lines, \
+ "running_Olden_bytecode.txt" u 1:9 t "perimeter" with lines, \
+ "running_Olden_bytecode.txt" u 1:10 t "treeadd" with lines, \
+ "running_Olden_bytecode.txt" u 1:11 t "voronoi" \
+ with lines
diff --git a/utils/NightlyTestTemplate.html b/utils/NightlyTestTemplate.html
new file mode 100644
index 0000000000..c38bb2e776
--- /dev/null
+++ b/utils/NightlyTestTemplate.html
@@ -0,0 +1,244 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><title>LLVM Test Results for $DateString</title></head>
+
+<body bgcolor=white>
+<center><font size=+3 face=Verdana><b>LLVM Test Results for $DateString</b></font></center>
+<hr height=1>
+
+<table width=100%>
+<tr><td valign=top align=center>
+
+<table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#000000">
+<table border="0" cellpadding="5" cellspacing="0"><tr><td bgcolor="#DDAA77">
+<font size=+1><b>Sections:</b></font><br>
+</td></tr><tr><td bgcolor="#FFCC99" align=center>
+<a href="#Overview">Overview</a><br>
+<a href="#Changes">Changes</a><br>
+<a href="#Dejagnu">Dejagnu Tests</a><br>
+<a href="#Trends">Trends</a><br>
+<a href="#Programs">Programs</a><br>
+</td></tr></table></td></tr></table>
+
+<p>
+<table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#000000">
+<table border="0" cellpadding="5" cellspacing="0"><tr><td bgcolor="#DDAA77"
+<font size=+1><b>Previous:</b></font><br>
+</td></tr><tr><td bgcolor="#FFCC99">
+ $PrevDaysList
+</td></tr></table></td></tr></table>
+<p>
+
+<font size=+1><b>Back to:</b></font><br>
+<a href="http://llvm.org/testresults/">Test&nbsp;Results</a><br>
+<a href="http://llvm.org/">LLVM&nbsp;Page</a><p>
+
+</td><td valign=top>
+
+<center>
+<table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#000000">
+<table border="0" cellpadding="10" cellspacing="0"><tr><td bgcolor="#DDAA77"
+<font size=+2 face=Verdana><b><a name="Overview">Today's Test Results Overview</font></b>
+</td></tr></table></td></tr></table></center><p>
+
+<!-- Running LOC graph -->
+<table align=right>
+<tr><td>
+<a href="running_loc_large.png"
+ ><img border=0 width=480 height=360 src="running_loc.png"></a>
+</td></tr>
+<tr><td align=center>Lines Of Code over Time<br>
+<font size=-1><a href="running_loc_large.png">Click for larger view</a></font>
+</td></tr>
+</table>
+
+<h2>Nightly Test Overview:</h2>
+<ul>
+ <li>Start: <b>$TestStartTime</b></li>
+ <li>Finish: <b>$TestFinishTime</b></li>
+ <li>Platform: <b>$TestPlatform</b></li>
+</ul>
+<h2>CVS Tree Overview:</h2>
+<ul>
+<li><a href="$DATE-CVS-Log.txt">CVS Checkout Log</a>
+<ul>
+ <b>$NumDirsInCVS</b> dirs, <b>$NumFilesInCVS</b> files, <b>$LOC</b>
+ lines of code, checked out in <b>$CVSCheckoutTime</b> seconds<br></ul>
+<li><a href="$DATE-Build-Log.txt">Compilation Log</a>
+<table>
+<tr><td><b>Item</b></td><td><b>CPU Time</b></td><td><b>Wall Clock</b></td></tr>
+<tr><td>Configure CVS Tree</td><td>$ConfigTime</td><td>$ConfigWallTime</td></tr>
+<tr><td>Build CVS Tree</td><td>$BuildTime</td><td>$BuildWallTime</td></tr>
+<tr><td>Run Dejagnu Tests</td><td>$DejagnuTime</td><td>$DejagnuWallTime</td></tr>
+</table></li>
+<li>Number of object files compiled: <b>$NumObjects</b></li>
+<li>Number of libraries linked: <b>$NumLibraries</b></li>
+<li>Number of executables linked:<b> $NumExecutables</b></li>
+<li>Build Status: $BuildStatus</li>
+</ul>
+
+<h2>Warnings during the build:</h2>
+$WarningsList
+
+<br><br><center>
+<table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#000000">
+<table border="0" cellpadding="10" cellspacing="0"><tr><td bgcolor="#DDAA77"
+<font size=+2 face=Verdana><b><a name="Changes">Changes from Yesterday</font></b>
+</td></tr></table></td></tr></table></center><p>
+
+<h2>Changes to CVS:</h2>
+<ul>
+<li>Users who committed to CVS: <b>$UserCommitList</b>
+<li>Users who updated from CVS: <b>$UserUpdateList</b>
+<li>Added Files: $AddedFilesList
+<li>Modified Files: $ModifiedFilesList
+<li>Removed Files: $RemovedFilesList
+</ul><p>
+
+<h2>Changes to Warnings:</h2>
+<p>Warnings Added:</p>
+$WarningsAdded
+<p>Warnings Removed:</p>
+$WarningsRemoved
+
+<h2>Changes in the test suite:</h2>
+<ul>
+<li>New Tests: $TestsAdded
+<li>Removed Tests: $TestsRemoved
+<li>Newly passing tests: $TestsFixed
+<li>Newly failing tests: $TestsBroken
+</ul>
+</td></tr></tbody></table>
+
+
+<br/><br/><center>
+<table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#000000">
+<table border="0" cellpadding="10" cellspacing="0"><tr><td bgcolor="#DDAA77"
+<font size=+2 face=Verdana><b><a name="Dejagnu">Dejagnu Test Results</font></b>
+</td></tr></table></td></tr></table></center>
+<br/>
+$DejagnuTestResults
+<p>A complete log of testing <a href="$DATE-Dejagnu-testrun.log">Feature and Regression</a> is available for further analysis.</p>
+
+<br><br><center>
+<table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#000000">
+<table border="0" cellpadding="10" cellspacing="0"><tr><td bgcolor="#DDAA77"
+<font size=+2 face=Verdana><b><a name="Trends">Changes Over Time</font></b>
+</td></tr></table></td></tr></table></center><p>
+
+
+Here are some charts showing how the LLVM optimizer and code generators are
+changing over time. For now we use the Olden benchmark suite to measure this,
+but eventually we will switch to using SPEC CPU2000. All programs are run with
+"LARGE_PROBLEM_SIZE" enabled. Click on any of the charts to get a larger
+version.<p>
+
+<h2>Compilation Measurements:</h2>
+
+<table border="0" align=center>
+<tr>
+<td width=50% align=center>
+<a href="running_Olden_bytecode_large.png"><img width=480 height=360 border=0 src="running_Olden_bytecode.png"></a><br>
+Size of LLVM bytecode files
+</td>
+<td width=50% align=center>
+<a href="running_Olden_opt_time_large.png"><img width=480 height=360 border=0 src="running_Olden_opt_time.png"></a><br>
+Time to run the LLVM optimizer on each program
+</td></tr>
+</table>
+
+<h2>Program Execution Measurements:</h2>
+
+<table border="0" align=center>
+<tr>
+<td width=50% align=center>
+<a href="running_Olden_cbe_time_large.png"><img width=480 height=360 border=0 src="running_Olden_cbe_time.png"></a><br>
+Execution time for CBE generated executable
+</td>
+<td width=50% align=center>
+<a href="running_Olden_llc_time_large.png"><img width=480 height=360 border=0 src="running_Olden_llc_time.png"></a><br>
+Execution time for the LLC generated executable
+</td></tr>
+
+<tr>
+<td align=center>
+<a href="running_Olden_jit_time_large.png"><img width=480 height=360 border=0 src="running_Olden_jit_time.png"></a><br>
+Execution time for program in the JIT
+</td>
+<td></td></tr>
+</table>
+
+
+
+
+<br><br><center>
+<table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#000000">
+<table border="0" cellpadding="10" cellspacing="0"><tr><td bgcolor="#DDAA77"
+<font size=+2 face=Verdana><b><a name="Programs">Program Tests</font></b>
+</td></tr></table></td></tr></table></center><p>
+
+This section tests LLVM on a variety of programs in the test suite. This
+includes benchmark suites like the Olden, McCat, Ptrdist, and SPEC benchmarks as
+well as a few random programs with test inputs. This section is meant to track
+how stable LLVM is as a whole. A failure in the execution of any test is marked
+with an asterisk: `*'. The columns of the tables are:<p>
+
+<ol>
+<li><a name="Program">Program</a> - The name of the program for that row.</li>
+<li><a name="GCCAS">GCCAS</a> - Time to run LLVM optimizers on the program.</li>
+<li><a name="Bytecode">Bytecode</a> - The size of the bytecode for the
+ program</li>
+<li><a name="Instrs">Instrs</a> - The number of LLVM instructions in the
+ compiled bytecode</li>
+<li><a name="LLC<br>compile">LLC compile</a> - The time taken compile with
+ LLC (the static backend)</li>
+<li><a name="JIT<br>codegen">JIT codegen</a> - The amount of time spent in the
+ JIT itself, instead of executing the program.</li>
+<li><a name="Machine<br>code">Machine code</a> - The number of bytes of machine
+ code generated by the JIT.</li>
+<li><a name="GCC">GCC</a> - The time taken to execute the program when compiled
+ with GCC -O2.</li>
+<li><a name="CBE">CBE</a> - The time taken to execute the program after
+ compilation through the C backend, compiled with -O2.</li>
+<li><a name="LLC">LLC</a> - How long does the program generated by the static
+ backend LLC take to execute </li>
+<li><a name="JIT">JIT</a> - The amount of time spent running the
+ program with the JIT; this includes the code generation phase (listed above)
+ and actually running the program.</li>
+<li><a name="GCC/LLC">GCC/LLC</a> - The speed-up of the LLC output vs the native
+ GCC output: greater than 1 is a speedup, less than 1 is a slowdown.</li>
+<li><a name="GCC/CBE">GCC/CBE</a> - The speed-up of the CBE output vs the native
+ GCC output: greater than 1 is a speedup, less than 1 is a slowdown.</li>
+<li><a name="LLC-BETA">LLC-BETA</a> - How long does the program generated by the static
+ backend LLC take to execute the program, when compiled with new experimental
+ features. This is temporary, for tuning.</li>
+</ol><p>
+
+A complete log of testing
+<a href="$DATE-SingleSource-ProgramTest.txt.gz">SingleSource</a>,
+<a href="$DATE-MultiSource-ProgramTest.txt.gz">MultiSource</a>, and
+<a href="$DATE-External-ProgramTest.txt.gz">External</a> programs are
+available for further analysis.
+
+<h2>Programs/External</h2>
+
+<center>
+<table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#000000">
+$ExternalProgramsTable
+</td></tr></table></center>
+
+<h2>Programs/MultiSource</h2>
+
+<center>
+<table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#000000">
+$MultiSourceProgramsTable
+</td></tr></table></center>
+
+<h2>Programs/SingleSource</h2>
+
+<center>
+<table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#000000">
+$SingleSourceProgramsTable
+</td></tr></table></center>
+
+</td></tr></html>
+
diff --git a/utils/OldenDataRecover.pl b/utils/OldenDataRecover.pl
new file mode 100644
index 0000000000..767839488b
--- /dev/null
+++ b/utils/OldenDataRecover.pl
@@ -0,0 +1,37 @@
+#this script is intended to help recover the running graphs when
+#the nightly tester decides to eat them.
+
+#zgrep -E "(=========)|(TEST-RESULT-llc-time)" *-Olden-tests.txt* |perl this > file
+#zgrep -E "(=========)|(TEST-RESULT-compile.*bc)" *-Olden-tests.tx* |perl this >file
+
+while (<>) {
+ if (/(\d*-\d*-\d*)-.*=========.*\/(.*)\' Program/) {
+# print "$1 $2\n";
+ $curP = $2;
+ $curD = $1;
+ $dates{$1} = 1;
+ } elsif (/(\d*-\d*-\d*)-.*TEST-RESULT-.*: program (\d*\.\d*)/) {
+# print "$1 $2\n";
+ if ($curD eq $1) {
+ $$data{$curD}{$curP} = $2;
+ }
+ } elsif (/(\d*-\d*-\d*)-.*TEST-RESULT-.*: (\d*)/) {
+# print "$1 $2\n";
+ if ($curD eq $1) {
+ $$data{$curD}{$curP} = $2;
+ }
+ }
+}
+@progs = ("bh", "em3d", "mst", "power", "tsp", "bisort", "health", "perimeter", "treeadd", "voronoi");
+
+foreach $date (sort keys %dates) {
+ print "$date: ";
+ foreach $prog (@progs) {
+ if ($$data{$date}{$prog}) {
+ print " $$data{$date}{$prog}";
+ } else {
+ print " 0";
+ }
+ }
+ print "\n";
+}
diff --git a/utils/PerfectShuffle/Makefile b/utils/PerfectShuffle/Makefile
new file mode 100644
index 0000000000..2f29573137
--- /dev/null
+++ b/utils/PerfectShuffle/Makefile
@@ -0,0 +1,14 @@
+##===- utils/PerfectShuffle/Makefile -----------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file was developed by Chris Lattner and is distributed under
+# the University of Illinois Open Source License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../..
+TOOLNAME = llvm-PerfectShuffle
+NO_INSTALL = 1
+include $(LEVEL)/Makefile.common
+
diff --git a/utils/PerfectShuffle/PerfectShuffle.cpp b/utils/PerfectShuffle/PerfectShuffle.cpp
new file mode 100644
index 0000000000..26d57bb905
--- /dev/null
+++ b/utils/PerfectShuffle/PerfectShuffle.cpp
@@ -0,0 +1,497 @@
+//===-- PerfectShuffle.cpp - Perfect Shuffle Generator --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file computes an optimal sequence of instructions for doing all shuffles
+// of two 4-element vectors. With a release build and when configured to emit
+// an altivec instruction table, this takes about 30s to run on a 2.7Ghz
+// PowerPC G5.
+//
+//===----------------------------------------------------------------------===//
+
+#include <iostream>
+#include <vector>
+#include <cassert>
+
+struct Operator;
+
+// Masks are 4-nibble hex numbers. Values 0-7 in any nibble means that it takes
+// an element from that value of the input vectors. A value of 8 means the
+// entry is undefined.
+
+// Mask manipulation functions.
+static inline unsigned short MakeMask(unsigned V0, unsigned V1,
+ unsigned V2, unsigned V3) {
+ return (V0 << (3*4)) | (V1 << (2*4)) | (V2 << (1*4)) | (V3 << (0*4));
+}
+
+/// getMaskElt - Return element N of the specified mask.
+static unsigned getMaskElt(unsigned Mask, unsigned Elt) {
+ return (Mask >> ((3-Elt)*4)) & 0xF;
+}
+
+static unsigned setMaskElt(unsigned Mask, unsigned Elt, unsigned NewVal) {
+ unsigned FieldShift = ((3-Elt)*4);
+ return (Mask & ~(0xF << FieldShift)) | (NewVal << FieldShift);
+}
+
+// Reject elements where the values are 9-15.
+static bool isValidMask(unsigned short Mask) {
+ unsigned short UndefBits = Mask & 0x8888;
+ return (Mask & ((UndefBits >> 1)|(UndefBits>>2)|(UndefBits>>3))) == 0;
+}
+
+/// hasUndefElements - Return true if any of the elements in the mask are undefs
+///
+static bool hasUndefElements(unsigned short Mask) {
+ return (Mask & 0x8888) != 0;
+}
+
+/// isOnlyLHSMask - Return true if this mask only refers to its LHS, not
+/// including undef values..
+static bool isOnlyLHSMask(unsigned short Mask) {
+ return (Mask & 0x4444) == 0;
+}
+
+/// getLHSOnlyMask - Given a mask that refers to its LHS and RHS, modify it to
+/// refer to the LHS only (for when one argument value is passed into the same
+/// function twice).
+#if 0
+static unsigned short getLHSOnlyMask(unsigned short Mask) {
+ return Mask & 0xBBBB; // Keep only LHS and Undefs.
+}
+#endif
+
+/// getCompressedMask - Turn a 16-bit uncompressed mask (where each elt uses 4
+/// bits) into a compressed 13-bit mask, where each elt is multiplied by 9.
+static unsigned getCompressedMask(unsigned short Mask) {
+ return getMaskElt(Mask, 0)*9*9*9 + getMaskElt(Mask, 1)*9*9 +
+ getMaskElt(Mask, 2)*9 + getMaskElt(Mask, 3);
+}
+
+static void PrintMask(unsigned i, std::ostream &OS) {
+ OS << "<" << (char)(getMaskElt(i, 0) == 8 ? 'u' : ('0'+getMaskElt(i, 0)))
+ << "," << (char)(getMaskElt(i, 1) == 8 ? 'u' : ('0'+getMaskElt(i, 1)))
+ << "," << (char)(getMaskElt(i, 2) == 8 ? 'u' : ('0'+getMaskElt(i, 2)))
+ << "," << (char)(getMaskElt(i, 3) == 8 ? 'u' : ('0'+getMaskElt(i, 3)))
+ << ">";
+}
+
+/// ShuffleVal - This represents a shufflevector operation.
+struct ShuffleVal {
+ unsigned Cost; // Number of instrs used to generate this value.
+ Operator *Op; // The Operation used to generate this value.
+ unsigned short Arg0, Arg1; // Input operands for this value.
+
+ ShuffleVal() : Cost(1000000) {}
+};
+
+
+/// ShufTab - This is the actual shuffle table that we are trying to generate.
+///
+static ShuffleVal ShufTab[65536];
+
+/// TheOperators - All of the operators that this target supports.
+static std::vector<Operator*> TheOperators;
+
+/// Operator - This is a vector operation that is available for use.
+struct Operator {
+ unsigned short ShuffleMask;
+ unsigned short OpNum;
+ const char *Name;
+
+ Operator(unsigned short shufflemask, const char *name, unsigned opnum)
+ : ShuffleMask(shufflemask), OpNum(opnum), Name(name) {
+ TheOperators.push_back(this);
+ }
+ ~Operator() {
+ assert(TheOperators.back() == this);
+ TheOperators.pop_back();
+ }
+
+ bool isOnlyLHSOperator() const {
+ return isOnlyLHSMask(ShuffleMask);
+ }
+
+ const char *getName() const { return Name; }
+
+ unsigned short getTransformedMask(unsigned short LHSMask, unsigned RHSMask) {
+ // Extract the elements from LHSMask and RHSMask, as appropriate.
+ unsigned Result = 0;
+ for (unsigned i = 0; i != 4; ++i) {
+ unsigned SrcElt = (ShuffleMask >> (4*i)) & 0xF;
+ unsigned ResElt;
+ if (SrcElt < 4)
+ ResElt = getMaskElt(LHSMask, SrcElt);
+ else if (SrcElt < 8)
+ ResElt = getMaskElt(RHSMask, SrcElt-4);
+ else {
+ assert(SrcElt == 8 && "Bad src elt!");
+ ResElt = 8;
+ }
+ Result |= ResElt << (4*i);
+ }
+ return Result;
+ }
+};
+
+static const char *getZeroCostOpName(unsigned short Op) {
+ if (ShufTab[Op].Arg0 == 0x0123)
+ return "LHS";
+ else if (ShufTab[Op].Arg0 == 0x4567)
+ return "RHS";
+ else {
+ assert(0 && "bad zero cost operation");
+ abort();
+ }
+}
+
+static void PrintOperation(unsigned ValNo, unsigned short Vals[]) {
+ unsigned short ThisOp = Vals[ValNo];
+ std::cerr << "t" << ValNo;
+ PrintMask(ThisOp, std::cerr);
+ std::cerr << " = " << ShufTab[ThisOp].Op->getName() << "(";
+
+ if (ShufTab[ShufTab[ThisOp].Arg0].Cost == 0) {
+ std::cerr << getZeroCostOpName(ShufTab[ThisOp].Arg0);
+ PrintMask(ShufTab[ThisOp].Arg0, std::cerr);
+ } else {
+ // Figure out what tmp # it is.
+ for (unsigned i = 0; ; ++i)
+ if (Vals[i] == ShufTab[ThisOp].Arg0) {
+ std::cerr << "t" << i;
+ break;
+ }
+ }
+
+ if (!ShufTab[Vals[ValNo]].Op->isOnlyLHSOperator()) {
+ std::cerr << ", ";
+ if (ShufTab[ShufTab[ThisOp].Arg1].Cost == 0) {
+ std::cerr << getZeroCostOpName(ShufTab[ThisOp].Arg1);
+ PrintMask(ShufTab[ThisOp].Arg1, std::cerr);
+ } else {
+ // Figure out what tmp # it is.
+ for (unsigned i = 0; ; ++i)
+ if (Vals[i] == ShufTab[ThisOp].Arg1) {
+ std::cerr << "t" << i;
+ break;
+ }
+ }
+ }
+ std::cerr << ") ";
+}
+
+static unsigned getNumEntered() {
+ unsigned Count = 0;
+ for (unsigned i = 0; i != 65536; ++i)
+ Count += ShufTab[i].Cost < 100;
+ return Count;
+}
+
+static void EvaluateOps(unsigned short Elt, unsigned short Vals[],
+ unsigned &NumVals) {
+ if (ShufTab[Elt].Cost == 0) return;
+
+ // If this value has already been evaluated, it is free. FIXME: match undefs.
+ for (unsigned i = 0, e = NumVals; i != e; ++i)
+ if (Vals[i] == Elt) return;
+
+ // Otherwise, get the operands of the value, then add it.
+ unsigned Arg0 = ShufTab[Elt].Arg0, Arg1 = ShufTab[Elt].Arg1;
+ if (ShufTab[Arg0].Cost)
+ EvaluateOps(Arg0, Vals, NumVals);
+ if (Arg0 != Arg1 && ShufTab[Arg1].Cost)
+ EvaluateOps(Arg1, Vals, NumVals);
+
+ Vals[NumVals++] = Elt;
+}
+
+
+int main() {
+ // Seed the table with accesses to the LHS and RHS.
+ ShufTab[0x0123].Cost = 0;
+ ShufTab[0x0123].Op = 0;
+ ShufTab[0x0123].Arg0 = 0x0123;
+ ShufTab[0x4567].Cost = 0;
+ ShufTab[0x4567].Op = 0;
+ ShufTab[0x4567].Arg0 = 0x4567;
+
+ // Seed the first-level of shuffles, shuffles whose inputs are the input to
+ // the vectorshuffle operation.
+ bool MadeChange = true;
+ unsigned OpCount = 0;
+ while (MadeChange) {
+ MadeChange = false;
+ ++OpCount;
+ std::cerr << "Starting iteration #" << OpCount << " with "
+ << getNumEntered() << " entries established.\n";
+
+ // Scan the table for two reasons: First, compute the maximum cost of any
+ // operation left in the table. Second, make sure that values with undefs
+ // have the cheapest alternative that they match.
+ unsigned MaxCost = ShufTab[0].Cost;
+ for (unsigned i = 1; i != 0x8889; ++i) {
+ if (!isValidMask(i)) continue;
+ if (ShufTab[i].Cost > MaxCost)
+ MaxCost = ShufTab[i].Cost;
+
+ // If this value has an undef, make it be computed the cheapest possible
+ // way of any of the things that it matches.
+ if (hasUndefElements(i)) {
+ // This code is a little bit tricky, so here's the idea: consider some
+ // permutation, like 7u4u. To compute the lowest cost for 7u4u, we
+ // need to take the minimum cost of all of 7[0-8]4[0-8], 81 entries. If
+ // there are 3 undefs, the number rises to 729 entries we have to scan,
+ // and for the 4 undef case, we have to scan the whole table.
+ //
+ // Instead of doing this huge amount of scanning, we process the table
+ // entries *in order*, and use the fact that 'u' is 8, larger than any
+ // valid index. Given an entry like 7u4u then, we only need to scan
+ // 7[0-7]4u - 8 entries. We can get away with this, because we already
+ // know that each of 704u, 714u, 724u, etc contain the minimum value of
+ // all of the 704[0-8], 714[0-8] and 724[0-8] entries respectively.
+ unsigned UndefIdx;
+ if (i & 0x8000)
+ UndefIdx = 0;
+ else if (i & 0x0800)
+ UndefIdx = 1;
+ else if (i & 0x0080)
+ UndefIdx = 2;
+ else if (i & 0x0008)
+ UndefIdx = 3;
+ else
+ abort();
+
+ unsigned MinVal = i;
+ unsigned MinCost = ShufTab[i].Cost;
+
+ // Scan the 8 entries.
+ for (unsigned j = 0; j != 8; ++j) {
+ unsigned NewElt = setMaskElt(i, UndefIdx, j);
+ if (ShufTab[NewElt].Cost < MinCost) {
+ MinCost = ShufTab[NewElt].Cost;
+ MinVal = NewElt;
+ }
+ }
+
+ // If we found something cheaper than what was here before, use it.
+ if (i != MinVal) {
+ MadeChange = true;
+ ShufTab[i] = ShufTab[MinVal];
+ }
+ }
+ }
+
+ for (unsigned LHS = 0; LHS != 0x8889; ++LHS) {
+ if (!isValidMask(LHS)) continue;
+ if (ShufTab[LHS].Cost > 1000) continue;
+
+ // If nothing involving this operand could possibly be cheaper than what
+ // we already have, don't consider it.
+ if (ShufTab[LHS].Cost + 1 >= MaxCost)
+ continue;
+
+ for (unsigned opnum = 0, e = TheOperators.size(); opnum != e; ++opnum) {
+ Operator *Op = TheOperators[opnum];
+
+ // Evaluate op(LHS,LHS)
+ unsigned ResultMask = Op->getTransformedMask(LHS, LHS);
+
+ unsigned Cost = ShufTab[LHS].Cost + 1;
+ if (Cost < ShufTab[ResultMask].Cost) {
+ ShufTab[ResultMask].Cost = Cost;
+ ShufTab[ResultMask].Op = Op;
+ ShufTab[ResultMask].Arg0 = LHS;
+ ShufTab[ResultMask].Arg1 = LHS;
+ MadeChange = true;
+ }
+
+ // If this is a two input instruction, include the op(x,y) cases. If
+ // this is a one input instruction, skip this.
+ if (Op->isOnlyLHSOperator()) continue;
+
+ for (unsigned RHS = 0; RHS != 0x8889; ++RHS) {
+ if (!isValidMask(RHS)) continue;
+ if (ShufTab[RHS].Cost > 1000) continue;
+
+ // If nothing involving this operand could possibly be cheaper than
+ // what we already have, don't consider it.
+ if (ShufTab[RHS].Cost + 1 >= MaxCost)
+ continue;
+
+
+ // Evaluate op(LHS,RHS)
+ unsigned ResultMask = Op->getTransformedMask(LHS, RHS);
+
+ if (ShufTab[ResultMask].Cost <= OpCount ||
+ ShufTab[ResultMask].Cost <= ShufTab[LHS].Cost ||
+ ShufTab[ResultMask].Cost <= ShufTab[RHS].Cost)
+ continue;
+
+ // Figure out the cost to evaluate this, knowing that CSE's only need
+ // to be evaluated once.
+ unsigned short Vals[30];
+ unsigned NumVals = 0;
+ EvaluateOps(LHS, Vals, NumVals);
+ EvaluateOps(RHS, Vals, NumVals);
+
+ unsigned Cost = NumVals + 1;
+ if (Cost < ShufTab[ResultMask].Cost) {
+ ShufTab[ResultMask].Cost = Cost;
+ ShufTab[ResultMask].Op = Op;
+ ShufTab[ResultMask].Arg0 = LHS;
+ ShufTab[ResultMask].Arg1 = RHS;
+ MadeChange = true;
+ }
+ }
+ }
+ }
+ }
+
+ std::cerr << "Finished Table has " << getNumEntered()
+ << " entries established.\n";
+
+ unsigned CostArray[10] = { 0 };
+
+ // Compute a cost histogram.
+ for (unsigned i = 0; i != 65536; ++i) {
+ if (!isValidMask(i)) continue;
+ if (ShufTab[i].Cost > 9)
+ ++CostArray[9];
+ else
+ ++CostArray[ShufTab[i].Cost];
+ }
+
+ for (unsigned i = 0; i != 9; ++i)
+ if (CostArray[i])
+ std::cout << "// " << CostArray[i] << " entries have cost " << i << "\n";
+ if (CostArray[9])
+ std::cout << "// " << CostArray[9] << " entries have higher cost!\n";
+
+
+ // Build up the table to emit.
+ std::cout << "\n// This table is 6561*4 = 26244 bytes in size.\n";
+ std::cout << "static const unsigned PerfectShuffleTable[6561+1] = {\n";
+
+ for (unsigned i = 0; i != 0x8889; ++i) {
+ if (!isValidMask(i)) continue;
+
+ // CostSat - The cost of this operation saturated to two bits.
+ unsigned CostSat = ShufTab[i].Cost;
+ if (CostSat > 4) CostSat = 4;
+ if (CostSat == 0) CostSat = 1;
+ --CostSat; // Cost is now between 0-3.
+
+ unsigned OpNum = ShufTab[i].Op ? ShufTab[i].Op->OpNum : 0;
+ assert(OpNum < 16 && "Too few bits to encode operation!");
+
+ unsigned LHS = getCompressedMask(ShufTab[i].Arg0);
+ unsigned RHS = getCompressedMask(ShufTab[i].Arg1);
+
+ // Encode this as 2 bits of saturated cost, 4 bits of opcodes, 13 bits of
+ // LHS, and 13 bits of RHS = 32 bits.
+ unsigned Val = (CostSat << 30) | (OpNum << 26) | (LHS << 13) | RHS;
+
+ std::cout << " " << Val << "U,\t// ";
+ PrintMask(i, std::cout);
+ std::cout << ": Cost " << ShufTab[i].Cost;
+ std::cout << " " << (ShufTab[i].Op ? ShufTab[i].Op->getName() : "copy");
+ std::cout << " ";
+ if (ShufTab[ShufTab[i].Arg0].Cost == 0) {
+ std::cout << getZeroCostOpName(ShufTab[i].Arg0);
+ } else {
+ PrintMask(ShufTab[i].Arg0, std::cout);
+ }
+
+ if (ShufTab[i].Op && !ShufTab[i].Op->isOnlyLHSOperator()) {
+ std::cout << ", ";
+ if (ShufTab[ShufTab[i].Arg1].Cost == 0) {
+ std::cout << getZeroCostOpName(ShufTab[i].Arg1);
+ } else {
+ PrintMask(ShufTab[i].Arg1, std::cout);
+ }
+ }
+ std::cout << "\n";
+ }
+ std::cout << " 0\n};\n";
+
+ if (0) {
+ // Print out the table.
+ for (unsigned i = 0; i != 0x8889; ++i) {
+ if (!isValidMask(i)) continue;
+ if (ShufTab[i].Cost < 1000) {
+ PrintMask(i, std::cerr);
+ std::cerr << " - Cost " << ShufTab[i].Cost << " - ";
+
+ unsigned short Vals[30];
+ unsigned NumVals = 0;
+ EvaluateOps(i, Vals, NumVals);
+
+ for (unsigned j = 0, e = NumVals; j != e; ++j)
+ PrintOperation(j, Vals);
+ std::cerr << "\n";
+ }
+ }
+ }
+}
+
+
+#define GENERATE_ALTIVEC
+
+#ifdef GENERATE_ALTIVEC
+
+///===---------------------------------------------------------------------===//
+/// The altivec instruction definitions. This is the altivec-specific part of
+/// this file.
+///===---------------------------------------------------------------------===//
+
+// Note that the opcode numbers here must match those in the PPC backend.
+enum {
+ OP_COPY = 0, // Copy, used for things like <u,u,u,3> to say it is <0,1,2,3>
+ OP_VMRGHW,
+ OP_VMRGLW,
+ OP_VSPLTISW0,
+ OP_VSPLTISW1,
+ OP_VSPLTISW2,
+ OP_VSPLTISW3,
+ OP_VSLDOI4,
+ OP_VSLDOI8,
+ OP_VSLDOI12
+};
+
+struct vmrghw : public Operator {
+ vmrghw() : Operator(0x0415, "vmrghw", OP_VMRGHW) {}
+} the_vmrghw;
+
+struct vmrglw : public Operator {
+ vmrglw() : Operator(0x2637, "vmrglw", OP_VMRGLW) {}
+} the_vmrglw;
+
+template<unsigned Elt>
+struct vspltisw : public Operator {
+ vspltisw(const char *N, unsigned Opc)
+ : Operator(MakeMask(Elt, Elt, Elt, Elt), N, Opc) {}
+};
+
+vspltisw<0> the_vspltisw0("vspltisw0", OP_VSPLTISW0);
+vspltisw<1> the_vspltisw1("vspltisw1", OP_VSPLTISW1);
+vspltisw<2> the_vspltisw2("vspltisw2", OP_VSPLTISW2);
+vspltisw<3> the_vspltisw3("vspltisw3", OP_VSPLTISW3);
+
+template<unsigned N>
+struct vsldoi : public Operator {
+ vsldoi(const char *Name, unsigned Opc)
+ : Operator(MakeMask(N&7, (N+1)&7, (N+2)&7, (N+3)&7), Name, Opc) {
+ }
+};
+
+vsldoi<1> the_vsldoi1("vsldoi4" , OP_VSLDOI4);
+vsldoi<2> the_vsldoi2("vsldoi8" , OP_VSLDOI8);
+vsldoi<3> the_vsldoi3("vsldoi12", OP_VSLDOI12);
+
+#endif
diff --git a/utils/RegressionFinder.pl b/utils/RegressionFinder.pl
new file mode 100755
index 0000000000..86b077780b
--- /dev/null
+++ b/utils/RegressionFinder.pl
@@ -0,0 +1,186 @@
+#! /usr/bin/perl
+# Script to find regressions by binary-searching a time interval in the
+# CVS tree. Written by Brian Gaeke on 2-Mar-2004.
+#
+
+require 5.6.0; # NOTE: This script not tested with earlier versions.
+use Getopt::Std;
+use POSIX;
+use Time::Local;
+use IO::Handle;
+
+sub usage {
+ print STDERR <<END;
+findRegression [-I] -w WTIME -d DTIME -t TOOLS -c SCRIPT
+
+The -w, -d, -t, and -c options are required.
+Run findRegression in the top level of an LLVM tree.
+WTIME is a time when you are sure the regression does NOT exist ("Works").
+DTIME is a time when you are sure the regression DOES exist ("Doesntwork").
+WTIME and DTIME are both in the format: "YYYY/MM/DD HH:MM".
+-I means run builds at WTIME and DTIME first to make sure.
+TOOLS is a comma separated list of tools to rebuild before running SCRIPT.
+SCRIPT exits 1 if the regression is present in TOOLS; 0 otherwise.
+END
+ exit 1;
+}
+
+sub timeAsSeconds {
+ my ($timestr) = @_;
+
+ if ( $timestr =~ /(\d\d\d\d)\/(\d\d)\/(\d\d) (\d\d):(\d\d)/ ) {
+ my ( $year, $mon, $mday, $hour, $min ) = ( $1, $2, $3, $4, $5 );
+ return timegm( 0, $min, $hour, $mday, $mon - 1, $year );
+ }
+ else {
+ die "** Can't parse date + time: $timestr\n";
+ }
+}
+
+sub timeAsString {
+ my ($secs) = @_;
+ return strftime( "%Y/%m/%d %H:%M", gmtime($secs) );
+}
+
+sub run {
+ my ($cmdline) = @_;
+ print LOG "** Running: $cmdline\n";
+ return system($cmdline);
+}
+
+sub buildLibrariesAndTools {
+ run("sh /home/vadve/gaeke/scripts/run-configure");
+ run("$MAKE -C lib/Support");
+ run("$MAKE -C utils");
+ run("$MAKE -C lib");
+ foreach my $tool (@TOOLS) { run("$MAKE -C tools/$tool"); }
+}
+
+sub contains {
+ my ( $file, $regex ) = @_;
+ local (*FILE);
+ open( FILE, "<$file" ) or die "** can't read $file: $!\n";
+ while (<FILE>) {
+ if (/$regex/) {
+ close FILE;
+ return 1;
+ }
+ }
+ close FILE;
+ return 0;
+}
+
+sub updateSources {
+ my ($time) = @_;
+ my $inst = "include/llvm/Instruction.h";
+ unlink($inst);
+ run( "cvs update -D'" . timeAsString($time) . "'" );
+ if ( !contains( $inst, 'class Instruction.*Annotable' ) ) {
+ run("patch -F100 -p0 < makeInstructionAnnotable.patch");
+ }
+}
+
+sub regressionPresentAt {
+ my ($time) = @_;
+
+ updateSources($time);
+ buildLibrariesAndTools();
+ my $rc = run($SCRIPT);
+ if ($rc) {
+ print LOG "** Found that regression was PRESENT at "
+ . timeAsString($time) . "\n";
+ return 1;
+ }
+ else {
+ print LOG "** Found that regression was ABSENT at "
+ . timeAsString($time) . "\n";
+ return 0;
+ }
+}
+
+sub regressionAbsentAt {
+ my ($time) = @_;
+ return !regressionPresentAt($time);
+}
+
+sub closeTo {
+ my ( $time1, $time2 ) = @_;
+ return abs( $time1 - $time2 ) < 600; # 10 minutes seems reasonable.
+}
+
+sub halfWayPoint {
+ my ( $time1, $time2 ) = @_;
+ my $halfSpan = int( abs( $time1 - $time2 ) / 2 );
+ if ( $time1 < $time2 ) {
+ return $time1 + $halfSpan;
+ }
+ else {
+ return $time2 + $halfSpan;
+ }
+}
+
+sub checkBoundaryConditions {
+ print LOG "** Checking for presence of regression at ", timeAsString($DTIME),
+ "\n";
+ if ( !regressionPresentAt($DTIME) ) {
+ die ( "** Can't help you; $SCRIPT says regression absent at dtime: "
+ . timeAsString($DTIME)
+ . "\n" );
+ }
+ print LOG "** Checking for absence of regression at ", timeAsString($WTIME),
+ "\n";
+ if ( !regressionAbsentAt($WTIME) ) {
+ die ( "** Can't help you; $SCRIPT says regression present at wtime: "
+ . timeAsString($WTIME)
+ . "\n" );
+ }
+}
+
+##############################################################################
+
+# Set up log files
+open (STDERR, ">&STDOUT") || die "** Can't redirect std.err: $!\n";
+autoflush STDOUT 1;
+autoflush STDERR 1;
+open (LOG, ">RegFinder.log") || die "** can't write RegFinder.log: $!\n";
+autoflush LOG 1;
+# Check command line arguments and environment variables
+getopts('Iw:d:t:c:');
+if ( !( $opt_w && $opt_d && $opt_t && $opt_c ) ) {
+ usage;
+}
+$MAKE = $ENV{'MAKE'};
+$MAKE = 'gmake' unless $MAKE;
+$WTIME = timeAsSeconds($opt_w);
+print LOG "** Assuming worked at ", timeAsString($WTIME), "\n";
+$DTIME = timeAsSeconds($opt_d);
+print LOG "** Assuming didn't work at ", timeAsString($DTIME), "\n";
+$opt_t =~ s/\s*//g;
+$SCRIPT = $opt_c;
+die "** $SCRIPT is not executable or not found\n" unless -x $SCRIPT;
+print LOG "** Checking for the regression using $SCRIPT\n";
+@TOOLS = split ( /,/, $opt_t );
+print LOG (
+ "** Going to rebuild: ",
+ ( join ", ", @TOOLS ),
+ " before each $SCRIPT run\n"
+);
+if ($opt_I) { checkBoundaryConditions(); }
+# do the dirty work:
+while ( !closeTo( $DTIME, $WTIME ) ) {
+ my $halfPt = halfWayPoint( $DTIME, $WTIME );
+ print LOG "** Checking whether regression is present at ",
+ timeAsString($halfPt), "\n";
+ if ( regressionPresentAt($halfPt) ) {
+ $DTIME = $halfPt;
+ }
+ else {
+ $WTIME = $halfPt;
+ }
+}
+# Tell them what we found
+print LOG "** Narrowed it down to:\n";
+print LOG "** Worked at: ", timeAsString($WTIME), "\n";
+print LOG "** Did not work at: ", timeAsString($DTIME), "\n";
+close LOG;
+exit 0;
diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp
new file mode 100644
index 0000000000..22ff064924
--- /dev/null
+++ b/utils/TableGen/AsmWriterEmitter.cpp
@@ -0,0 +1,700 @@
+//===- AsmWriterEmitter.cpp - Generate an assembly writer -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend is emits an assembly printer for the current target.
+// Note that this is currently fairly skeletal, but will grow over time.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AsmWriterEmitter.h"
+#include "CodeGenTarget.h"
+#include "Record.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MathExtras.h"
+#include <algorithm>
+using namespace llvm;
+
+static bool isIdentChar(char C) {
+ return (C >= 'a' && C <= 'z') ||
+ (C >= 'A' && C <= 'Z') ||
+ (C >= '0' && C <= '9') ||
+ C == '_';
+}
+
+// This should be an anon namespace, this works around a GCC warning.
+namespace llvm {
+ struct AsmWriterOperand {
+ enum { isLiteralTextOperand, isMachineInstrOperand } OperandType;
+
+ /// Str - For isLiteralTextOperand, this IS the literal text. For
+ /// isMachineInstrOperand, this is the PrinterMethodName for the operand.
+ std::string Str;
+
+ /// MiOpNo - For isMachineInstrOperand, this is the operand number of the
+ /// machine instruction.
+ unsigned MIOpNo;
+
+ /// MiModifier - For isMachineInstrOperand, this is the modifier string for
+ /// an operand, specified with syntax like ${opname:modifier}.
+ std::string MiModifier;
+
+ AsmWriterOperand(const std::string &LitStr)
+ : OperandType(isLiteralTextOperand), Str(LitStr) {}
+
+ AsmWriterOperand(const std::string &Printer, unsigned OpNo,
+ const std::string &Modifier)
+ : OperandType(isMachineInstrOperand), Str(Printer), MIOpNo(OpNo),
+ MiModifier(Modifier) {}
+
+ bool operator!=(const AsmWriterOperand &Other) const {
+ if (OperandType != Other.OperandType || Str != Other.Str) return true;
+ if (OperandType == isMachineInstrOperand)
+ return MIOpNo != Other.MIOpNo || MiModifier != Other.MiModifier;
+ return false;
+ }
+ bool operator==(const AsmWriterOperand &Other) const {
+ return !operator!=(Other);
+ }
+
+ /// getCode - Return the code that prints this operand.
+ std::string getCode() const;
+ };
+}
+
+namespace llvm {
+ class AsmWriterInst {
+ public:
+ std::vector<AsmWriterOperand> Operands;
+ const CodeGenInstruction *CGI;
+
+ AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant);
+
+ /// MatchesAllButOneOp - If this instruction is exactly identical to the
+ /// specified instruction except for one differing operand, return the
+ /// differing operand number. Otherwise return ~0.
+ unsigned MatchesAllButOneOp(const AsmWriterInst &Other) const;
+
+ private:
+ void AddLiteralString(const std::string &Str) {
+ // If the last operand was already a literal text string, append this to
+ // it, otherwise add a new operand.
+ if (!Operands.empty() &&
+ Operands.back().OperandType == AsmWriterOperand::isLiteralTextOperand)
+ Operands.back().Str.append(Str);
+ else
+ Operands.push_back(AsmWriterOperand(Str));
+ }
+ };
+}
+
+
+std::string AsmWriterOperand::getCode() const {
+ if (OperandType == isLiteralTextOperand)
+ return "O << \"" + Str + "\"; ";
+
+ std::string Result = Str + "(MI";
+ if (MIOpNo != ~0U)
+ Result += ", " + utostr(MIOpNo);
+ if (!MiModifier.empty())
+ Result += ", \"" + MiModifier + '"';
+ return Result + "); ";
+}
+
+
+/// ParseAsmString - Parse the specified Instruction's AsmString into this
+/// AsmWriterInst.
+///
+AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant) {
+ this->CGI = &CGI;
+ unsigned CurVariant = ~0U; // ~0 if we are outside a {.|.|.} region, other #.
+
+ // NOTE: Any extensions to this code need to be mirrored in the
+ // AsmPrinter::printInlineAsm code that executes as compile time (assuming
+ // that inline asm strings should also get the new feature)!
+ const std::string &AsmString = CGI.AsmString;
+ std::string::size_type LastEmitted = 0;
+ while (LastEmitted != AsmString.size()) {
+ std::string::size_type DollarPos =
+ AsmString.find_first_of("${|}", LastEmitted);
+ if (DollarPos == std::string::npos) DollarPos = AsmString.size();
+
+ // Emit a constant string fragment.
+ if (DollarPos != LastEmitted) {
+ // TODO: this should eventually handle escaping.
+ if (CurVariant == Variant || CurVariant == ~0U)
+ AddLiteralString(std::string(AsmString.begin()+LastEmitted,
+ AsmString.begin()+DollarPos));
+ LastEmitted = DollarPos;
+ } else if (AsmString[DollarPos] == '{') {
+ if (CurVariant != ~0U)
+ throw "Nested variants found for instruction '" +
+ CGI.TheDef->getName() + "'!";
+ LastEmitted = DollarPos+1;
+ CurVariant = 0; // We are now inside of the variant!
+ } else if (AsmString[DollarPos] == '|') {
+ if (CurVariant == ~0U)
+ throw "'|' character found outside of a variant in instruction '"
+ + CGI.TheDef->getName() + "'!";
+ ++CurVariant;
+ ++LastEmitted;
+ } else if (AsmString[DollarPos] == '}') {
+ if (CurVariant == ~0U)
+ throw "'}' character found outside of a variant in instruction '"
+ + CGI.TheDef->getName() + "'!";
+ ++LastEmitted;
+ CurVariant = ~0U;
+ } else if (DollarPos+1 != AsmString.size() &&
+ AsmString[DollarPos+1] == '$') {
+ if (CurVariant == Variant || CurVariant == ~0U)
+ AddLiteralString("$"); // "$$" -> $
+ LastEmitted = DollarPos+2;
+ } else {
+ // Get the name of the variable.
+ std::string::size_type VarEnd = DollarPos+1;
+
+ // handle ${foo}bar as $foo by detecting whether the character following
+ // the dollar sign is a curly brace. If so, advance VarEnd and DollarPos
+ // so the variable name does not contain the leading curly brace.
+ bool hasCurlyBraces = false;
+ if (VarEnd < AsmString.size() && '{' == AsmString[VarEnd]) {
+ hasCurlyBraces = true;
+ ++DollarPos;
+ ++VarEnd;
+ }
+
+ while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd]))
+ ++VarEnd;
+ std::string VarName(AsmString.begin()+DollarPos+1,
+ AsmString.begin()+VarEnd);
+
+ // Modifier - Support ${foo:modifier} syntax, where "modifier" is passed
+ // into printOperand. Also support ${:feature}, which is passed into
+ // PrintSpecial.
+ std::string Modifier;
+
+ // In order to avoid starting the next string at the terminating curly
+ // brace, advance the end position past it if we found an opening curly
+ // brace.
+ if (hasCurlyBraces) {
+ if (VarEnd >= AsmString.size())
+ throw "Reached end of string before terminating curly brace in '"
+ + CGI.TheDef->getName() + "'";
+
+ // Look for a modifier string.
+ if (AsmString[VarEnd] == ':') {
+ ++VarEnd;
+ if (VarEnd >= AsmString.size())
+ throw "Reached end of string before terminating curly brace in '"
+ + CGI.TheDef->getName() + "'";
+
+ unsigned ModifierStart = VarEnd;
+ while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd]))
+ ++VarEnd;
+ Modifier = std::string(AsmString.begin()+ModifierStart,
+ AsmString.begin()+VarEnd);
+ if (Modifier.empty())
+ throw "Bad operand modifier name in '"+ CGI.TheDef->getName() + "'";
+ }
+
+ if (AsmString[VarEnd] != '}')
+ throw "Variable name beginning with '{' did not end with '}' in '"
+ + CGI.TheDef->getName() + "'";
+ ++VarEnd;
+ }
+ if (VarName.empty() && Modifier.empty())
+ throw "Stray '$' in '" + CGI.TheDef->getName() +
+ "' asm string, maybe you want $$?";
+
+ if (VarName.empty()) {
+ // Just a modifier, pass this into PrintSpecial.
+ Operands.push_back(AsmWriterOperand("PrintSpecial", ~0U, Modifier));
+ } else {
+ // Otherwise, normal operand.
+ unsigned OpNo = CGI.getOperandNamed(VarName);
+ CodeGenInstruction::OperandInfo OpInfo = CGI.OperandList[OpNo];
+
+ if (CurVariant == Variant || CurVariant == ~0U) {
+ unsigned MIOp = OpInfo.MIOperandNo;
+ Operands.push_back(AsmWriterOperand(OpInfo.PrinterMethodName, MIOp,
+ Modifier));
+ }
+ }
+ LastEmitted = VarEnd;
+ }
+ }
+
+ AddLiteralString("\\n");
+}
+
+/// MatchesAllButOneOp - If this instruction is exactly identical to the
+/// specified instruction except for one differing operand, return the differing
+/// operand number. If more than one operand mismatches, return ~1, otherwise
+/// if the instructions are identical return ~0.
+unsigned AsmWriterInst::MatchesAllButOneOp(const AsmWriterInst &Other)const{
+ if (Operands.size() != Other.Operands.size()) return ~1;
+
+ unsigned MismatchOperand = ~0U;
+ for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
+ if (Operands[i] != Other.Operands[i])
+ if (MismatchOperand != ~0U) // Already have one mismatch?
+ return ~1U;
+ else
+ MismatchOperand = i;
+ }
+ return MismatchOperand;
+}
+
+static void PrintCases(std::vector<std::pair<std::string,
+ AsmWriterOperand> > &OpsToPrint, std::ostream &O) {
+ O << " case " << OpsToPrint.back().first << ": ";
+ AsmWriterOperand TheOp = OpsToPrint.back().second;
+ OpsToPrint.pop_back();
+
+ // Check to see if any other operands are identical in this list, and if so,
+ // emit a case label for them.
+ for (unsigned i = OpsToPrint.size(); i != 0; --i)
+ if (OpsToPrint[i-1].second == TheOp) {
+ O << "\n case " << OpsToPrint[i-1].first << ": ";
+ OpsToPrint.erase(OpsToPrint.begin()+i-1);
+ }
+
+ // Finally, emit the code.
+ O << TheOp.getCode();
+ O << "break;\n";
+}
+
+
+/// EmitInstructions - Emit the last instruction in the vector and any other
+/// instructions that are suitably similar to it.
+static void EmitInstructions(std::vector<AsmWriterInst> &Insts,
+ std::ostream &O) {
+ AsmWriterInst FirstInst = Insts.back();
+ Insts.pop_back();
+
+ std::vector<AsmWriterInst> SimilarInsts;
+ unsigned DifferingOperand = ~0;
+ for (unsigned i = Insts.size(); i != 0; --i) {
+ unsigned DiffOp = Insts[i-1].MatchesAllButOneOp(FirstInst);
+ if (DiffOp != ~1U) {
+ if (DifferingOperand == ~0U) // First match!
+ DifferingOperand = DiffOp;
+
+ // If this differs in the same operand as the rest of the instructions in
+ // this class, move it to the SimilarInsts list.
+ if (DifferingOperand == DiffOp || DiffOp == ~0U) {
+ SimilarInsts.push_back(Insts[i-1]);
+ Insts.erase(Insts.begin()+i-1);
+ }
+ }
+ }
+
+ O << " case " << FirstInst.CGI->Namespace << "::"
+ << FirstInst.CGI->TheDef->getName() << ":\n";
+ for (unsigned i = 0, e = SimilarInsts.size(); i != e; ++i)
+ O << " case " << SimilarInsts[i].CGI->Namespace << "::"
+ << SimilarInsts[i].CGI->TheDef->getName() << ":\n";
+ for (unsigned i = 0, e = FirstInst.Operands.size(); i != e; ++i) {
+ if (i != DifferingOperand) {
+ // If the operand is the same for all instructions, just print it.
+ O << " " << FirstInst.Operands[i].getCode();
+ } else {
+ // If this is the operand that varies between all of the instructions,
+ // emit a switch for just this operand now.
+ O << " switch (MI->getOpcode()) {\n";
+ std::vector<std::pair<std::string, AsmWriterOperand> > OpsToPrint;
+ OpsToPrint.push_back(std::make_pair(FirstInst.CGI->Namespace + "::" +
+ FirstInst.CGI->TheDef->getName(),
+ FirstInst.Operands[i]));
+
+ for (unsigned si = 0, e = SimilarInsts.size(); si != e; ++si) {
+ AsmWriterInst &AWI = SimilarInsts[si];
+ OpsToPrint.push_back(std::make_pair(AWI.CGI->Namespace+"::"+
+ AWI.CGI->TheDef->getName(),
+ AWI.Operands[i]));
+ }
+ std::reverse(OpsToPrint.begin(), OpsToPrint.end());
+ while (!OpsToPrint.empty())
+ PrintCases(OpsToPrint, O);
+ O << " }";
+ }
+ O << "\n";
+ }
+
+ O << " break;\n";
+}
+
+void AsmWriterEmitter::
+FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands,
+ std::vector<unsigned> &InstIdxs,
+ std::vector<unsigned> &InstOpsUsed) const {
+ InstIdxs.assign(NumberedInstructions.size(), ~0U);
+
+ // This vector parallels UniqueOperandCommands, keeping track of which
+ // instructions each case are used for. It is a comma separated string of
+ // enums.
+ std::vector<std::string> InstrsForCase;
+ InstrsForCase.resize(UniqueOperandCommands.size());
+ InstOpsUsed.assign(UniqueOperandCommands.size(), 0);
+
+ for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
+ const AsmWriterInst *Inst = getAsmWriterInstByID(i);
+ if (Inst == 0) continue; // PHI, INLINEASM, LABEL, etc.
+
+ std::string Command;
+ if (Inst->Operands.empty())
+ continue; // Instruction already done.
+
+ Command = " " + Inst->Operands[0].getCode() + "\n";
+
+ // If this is the last operand, emit a return.
+ if (Inst->Operands.size() == 1)
+ Command += " return true;\n";
+
+ // Check to see if we already have 'Command' in UniqueOperandCommands.
+ // If not, add it.
+ bool FoundIt = false;
+ for (unsigned idx = 0, e = UniqueOperandCommands.size(); idx != e; ++idx)
+ if (UniqueOperandCommands[idx] == Command) {
+ InstIdxs[i] = idx;
+ InstrsForCase[idx] += ", ";
+ InstrsForCase[idx] += Inst->CGI->TheDef->getName();
+ FoundIt = true;
+ break;
+ }
+ if (!FoundIt) {
+ InstIdxs[i] = UniqueOperandCommands.size();
+ UniqueOperandCommands.push_back(Command);
+ InstrsForCase.push_back(Inst->CGI->TheDef->getName());
+
+ // This command matches one operand so far.
+ InstOpsUsed.push_back(1);
+ }
+ }
+
+ // For each entry of UniqueOperandCommands, there is a set of instructions
+ // that uses it. If the next command of all instructions in the set are
+ // identical, fold it into the command.
+ for (unsigned CommandIdx = 0, e = UniqueOperandCommands.size();
+ CommandIdx != e; ++CommandIdx) {
+
+ for (unsigned Op = 1; ; ++Op) {
+ // Scan for the first instruction in the set.
+ std::vector<unsigned>::iterator NIT =
+ std::find(InstIdxs.begin(), InstIdxs.end(), CommandIdx);
+ if (NIT == InstIdxs.end()) break; // No commonality.
+
+ // If this instruction has no more operands, we isn't anything to merge
+ // into this command.
+ const AsmWriterInst *FirstInst =
+ getAsmWriterInstByID(NIT-InstIdxs.begin());
+ if (!FirstInst || FirstInst->Operands.size() == Op)
+ break;
+
+ // Otherwise, scan to see if all of the other instructions in this command
+ // set share the operand.
+ bool AllSame = true;
+
+ for (NIT = std::find(NIT+1, InstIdxs.end(), CommandIdx);
+ NIT != InstIdxs.end();
+ NIT = std::find(NIT+1, InstIdxs.end(), CommandIdx)) {
+ // Okay, found another instruction in this command set. If the operand
+ // matches, we're ok, otherwise bail out.
+ const AsmWriterInst *OtherInst =
+ getAsmWriterInstByID(NIT-InstIdxs.begin());
+ if (!OtherInst || OtherInst->Operands.size() == Op ||
+ OtherInst->Operands[Op] != FirstInst->Operands[Op]) {
+ AllSame = false;
+ break;
+ }
+ }
+ if (!AllSame) break;
+
+ // Okay, everything in this command set has the same next operand. Add it
+ // to UniqueOperandCommands and remember that it was consumed.
+ std::string Command = " " + FirstInst->Operands[Op].getCode() + "\n";
+
+ // If this is the last operand, emit a return after the code.
+ if (FirstInst->Operands.size() == Op+1)
+ Command += " return true;\n";
+
+ UniqueOperandCommands[CommandIdx] += Command;
+ InstOpsUsed[CommandIdx]++;
+ }
+ }
+
+ // Prepend some of the instructions each case is used for onto the case val.
+ for (unsigned i = 0, e = InstrsForCase.size(); i != e; ++i) {
+ std::string Instrs = InstrsForCase[i];
+ if (Instrs.size() > 70) {
+ Instrs.erase(Instrs.begin()+70, Instrs.end());
+ Instrs += "...";
+ }
+
+ if (!Instrs.empty())
+ UniqueOperandCommands[i] = " // " + Instrs + "\n" +
+ UniqueOperandCommands[i];
+ }
+}
+
+
+
+void AsmWriterEmitter::run(std::ostream &O) {
+ EmitSourceFileHeader("Assembly Writer Source Fragment", O);
+
+ CodeGenTarget Target;
+ Record *AsmWriter = Target.getAsmWriter();
+ std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
+ unsigned Variant = AsmWriter->getValueAsInt("Variant");
+
+ O <<
+ "/// printInstruction - This method is automatically generated by tablegen\n"
+ "/// from the instruction set description. This method returns true if the\n"
+ "/// machine instruction was sufficiently described to print it, otherwise\n"
+ "/// it returns false.\n"
+ "bool " << Target.getName() << ClassName
+ << "::printInstruction(const MachineInstr *MI) {\n";
+
+ std::vector<AsmWriterInst> Instructions;
+
+ for (CodeGenTarget::inst_iterator I = Target.inst_begin(),
+ E = Target.inst_end(); I != E; ++I)
+ if (!I->second.AsmString.empty())
+ Instructions.push_back(AsmWriterInst(I->second, Variant));
+
+ // Get the instruction numbering.
+ Target.getInstructionsByEnumValue(NumberedInstructions);
+
+ // Compute the CodeGenInstruction -> AsmWriterInst mapping. Note that not
+ // all machine instructions are necessarily being printed, so there may be
+ // target instructions not in this map.
+ for (unsigned i = 0, e = Instructions.size(); i != e; ++i)
+ CGIAWIMap.insert(std::make_pair(Instructions[i].CGI, &Instructions[i]));
+
+ // Build an aggregate string, and build a table of offsets into it.
+ std::map<std::string, unsigned> StringOffset;
+ std::string AggregateString;
+ AggregateString.push_back(0); // "\0"
+ AggregateString.push_back(0); // "\0"
+
+ /// OpcodeInfo - This encodes the index of the string to use for the first
+ /// chunk of the output as well as indices used for operand printing.
+ std::vector<unsigned> OpcodeInfo;
+
+ unsigned MaxStringIdx = 0;
+ for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
+ AsmWriterInst *AWI = CGIAWIMap[NumberedInstructions[i]];
+ unsigned Idx;
+ if (AWI == 0) {
+ // Something not handled by the asmwriter printer.
+ Idx = 0;
+ } else if (AWI->Operands[0].OperandType !=
+ AsmWriterOperand::isLiteralTextOperand ||
+ AWI->Operands[0].Str.empty()) {
+ // Something handled by the asmwriter printer, but with no leading string.
+ Idx = 1;
+ } else {
+ unsigned &Entry = StringOffset[AWI->Operands[0].Str];
+ if (Entry == 0) {
+ // Add the string to the aggregate if this is the first time found.
+ MaxStringIdx = Entry = AggregateString.size();
+ std::string Str = AWI->Operands[0].Str;
+ UnescapeString(Str);
+ AggregateString += Str;
+ AggregateString += '\0';
+ }
+ Idx = Entry;
+
+ // Nuke the string from the operand list. It is now handled!
+ AWI->Operands.erase(AWI->Operands.begin());
+ }
+ OpcodeInfo.push_back(Idx);
+ }
+
+ // Figure out how many bits we used for the string index.
+ unsigned AsmStrBits = Log2_32_Ceil(MaxStringIdx);
+
+ // To reduce code size, we compactify common instructions into a few bits
+ // in the opcode-indexed table.
+ unsigned BitsLeft = 32-AsmStrBits;
+
+ std::vector<std::vector<std::string> > TableDrivenOperandPrinters;
+
+ bool isFirst = true;
+ while (1) {
+ std::vector<std::string> UniqueOperandCommands;
+
+ // For the first operand check, add a default value for instructions with
+ // just opcode strings to use.
+ if (isFirst) {
+ UniqueOperandCommands.push_back(" return true;\n");
+ isFirst = false;
+ }
+
+ std::vector<unsigned> InstIdxs;
+ std::vector<unsigned> NumInstOpsHandled;
+ FindUniqueOperandCommands(UniqueOperandCommands, InstIdxs,
+ NumInstOpsHandled);
+
+ // If we ran out of operands to print, we're done.
+ if (UniqueOperandCommands.empty()) break;
+
+ // Compute the number of bits we need to represent these cases, this is
+ // ceil(log2(numentries)).
+ unsigned NumBits = Log2_32_Ceil(UniqueOperandCommands.size());
+
+ // If we don't have enough bits for this operand, don't include it.
+ if (NumBits > BitsLeft) {
+ DOUT << "Not enough bits to densely encode " << NumBits
+ << " more bits\n";
+ break;
+ }
+
+ // Otherwise, we can include this in the initial lookup table. Add it in.
+ BitsLeft -= NumBits;
+ for (unsigned i = 0, e = InstIdxs.size(); i != e; ++i)
+ if (InstIdxs[i] != ~0U)
+ OpcodeInfo[i] |= InstIdxs[i] << (BitsLeft+AsmStrBits);
+
+ // Remove the info about this operand.
+ for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
+ if (AsmWriterInst *Inst = getAsmWriterInstByID(i))
+ if (!Inst->Operands.empty()) {
+ unsigned NumOps = NumInstOpsHandled[InstIdxs[i]];
+ assert(NumOps <= Inst->Operands.size() &&
+ "Can't remove this many ops!");
+ Inst->Operands.erase(Inst->Operands.begin(),
+ Inst->Operands.begin()+NumOps);
+ }
+ }
+
+ // Remember the handlers for this set of operands.
+ TableDrivenOperandPrinters.push_back(UniqueOperandCommands);
+ }
+
+
+
+ O<<" static const unsigned OpInfo[] = {\n";
+ for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
+ O << " " << OpcodeInfo[i] << "U,\t// "
+ << NumberedInstructions[i]->TheDef->getName() << "\n";
+ }
+ // Add a dummy entry so the array init doesn't end with a comma.
+ O << " 0U\n";
+ O << " };\n\n";
+
+ // Emit the string itself.
+ O << " const char *AsmStrs = \n \"";
+ unsigned CharsPrinted = 0;
+ EscapeString(AggregateString);
+ for (unsigned i = 0, e = AggregateString.size(); i != e; ++i) {
+ if (CharsPrinted > 70) {
+ O << "\"\n \"";
+ CharsPrinted = 0;
+ }
+ O << AggregateString[i];
+ ++CharsPrinted;
+
+ // Print escape sequences all together.
+ if (AggregateString[i] == '\\') {
+ assert(i+1 < AggregateString.size() && "Incomplete escape sequence!");
+ if (isdigit(AggregateString[i+1])) {
+ assert(isdigit(AggregateString[i+2]) && isdigit(AggregateString[i+3]) &&
+ "Expected 3 digit octal escape!");
+ O << AggregateString[++i];
+ O << AggregateString[++i];
+ O << AggregateString[++i];
+ CharsPrinted += 3;
+ } else {
+ O << AggregateString[++i];
+ ++CharsPrinted;
+ }
+ }
+ }
+ O << "\";\n\n";
+
+ O << " if (MI->getOpcode() == TargetInstrInfo::INLINEASM) {\n"
+ << " printInlineAsm(MI);\n"
+ << " return true;\n"
+ << " } else if (MI->getOpcode() == TargetInstrInfo::LABEL) {\n"
+ << " printLabel(MI);\n"
+ << " return true;\n"
+ << " }\n\n";
+
+ O << " // Emit the opcode for the instruction.\n"
+ << " unsigned Bits = OpInfo[MI->getOpcode()];\n"
+ << " if (Bits == 0) return false;\n"
+ << " O << AsmStrs+(Bits & " << (1 << AsmStrBits)-1 << ");\n\n";
+
+ // Output the table driven operand information.
+ BitsLeft = 32-AsmStrBits;
+ for (unsigned i = 0, e = TableDrivenOperandPrinters.size(); i != e; ++i) {
+ std::vector<std::string> &Commands = TableDrivenOperandPrinters[i];
+
+ // Compute the number of bits we need to represent these cases, this is
+ // ceil(log2(numentries)).
+ unsigned NumBits = Log2_32_Ceil(Commands.size());
+ assert(NumBits <= BitsLeft && "consistency error");
+
+ // Emit code to extract this field from Bits.
+ BitsLeft -= NumBits;
+
+ O << "\n // Fragment " << i << " encoded into " << NumBits
+ << " bits for " << Commands.size() << " unique commands.\n";
+
+ if (Commands.size() == 2) {
+ // Emit two possibilitys with if/else.
+ O << " if ((Bits >> " << (BitsLeft+AsmStrBits) << ") & "
+ << ((1 << NumBits)-1) << ") {\n"
+ << Commands[1]
+ << " } else {\n"
+ << Commands[0]
+ << " }\n\n";
+ } else {
+ O << " switch ((Bits >> " << (BitsLeft+AsmStrBits) << ") & "
+ << ((1 << NumBits)-1) << ") {\n"
+ << " default: // unreachable.\n";
+
+ // Print out all the cases.
+ for (unsigned i = 0, e = Commands.size(); i != e; ++i) {
+ O << " case " << i << ":\n";
+ O << Commands[i];
+ O << " break;\n";
+ }
+ O << " }\n\n";
+ }
+ }
+
+ // Okay, delete instructions with no operand info left.
+ for (unsigned i = 0, e = Instructions.size(); i != e; ++i) {
+ // Entire instruction has been emitted?
+ AsmWriterInst &Inst = Instructions[i];
+ if (Inst.Operands.empty()) {
+ Instructions.erase(Instructions.begin()+i);
+ --i; --e;
+ }
+ }
+
+
+ // Because this is a vector, we want to emit from the end. Reverse all of the
+ // elements in the vector.
+ std::reverse(Instructions.begin(), Instructions.end());
+
+ if (!Instructions.empty()) {
+ // Find the opcode # of inline asm.
+ O << " switch (MI->getOpcode()) {\n";
+ while (!Instructions.empty())
+ EmitInstructions(Instructions, O);
+
+ O << " }\n";
+ O << " return true;\n";
+ }
+
+ O << "}\n";
+}
diff --git a/utils/TableGen/AsmWriterEmitter.h b/utils/TableGen/AsmWriterEmitter.h
new file mode 100644
index 0000000000..7932b1a693
--- /dev/null
+++ b/utils/TableGen/AsmWriterEmitter.h
@@ -0,0 +1,50 @@
+//===- AsmWriterEmitter.h - Generate an assembly writer ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend is responsible for emitting an assembly printer for the
+// code generator.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ASMWRITER_EMITTER_H
+#define ASMWRITER_EMITTER_H
+
+#include "TableGenBackend.h"
+#include <map>
+#include <vector>
+#include <cassert>
+
+namespace llvm {
+ class AsmWriterInst;
+ class CodeGenInstruction;
+
+ class AsmWriterEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+ std::map<const CodeGenInstruction*, AsmWriterInst*> CGIAWIMap;
+ std::vector<const CodeGenInstruction*> NumberedInstructions;
+ public:
+ AsmWriterEmitter(RecordKeeper &R) : Records(R) {}
+
+ // run - Output the asmwriter, returning true on failure.
+ void run(std::ostream &o);
+
+private:
+ AsmWriterInst *getAsmWriterInstByID(unsigned ID) const {
+ assert(ID < NumberedInstructions.size());
+ std::map<const CodeGenInstruction*, AsmWriterInst*>::const_iterator I =
+ CGIAWIMap.find(NumberedInstructions[ID]);
+ assert(I != CGIAWIMap.end() && "Didn't find inst!");
+ return I->second;
+ }
+ void FindUniqueOperandCommands(std::vector<std::string> &UOC,
+ std::vector<unsigned> &InstIdxs,
+ std::vector<unsigned> &InstOpsUsed) const;
+ };
+}
+#endif
diff --git a/utils/TableGen/CallingConvEmitter.cpp b/utils/TableGen/CallingConvEmitter.cpp
new file mode 100644
index 0000000000..2929aba820
--- /dev/null
+++ b/utils/TableGen/CallingConvEmitter.cpp
@@ -0,0 +1,139 @@
+//===- CallingConvEmitter.cpp - Generate calling conventions --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend is responsible for emitting descriptions of the calling
+// conventions supported by this target.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CallingConvEmitter.h"
+#include "Record.h"
+#include "CodeGenTarget.h"
+using namespace llvm;
+
+void CallingConvEmitter::run(std::ostream &O) {
+ EmitSourceFileHeader("Calling Convention Implementation Fragment", O);
+
+ std::vector<Record*> CCs = Records.getAllDerivedDefinitions("CallingConv");
+
+ // Emit prototypes for all of the CC's so that they can forward ref each
+ // other.
+ for (unsigned i = 0, e = CCs.size(); i != e; ++i) {
+ O << "static bool " << CCs[i]->getName()
+ << "(unsigned ValNo, MVT::ValueType ValVT,\n"
+ << std::string(CCs[i]->getName().size()+13, ' ')
+ << "MVT::ValueType LocVT, CCValAssign::LocInfo LocInfo,\n"
+ << std::string(CCs[i]->getName().size()+13, ' ')
+ << "unsigned ArgFlags, CCState &State);\n";
+ }
+
+ // Emit each calling convention description in full.
+ for (unsigned i = 0, e = CCs.size(); i != e; ++i)
+ EmitCallingConv(CCs[i], O);
+}
+
+
+void CallingConvEmitter::EmitCallingConv(Record *CC, std::ostream &O) {
+ ListInit *CCActions = CC->getValueAsListInit("Actions");
+ Counter = 0;
+
+ O << "\n\nstatic bool " << CC->getName()
+ << "(unsigned ValNo, MVT::ValueType ValVT,\n"
+ << std::string(CC->getName().size()+13, ' ')
+ << "MVT::ValueType LocVT, CCValAssign::LocInfo LocInfo,\n"
+ << std::string(CC->getName().size()+13, ' ')
+ << "unsigned ArgFlags, CCState &State) {\n";
+ // Emit all of the actions, in order.
+ for (unsigned i = 0, e = CCActions->getSize(); i != e; ++i) {
+ O << "\n";
+ EmitAction(CCActions->getElementAsRecord(i), 2, O);
+ }
+
+ O << "\n return true; // CC didn't match.\n";
+ O << "}\n";
+}
+
+void CallingConvEmitter::EmitAction(Record *Action,
+ unsigned Indent, std::ostream &O) {
+ std::string IndentStr = std::string(Indent, ' ');
+
+ if (Action->isSubClassOf("CCPredicateAction")) {
+ O << IndentStr << "if (";
+
+ if (Action->isSubClassOf("CCIfType")) {
+ ListInit *VTs = Action->getValueAsListInit("VTs");
+ for (unsigned i = 0, e = VTs->getSize(); i != e; ++i) {
+ Record *VT = VTs->getElementAsRecord(i);
+ if (i != 0) O << " ||\n " << IndentStr;
+ O << "LocVT == " << getEnumName(getValueType(VT));
+ }
+
+ } else if (Action->isSubClassOf("CCIf")) {
+ O << Action->getValueAsString("Predicate");
+ } else {
+ Action->dump();
+ throw "Unknown CCPredicateAction!";
+ }
+
+ O << ") {\n";
+ EmitAction(Action->getValueAsDef("SubAction"), Indent+2, O);
+ O << IndentStr << "}\n";
+ } else {
+ if (Action->isSubClassOf("CCDelegateTo")) {
+ Record *CC = Action->getValueAsDef("CC");
+ O << IndentStr << "if (!" << CC->getName()
+ << "(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State))\n"
+ << IndentStr << " return false;\n";
+ } else if (Action->isSubClassOf("CCAssignToReg")) {
+ ListInit *RegList = Action->getValueAsListInit("RegList");
+ if (RegList->getSize() == 1) {
+ O << IndentStr << "if (unsigned Reg = State.AllocateReg(";
+ O << getQualifiedName(RegList->getElementAsRecord(0)) << ")) {\n";
+ } else {
+ O << IndentStr << "static const unsigned RegList" << ++Counter
+ << "[] = {\n";
+ O << IndentStr << " ";
+ for (unsigned i = 0, e = RegList->getSize(); i != e; ++i) {
+ if (i != 0) O << ", ";
+ O << getQualifiedName(RegList->getElementAsRecord(i));
+ }
+ O << "\n" << IndentStr << "};\n";
+ O << IndentStr << "if (unsigned Reg = State.AllocateReg(RegList"
+ << Counter << ", " << RegList->getSize() << ")) {\n";
+ }
+ O << IndentStr << " State.addLoc(CCValAssign::getReg(ValNo, ValVT, "
+ << "Reg, LocVT, LocInfo));\n";
+ O << IndentStr << " return false;\n";
+ O << IndentStr << "}\n";
+ } else if (Action->isSubClassOf("CCAssignToStack")) {
+ int Size = Action->getValueAsInt("Size");
+ int Align = Action->getValueAsInt("Align");
+
+ O << IndentStr << "unsigned Offset" << ++Counter
+ << " = State.AllocateStack(" << Size << ", " << Align << ");\n";
+ O << IndentStr << "State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset"
+ << Counter << ", LocVT, LocInfo));\n";
+ O << IndentStr << "return false;\n";
+ } else if (Action->isSubClassOf("CCPromoteToType")) {
+ Record *DestTy = Action->getValueAsDef("DestTy");
+ O << IndentStr << "LocVT = " << getEnumName(getValueType(DestTy)) <<";\n";
+ O << IndentStr << "if (ArgFlags & ISD::ParamFlags::SExt)\n"
+ << IndentStr << IndentStr << "LocInfo = CCValAssign::SExt;\n"
+ << IndentStr << "else if (ArgFlags & ISD::ParamFlags::ZExt)\n"
+ << IndentStr << IndentStr << "LocInfo = CCValAssign::ZExt;\n"
+ << IndentStr << "else\n"
+ << IndentStr << IndentStr << "LocInfo = CCValAssign::AExt;\n";
+ } else if (Action->isSubClassOf("CCStructAssign")) {
+ O << "assert(0 && \"Not Implemented\");\n";
+ } else {
+ Action->dump();
+ throw "Unknown CCAction!";
+ }
+ }
+}
diff --git a/utils/TableGen/CallingConvEmitter.h b/utils/TableGen/CallingConvEmitter.h
new file mode 100644
index 0000000000..a0bfab3e75
--- /dev/null
+++ b/utils/TableGen/CallingConvEmitter.h
@@ -0,0 +1,38 @@
+//===- CallingConvEmitter.h - Generate calling conventions ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend is responsible for emitting descriptions of the calling
+// conventions supported by this target.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CALLINGCONV_EMITTER_H
+#define CALLINGCONV_EMITTER_H
+
+#include "TableGenBackend.h"
+#include <map>
+#include <vector>
+#include <cassert>
+
+namespace llvm {
+ class CallingConvEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+ public:
+ CallingConvEmitter(RecordKeeper &R) : Records(R) {}
+
+ // run - Output the asmwriter, returning true on failure.
+ void run(std::ostream &o);
+
+ private:
+ void EmitCallingConv(Record *CC, std::ostream &O);
+ void EmitAction(Record *Action, unsigned Indent, std::ostream &O);
+ unsigned Counter;
+ };
+}
+#endif
diff --git a/utils/TableGen/CodeEmitterGen.cpp b/utils/TableGen/CodeEmitterGen.cpp
new file mode 100644
index 0000000000..300a1009a7
--- /dev/null
+++ b/utils/TableGen/CodeEmitterGen.cpp
@@ -0,0 +1,228 @@
+//===- CodeEmitterGen.cpp - Code Emitter Generator ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// CodeEmitterGen uses the descriptions of instructions and their fields to
+// construct an automated code emitter: a function that, given a MachineInstr,
+// returns the (currently, 32-bit unsigned) value of the instruction.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeEmitterGen.h"
+#include "CodeGenTarget.h"
+#include "Record.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Debug.h"
+using namespace llvm;
+
+void CodeEmitterGen::reverseBits(std::vector<Record*> &Insts) {
+ for (std::vector<Record*>::iterator I = Insts.begin(), E = Insts.end();
+ I != E; ++I) {
+ Record *R = *I;
+ if (R->getName() == "PHI" ||
+ R->getName() == "INLINEASM" ||
+ R->getName() == "LABEL") continue;
+
+ BitsInit *BI = R->getValueAsBitsInit("Inst");
+
+ unsigned numBits = BI->getNumBits();
+ BitsInit *NewBI = new BitsInit(numBits);
+ for (unsigned bit = 0, end = numBits / 2; bit != end; ++bit) {
+ unsigned bitSwapIdx = numBits - bit - 1;
+ Init *OrigBit = BI->getBit(bit);
+ Init *BitSwap = BI->getBit(bitSwapIdx);
+ NewBI->setBit(bit, BitSwap);
+ NewBI->setBit(bitSwapIdx, OrigBit);
+ }
+ if (numBits % 2) {
+ unsigned middle = (numBits + 1) / 2;
+ NewBI->setBit(middle, BI->getBit(middle));
+ }
+
+ // Update the bits in reversed order so that emitInstrOpBits will get the
+ // correct endianness.
+ R->getValue("Inst")->setValue(NewBI);
+ }
+}
+
+
+// If the VarBitInit at position 'bit' matches the specified variable then
+// return the variable bit position. Otherwise return -1.
+int CodeEmitterGen::getVariableBit(const std::string &VarName,
+ BitsInit *BI, int bit) {
+ if (VarBitInit *VBI = dynamic_cast<VarBitInit*>(BI->getBit(bit))) {
+ TypedInit *TI = VBI->getVariable();
+
+ if (VarInit *VI = dynamic_cast<VarInit*>(TI)) {
+ if (VI->getName() == VarName) return VBI->getBitNum();
+ }
+ }
+
+ return -1;
+}
+
+
+void CodeEmitterGen::run(std::ostream &o) {
+ CodeGenTarget Target;
+ std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction");
+
+ // For little-endian instruction bit encodings, reverse the bit order
+ if (Target.isLittleEndianEncoding()) reverseBits(Insts);
+
+ EmitSourceFileHeader("Machine Code Emitter", o);
+ std::string Namespace = Insts[0]->getValueAsString("Namespace") + "::";
+
+ std::vector<const CodeGenInstruction*> NumberedInstructions;
+ Target.getInstructionsByEnumValue(NumberedInstructions);
+
+ // Emit function declaration
+ o << "unsigned " << Target.getName() << "CodeEmitter::"
+ << "getBinaryCodeForInstr(MachineInstr &MI) {\n";
+
+ // Emit instruction base values
+ o << " static const unsigned InstBits[] = {\n";
+ for (std::vector<const CodeGenInstruction*>::iterator
+ IN = NumberedInstructions.begin(),
+ EN = NumberedInstructions.end();
+ IN != EN; ++IN) {
+ const CodeGenInstruction *CGI = *IN;
+ Record *R = CGI->TheDef;
+
+ if (IN != NumberedInstructions.begin()) o << ",\n";
+
+ if (R->getName() == "PHI" ||
+ R->getName() == "INLINEASM" ||
+ R->getName() == "LABEL") {
+ o << " 0U";
+ continue;
+ }
+
+ BitsInit *BI = R->getValueAsBitsInit("Inst");
+
+ // Start by filling in fixed values...
+ unsigned Value = 0;
+ 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);
+ }
+ }
+ o << " " << Value << "U";
+ }
+ o << "\n };\n";
+
+ // Map to accumulate all the cases.
+ std::map<std::string, std::vector<std::string> > CaseMap;
+
+ // Construct all cases statement for each opcode
+ for (std::vector<Record*>::iterator IC = Insts.begin(), EC = Insts.end();
+ IC != EC; ++IC) {
+ Record *R = *IC;
+ const std::string &InstName = R->getName();
+ std::string Case("");
+
+ if (InstName == "PHI" ||
+ InstName == "INLINEASM" ||
+ InstName == "LABEL") continue;
+
+ BitsInit *BI = R->getValueAsBitsInit("Inst");
+ const std::vector<RecordVal> &Vals = R->getValues();
+ CodeGenInstruction &CGI = Target.getInstruction(InstName);
+
+ // Loop over all of the fields in the instruction, determining which are the
+ // operands to the instruction.
+ unsigned op = 0;
+ 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 std::string &VarName = Vals[i].getName();
+ bool gotOp = false;
+
+ for (int bit = BI->getNumBits()-1; bit >= 0; ) {
+ int varBit = getVariableBit(VarName, BI, bit);
+
+ if (varBit == -1) {
+ --bit;
+ } else {
+ int beginInstBit = bit;
+ int beginVarBit = varBit;
+ int N = 1;
+
+ for (--bit; bit >= 0;) {
+ varBit = getVariableBit(VarName, BI, bit);
+ if (varBit == -1 || varBit != (beginVarBit - N)) break;
+ ++N;
+ --bit;
+ }
+
+ if (!gotOp) {
+ /// If this operand is not supposed to be emitted by the generated
+ /// emitter, skip it.
+ while (CGI.isFlatOperandNotEmitted(op))
+ ++op;
+
+ Case += " // op: " + VarName + "\n"
+ + " op = getMachineOpValue(MI, MI.getOperand("
+ + utostr(op++) + "));\n";
+ gotOp = true;
+ }
+
+ unsigned opMask = (1 << N) - 1;
+ int opShift = beginVarBit - N + 1;
+ opMask <<= opShift;
+ opShift = beginInstBit - beginVarBit;
+
+ if (opShift > 0) {
+ Case += " Value |= (op & " + utostr(opMask) + "U) << "
+ + itostr(opShift) + ";\n";
+ } else if (opShift < 0) {
+ Case += " Value |= (op & " + utostr(opMask) + "U) >> "
+ + itostr(-opShift) + ";\n";
+ } else {
+ Case += " Value |= op & " + utostr(opMask) + "U;\n";
+ }
+ }
+ }
+ }
+ }
+
+ std::vector<std::string> &InstList = CaseMap[Case];
+ InstList.push_back(InstName);
+ }
+
+
+ // Emit initial function code
+ o << " const unsigned opcode = MI.getOpcode();\n"
+ << " unsigned Value = InstBits[opcode];\n"
+ << " unsigned op;\n"
+ << " switch (opcode) {\n";
+
+ // Emit each case statement
+ std::map<std::string, std::vector<std::string> >::iterator IE, EE;
+ for (IE = CaseMap.begin(), EE = CaseMap.end(); IE != EE; ++IE) {
+ const std::string &Case = IE->first;
+ std::vector<std::string> &InstList = IE->second;
+
+ for (int i = 0, N = InstList.size(); i < N; i++) {
+ if (i) o << "\n";
+ o << " case " << Namespace << InstList[i] << ":";
+ }
+ o << " {\n";
+ o << Case;
+ o << " break;\n"
+ << " }\n";
+ }
+
+ // Default case: unhandled opcode
+ o << " default:\n"
+ << " cerr << \"Not supported instr: \" << MI << \"\\n\";\n"
+ << " abort();\n"
+ << " }\n"
+ << " return Value;\n"
+ << "}\n\n";
+}
diff --git a/utils/TableGen/CodeEmitterGen.h b/utils/TableGen/CodeEmitterGen.h
new file mode 100644
index 0000000000..e0a7071ed6
--- /dev/null
+++ b/utils/TableGen/CodeEmitterGen.h
@@ -0,0 +1,43 @@
+//===- CodeEmitterGen.h - Code Emitter Generator ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// FIXME: document
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CODEMITTERGEN_H
+#define CODEMITTERGEN_H
+
+#include "TableGenBackend.h"
+#include <map>
+#include <vector>
+#include <string>
+
+namespace llvm {
+
+class RecordVal;
+class BitsInit;
+
+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);
+ void reverseBits(std::vector<Record*> &Insts);
+ int getVariableBit(const std::string &VarName, BitsInit *BI, int bit);
+};
+
+} // End llvm namespace
+
+#endif
diff --git a/utils/TableGen/CodeGenInstruction.h b/utils/TableGen/CodeGenInstruction.h
new file mode 100644
index 0000000000..3f59c23a87
--- /dev/null
+++ b/utils/TableGen/CodeGenInstruction.h
@@ -0,0 +1,146 @@
+//===- CodeGenInstruction.h - Instruction Class Wrapper ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a wrapper class for the 'Instruction' TableGen class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CODEGEN_INSTRUCTION_H
+#define CODEGEN_INSTRUCTION_H
+
+#include "llvm/CodeGen/ValueTypes.h"
+#include <string>
+#include <vector>
+#include <utility>
+
+namespace llvm {
+ class Record;
+ class DagInit;
+
+ class CodeGenInstruction {
+ public:
+ Record *TheDef; // The actual record defining this instruction.
+ std::string Name; // Contents of the 'Name' field.
+ std::string Namespace; // The namespace the instruction is in.
+
+ /// AsmString - The format string used to emit a .s file for the
+ /// instruction.
+ std::string AsmString;
+
+ /// OperandInfo - The information we keep track of for each operand in the
+ /// operand list for a tablegen instruction.
+ struct OperandInfo {
+ /// Rec - The definition this operand is declared as.
+ ///
+ Record *Rec;
+
+ /// Name - If this operand was assigned a symbolic name, this is it,
+ /// otherwise, it's empty.
+ std::string Name;
+
+ /// PrinterMethodName - The method used to print operands of this type in
+ /// the asmprinter.
+ std::string PrinterMethodName;
+
+ /// MIOperandNo - Currently (this is meant to be phased out), some logical
+ /// operands correspond to multiple MachineInstr operands. In the X86
+ /// target for example, one address operand is represented as 4
+ /// MachineOperands. Because of this, the operand number in the
+ /// OperandList may not match the MachineInstr operand num. Until it
+ /// does, this contains the MI operand index of this operand.
+ unsigned MIOperandNo;
+ unsigned MINumOperands; // The number of operands.
+
+ /// DoNotEncode - Bools are set to true in this vector for each operand in
+ /// the DisableEncoding list. These should not be emitted by the code
+ /// emitter.
+ std::vector<bool> DoNotEncode;
+
+ /// MIOperandInfo - Default MI operand type. Note an operand may be made
+ /// up of multiple MI operands.
+ DagInit *MIOperandInfo;
+
+ /// Constraint info for this operand. This operand can have pieces, so we
+ /// track constraint info for each.
+ std::vector<std::string> Constraints;
+
+ OperandInfo(Record *R, const std::string &N, const std::string &PMN,
+ unsigned MION, unsigned MINO, DagInit *MIOI)
+ : Rec(R), Name(N), PrinterMethodName(PMN), MIOperandNo(MION),
+ MINumOperands(MINO), MIOperandInfo(MIOI) {}
+ };
+
+ /// OperandList - The list of declared operands, along with their declared
+ /// type (which is a record).
+ std::vector<OperandInfo> OperandList;
+
+ // Various boolean values we track for the instruction.
+ bool isReturn;
+ bool isBranch;
+ bool isBarrier;
+ bool isCall;
+ bool isLoad;
+ bool isStore;
+ bool isPredicable;
+ bool isConvertibleToThreeAddress;
+ bool isCommutable;
+ bool isTerminator;
+ bool isReMaterializable;
+ bool hasDelaySlot;
+ bool usesCustomDAGSchedInserter;
+ bool hasVariableNumberOfOperands;
+ bool hasCtrlDep;
+ bool noResults;
+ bool isNotDuplicable;
+ bool hasOptionalDef;
+
+ /// ParseOperandName - Parse an operand name like "$foo" or "$foo.bar",
+ /// where $foo is a whole operand and $foo.bar refers to a suboperand.
+ /// This throws an exception if the name is invalid. If AllowWholeOp is
+ /// true, references to operands with suboperands are allowed, otherwise
+ /// not.
+ std::pair<unsigned,unsigned> ParseOperandName(const std::string &Op,
+ bool AllowWholeOp = true);
+
+ /// getFlattenedOperandNumber - Flatten a operand/suboperand pair into a
+ /// flat machineinstr operand #.
+ unsigned getFlattenedOperandNumber(std::pair<unsigned,unsigned> Op) const {
+ return OperandList[Op.first].MIOperandNo + Op.second;
+ }
+
+ /// getSubOperandNumber - Unflatten a operand number into an
+ /// operand/suboperand pair.
+ std::pair<unsigned,unsigned> getSubOperandNumber(unsigned Op) const {
+ for (unsigned i = 0; ; ++i) {
+ assert(i < OperandList.size() && "Invalid flat operand #");
+ if (OperandList[i].MIOperandNo+OperandList[i].MINumOperands > Op)
+ return std::make_pair(i, Op-OperandList[i].MIOperandNo);
+ }
+ }
+
+
+ /// isFlatOperandNotEmitted - Return true if the specified flat operand #
+ /// should not be emitted with the code emitter.
+ bool isFlatOperandNotEmitted(unsigned FlatOpNo) const {
+ std::pair<unsigned,unsigned> Op = getSubOperandNumber(FlatOpNo);
+ if (OperandList[Op.first].DoNotEncode.size() > Op.second)
+ return OperandList[Op.first].DoNotEncode[Op.second];
+ return false;
+ }
+
+ CodeGenInstruction(Record *R, const std::string &AsmStr);
+
+ /// getOperandNamed - Return the index of the operand with the specified
+ /// non-empty name. If the instruction does not have an operand with the
+ /// specified name, throw an exception.
+ unsigned getOperandNamed(const std::string &Name) const;
+ };
+}
+
+#endif
diff --git a/utils/TableGen/CodeGenIntrinsics.h b/utils/TableGen/CodeGenIntrinsics.h
new file mode 100644
index 0000000000..57f85ad422
--- /dev/null
+++ b/utils/TableGen/CodeGenIntrinsics.h
@@ -0,0 +1,64 @@
+//===- CodeGenIntrinsic.h - Intrinsic Class Wrapper ------------*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a wrapper class for the 'Intrinsic' TableGen class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CODEGEN_INTRINSIC_H
+#define CODEGEN_INTRINSIC_H
+
+#include <string>
+#include <vector>
+#include "llvm/CodeGen/ValueTypes.h"
+
+namespace llvm {
+ class Record;
+ class RecordKeeper;
+ class CodeGenTarget;
+
+ struct CodeGenIntrinsic {
+ Record *TheDef; // The actual record defining this intrinsic.
+ std::string Name; // The name of the LLVM function "llvm.bswap.i32"
+ std::string EnumName; // The name of the enum "bswap_i32"
+ std::string GCCBuiltinName;// Name of the corresponding GCC builtin, or "".
+ std::string TargetPrefix; // Target prefix, e.g. "ppc" for t-s intrinsics.
+
+ /// ArgTypes - The type primitive enum value for the return value and all
+ /// of the arguments. These are things like Type::IntegerTyID.
+ std::vector<std::string> ArgTypes;
+
+ /// ArgVTs - The MVT::ValueType for each argument type. Note that this list
+ /// is only populated when in the context of a target .td file. When
+ /// building Intrinsics.td, this isn't available, because we don't know the
+ /// target pointer size.
+ std::vector<MVT::ValueType> ArgVTs;
+
+ /// ArgTypeDefs - The records for each argument type.
+ ///
+ std::vector<Record*> ArgTypeDefs;
+
+ // Memory mod/ref behavior of this intrinsic.
+ enum {
+ NoMem, ReadArgMem, ReadMem, WriteArgMem, WriteMem
+ } ModRef;
+
+ // This is set to true if the intrinsic is overloaded by its argument
+ // types.
+ bool isOverloaded;
+
+ CodeGenIntrinsic(Record *R, CodeGenTarget *CGT);
+ };
+
+ /// LoadIntrinsics - Read all of the intrinsics defined in the specified
+ /// .td file.
+ std::vector<CodeGenIntrinsic> LoadIntrinsics(const RecordKeeper &RC);
+}
+
+#endif
diff --git a/utils/TableGen/CodeGenRegisters.h b/utils/TableGen/CodeGenRegisters.h
new file mode 100644
index 0000000000..83c85b8f3a
--- /dev/null
+++ b/utils/TableGen/CodeGenRegisters.h
@@ -0,0 +1,59 @@
+//===- CodeGenRegisters.h - Register and RegisterClass Info -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines structures to encapsulate information gleaned from the
+// target register and register class definitions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CODEGEN_REGISTERS_H
+#define CODEGEN_REGISTERS_H
+
+#include <string>
+#include <vector>
+#include "llvm/CodeGen/ValueTypes.h"
+
+namespace llvm {
+ class Record;
+
+ /// CodeGenRegister - Represents a register definition.
+ struct CodeGenRegister {
+ Record *TheDef;
+ const std::string &getName() const;
+ unsigned DeclaredSpillSize, DeclaredSpillAlignment;
+ CodeGenRegister(Record *R);
+ };
+
+
+ struct CodeGenRegisterClass {
+ Record *TheDef;
+ std::string Namespace;
+ std::vector<Record*> Elements;
+ std::vector<MVT::ValueType> VTs;
+ unsigned SpillSize;
+ unsigned SpillAlignment;
+ std::vector<Record*> SubRegClasses;
+ std::string MethodProtos, MethodBodies;
+
+ const std::string &getName() const;
+ const std::vector<MVT::ValueType> &getValueTypes() const { return VTs; }
+ unsigned getNumValueTypes() const { return VTs.size(); }
+
+ const MVT::ValueType getValueTypeNum(unsigned VTNum) const {
+ if (VTNum < VTs.size())
+ return VTs[VTNum];
+ assert(0 && "VTNum greater than number of ValueTypes in RegClass!");
+ abort();
+ }
+
+ CodeGenRegisterClass(Record *R);
+ };
+}
+
+#endif
diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp
new file mode 100644
index 0000000000..2aabe51c51
--- /dev/null
+++ b/utils/TableGen/CodeGenTarget.cpp
@@ -0,0 +1,655 @@
+//===- CodeGenTarget.cpp - CodeGen Target Class Wrapper ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class 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 "CodeGenTarget.h"
+#include "CodeGenIntrinsics.h"
+#include "Record.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Streams.h"
+#include <set>
+#include <algorithm>
+using namespace llvm;
+
+static cl::opt<unsigned>
+AsmWriterNum("asmwriternum", cl::init(0),
+ cl::desc("Make -gen-asm-writer emit assembly writer #N"));
+
+/// getValueType - Return the MCV::ValueType that the specified TableGen record
+/// corresponds to.
+MVT::ValueType llvm::getValueType(Record *Rec) {
+ return (MVT::ValueType)Rec->getValueAsInt("Value");
+}
+
+std::string llvm::getName(MVT::ValueType T) {
+ switch (T) {
+ case MVT::Other: return "UNKNOWN";
+ case MVT::i1: return "MVT::i1";
+ case MVT::i8: return "MVT::i8";
+ case MVT::i16: return "MVT::i16";
+ case MVT::i32: return "MVT::i32";
+ case MVT::i64: return "MVT::i64";
+ case MVT::i128: return "MVT::i128";
+ case MVT::iAny: return "MVT::iAny";
+ case MVT::f32: return "MVT::f32";
+ case MVT::f64: return "MVT::f64";
+ case MVT::f80: return "MVT::f80";
+ case MVT::f128: return "MVT::f128";
+ case MVT::Flag: return "MVT::Flag";
+ case MVT::isVoid:return "MVT::void";
+ case MVT::v8i8: return "MVT::v8i8";
+ case MVT::v4i16: return "MVT::v4i16";
+ case MVT::v2i32: return "MVT::v2i32";
+ case MVT::v1i64: return "MVT::v1i64";
+ case MVT::v16i8: return "MVT::v16i8";
+ case MVT::v8i16: return "MVT::v8i16";
+ case MVT::v4i32: return "MVT::v4i32";
+ case MVT::v2i64: return "MVT::v2i64";
+ case MVT::v2f32: return "MVT::v2f32";
+ case MVT::v4f32: return "MVT::v4f32";
+ case MVT::v2f64: return "MVT::v2f64";
+ case MVT::iPTR: return "TLI.getPointerTy()";
+ default: assert(0 && "ILLEGAL VALUE TYPE!"); return "";
+ }
+}
+
+std::string llvm::getEnumName(MVT::ValueType T) {
+ switch (T) {
+ case MVT::Other: return "MVT::Other";
+ case MVT::i1: return "MVT::i1";
+ case MVT::i8: return "MVT::i8";
+ case MVT::i16: return "MVT::i16";
+ case MVT::i32: return "MVT::i32";
+ case MVT::i64: return "MVT::i64";
+ case MVT::i128: return "MVT::i128";
+ case MVT::iAny: return "MVT::iAny";
+ case MVT::f32: return "MVT::f32";
+ case MVT::f64: return "MVT::f64";
+ case MVT::f80: return "MVT::f80";
+ case MVT::f128: return "MVT::f128";
+ case MVT::Flag: return "MVT::Flag";
+ case MVT::isVoid:return "MVT::isVoid";
+ case MVT::v8i8: return "MVT::v8i8";
+ case MVT::v4i16: return "MVT::v4i16";
+ case MVT::v2i32: return "MVT::v2i32";
+ case MVT::v1i64: return "MVT::v1i64";
+ case MVT::v16i8: return "MVT::v16i8";
+ case MVT::v8i16: return "MVT::v8i16";
+ case MVT::v4i32: return "MVT::v4i32";
+ case MVT::v2i64: return "MVT::v2i64";
+ case MVT::v2f32: return "MVT::v2f32";
+ case MVT::v4f32: return "MVT::v4f32";
+ case MVT::v2f64: return "MVT::v2f64";
+ case MVT::iPTR: return "TLI.getPointerTy()";
+ default: assert(0 && "ILLEGAL VALUE TYPE!"); return "";
+ }
+}
+
+
+/// getTarget - Return the current instance of the Target class.
+///
+CodeGenTarget::CodeGenTarget() {
+ std::vector<Record*> Targets = Records.getAllDerivedDefinitions("Target");
+ if (Targets.size() == 0)
+ throw std::string("ERROR: No 'Target' subclasses defined!");
+ if (Targets.size() != 1)
+ throw std::string("ERROR: Multiple subclasses of Target defined!");
+ TargetRec = Targets[0];
+}
+
+
+const std::string &CodeGenTarget::getName() const {
+ return TargetRec->getName();
+}
+
+Record *CodeGenTarget::getInstructionSet() const {
+ return TargetRec->getValueAsDef("InstructionSet");
+}
+
+/// getAsmWriter - Return the AssemblyWriter definition for this target.
+///
+Record *CodeGenTarget::getAsmWriter() const {
+ std::vector<Record*> LI = TargetRec->getValueAsListOfDefs("AssemblyWriters");
+ if (AsmWriterNum >= LI.size())
+ throw "Target does not have an AsmWriter #" + utostr(AsmWriterNum) + "!";
+ return LI[AsmWriterNum];
+}
+
+void CodeGenTarget::ReadRegisters() const {
+ std::vector<Record*> Regs = Records.getAllDerivedDefinitions("Register");
+ if (Regs.empty())
+ throw std::string("No 'Register' subclasses defined!");
+
+ Registers.reserve(Regs.size());
+ Registers.assign(Regs.begin(), Regs.end());
+}
+
+CodeGenRegister::CodeGenRegister(Record *R) : TheDef(R) {
+ DeclaredSpillSize = R->getValueAsInt("SpillSize");
+ DeclaredSpillAlignment = R->getValueAsInt("SpillAlignment");
+}
+
+const std::string &CodeGenRegister::getName() const {
+ return TheDef->getName();
+}
+
+void CodeGenTarget::ReadRegisterClasses() const {
+ std::vector<Record*> RegClasses =
+ Records.getAllDerivedDefinitions("RegisterClass");
+ if (RegClasses.empty())
+ throw std::string("No 'RegisterClass' subclasses defined!");
+
+ RegisterClasses.reserve(RegClasses.size());
+ RegisterClasses.assign(RegClasses.begin(), RegClasses.end());
+}
+
+std::vector<unsigned char> CodeGenTarget::getRegisterVTs(Record *R) const {
+ std::vector<unsigned char> Result;
+ const std::vector<CodeGenRegisterClass> &RCs = getRegisterClasses();
+ for (unsigned i = 0, e = RCs.size(); i != e; ++i) {
+ const CodeGenRegisterClass &RC = RegisterClasses[i];
+ for (unsigned ei = 0, ee = RC.Elements.size(); ei != ee; ++ei) {
+ if (R == RC.Elements[ei]) {
+ const std::vector<MVT::ValueType> &InVTs = RC.getValueTypes();
+ for (unsigned i = 0, e = InVTs.size(); i != e; ++i)
+ Result.push_back(InVTs[i]);
+ }
+ }
+ }
+ return Result;
+}
+
+
+CodeGenRegisterClass::CodeGenRegisterClass(Record *R) : TheDef(R) {
+ // Rename anonymous register classes.
+ if (R->getName().size() > 9 && R->getName()[9] == '.') {
+ static unsigned AnonCounter = 0;
+ R->setName("AnonRegClass_"+utostr(AnonCounter++));
+ }
+
+ std::vector<Record*> TypeList = R->getValueAsListOfDefs("RegTypes");
+ for (unsigned i = 0, e = TypeList.size(); i != e; ++i) {
+ Record *Type = TypeList[i];
+ if (!Type->isSubClassOf("ValueType"))
+ throw "RegTypes list member '" + Type->getName() +
+ "' does not derive from the ValueType class!";
+ VTs.push_back(getValueType(Type));
+ }
+ assert(!VTs.empty() && "RegisterClass must contain at least one ValueType!");
+
+ std::vector<Record*> RegList = R->getValueAsListOfDefs("MemberList");
+ for (unsigned i = 0, e = RegList.size(); i != e; ++i) {
+ Record *Reg = RegList[i];
+ if (!Reg->isSubClassOf("Register"))
+ throw "Register Class member '" + Reg->getName() +
+ "' does not derive from the Register class!";
+ Elements.push_back(Reg);
+ }
+
+ std::vector<Record*> SubRegClassList =
+ R->getValueAsListOfDefs("SubRegClassList");
+ for (unsigned i = 0, e = SubRegClassList.size(); i != e; ++i) {
+ Record *SubRegClass = SubRegClassList[i];
+ if (!SubRegClass->isSubClassOf("RegisterClass"))
+ throw "Register Class member '" + SubRegClass->getName() +
+ "' does not derive from the RegisterClass class!";
+ SubRegClasses.push_back(SubRegClass);
+ }
+
+ // Allow targets to override the size in bits of the RegisterClass.
+ unsigned Size = R->getValueAsInt("Size");
+
+ Namespace = R->getValueAsString("Namespace");
+ SpillSize = Size ? Size : MVT::getSizeInBits(VTs[0]);
+ SpillAlignment = R->getValueAsInt("Alignment");
+ MethodBodies = R->getValueAsCode("MethodBodies");
+ MethodProtos = R->getValueAsCode("MethodProtos");
+}
+
+const std::string &CodeGenRegisterClass::getName() const {
+ return TheDef->getName();
+}
+
+void CodeGenTarget::ReadLegalValueTypes() const {
+ const std::vector<CodeGenRegisterClass> &RCs = getRegisterClasses();
+ for (unsigned i = 0, e = RCs.size(); i != e; ++i)
+ for (unsigned ri = 0, re = RCs[i].VTs.size(); ri != re; ++ri)
+ LegalValueTypes.push_back(RCs[i].VTs[ri]);
+
+ // Remove duplicates.
+ std::sort(LegalValueTypes.begin(), LegalValueTypes.end());
+ LegalValueTypes.erase(std::unique(LegalValueTypes.begin(),
+ LegalValueTypes.end()),
+ LegalValueTypes.end());
+}
+
+
+void CodeGenTarget::ReadInstructions() const {
+ std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction");
+ if (Insts.size() <= 2)
+ throw std::string("No 'Instruction' subclasses defined!");
+
+ // Parse the instructions defined in the .td file.
+ std::string InstFormatName =
+ getAsmWriter()->getValueAsString("InstFormatName");
+
+ for (unsigned i = 0, e = Insts.size(); i != e; ++i) {
+ std::string AsmStr = Insts[i]->getValueAsString(InstFormatName);
+ Instructions.insert(std::make_pair(Insts[i]->getName(),
+ CodeGenInstruction(Insts[i], AsmStr)));
+ }
+}
+
+/// getInstructionsByEnumValue - Return all of the instructions defined by the
+/// target, ordered by their enum value.
+void CodeGenTarget::
+getInstructionsByEnumValue(std::vector<const CodeGenInstruction*>
+ &NumberedInstructions) {
+ std::map<std::string, CodeGenInstruction>::const_iterator I;
+ I = getInstructions().find("PHI");
+ if (I == Instructions.end()) throw "Could not find 'PHI' instruction!";
+ const CodeGenInstruction *PHI = &I->second;
+
+ I = getInstructions().find("INLINEASM");
+ if (I == Instructions.end()) throw "Could not find 'INLINEASM' instruction!";
+ const CodeGenInstruction *INLINEASM = &I->second;
+
+ I = getInstructions().find("LABEL");
+ if (I == Instructions.end()) throw "Could not find 'LABEL' instruction!";
+ const CodeGenInstruction *LABEL = &I->second;
+
+ // Print out the rest of the instructions now.
+ NumberedInstructions.push_back(PHI);
+ NumberedInstructions.push_back(INLINEASM);
+ NumberedInstructions.push_back(LABEL);
+ for (inst_iterator II = inst_begin(), E = inst_end(); II != E; ++II)
+ if (&II->second != PHI &&
+ &II->second != INLINEASM &&
+ &II->second != LABEL)
+ NumberedInstructions.push_back(&II->second);
+}
+
+
+/// isLittleEndianEncoding - Return whether this target encodes its instruction
+/// in little-endian format, i.e. bits laid out in the order [0..n]
+///
+bool CodeGenTarget::isLittleEndianEncoding() const {
+ return getInstructionSet()->getValueAsBit("isLittleEndianEncoding");
+}
+
+
+
+static void ParseConstraint(const std::string &CStr, CodeGenInstruction *I) {
+ // FIXME: Only supports TIED_TO for now.
+ std::string::size_type pos = CStr.find_first_of('=');
+ assert(pos != std::string::npos && "Unrecognized constraint");
+ std::string Name = CStr.substr(0, pos);
+
+ // TIED_TO: $src1 = $dst
+ std::string::size_type wpos = Name.find_first_of(" \t");
+ if (wpos == std::string::npos)
+ throw "Illegal format for tied-to constraint: '" + CStr + "'";
+ std::string DestOpName = Name.substr(0, wpos);
+ std::pair<unsigned,unsigned> DestOp = I->ParseOperandName(DestOpName, false);
+
+ Name = CStr.substr(pos+1);
+ wpos = Name.find_first_not_of(" \t");
+ if (wpos == std::string::npos)
+ throw "Illegal format for tied-to constraint: '" + CStr + "'";
+
+ std::pair<unsigned,unsigned> SrcOp =
+ I->ParseOperandName(Name.substr(wpos), false);
+ if (SrcOp > DestOp)
+ throw "Illegal tied-to operand constraint '" + CStr + "'";
+
+
+ unsigned FlatOpNo = I->getFlattenedOperandNumber(SrcOp);
+ // Build the string for the operand.
+ std::string OpConstraint =
+ "((" + utostr(FlatOpNo) + " << 16) | (1 << TOI::TIED_TO))";
+
+
+ if (!I->OperandList[DestOp.first].Constraints[DestOp.second].empty())
+ throw "Operand '" + DestOpName + "' cannot have multiple constraints!";
+ I->OperandList[DestOp.first].Constraints[DestOp.second] = OpConstraint;
+}
+
+static void ParseConstraints(const std::string &CStr, CodeGenInstruction *I) {
+ // Make sure the constraints list for each operand is large enough to hold
+ // constraint info, even if none is present.
+ for (unsigned i = 0, e = I->OperandList.size(); i != e; ++i)
+ I->OperandList[i].Constraints.resize(I->OperandList[i].MINumOperands);
+
+ if (CStr.empty()) return;
+
+ const std::string delims(",");
+ std::string::size_type bidx, eidx;
+
+ bidx = CStr.find_first_not_of(delims);
+ while (bidx != std::string::npos) {
+ eidx = CStr.find_first_of(delims, bidx);
+ if (eidx == std::string::npos)
+ eidx = CStr.length();
+
+ ParseConstraint(CStr.substr(bidx, eidx), I);
+ bidx = CStr.find_first_not_of(delims, eidx);
+ }
+}
+
+CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr)
+ : TheDef(R), AsmString(AsmStr) {
+ Name = R->getValueAsString("Name");
+ Namespace = R->getValueAsString("Namespace");
+
+ isReturn = R->getValueAsBit("isReturn");
+ isBranch = R->getValueAsBit("isBranch");
+ isBarrier = R->getValueAsBit("isBarrier");
+ isCall = R->getValueAsBit("isCall");
+ isLoad = R->getValueAsBit("isLoad");
+ isStore = R->getValueAsBit("isStore");
+ bool isTwoAddress = R->getValueAsBit("isTwoAddress");
+ isPredicable = R->getValueAsBit("isPredicable");
+ isConvertibleToThreeAddress = R->getValueAsBit("isConvertibleToThreeAddress");
+ isCommutable = R->getValueAsBit("isCommutable");
+ isTerminator = R->getValueAsBit("isTerminator");
+ isReMaterializable = R->getValueAsBit("isReMaterializable");
+ hasDelaySlot = R->getValueAsBit("hasDelaySlot");
+ usesCustomDAGSchedInserter = R->getValueAsBit("usesCustomDAGSchedInserter");
+ hasCtrlDep = R->getValueAsBit("hasCtrlDep");
+ noResults = R->getValueAsBit("noResults");
+ isNotDuplicable = R->getValueAsBit("isNotDuplicable");
+ hasOptionalDef = false;
+ hasVariableNumberOfOperands = false;
+
+ DagInit *DI;
+ try {
+ DI = R->getValueAsDag("OperandList");
+ } catch (...) {
+ // Error getting operand list, just ignore it (sparcv9).
+ AsmString.clear();
+ OperandList.clear();
+ return;
+ }
+
+ unsigned MIOperandNo = 0;
+ std::set<std::string> OperandNames;
+ for (unsigned i = 0, e = DI->getNumArgs(); i != e; ++i) {
+ DefInit *Arg = dynamic_cast<DefInit*>(DI->getArg(i));
+ if (!Arg)
+ throw "Illegal operand for the '" + R->getName() + "' instruction!";
+
+ Record *Rec = Arg->getDef();
+ std::string PrintMethod = "printOperand";
+ unsigned NumOps = 1;
+ DagInit *MIOpInfo = 0;
+ if (Rec->isSubClassOf("Operand")) {
+ PrintMethod = Rec->getValueAsString("PrintMethod");
+ MIOpInfo = Rec->getValueAsDag("MIOperandInfo");
+
+ // Verify that MIOpInfo has an 'ops' root value.
+ if (!dynamic_cast<DefInit*>(MIOpInfo->getOperator()) ||
+ dynamic_cast<DefInit*>(MIOpInfo->getOperator())
+ ->getDef()->getName() != "ops")
+ throw "Bad value for MIOperandInfo in operand '" + Rec->getName() +
+ "'\n";
+
+ // If we have MIOpInfo, then we have #operands equal to number of entries
+ // in MIOperandInfo.
+ if (unsigned NumArgs = MIOpInfo->getNumArgs())
+ NumOps = NumArgs;
+
+ if (Rec->isSubClassOf("PredicateOperand"))
+ isPredicable = true;
+ else if (Rec->isSubClassOf("OptionalDefOperand"))
+ hasOptionalDef = true;
+ } else if (Rec->getName() == "variable_ops") {
+ hasVariableNumberOfOperands = true;
+ continue;
+ } else if (!Rec->isSubClassOf("RegisterClass") &&
+ Rec->getName() != "ptr_rc")
+ throw "Unknown operand class '" + Rec->getName() +
+ "' in instruction '" + R->getName() + "' instruction!";
+
+ // Check that the operand has a name and that it's unique.
+ if (DI->getArgName(i).empty())
+ throw "In instruction '" + R->getName() + "', operand #" + utostr(i) +
+ " has no name!";
+ if (!OperandNames.insert(DI->getArgName(i)).second)
+ throw "In instruction '" + R->getName() + "', operand #" + utostr(i) +
+ " has the same name as a previous operand!";
+
+ OperandList.push_back(OperandInfo(Rec, DI->getArgName(i), PrintMethod,
+ MIOperandNo, NumOps, MIOpInfo));
+ MIOperandNo += NumOps;
+ }
+
+ // Parse Constraints.
+ ParseConstraints(R->getValueAsString("Constraints"), this);
+
+ // For backward compatibility: isTwoAddress means operand 1 is tied to
+ // operand 0.
+ if (isTwoAddress) {
+ if (!OperandList[1].Constraints[0].empty())
+ throw R->getName() + ": cannot use isTwoAddress property: instruction "
+ "already has constraint set!";
+ OperandList[1].Constraints[0] = "((0 << 16) | (1 << TOI::TIED_TO))";
+ }
+
+ // Any operands with unset constraints get 0 as their constraint.
+ for (unsigned op = 0, e = OperandList.size(); op != e; ++op)
+ for (unsigned j = 0, e = OperandList[op].MINumOperands; j != e; ++j)
+ if (OperandList[op].Constraints[j].empty())
+ OperandList[op].Constraints[j] = "0";
+
+ // Parse the DisableEncoding field.
+ std::string DisableEncoding = R->getValueAsString("DisableEncoding");
+ while (1) {
+ std::string OpName = getToken(DisableEncoding, " ,\t");
+ if (OpName.empty()) break;
+
+ // Figure out which operand this is.
+ std::pair<unsigned,unsigned> Op = ParseOperandName(OpName, false);
+
+ // Mark the operand as not-to-be encoded.
+ if (Op.second >= OperandList[Op.first].DoNotEncode.size())
+ OperandList[Op.first].DoNotEncode.resize(Op.second+1);
+ OperandList[Op.first].DoNotEncode[Op.second] = true;
+ }
+}
+
+
+
+/// getOperandNamed - Return the index of the operand with the specified
+/// non-empty name. If the instruction does not have an operand with the
+/// specified name, throw an exception.
+///
+unsigned CodeGenInstruction::getOperandNamed(const std::string &Name) const {
+ assert(!Name.empty() && "Cannot search for operand with no name!");
+ for (unsigned i = 0, e = OperandList.size(); i != e; ++i)
+ if (OperandList[i].Name == Name) return i;
+ throw "Instruction '" + TheDef->getName() +
+ "' does not have an operand named '$" + Name + "'!";
+}
+
+std::pair<unsigned,unsigned>
+CodeGenInstruction::ParseOperandName(const std::string &Op,
+ bool AllowWholeOp) {
+ if (Op.empty() || Op[0] != '$')
+ throw TheDef->getName() + ": Illegal operand name: '" + Op + "'";
+
+ std::string OpName = Op.substr(1);
+ std::string SubOpName;
+
+ // Check to see if this is $foo.bar.
+ std::string::size_type DotIdx = OpName.find_first_of(".");
+ if (DotIdx != std::string::npos) {
+ SubOpName = OpName.substr(DotIdx+1);
+ if (SubOpName.empty())
+ throw TheDef->getName() + ": illegal empty suboperand name in '" +Op +"'";
+ OpName = OpName.substr(0, DotIdx);
+ }
+
+ unsigned OpIdx = getOperandNamed(OpName);
+
+ if (SubOpName.empty()) { // If no suboperand name was specified:
+ // If one was needed, throw.
+ if (OperandList[OpIdx].MINumOperands > 1 && !AllowWholeOp &&
+ SubOpName.empty())
+ throw TheDef->getName() + ": Illegal to refer to"
+ " whole operand part of complex operand '" + Op + "'";
+
+ // Otherwise, return the operand.
+ return std::make_pair(OpIdx, 0U);
+ }
+
+ // Find the suboperand number involved.
+ DagInit *MIOpInfo = OperandList[OpIdx].MIOperandInfo;
+ if (MIOpInfo == 0)
+ throw TheDef->getName() + ": unknown suboperand name in '" + Op + "'";
+
+ // Find the operand with the right name.
+ for (unsigned i = 0, e = MIOpInfo->getNumArgs(); i != e; ++i)
+ if (MIOpInfo->getArgName(i) == SubOpName)
+ return std::make_pair(OpIdx, i);
+
+ // Otherwise, didn't find it!
+ throw TheDef->getName() + ": unknown suboperand name in '" + Op + "'";
+}
+
+
+
+
+//===----------------------------------------------------------------------===//
+// ComplexPattern implementation
+//
+ComplexPattern::ComplexPattern(Record *R) {
+ Ty = ::getValueType(R->getValueAsDef("Ty"));
+ NumOperands = R->getValueAsInt("NumOperands");
+ SelectFunc = R->getValueAsString("SelectFunc");
+ RootNodes = R->getValueAsListOfDefs("RootNodes");
+
+ // Parse the properties.
+ Properties = 0;
+ std::vector<Record*> PropList = R->getValueAsListOfDefs("Properties");
+ for (unsigned i = 0, e = PropList.size(); i != e; ++i)
+ if (PropList[i]->getName() == "SDNPHasChain") {
+ Properties |= 1 << SDNPHasChain;
+ } else if (PropList[i]->getName() == "SDNPOptInFlag") {
+ Properties |= 1 << SDNPOptInFlag;
+ } else {
+ cerr << "Unsupported SD Node property '" << PropList[i]->getName()
+ << "' on ComplexPattern '" << R->getName() << "'!\n";
+ exit(1);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// CodeGenIntrinsic Implementation
+//===----------------------------------------------------------------------===//
+
+std::vector<CodeGenIntrinsic> llvm::LoadIntrinsics(const RecordKeeper &RC) {
+ std::vector<Record*> I = RC.getAllDerivedDefinitions("Intrinsic");
+
+ std::vector<CodeGenIntrinsic> Result;
+
+ // If we are in the context of a target .td file, get the target info so that
+ // we can decode the current intptr_t.
+ CodeGenTarget *CGT = 0;
+ if (Records.getClass("Target") &&
+ Records.getAllDerivedDefinitions("Target").size() == 1)
+ CGT = new CodeGenTarget();
+
+ for (unsigned i = 0, e = I.size(); i != e; ++i)
+ Result.push_back(CodeGenIntrinsic(I[i], CGT));
+ delete CGT;
+ return Result;
+}
+
+CodeGenIntrinsic::CodeGenIntrinsic(Record *R, CodeGenTarget *CGT) {
+ TheDef = R;
+ std::string DefName = R->getName();
+ ModRef = WriteMem;
+ isOverloaded = false;
+
+ if (DefName.size() <= 4 ||
+ std::string(DefName.begin(), DefName.begin()+4) != "int_")
+ throw "Intrinsic '" + DefName + "' does not start with 'int_'!";
+ EnumName = std::string(DefName.begin()+4, DefName.end());
+ if (R->getValue("GCCBuiltinName")) // Ignore a missing GCCBuiltinName field.
+ GCCBuiltinName = R->getValueAsString("GCCBuiltinName");
+ TargetPrefix = R->getValueAsString("TargetPrefix");
+ Name = R->getValueAsString("LLVMName");
+ if (Name == "") {
+ // If an explicit name isn't specified, derive one from the DefName.
+ Name = "llvm.";
+ for (unsigned i = 0, e = EnumName.size(); i != e; ++i)
+ if (EnumName[i] == '_')
+ Name += '.';
+ else
+ Name += EnumName[i];
+ } else {
+ // Verify it starts with "llvm.".
+ if (Name.size() <= 5 ||
+ std::string(Name.begin(), Name.begin()+5) != "llvm.")
+ throw "Intrinsic '" + DefName + "'s name does not start with 'llvm.'!";
+ }
+
+ // If TargetPrefix is specified, make sure that Name starts with
+ // "llvm.<targetprefix>.".
+ if (!TargetPrefix.empty()) {
+ if (Name.size() < 6+TargetPrefix.size() ||
+ std::string(Name.begin()+5, Name.begin()+6+TargetPrefix.size())
+ != (TargetPrefix+"."))
+ throw "Intrinsic '" + DefName + "' does not start with 'llvm." +
+ TargetPrefix + ".'!";
+ }
+
+ // Parse the list of argument types.
+ ListInit *TypeList = R->getValueAsListInit("Types");
+ for (unsigned i = 0, e = TypeList->getSize(); i != e; ++i) {
+ Record *TyEl = TypeList->getElementAsRecord(i);
+ assert(TyEl->isSubClassOf("LLVMType") && "Expected a type!");
+ ArgTypes.push_back(TyEl->getValueAsString("TypeVal"));
+ MVT::ValueType VT = getValueType(TyEl->getValueAsDef("VT"));
+ isOverloaded |= VT == MVT::iAny;
+ ArgVTs.push_back(VT);
+ ArgTypeDefs.push_back(TyEl);
+ }
+ if (ArgTypes.size() == 0)
+ throw "Intrinsic '"+DefName+"' needs at least a type for the ret value!";
+
+
+ // Parse the intrinsic properties.
+ ListInit *PropList = R->getValueAsListInit("Properties");
+ for (unsigned i = 0, e = PropList->getSize(); i != e; ++i) {
+ Record *Property = PropList->getElementAsRecord(i);
+ assert(Property->isSubClassOf("IntrinsicProperty") &&
+ "Expected a property!");
+
+ if (Property->getName() == "IntrNoMem")
+ ModRef = NoMem;
+ else if (Property->getName() == "IntrReadArgMem")
+ ModRef = ReadArgMem;
+ else if (Property->getName() == "IntrReadMem")
+ ModRef = ReadMem;
+ else if (Property->getName() == "IntrWriteArgMem")
+ ModRef = WriteArgMem;
+ else if (Property->getName() == "IntrWriteMem")
+ ModRef = WriteMem;
+ else
+ assert(0 && "Unknown property!");
+ }
+}
diff --git a/utils/TableGen/CodeGenTarget.h b/utils/TableGen/CodeGenTarget.h
new file mode 100644
index 0000000000..7f5f0a7fad
--- /dev/null
+++ b/utils/TableGen/CodeGenTarget.h
@@ -0,0 +1,180 @@
+//===- CodeGenTarget.h - Target Class Wrapper -------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines wrappers for the Target class and related global
+// functionality. 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 CODEGEN_TARGET_H
+#define CODEGEN_TARGET_H
+
+#include "CodeGenRegisters.h"
+#include "CodeGenInstruction.h"
+#include <iosfwd>
+#include <map>
+
+namespace llvm {
+
+class Record;
+class RecordKeeper;
+struct CodeGenRegister;
+class CodeGenTarget;
+
+// SelectionDAG node properties.
+enum SDNP { SDNPCommutative, SDNPAssociative, SDNPHasChain,
+ SDNPOutFlag, SDNPInFlag, SDNPOptInFlag };
+
+/// getValueType - Return the MVT::ValueType that the specified TableGen record
+/// corresponds to.
+MVT::ValueType getValueType(Record *Rec);
+
+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;
+
+ mutable std::map<std::string, CodeGenInstruction> Instructions;
+ mutable std::vector<CodeGenRegister> Registers;
+ mutable std::vector<CodeGenRegisterClass> RegisterClasses;
+ mutable std::vector<MVT::ValueType> LegalValueTypes;
+ void ReadRegisters() const;
+ void ReadRegisterClasses() const;
+ void ReadInstructions() const;
+ void ReadLegalValueTypes() const;
+public:
+ CodeGenTarget();
+
+ Record *getTargetRecord() const { return TargetRec; }
+ const std::string &getName() const;
+
+ /// getInstructionSet - Return the InstructionSet object.
+ ///
+ Record *getInstructionSet() const;
+
+ /// getAsmWriter - Return the AssemblyWriter definition for this target.
+ ///
+ Record *getAsmWriter() const;
+
+ const std::vector<CodeGenRegister> &getRegisters() const {
+ if (Registers.empty()) ReadRegisters();
+ return Registers;
+ }
+
+ const std::vector<CodeGenRegisterClass> &getRegisterClasses() const {
+ if (RegisterClasses.empty()) ReadRegisterClasses();
+ return RegisterClasses;
+ }
+
+ const CodeGenRegisterClass &getRegisterClass(Record *R) const {
+ const std::vector<CodeGenRegisterClass> &RC = getRegisterClasses();
+ for (unsigned i = 0, e = RC.size(); i != e; ++i)
+ if (RC[i].TheDef == R)
+ return RC[i];
+ assert(0 && "Didn't find the register class");
+ abort();
+ }
+
+ /// getRegisterClassForRegister - Find the register class that contains the
+ /// specified physical register. If there register exists in multiple
+ /// register classes or is not in a register class, return null.
+ const CodeGenRegisterClass *getRegisterClassForRegister(Record *R) const {
+ const std::vector<CodeGenRegisterClass> &RCs = getRegisterClasses();
+ const CodeGenRegisterClass *FoundRC = 0;
+ for (unsigned i = 0, e = RCs.size(); i != e; ++i) {
+ const CodeGenRegisterClass &RC = RegisterClasses[i];
+ for (unsigned ei = 0, ee = RC.Elements.size(); ei != ee; ++ei) {
+ if (R == RC.Elements[ei]) {
+ if (FoundRC) return 0; // In multiple RC's
+ FoundRC = &RC;
+ break;
+ }
+ }
+ }
+ return FoundRC;
+ }
+
+ /// getRegisterVTs - Find the union of all possible ValueTypes for the
+ /// specified physical register.
+ std::vector<unsigned char> getRegisterVTs(Record *R) const;
+
+ const std::vector<MVT::ValueType> &getLegalValueTypes() const {
+ if (LegalValueTypes.empty()) ReadLegalValueTypes();
+ return LegalValueTypes;
+ }
+
+ /// isLegalValueType - Return true if the specified value type is natively
+ /// supported by the target (i.e. there are registers that directly hold it).
+ bool isLegalValueType(MVT::ValueType VT) const {
+ const std::vector<MVT::ValueType> &LegalVTs = getLegalValueTypes();
+ for (unsigned i = 0, e = LegalVTs.size(); i != e; ++i)
+ if (LegalVTs[i] == VT) return true;
+ return false;
+ }
+
+ /// getInstructions - Return all of the instructions defined for this target.
+ ///
+ const std::map<std::string, CodeGenInstruction> &getInstructions() const {
+ if (Instructions.empty()) ReadInstructions();
+ return Instructions;
+ }
+
+ CodeGenInstruction &getInstruction(const std::string &Name) const {
+ const std::map<std::string, CodeGenInstruction> &Insts = getInstructions();
+ assert(Insts.count(Name) && "Not an instruction!");
+ return const_cast<CodeGenInstruction&>(Insts.find(Name)->second);
+ }
+
+ typedef std::map<std::string,
+ CodeGenInstruction>::const_iterator inst_iterator;
+ inst_iterator inst_begin() const { return getInstructions().begin(); }
+ inst_iterator inst_end() const { return Instructions.end(); }
+
+ /// getInstructionsByEnumValue - Return all of the instructions defined by the
+ /// target, ordered by their enum value.
+ void getInstructionsByEnumValue(std::vector<const CodeGenInstruction*>
+ &NumberedInstructions);
+
+
+ /// isLittleEndianEncoding - are instruction bit patterns defined as [0..n]?
+ ///
+ bool isLittleEndianEncoding() const;
+};
+
+/// ComplexPattern - ComplexPattern info, corresponding to the ComplexPattern
+/// tablegen class in TargetSelectionDAG.td
+class ComplexPattern {
+ MVT::ValueType Ty;
+ unsigned NumOperands;
+ std::string SelectFunc;
+ std::vector<Record*> RootNodes;
+ unsigned Properties;
+public:
+ ComplexPattern() : NumOperands(0) {};
+ ComplexPattern(Record *R);
+
+ MVT::ValueType getValueType() const { return Ty; }
+ unsigned getNumOperands() const { return NumOperands; }
+ const std::string &getSelectFunc() const { return SelectFunc; }
+ const std::vector<Record*> &getRootNodes() const {
+ return RootNodes;
+ }
+ bool hasProperty(enum SDNP Prop) const { return Properties & (1 << Prop); }
+
+};
+
+} // End llvm namespace
+
+#endif
diff --git a/utils/TableGen/DAGISelEmitter.cpp b/utils/TableGen/DAGISelEmitter.cpp
new file mode 100644
index 0000000000..fcad318587
--- /dev/null
+++ b/utils/TableGen/DAGISelEmitter.cpp
@@ -0,0 +1,4001 @@
+//===- DAGISelEmitter.cpp - Generate an instruction selector --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend emits a DAG instruction selector.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DAGISelEmitter.h"
+#include "Record.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/Streams.h"
+#include <algorithm>
+#include <set>
+using namespace llvm;
+
+//===----------------------------------------------------------------------===//
+// Helpers for working with extended types.
+
+/// FilterVTs - Filter a list of VT's according to a predicate.
+///
+template<typename T>
+static std::vector<MVT::ValueType>
+FilterVTs(const std::vector<MVT::ValueType> &InVTs, T Filter) {
+ std::vector<MVT::ValueType> Result;
+ for (unsigned i = 0, e = InVTs.size(); i != e; ++i)
+ if (Filter(InVTs[i]))
+ Result.push_back(InVTs[i]);
+ return Result;
+}
+
+template<typename T>
+static std::vector<unsigned char>
+FilterEVTs(const std::vector<unsigned char> &InVTs, T Filter) {
+ std::vector<unsigned char> Result;
+ for (unsigned i = 0, e = InVTs.size(); i != e; ++i)
+ if (Filter((MVT::ValueType)InVTs[i]))
+ Result.push_back(InVTs[i]);
+ return Result;
+}
+
+static std::vector<unsigned char>
+ConvertVTs(const std::vector<MVT::ValueType> &InVTs) {
+ std::vector<unsigned char> Result;
+ for (unsigned i = 0, e = InVTs.size(); i != e; ++i)
+ Result.push_back(InVTs[i]);
+ return Result;
+}
+
+static bool LHSIsSubsetOfRHS(const std::vector<unsigned char> &LHS,
+ const std::vector<unsigned char> &RHS) {
+ if (LHS.size() > RHS.size()) return false;
+ for (unsigned i = 0, e = LHS.size(); i != e; ++i)
+ if (std::find(RHS.begin(), RHS.end(), LHS[i]) == RHS.end())
+ return false;
+ return true;
+}
+
+/// isExtIntegerVT - Return true if the specified extended value type vector
+/// contains isInt or an integer value type.
+static bool isExtIntegerInVTs(const std::vector<unsigned char> &EVTs) {
+ assert(!EVTs.empty() && "Cannot check for integer in empty ExtVT list!");
+ return EVTs[0] == MVT::isInt || !(FilterEVTs(EVTs, MVT::isInteger).empty());
+}
+
+/// isExtFloatingPointVT - Return true if the specified extended value type
+/// vector contains isFP or a FP value type.
+static bool isExtFloatingPointInVTs(const std::vector<unsigned char> &EVTs) {
+ assert(!EVTs.empty() && "Cannot check for integer in empty ExtVT list!");
+ return EVTs[0] == MVT::isFP ||
+ !(FilterEVTs(EVTs, MVT::isFloatingPoint).empty());
+}
+
+//===----------------------------------------------------------------------===//
+// SDTypeConstraint implementation
+//
+
+SDTypeConstraint::SDTypeConstraint(Record *R) {
+ OperandNo = R->getValueAsInt("OperandNum");
+
+ if (R->isSubClassOf("SDTCisVT")) {
+ ConstraintType = SDTCisVT;
+ x.SDTCisVT_Info.VT = getValueType(R->getValueAsDef("VT"));
+ } else if (R->isSubClassOf("SDTCisPtrTy")) {
+ ConstraintType = SDTCisPtrTy;
+ } else if (R->isSubClassOf("SDTCisInt")) {
+ ConstraintType = SDTCisInt;
+ } else if (R->isSubClassOf("SDTCisFP")) {
+ ConstraintType = SDTCisFP;
+ } else if (R->isSubClassOf("SDTCisSameAs")) {
+ ConstraintType = SDTCisSameAs;
+ x.SDTCisSameAs_Info.OtherOperandNum = R->getValueAsInt("OtherOperandNum");
+ } else if (R->isSubClassOf("SDTCisVTSmallerThanOp")) {
+ ConstraintType = SDTCisVTSmallerThanOp;
+ x.SDTCisVTSmallerThanOp_Info.OtherOperandNum =
+ R->getValueAsInt("OtherOperandNum");
+ } else if (R->isSubClassOf("SDTCisOpSmallerThanOp")) {
+ ConstraintType = SDTCisOpSmallerThanOp;
+ x.SDTCisOpSmallerThanOp_Info.BigOperandNum =
+ R->getValueAsInt("BigOperandNum");
+ } else if (R->isSubClassOf("SDTCisIntVectorOfSameSize")) {
+ ConstraintType = SDTCisIntVectorOfSameSize;
+ x.SDTCisIntVectorOfSameSize_Info.OtherOperandNum =
+ R->getValueAsInt("OtherOpNum");
+ } else {
+ cerr << "Unrecognized SDTypeConstraint '" << R->getName() << "'!\n";
+ exit(1);
+ }
+}
+
+/// getOperandNum - Return the node corresponding to operand #OpNo in tree
+/// N, which has NumResults results.
+TreePatternNode *SDTypeConstraint::getOperandNum(unsigned OpNo,
+ TreePatternNode *N,
+ unsigned NumResults) const {
+ assert(NumResults <= 1 &&
+ "We only work with nodes with zero or one result so far!");
+
+ if (OpNo >= (NumResults + N->getNumChildren())) {
+ cerr << "Invalid operand number " << OpNo << " ";
+ N->dump();
+ cerr << '\n';
+ exit(1);
+ }
+
+ if (OpNo < NumResults)
+ return N; // FIXME: need value #
+ else
+ return N->getChild(OpNo-NumResults);
+}
+
+/// ApplyTypeConstraint - Given a node in a pattern, apply this type
+/// constraint to the nodes operands. This returns true if it makes a
+/// change, false otherwise. If a type contradiction is found, throw an
+/// exception.
+bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N,
+ const SDNodeInfo &NodeInfo,
+ TreePattern &TP) const {
+ unsigned NumResults = NodeInfo.getNumResults();
+ assert(NumResults <= 1 &&
+ "We only work with nodes with zero or one result so far!");
+
+ // Check that the number of operands is sane. Negative operands -> varargs.
+ if (NodeInfo.getNumOperands() >= 0) {
+ if (N->getNumChildren() != (unsigned)NodeInfo.getNumOperands())
+ TP.error(N->getOperator()->getName() + " node requires exactly " +
+ itostr(NodeInfo.getNumOperands()) + " operands!");
+ }
+
+ const CodeGenTarget &CGT = TP.getDAGISelEmitter().getTargetInfo();
+
+ TreePatternNode *NodeToApply = getOperandNum(OperandNo, N, NumResults);
+
+ switch (ConstraintType) {
+ default: assert(0 && "Unknown constraint type!");
+ case SDTCisVT:
+ // Operand must be a particular type.
+ return NodeToApply->UpdateNodeType(x.SDTCisVT_Info.VT, TP);
+ case SDTCisPtrTy: {
+ // Operand must be same as target pointer type.
+ return NodeToApply->UpdateNodeType(MVT::iPTR, TP);
+ }
+ case SDTCisInt: {
+ // If there is only one integer type supported, this must be it.
+ std::vector<MVT::ValueType> IntVTs =
+ FilterVTs(CGT.getLegalValueTypes(), MVT::isInteger);
+
+ // If we found exactly one supported integer type, apply it.
+ if (IntVTs.size() == 1)
+ return NodeToApply->UpdateNodeType(IntVTs[0], TP);
+ return NodeToApply->UpdateNodeType(MVT::isInt, TP);
+ }
+ case SDTCisFP: {
+ // If there is only one FP type supported, this must be it.
+ std::vector<MVT::ValueType> FPVTs =
+ FilterVTs(CGT.getLegalValueTypes(), MVT::isFloatingPoint);
+
+ // If we found exactly one supported FP type, apply it.
+ if (FPVTs.size() == 1)
+ return NodeToApply->UpdateNodeType(FPVTs[0], TP);
+ return NodeToApply->UpdateNodeType(MVT::isFP, TP);
+ }
+ case SDTCisSameAs: {
+ TreePatternNode *OtherNode =
+ getOperandNum(x.SDTCisSameAs_Info.OtherOperandNum, N, NumResults);
+ return NodeToApply->UpdateNodeType(OtherNode->getExtTypes(), TP) |
+ OtherNode->UpdateNodeType(NodeToApply->getExtTypes(), TP);
+ }
+ case SDTCisVTSmallerThanOp: {
+ // The NodeToApply must be a leaf node that is a VT. OtherOperandNum must
+ // have an integer type that is smaller than the VT.
+ if (!NodeToApply->isLeaf() ||
+ !dynamic_cast<DefInit*>(NodeToApply->getLeafValue()) ||
+ !static_cast<DefInit*>(NodeToApply->getLeafValue())->getDef()
+ ->isSubClassOf("ValueType"))
+ TP.error(N->getOperator()->getName() + " expects a VT operand!");
+ MVT::ValueType VT =
+ getValueType(static_cast<DefInit*>(NodeToApply->getLeafValue())->getDef());
+ if (!MVT::isInteger(VT))
+ TP.error(N->getOperator()->getName() + " VT operand must be integer!");
+
+ TreePatternNode *OtherNode =
+ getOperandNum(x.SDTCisVTSmallerThanOp_Info.OtherOperandNum, N,NumResults);
+
+ // It must be integer.
+ bool MadeChange = false;
+ MadeChange |= OtherNode->UpdateNodeType(MVT::isInt, TP);
+
+ // This code only handles nodes that have one type set. Assert here so
+ // that we can change this if we ever need to deal with multiple value
+ // types at this point.
+ assert(OtherNode->getExtTypes().size() == 1 && "Node has too many types!");
+ if (OtherNode->hasTypeSet() && OtherNode->getTypeNum(0) <= VT)
+ OtherNode->UpdateNodeType(MVT::Other, TP); // Throw an error.
+ return false;
+ }
+ case SDTCisOpSmallerThanOp: {
+ TreePatternNode *BigOperand =
+ getOperandNum(x.SDTCisOpSmallerThanOp_Info.BigOperandNum, N, NumResults);
+
+ // Both operands must be integer or FP, but we don't care which.
+ bool MadeChange = false;
+
+ // This code does not currently handle nodes which have multiple types,
+ // where some types are integer, and some are fp. Assert that this is not
+ // the case.
+ assert(!(isExtIntegerInVTs(NodeToApply->getExtTypes()) &&
+ isExtFloatingPointInVTs(NodeToApply->getExtTypes())) &&
+ !(isExtIntegerInVTs(BigOperand->getExtTypes()) &&
+ isExtFloatingPointInVTs(BigOperand->getExtTypes())) &&
+ "SDTCisOpSmallerThanOp does not handle mixed int/fp types!");
+ if (isExtIntegerInVTs(NodeToApply->getExtTypes()))
+ MadeChange |= BigOperand->UpdateNodeType(MVT::isInt, TP);
+ else if (isExtFloatingPointInVTs(NodeToApply->getExtTypes()))
+ MadeChange |= BigOperand->UpdateNodeType(MVT::isFP, TP);
+ if (isExtIntegerInVTs(BigOperand->getExtTypes()))
+ MadeChange |= NodeToApply->UpdateNodeType(MVT::isInt, TP);
+ else if (isExtFloatingPointInVTs(BigOperand->getExtTypes()))
+ MadeChange |= NodeToApply->UpdateNodeType(MVT::isFP, TP);
+
+ std::vector<MVT::ValueType> VTs = CGT.getLegalValueTypes();
+
+ if (isExtIntegerInVTs(NodeToApply->getExtTypes())) {
+ VTs = FilterVTs(VTs, MVT::isInteger);
+ } else if (isExtFloatingPointInVTs(NodeToApply->getExtTypes())) {
+ VTs = FilterVTs(VTs, MVT::isFloatingPoint);
+ } else {
+ VTs.clear();
+ }
+
+ switch (VTs.size()) {
+ default: // Too many VT's to pick from.
+ case 0: break; // No info yet.
+ case 1:
+ // Only one VT of this flavor. Cannot ever satisify the constraints.
+ return NodeToApply->UpdateNodeType(MVT::Other, TP); // throw
+ case 2:
+ // If we have exactly two possible types, the little operand must be the
+ // small one, the big operand should be the big one. Common with
+ // float/double for example.
+ assert(VTs[0] < VTs[1] && "Should be sorted!");
+ MadeChange |= NodeToApply->UpdateNodeType(VTs[0], TP);
+ MadeChange |= BigOperand->UpdateNodeType(VTs[1], TP);
+ break;
+ }
+ return MadeChange;
+ }
+ case SDTCisIntVectorOfSameSize: {
+ TreePatternNode *OtherOperand =
+ getOperandNum(x.SDTCisIntVectorOfSameSize_Info.OtherOperandNum,
+ N, NumResults);
+ if (OtherOperand->hasTypeSet()) {
+ if (!MVT::isVector(OtherOperand->getTypeNum(0)))
+ TP.error(N->getOperator()->getName() + " VT operand must be a vector!");
+ MVT::ValueType IVT = OtherOperand->getTypeNum(0);
+ IVT = MVT::getIntVectorWithNumElements(MVT::getVectorNumElements(IVT));
+ return NodeToApply->UpdateNodeType(IVT, TP);
+ }
+ return false;
+ }
+ }
+ return false;
+}
+
+
+//===----------------------------------------------------------------------===//
+// SDNodeInfo implementation
+//
+SDNodeInfo::SDNodeInfo(Record *R) : Def(R) {
+ EnumName = R->getValueAsString("Opcode");
+ SDClassName = R->getValueAsString("SDClass");
+ Record *TypeProfile = R->getValueAsDef("TypeProfile");
+ NumResults = TypeProfile->getValueAsInt("NumResults");
+ NumOperands = TypeProfile->getValueAsInt("NumOperands");
+
+ // Parse the properties.
+ Properties = 0;
+ std::vector<Record*> PropList = R->getValueAsListOfDefs("Properties");
+ for (unsigned i = 0, e = PropList.size(); i != e; ++i) {
+ if (PropList[i]->getName() == "SDNPCommutative") {
+ Properties |= 1 << SDNPCommutative;
+ } else if (PropList[i]->getName() == "SDNPAssociative") {
+ Properties |= 1 << SDNPAssociative;
+ } else if (PropList[i]->getName() == "SDNPHasChain") {
+ Properties |= 1 << SDNPHasChain;
+ } else if (PropList[i]->getName() == "SDNPOutFlag") {
+ Properties |= 1 << SDNPOutFlag;
+ } else if (PropList[i]->getName() == "SDNPInFlag") {
+ Properties |= 1 << SDNPInFlag;
+ } else if (PropList[i]->getName() == "SDNPOptInFlag") {
+ Properties |= 1 << SDNPOptInFlag;
+ } else {
+ cerr << "Unknown SD Node property '" << PropList[i]->getName()
+ << "' on node '" << R->getName() << "'!\n";
+ exit(1);
+ }
+ }
+
+
+ // Parse the type constraints.
+ std::vector<Record*> ConstraintList =
+ TypeProfile->getValueAsListOfDefs("Constraints");
+ TypeConstraints.assign(ConstraintList.begin(), ConstraintList.end());
+}
+
+//===----------------------------------------------------------------------===//
+// TreePatternNode implementation
+//
+
+TreePatternNode::~TreePatternNode() {
+#if 0 // FIXME: implement refcounted tree nodes!
+ for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
+ delete getChild(i);
+#endif
+}
+
+/// 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 TreePatternNode::UpdateNodeType(const std::vector<unsigned char> &ExtVTs,
+ TreePattern &TP) {
+ assert(!ExtVTs.empty() && "Cannot update node type with empty type vector!");
+
+ if (ExtVTs[0] == MVT::isUnknown || LHSIsSubsetOfRHS(getExtTypes(), ExtVTs))
+ return false;
+ if (isTypeCompletelyUnknown() || LHSIsSubsetOfRHS(ExtVTs, getExtTypes())) {
+ setTypes(ExtVTs);
+ return true;
+ }
+
+ if (getExtTypeNum(0) == MVT::iPTR) {
+ if (ExtVTs[0] == MVT::iPTR || ExtVTs[0] == MVT::isInt)
+ return false;
+ if (isExtIntegerInVTs(ExtVTs)) {
+ std::vector<unsigned char> FVTs = FilterEVTs(ExtVTs, MVT::isInteger);
+ if (FVTs.size()) {
+ setTypes(ExtVTs);
+ return true;
+ }
+ }
+ }
+
+ if (ExtVTs[0] == MVT::isInt && isExtIntegerInVTs(getExtTypes())) {
+ assert(hasTypeSet() && "should be handled above!");
+ std::vector<unsigned char> FVTs = FilterEVTs(getExtTypes(), MVT::isInteger);
+ if (getExtTypes() == FVTs)
+ return false;
+ setTypes(FVTs);
+ return true;
+ }
+ if (ExtVTs[0] == MVT::iPTR && isExtIntegerInVTs(getExtTypes())) {
+ //assert(hasTypeSet() && "should be handled above!");
+ std::vector<unsigned char> FVTs = FilterEVTs(getExtTypes(), MVT::isInteger);
+ if (getExtTypes() == FVTs)
+ return false;
+ if (FVTs.size()) {
+ setTypes(FVTs);
+ return true;
+ }
+ }
+ if (ExtVTs[0] == MVT::isFP && isExtFloatingPointInVTs(getExtTypes())) {
+ assert(hasTypeSet() && "should be handled above!");
+ std::vector<unsigned char> FVTs =
+ FilterEVTs(getExtTypes(), MVT::isFloatingPoint);
+ if (getExtTypes() == FVTs)
+ return false;
+ setTypes(FVTs);
+ return true;
+ }
+
+ // If we know this is an int or fp type, and we are told it is a specific one,
+ // take the advice.
+ //
+ // Similarly, we should probably set the type here to the intersection of
+ // {isInt|isFP} and ExtVTs
+ if ((getExtTypeNum(0) == MVT::isInt && isExtIntegerInVTs(ExtVTs)) ||
+ (getExtTypeNum(0) == MVT::isFP && isExtFloatingPointInVTs(ExtVTs))) {
+ setTypes(ExtVTs);
+ return true;
+ }
+ if (getExtTypeNum(0) == MVT::isInt && ExtVTs[0] == MVT::iPTR) {
+ setTypes(ExtVTs);
+ return true;
+ }
+
+ if (isLeaf()) {
+ dump();
+ cerr << " ";
+ TP.error("Type inference contradiction found in node!");
+ } else {
+ TP.error("Type inference contradiction found in node " +
+ getOperator()->getName() + "!");
+ }
+ return true; // unreachable
+}
+
+
+void TreePatternNode::print(std::ostream &OS) const {
+ if (isLeaf()) {
+ OS << *getLeafValue();
+ } else {
+ OS << "(" << getOperator()->getName();
+ }
+
+ // FIXME: At some point we should handle printing all the value types for
+ // nodes that are multiply typed.
+ switch (getExtTypeNum(0)) {
+ case MVT::Other: OS << ":Other"; break;
+ case MVT::isInt: OS << ":isInt"; break;
+ case MVT::isFP : OS << ":isFP"; break;
+ case MVT::isUnknown: ; /*OS << ":?";*/ break;
+ case MVT::iPTR: OS << ":iPTR"; break;
+ default: {
+ std::string VTName = llvm::getName(getTypeNum(0));
+ // Strip off MVT:: prefix if present.
+ if (VTName.substr(0,5) == "MVT::")
+ VTName = VTName.substr(5);
+ OS << ":" << VTName;
+ break;
+ }
+ }
+
+ if (!isLeaf()) {
+ if (getNumChildren() != 0) {
+ OS << " ";
+ getChild(0)->print(OS);
+ for (unsigned i = 1, e = getNumChildren(); i != e; ++i) {
+ OS << ", ";
+ getChild(i)->print(OS);
+ }
+ }
+ OS << ")";
+ }
+
+ if (!PredicateFn.empty())
+ OS << "<<P:" << PredicateFn << ">>";
+ if (TransformFn)
+ OS << "<<X:" << TransformFn->getName() << ">>";
+ if (!getName().empty())
+ OS << ":$" << getName();
+
+}
+void TreePatternNode::dump() const {
+ print(*cerr.stream());
+}
+
+/// isIsomorphicTo - Return true if this node is recursively isomorphic to
+/// the specified node. For this comparison, all of the state of the node
+/// is considered, except for the assigned name. Nodes with differing names
+/// that are otherwise identical are considered isomorphic.
+bool TreePatternNode::isIsomorphicTo(const TreePatternNode *N) const {
+ if (N == this) return true;
+ if (N->isLeaf() != isLeaf() || getExtTypes() != N->getExtTypes() ||
+ getPredicateFn() != N->getPredicateFn() ||
+ getTransformFn() != N->getTransformFn())
+ return false;
+
+ if (isLeaf()) {
+ if (DefInit *DI = dynamic_cast<DefInit*>(getLeafValue()))
+ if (DefInit *NDI = dynamic_cast<DefInit*>(N->getLeafValue()))
+ return DI->getDef() == NDI->getDef();
+ return getLeafValue() == N->getLeafValue();
+ }
+
+ if (N->getOperator() != getOperator() ||
+ N->getNumChildren() != getNumChildren()) return false;
+ for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
+ if (!getChild(i)->isIsomorphicTo(N->getChild(i)))
+ return false;
+ return true;
+}
+
+/// clone - Make a copy of this tree and all of its children.
+///
+TreePatternNode *TreePatternNode::clone() const {
+ TreePatternNode *New;
+ if (isLeaf()) {
+ New = new TreePatternNode(getLeafValue());
+ } else {
+ std::vector<TreePatternNode*> CChildren;
+ CChildren.reserve(Children.size());
+ for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
+ CChildren.push_back(getChild(i)->clone());
+ New = new TreePatternNode(getOperator(), CChildren);
+ }
+ New->setName(getName());
+ New->setTypes(getExtTypes());
+ New->setPredicateFn(getPredicateFn());
+ New->setTransformFn(getTransformFn());
+ return New;
+}
+
+/// SubstituteFormalArguments - Replace the formal arguments in this tree
+/// with actual values specified by ArgMap.
+void TreePatternNode::
+SubstituteFormalArguments(std::map<std::string, TreePatternNode*> &ArgMap) {
+ if (isLeaf()) return;
+
+ for (unsigned i = 0, e = getNumChildren(); i != e; ++i) {
+ TreePatternNode *Child = getChild(i);
+ if (Child->isLeaf()) {
+ Init *Val = Child->getLeafValue();
+ if (dynamic_cast<DefInit*>(Val) &&
+ static_cast<DefInit*>(Val)->getDef()->getName() == "node") {
+ // We found a use of a formal argument, replace it with its value.
+ Child = ArgMap[Child->getName()];
+ assert(Child && "Couldn't find formal argument!");
+ setChild(i, Child);
+ }
+ } else {
+ getChild(i)->SubstituteFormalArguments(ArgMap);
+ }
+ }
+}
+
+
+/// InlinePatternFragments - If this pattern refers to any pattern
+/// fragments, inline them into place, giving us a pattern without any
+/// PatFrag references.
+TreePatternNode *TreePatternNode::InlinePatternFragments(TreePattern &TP) {
+ if (isLeaf()) return this; // nothing to do.
+ Record *Op = getOperator();
+
+ if (!Op->isSubClassOf("PatFrag")) {
+ // Just recursively inline children nodes.
+ for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
+ setChild(i, getChild(i)->InlinePatternFragments(TP));
+ return this;
+ }
+
+ // Otherwise, we found a reference to a fragment. First, look up its
+ // TreePattern record.
+ TreePattern *Frag = TP.getDAGISelEmitter().getPatternFragment(Op);
+
+ // Verify that we are passing the right number of operands.
+ if (Frag->getNumArgs() != Children.size())
+ TP.error("'" + Op->getName() + "' fragment requires " +
+ utostr(Frag->getNumArgs()) + " operands!");
+
+ TreePatternNode *FragTree = Frag->getOnlyTree()->clone();
+
+ // Resolve formal arguments to their actual value.
+ if (Frag->getNumArgs()) {
+ // Compute the map of formal to actual arguments.
+ std::map<std::string, TreePatternNode*> ArgMap;
+ for (unsigned i = 0, e = Frag->getNumArgs(); i != e; ++i)
+ ArgMap[Frag->getArgName(i)] = getChild(i)->InlinePatternFragments(TP);
+
+ FragTree->SubstituteFormalArguments(ArgMap);
+ }
+
+ FragTree->setName(getName());
+ FragTree->UpdateNodeType(getExtTypes(), TP);
+
+ // Get a new copy of this fragment to stitch into here.
+ //delete this; // FIXME: implement refcounting!
+ return FragTree;
+}
+
+/// getImplicitType - Check to see if the specified record has an implicit
+/// type which should be applied to it. This infer the type of register
+/// references from the register file information, for example.
+///
+static std::vector<unsigned char> getImplicitType(Record *R, bool NotRegisters,
+ TreePattern &TP) {
+ // Some common return values
+ std::vector<unsigned char> Unknown(1, MVT::isUnknown);
+ std::vector<unsigned char> Other(1, MVT::Other);
+
+ // Check to see if this is a register or a register class...
+ if (R->isSubClassOf("RegisterClass")) {
+ if (NotRegisters)
+ return Unknown;
+ const CodeGenRegisterClass &RC =
+ TP.getDAGISelEmitter().getTargetInfo().getRegisterClass(R);
+ return ConvertVTs(RC.getValueTypes());
+ } else if (R->isSubClassOf("PatFrag")) {
+ // Pattern fragment types will be resolved when they are inlined.
+ return Unknown;
+ } else if (R->isSubClassOf("Register")) {
+ if (NotRegisters)
+ return Unknown;
+ const CodeGenTarget &T = TP.getDAGISelEmitter().getTargetInfo();
+ return T.getRegisterVTs(R);
+ } else if (R->isSubClassOf("ValueType") || R->isSubClassOf("CondCode")) {
+ // Using a VTSDNode or CondCodeSDNode.
+ return Other;
+ } else if (R->isSubClassOf("ComplexPattern")) {
+ if (NotRegisters)
+ return Unknown;
+ std::vector<unsigned char>
+ ComplexPat(1, TP.getDAGISelEmitter().getComplexPattern(R).getValueType());
+ return ComplexPat;
+ } else if (R->getName() == "ptr_rc") {
+ Other[0] = MVT::iPTR;
+ return Other;
+ } else if (R->getName() == "node" || R->getName() == "srcvalue" ||
+ R->getName() == "zero_reg") {
+ // Placeholder.
+ return Unknown;
+ }
+
+ TP.error("Unknown node flavor used in pattern: " + R->getName());
+ return Other;
+}
+
+/// ApplyTypeConstraints - Apply all of the type constraints relevent to
+/// this node and its children in the tree. This returns true if it makes a
+/// change, false otherwise. If a type contradiction is found, throw an
+/// exception.
+bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
+ DAGISelEmitter &ISE = TP.getDAGISelEmitter();
+ if (isLeaf()) {
+ if (DefInit *DI = dynamic_cast<DefInit*>(getLeafValue())) {
+ // If it's a regclass or something else known, include the type.
+ return UpdateNodeType(getImplicitType(DI->getDef(), NotRegisters, TP),TP);
+ } else if (IntInit *II = dynamic_cast<IntInit*>(getLeafValue())) {
+ // Int inits are always integers. :)
+ bool MadeChange = UpdateNodeType(MVT::isInt, TP);
+
+ if (hasTypeSet()) {
+ // At some point, it may make sense for this tree pattern to have
+ // multiple types. Assert here that it does not, so we revisit this
+ // code when appropriate.
+ assert(getExtTypes().size() >= 1 && "TreePattern doesn't have a type!");
+ MVT::ValueType VT = getTypeNum(0);
+ for (unsigned i = 1, e = getExtTypes().size(); i != e; ++i)
+ assert(getTypeNum(i) == VT && "TreePattern has too many types!");
+
+ VT = getTypeNum(0);
+ if (VT != MVT::iPTR) {
+ unsigned Size = MVT::getSizeInBits(VT);
+ // Make sure that the value is representable for this type.
+ if (Size < 32) {
+ int Val = (II->getValue() << (32-Size)) >> (32-Size);
+ if (Val != II->getValue())
+ TP.error("Sign-extended integer value '" + itostr(II->getValue())+
+ "' is out of range for type '" +
+ getEnumName(getTypeNum(0)) + "'!");
+ }
+ }
+ }
+
+ return MadeChange;
+ }
+ return false;
+ }
+
+ // special handling for set, which isn't really an SDNode.
+ if (getOperator()->getName() == "set") {
+ assert (getNumChildren() == 2 && "Only handle 2 operand set's for now!");
+ bool MadeChange = getChild(0)->ApplyTypeConstraints(TP, NotRegisters);
+ MadeChange |= getChild(1)->ApplyTypeConstraints(TP, NotRegisters);
+
+ // Types of operands must match.
+ MadeChange |= getChild(0)->UpdateNodeType(getChild(1)->getExtTypes(), TP);
+ MadeChange |= getChild(1)->UpdateNodeType(getChild(0)->getExtTypes(), TP);
+ MadeChange |= UpdateNodeType(MVT::isVoid, TP);
+ return MadeChange;
+ } else if (getOperator() == ISE.get_intrinsic_void_sdnode() ||
+ getOperator() == ISE.get_intrinsic_w_chain_sdnode() ||
+ getOperator() == ISE.get_intrinsic_wo_chain_sdnode()) {
+ unsigned IID =
+ dynamic_cast<IntInit*>(getChild(0)->getLeafValue())->getValue();
+ const CodeGenIntrinsic &Int = ISE.getIntrinsicInfo(IID);
+ bool MadeChange = false;
+
+ // Apply the result type to the node.
+ MadeChange = UpdateNodeType(Int.ArgVTs[0], TP);
+
+ if (getNumChildren() != Int.ArgVTs.size())
+ TP.error("Intrinsic '" + Int.Name + "' expects " +
+ utostr(Int.ArgVTs.size()-1) + " operands, not " +
+ utostr(getNumChildren()-1) + " operands!");
+
+ // Apply type info to the intrinsic ID.
+ MadeChange |= getChild(0)->UpdateNodeType(MVT::iPTR, TP);
+
+ for (unsigned i = 1, e = getNumChildren(); i != e; ++i) {
+ MVT::ValueType OpVT = Int.ArgVTs[i];
+ MadeChange |= getChild(i)->UpdateNodeType(OpVT, TP);
+ MadeChange |= getChild(i)->ApplyTypeConstraints(TP, NotRegisters);
+ }
+ return MadeChange;
+ } else if (getOperator()->isSubClassOf("SDNode")) {
+ const SDNodeInfo &NI = ISE.getSDNodeInfo(getOperator());
+
+ bool MadeChange = NI.ApplyTypeConstraints(this, TP);
+ for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
+ MadeChange |= getChild(i)->ApplyTypeConstraints(TP, NotRegisters);
+ // Branch, etc. do not produce results and top-level forms in instr pattern
+ // must have void types.
+ if (NI.getNumResults() == 0)
+ MadeChange |= UpdateNodeType(MVT::isVoid, TP);
+
+ // If this is a vector_shuffle operation, apply types to the build_vector
+ // operation. The types of the integers don't matter, but this ensures they
+ // won't get checked.
+ if (getOperator()->getName() == "vector_shuffle" &&
+ getChild(2)->getOperator()->getName() == "build_vector") {
+ TreePatternNode *BV = getChild(2);
+ const std::vector<MVT::ValueType> &LegalVTs
+ = ISE.getTargetInfo().getLegalValueTypes();
+ MVT::ValueType LegalIntVT = MVT::Other;
+ for (unsigned i = 0, e = LegalVTs.size(); i != e; ++i)
+ if (MVT::isInteger(LegalVTs[i]) && !MVT::isVector(LegalVTs[i])) {
+ LegalIntVT = LegalVTs[i];
+ break;
+ }
+ assert(LegalIntVT != MVT::Other && "No legal integer VT?");
+
+ for (unsigned i = 0, e = BV->getNumChildren(); i != e; ++i)
+ MadeChange |= BV->getChild(i)->UpdateNodeType(LegalIntVT, TP);
+ }
+ return MadeChange;
+ } else if (getOperator()->isSubClassOf("Instruction")) {
+ const DAGInstruction &Inst = ISE.getInstruction(getOperator());
+ bool MadeChange = false;
+ unsigned NumResults = Inst.getNumResults();
+
+ assert(NumResults <= 1 &&
+ "Only supports zero or one result instrs!");
+
+ CodeGenInstruction &InstInfo =
+ ISE.getTargetInfo().getInstruction(getOperator()->getName());
+ // Apply the result type to the node
+ if (NumResults == 0 || InstInfo.noResults) { // FIXME: temporary hack.
+ MadeChange = UpdateNodeType(MVT::isVoid, TP);
+ } else {
+ Record *ResultNode = Inst.getResult(0);
+
+ if (ResultNode->getName() == "ptr_rc") {
+ std::vector<unsigned char> VT;
+ VT.push_back(MVT::iPTR);
+ MadeChange = UpdateNodeType(VT, TP);
+ } else {
+ assert(ResultNode->isSubClassOf("RegisterClass") &&
+ "Operands should be register classes!");
+
+ const CodeGenRegisterClass &RC =
+ ISE.getTargetInfo().getRegisterClass(ResultNode);
+ MadeChange = UpdateNodeType(ConvertVTs(RC.getValueTypes()), TP);
+ }
+ }
+
+ unsigned ChildNo = 0;
+ for (unsigned i = 0, e = Inst.getNumOperands(); i != e; ++i) {
+ Record *OperandNode = Inst.getOperand(i);
+
+ // If the instruction expects a predicate or optional def operand, we
+ // codegen this by setting the operand to it's default value if it has a
+ // non-empty DefaultOps field.
+ if ((OperandNode->isSubClassOf("PredicateOperand") ||
+ OperandNode->isSubClassOf("OptionalDefOperand")) &&
+ !ISE.getDefaultOperand(OperandNode).DefaultOps.empty())
+ continue;
+
+ // Verify that we didn't run out of provided operands.
+ if (ChildNo >= getNumChildren())
+ TP.error("Instruction '" + getOperator()->getName() +
+ "' expects more operands than were provided.");
+
+ MVT::ValueType VT;
+ TreePatternNode *Child = getChild(ChildNo++);
+ if (OperandNode->isSubClassOf("RegisterClass")) {
+ const CodeGenRegisterClass &RC =
+ ISE.getTargetInfo().getRegisterClass(OperandNode);
+ MadeChange |= Child->UpdateNodeType(ConvertVTs(RC.getValueTypes()), TP);
+ } else if (OperandNode->isSubClassOf("Operand")) {
+ VT = getValueType(OperandNode->getValueAsDef("Type"));
+ MadeChange |= Child->UpdateNodeType(VT, TP);
+ } else if (OperandNode->getName() == "ptr_rc") {
+ MadeChange |= Child->UpdateNodeType(MVT::iPTR, TP);
+ } else {
+ assert(0 && "Unknown operand type!");
+ abort();
+ }
+ MadeChange |= Child->ApplyTypeConstraints(TP, NotRegisters);
+ }
+
+ if (ChildNo != getNumChildren())
+ TP.error("Instruction '" + getOperator()->getName() +
+ "' was provided too many operands!");
+
+ return MadeChange;
+ } else {
+ assert(getOperator()->isSubClassOf("SDNodeXForm") && "Unknown node type!");
+
+ // Node transforms always take one operand.
+ if (getNumChildren() != 1)
+ TP.error("Node transform '" + getOperator()->getName() +
+ "' requires one operand!");
+
+ // If either the output or input of the xform does not have exact
+ // type info. We assume they must be the same. Otherwise, it is perfectly
+ // legal to transform from one type to a completely different type.
+ if (!hasTypeSet() || !getChild(0)->hasTypeSet()) {
+ bool MadeChange = UpdateNodeType(getChild(0)->getExtTypes(), TP);
+ MadeChange |= getChild(0)->UpdateNodeType(getExtTypes(), TP);
+ return MadeChange;
+ }
+ return false;
+ }
+}
+
+/// OnlyOnRHSOfCommutative - Return true if this value is only allowed on the
+/// RHS of a commutative operation, not the on LHS.
+static bool OnlyOnRHSOfCommutative(TreePatternNode *N) {
+ if (!N->isLeaf() && N->getOperator()->getName() == "imm")
+ return true;
+ if (N->isLeaf() && dynamic_cast<IntInit*>(N->getLeafValue()))
+ return true;
+ return false;
+}
+
+
+/// canPatternMatch - If it is impossible for this pattern to match on this
+/// target, fill in Reason and return false. Otherwise, return true. This is
+/// used as a santity check for .td files (to prevent people from writing stuff
+/// that can never possibly work), and to prevent the pattern permuter from
+/// generating stuff that is useless.
+bool TreePatternNode::canPatternMatch(std::string &Reason, DAGISelEmitter &ISE){
+ if (isLeaf()) return true;
+
+ for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
+ if (!getChild(i)->canPatternMatch(Reason, ISE))
+ return false;
+
+ // If this is an intrinsic, handle cases that would make it not match. For
+ // example, if an operand is required to be an immediate.
+ if (getOperator()->isSubClassOf("Intrinsic")) {
+ // TODO:
+ return true;
+ }
+
+ // If this node is a commutative operator, check that the LHS isn't an
+ // immediate.
+ const SDNodeInfo &NodeInfo = ISE.getSDNodeInfo(getOperator());
+ if (NodeInfo.hasProperty(SDNPCommutative)) {
+ // Scan all of the operands of the node and make sure that only the last one
+ // is a constant node, unless the RHS also is.
+ if (!OnlyOnRHSOfCommutative(getChild(getNumChildren()-1))) {
+ for (unsigned i = 0, e = getNumChildren()-1; i != e; ++i)
+ if (OnlyOnRHSOfCommutative(getChild(i))) {
+ Reason="Immediate value must be on the RHS of commutative operators!";
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// TreePattern implementation
+//
+
+TreePattern::TreePattern(Record *TheRec, ListInit *RawPat, bool isInput,
+ DAGISelEmitter &ise) : TheRecord(TheRec), ISE(ise) {
+ isInputPattern = isInput;
+ for (unsigned i = 0, e = RawPat->getSize(); i != e; ++i)
+ Trees.push_back(ParseTreePattern((DagInit*)RawPat->getElement(i)));
+}
+
+TreePattern::TreePattern(Record *TheRec, DagInit *Pat, bool isInput,
+ DAGISelEmitter &ise) : TheRecord(TheRec), ISE(ise) {
+ isInputPattern = isInput;
+ Trees.push_back(ParseTreePattern(Pat));
+}
+
+TreePattern::TreePattern(Record *TheRec, TreePatternNode *Pat, bool isInput,
+ DAGISelEmitter &ise) : TheRecord(TheRec), ISE(ise) {
+ isInputPattern = isInput;
+ Trees.push_back(Pat);
+}
+
+
+
+void TreePattern::error(const std::string &Msg) const {
+ dump();
+ throw "In " + TheRecord->getName() + ": " + Msg;
+}
+
+TreePatternNode *TreePattern::ParseTreePattern(DagInit *Dag) {
+ DefInit *OpDef = dynamic_cast<DefInit*>(Dag->getOperator());
+ if (!OpDef) error("Pattern has unexpected operator type!");
+ Record *Operator = OpDef->getDef();
+
+ if (Operator->isSubClassOf("ValueType")) {
+ // If the operator is a ValueType, then this must be "type cast" of a leaf
+ // node.
+ if (Dag->getNumArgs() != 1)
+ error("Type cast only takes one operand!");
+
+ Init *Arg = Dag->getArg(0);
+ TreePatternNode *New;
+ if (DefInit *DI = dynamic_cast<DefInit*>(Arg)) {
+ Record *R = DI->getDef();
+ if (R->isSubClassOf("SDNode") || R->isSubClassOf("PatFrag")) {
+ Dag->setArg(0, new DagInit(DI,
+ std::vector<std::pair<Init*, std::string> >()));
+ return ParseTreePattern(Dag);
+ }
+ New = new TreePatternNode(DI);
+ } else if (DagInit *DI = dynamic_cast<DagInit*>(Arg)) {
+ New = ParseTreePattern(DI);
+ } else if (IntInit *II = dynamic_cast<IntInit*>(Arg)) {
+ New = new TreePatternNode(II);
+ if (!Dag->getArgName(0).empty())
+ error("Constant int argument should not have a name!");
+ } else if (BitsInit *BI = dynamic_cast<BitsInit*>(Arg)) {
+ // Turn this into an IntInit.
+ Init *II = BI->convertInitializerTo(new IntRecTy());
+ if (II == 0 || !dynamic_cast<IntInit*>(II))
+ error("Bits value must be constants!");
+
+ New = new TreePatternNode(dynamic_cast<IntInit*>(II));
+ if (!Dag->getArgName(0).empty())
+ error("Constant int argument should not have a name!");
+ } else {
+ Arg->dump();
+ error("Unknown leaf value for tree pattern!");
+ return 0;
+ }
+
+ // Apply the type cast.
+ New->UpdateNodeType(getValueType(Operator), *this);
+ New->setName(Dag->getArgName(0));
+ return New;
+ }
+
+ // Verify that this is something that makes sense for an operator.
+ if (!Operator->isSubClassOf("PatFrag") && !Operator->isSubClassOf("SDNode") &&
+ !Operator->isSubClassOf("Instruction") &&
+ !Operator->isSubClassOf("SDNodeXForm") &&
+ !Operator->isSubClassOf("Intrinsic") &&
+ Operator->getName() != "set")
+ error("Unrecognized node '" + Operator->getName() + "'!");
+
+ // Check to see if this is something that is illegal in an input pattern.
+ if (isInputPattern && (Operator->isSubClassOf("Instruction") ||
+ Operator->isSubClassOf("SDNodeXForm")))
+ error("Cannot use '" + Operator->getName() + "' in an input pattern!");
+
+ std::vector<TreePatternNode*> Children;
+
+ for (unsigned i = 0, e = Dag->getNumArgs(); i != e; ++i) {
+ Init *Arg = Dag->getArg(i);
+ if (DagInit *DI = dynamic_cast<DagInit*>(Arg)) {
+ Children.push_back(ParseTreePattern(DI));
+ if (Children.back()->getName().empty())
+ Children.back()->setName(Dag->getArgName(i));
+ } else if (DefInit *DefI = dynamic_cast<DefInit*>(Arg)) {
+ Record *R = DefI->getDef();
+ // Direct reference to a leaf DagNode or PatFrag? Turn it into a
+ // TreePatternNode if its own.
+ if (R->isSubClassOf("SDNode") || R->isSubClassOf("PatFrag")) {
+ Dag->setArg(i, new DagInit(DefI,
+ std::vector<std::pair<Init*, std::string> >()));
+ --i; // Revisit this node...
+ } else {
+ TreePatternNode *Node = new TreePatternNode(DefI);
+ Node->setName(Dag->getArgName(i));
+ Children.push_back(Node);
+
+ // Input argument?
+ if (R->getName() == "node") {
+ if (Dag->getArgName(i).empty())
+ error("'node' argument requires a name to match with operand list");
+ Args.push_back(Dag->getArgName(i));
+ }
+ }
+ } else if (IntInit *II = dynamic_cast<IntInit*>(Arg)) {
+ TreePatternNode *Node = new TreePatternNode(II);
+ if (!Dag->getArgName(i).empty())
+ error("Constant int argument should not have a name!");
+ Children.push_back(Node);
+ } else if (BitsInit *BI = dynamic_cast<BitsInit*>(Arg)) {
+ // Turn this into an IntInit.
+ Init *II = BI->convertInitializerTo(new IntRecTy());
+ if (II == 0 || !dynamic_cast<IntInit*>(II))
+ error("Bits value must be constants!");
+
+ TreePatternNode *Node = new TreePatternNode(dynamic_cast<IntInit*>(II));
+ if (!Dag->getArgName(i).empty())
+ error("Constant int argument should not have a name!");
+ Children.push_back(Node);
+ } else {
+ cerr << '"';
+ Arg->dump();
+ cerr << "\": ";
+ error("Unknown leaf value for tree pattern!");
+ }
+ }
+
+ // If the operator is an intrinsic, then this is just syntactic sugar for for
+ // (intrinsic_* <number>, ..children..). Pick the right intrinsic node, and
+ // convert the intrinsic name to a number.
+ if (Operator->isSubClassOf("Intrinsic")) {
+ const CodeGenIntrinsic &Int = getDAGISelEmitter().getIntrinsic(Operator);
+ unsigned IID = getDAGISelEmitter().getIntrinsicID(Operator)+1;
+
+ // If this intrinsic returns void, it must have side-effects and thus a
+ // chain.
+ if (Int.ArgVTs[0] == MVT::isVoid) {
+ Operator = getDAGISelEmitter().get_intrinsic_void_sdnode();
+ } else if (Int.ModRef != CodeGenIntrinsic::NoMem) {
+ // Has side-effects, requires chain.
+ Operator = getDAGISelEmitter().get_intrinsic_w_chain_sdnode();
+ } else {
+ // Otherwise, no chain.
+ Operator = getDAGISelEmitter().get_intrinsic_wo_chain_sdnode();
+ }
+
+ TreePatternNode *IIDNode = new TreePatternNode(new IntInit(IID));
+ Children.insert(Children.begin(), IIDNode);
+ }
+
+ return new TreePatternNode(Operator, Children);
+}
+
+/// InferAllTypes - Infer/propagate as many types throughout the expression
+/// patterns as possible. Return true if all types are infered, false
+/// otherwise. Throw an exception if a type contradiction is found.
+bool TreePattern::InferAllTypes() {
+ bool MadeChange = true;
+ while (MadeChange) {
+ MadeChange = false;
+ for (unsigned i = 0, e = Trees.size(); i != e; ++i)
+ MadeChange |= Trees[i]->ApplyTypeConstraints(*this, false);
+ }
+
+ bool HasUnresolvedTypes = false;
+ for (unsigned i = 0, e = Trees.size(); i != e; ++i)
+ HasUnresolvedTypes |= Trees[i]->ContainsUnresolvedType();
+ return !HasUnresolvedTypes;
+}
+
+void TreePattern::print(std::ostream &OS) const {
+ OS << getRecord()->getName();
+ if (!Args.empty()) {
+ OS << "(" << Args[0];
+ for (unsigned i = 1, e = Args.size(); i != e; ++i)
+ OS << ", " << Args[i];
+ OS << ")";
+ }
+ OS << ": ";
+
+ if (Trees.size() > 1)
+ OS << "[\n";
+ for (unsigned i = 0, e = Trees.size(); i != e; ++i) {
+ OS << "\t";
+ Trees[i]->print(OS);
+ OS << "\n";
+ }
+
+ if (Trees.size() > 1)
+ OS << "]\n";
+}
+
+void TreePattern::dump() const { print(*cerr.stream()); }
+
+
+
+//===----------------------------------------------------------------------===//
+// DAGISelEmitter implementation
+//
+
+// Parse all of the SDNode definitions for the target, populating SDNodes.
+void DAGISelEmitter::ParseNodeInfo() {
+ std::vector<Record*> Nodes = Records.getAllDerivedDefinitions("SDNode");
+ while (!Nodes.empty()) {
+ SDNodes.insert(std::make_pair(Nodes.back(), Nodes.back()));
+ Nodes.pop_back();
+ }
+
+ // Get the buildin intrinsic nodes.
+ intrinsic_void_sdnode = getSDNodeNamed("intrinsic_void");
+ intrinsic_w_chain_sdnode = getSDNodeNamed("intrinsic_w_chain");
+ intrinsic_wo_chain_sdnode = getSDNodeNamed("intrinsic_wo_chain");
+}
+
+/// ParseNodeTransforms - Parse all SDNodeXForm instances into the SDNodeXForms
+/// map, and emit them to the file as functions.
+void DAGISelEmitter::ParseNodeTransforms(std::ostream &OS) {
+ OS << "\n// Node transformations.\n";
+ std::vector<Record*> Xforms = Records.getAllDerivedDefinitions("SDNodeXForm");
+ while (!Xforms.empty()) {
+ Record *XFormNode = Xforms.back();
+ Record *SDNode = XFormNode->getValueAsDef("Opcode");
+ std::string Code = XFormNode->getValueAsCode("XFormFunction");
+ SDNodeXForms.insert(std::make_pair(XFormNode,
+ std::make_pair(SDNode, Code)));
+
+ if (!Code.empty()) {
+ std::string ClassName = getSDNodeInfo(SDNode).getSDClassName();
+ const char *C2 = ClassName == "SDNode" ? "N" : "inN";
+
+ OS << "inline SDOperand Transform_" << XFormNode->getName()
+ << "(SDNode *" << C2 << ") {\n";
+ if (ClassName != "SDNode")
+ OS << " " << ClassName << " *N = cast<" << ClassName << ">(inN);\n";
+ OS << Code << "\n}\n";
+ }
+
+ Xforms.pop_back();
+ }
+}
+
+void DAGISelEmitter::ParseComplexPatterns() {
+ std::vector<Record*> AMs = Records.getAllDerivedDefinitions("ComplexPattern");
+ while (!AMs.empty()) {
+ ComplexPatterns.insert(std::make_pair(AMs.back(), AMs.back()));
+ AMs.pop_back();
+ }
+}
+
+
+/// ParsePatternFragments - Parse all of the PatFrag definitions in the .td
+/// file, building up the PatternFragments map. After we've collected them all,
+/// inline fragments together as necessary, so that there are no references left
+/// inside a pattern fragment to a pattern fragment.
+///
+/// This also emits all of the predicate functions to the output file.
+///
+void DAGISelEmitter::ParsePatternFragments(std::ostream &OS) {
+ std::vector<Record*> Fragments = Records.getAllDerivedDefinitions("PatFrag");
+
+ // First step, parse all of the fragments and emit predicate functions.
+ OS << "\n// Predicate functions.\n";
+ for (unsigned i = 0, e = Fragments.size(); i != e; ++i) {
+ DagInit *Tree = Fragments[i]->getValueAsDag("Fragment");
+ TreePattern *P = new TreePattern(Fragments[i], Tree, true, *this);
+ PatternFragments[Fragments[i]] = P;
+
+ // Validate the argument list, converting it to map, to discard duplicates.
+ std::vector<std::string> &Args = P->getArgList();
+ std::set<std::string> OperandsMap(Args.begin(), Args.end());
+
+ if (OperandsMap.count(""))
+ P->error("Cannot have unnamed 'node' values in pattern fragment!");
+
+ // Parse the operands list.
+ DagInit *OpsList = Fragments[i]->getValueAsDag("Operands");
+ DefInit *OpsOp = dynamic_cast<DefInit*>(OpsList->getOperator());
+ if (!OpsOp || OpsOp->getDef()->getName() != "ops")
+ P->error("Operands list should start with '(ops ... '!");
+
+ // Copy over the arguments.
+ Args.clear();
+ for (unsigned j = 0, e = OpsList->getNumArgs(); j != e; ++j) {
+ if (!dynamic_cast<DefInit*>(OpsList->getArg(j)) ||
+ static_cast<DefInit*>(OpsList->getArg(j))->
+ getDef()->getName() != "node")
+ P->error("Operands list should all be 'node' values.");
+ if (OpsList->getArgName(j).empty())
+ P->error("Operands list should have names for each operand!");
+ if (!OperandsMap.count(OpsList->getArgName(j)))
+ P->error("'" + OpsList->getArgName(j) +
+ "' does not occur in pattern or was multiply specified!");
+ OperandsMap.erase(OpsList->getArgName(j));
+ Args.push_back(OpsList->getArgName(j));
+ }
+
+ if (!OperandsMap.empty())
+ P->error("Operands list does not contain an entry for operand '" +
+ *OperandsMap.begin() + "'!");
+
+ // If there is a code init for this fragment, emit the predicate code and
+ // keep track of the fact that this fragment uses it.
+ std::string Code = Fragments[i]->getValueAsCode("Predicate");
+ if (!Code.empty()) {
+ if (P->getOnlyTree()->isLeaf())
+ OS << "inline bool Predicate_" << Fragments[i]->getName()
+ << "(SDNode *N) {\n";
+ else {
+ std::string ClassName =
+ getSDNodeInfo(P->getOnlyTree()->getOperator()).getSDClassName();
+ const char *C2 = ClassName == "SDNode" ? "N" : "inN";
+
+ OS << "inline bool Predicate_" << Fragments[i]->getName()
+ << "(SDNode *" << C2 << ") {\n";
+ if (ClassName != "SDNode")
+ OS << " " << ClassName << " *N = cast<" << ClassName << ">(inN);\n";
+ }
+ OS << Code << "\n}\n";
+ P->getOnlyTree()->setPredicateFn("Predicate_"+Fragments[i]->getName());
+ }
+
+ // If there is a node transformation corresponding to this, keep track of
+ // it.
+ Record *Transform = Fragments[i]->getValueAsDef("OperandTransform");
+ if (!getSDNodeTransform(Transform).second.empty()) // not noop xform?
+ P->getOnlyTree()->setTransformFn(Transform);
+ }
+
+ OS << "\n\n";
+
+ // Now that we've parsed all of the tree fragments, do a closure on them so
+ // that there are not references to PatFrags left inside of them.
+ for (std::map<Record*, TreePattern*>::iterator I = PatternFragments.begin(),
+ E = PatternFragments.end(); I != E; ++I) {
+ TreePattern *ThePat = I->second;
+ ThePat->InlinePatternFragments();
+
+ // Infer as many types as possible. Don't worry about it if we don't infer
+ // all of them, some may depend on the inputs of the pattern.
+ try {
+ ThePat->InferAllTypes();
+ } catch (...) {
+ // If this pattern fragment is not supported by this target (no types can
+ // satisfy its constraints), just ignore it. If the bogus pattern is
+ // actually used by instructions, the type consistency error will be
+ // reported there.
+ }
+
+ // If debugging, print out the pattern fragment result.
+ DEBUG(ThePat->dump());
+ }
+}
+
+void DAGISelEmitter::ParseDefaultOperands() {
+ std::vector<Record*> DefaultOps[2];
+ DefaultOps[0] = Records.getAllDerivedDefinitions("PredicateOperand");
+ DefaultOps[1] = Records.getAllDerivedDefinitions("OptionalDefOperand");
+
+ // Find some SDNode.
+ assert(!SDNodes.empty() && "No SDNodes parsed?");
+ Init *SomeSDNode = new DefInit(SDNodes.begin()->first);
+
+ for (unsigned iter = 0; iter != 2; ++iter) {
+ for (unsigned i = 0, e = DefaultOps[iter].size(); i != e; ++i) {
+ DagInit *DefaultInfo = DefaultOps[iter][i]->getValueAsDag("DefaultOps");
+
+ // Clone the DefaultInfo dag node, changing the operator from 'ops' to
+ // SomeSDnode so that we can parse this.
+ std::vector<std::pair<Init*, std::string> > Ops;
+ for (unsigned op = 0, e = DefaultInfo->getNumArgs(); op != e; ++op)
+ Ops.push_back(std::make_pair(DefaultInfo->getArg(op),
+ DefaultInfo->getArgName(op)));
+ DagInit *DI = new DagInit(SomeSDNode, Ops);
+
+ // Create a TreePattern to parse this.
+ TreePattern P(DefaultOps[iter][i], DI, false, *this);
+ assert(P.getNumTrees() == 1 && "This ctor can only produce one tree!");
+
+ // Copy the operands over into a DAGDefaultOperand.
+ DAGDefaultOperand DefaultOpInfo;
+
+ TreePatternNode *T = P.getTree(0);
+ for (unsigned op = 0, e = T->getNumChildren(); op != e; ++op) {
+ TreePatternNode *TPN = T->getChild(op);
+ while (TPN->ApplyTypeConstraints(P, false))
+ /* Resolve all types */;
+
+ if (TPN->ContainsUnresolvedType())
+ if (iter == 0)
+ throw "Value #" + utostr(i) + " of PredicateOperand '" +
+ DefaultOps[iter][i]->getName() + "' doesn't have a concrete type!";
+ else
+ throw "Value #" + utostr(i) + " of OptionalDefOperand '" +
+ DefaultOps[iter][i]->getName() + "' doesn't have a concrete type!";
+
+ DefaultOpInfo.DefaultOps.push_back(TPN);
+ }
+
+ // Insert it into the DefaultOperands map so we can find it later.
+ DefaultOperands[DefaultOps[iter][i]] = DefaultOpInfo;
+ }
+ }
+}
+
+/// HandleUse - Given "Pat" a leaf in the pattern, check to see if it is an
+/// instruction input. Return true if this is a real use.
+static bool HandleUse(TreePattern *I, TreePatternNode *Pat,
+ std::map<std::string, TreePatternNode*> &InstInputs,
+ std::vector<Record*> &InstImpInputs) {
+ // No name -> not interesting.
+ if (Pat->getName().empty()) {
+ if (Pat->isLeaf()) {
+ DefInit *DI = dynamic_cast<DefInit*>(Pat->getLeafValue());
+ if (DI && DI->getDef()->isSubClassOf("RegisterClass"))
+ I->error("Input " + DI->getDef()->getName() + " must be named!");
+ else if (DI && DI->getDef()->isSubClassOf("Register"))
+ InstImpInputs.push_back(DI->getDef());
+ }
+ return false;
+ }
+
+ Record *Rec;
+ if (Pat->isLeaf()) {
+ DefInit *DI = dynamic_cast<DefInit*>(Pat->getLeafValue());
+ if (!DI) I->error("Input $" + Pat->getName() + " must be an identifier!");
+ Rec = DI->getDef();
+ } else {
+ assert(Pat->getNumChildren() == 0 && "can't be a use with children!");
+ Rec = Pat->getOperator();
+ }
+
+ // SRCVALUE nodes are ignored.
+ if (Rec->getName() == "srcvalue")
+ return false;
+
+ TreePatternNode *&Slot = InstInputs[Pat->getName()];
+ if (!Slot) {
+ Slot = Pat;
+ } else {
+ Record *SlotRec;
+ if (Slot->isLeaf()) {
+ SlotRec = dynamic_cast<DefInit*>(Slot->getLeafValue())->getDef();
+ } else {
+ assert(Slot->getNumChildren() == 0 && "can't be a use with children!");
+ SlotRec = Slot->getOperator();
+ }
+
+ // Ensure that the inputs agree if we've already seen this input.
+ if (Rec != SlotRec)
+ I->error("All $" + Pat->getName() + " inputs must agree with each other");
+ if (Slot->getExtTypes() != Pat->getExtTypes())
+ I->error("All $" + Pat->getName() + " inputs must agree with each other");
+ }
+ return true;
+}
+
+/// FindPatternInputsAndOutputs - Scan the specified TreePatternNode (which is
+/// part of "I", the instruction), computing the set of inputs and outputs of
+/// the pattern. Report errors if we see anything naughty.
+void DAGISelEmitter::
+FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat,
+ std::map<std::string, TreePatternNode*> &InstInputs,
+ std::map<std::string, TreePatternNode*>&InstResults,
+ std::vector<Record*> &InstImpInputs,
+ std::vector<Record*> &InstImpResults) {
+ if (Pat->isLeaf()) {
+ bool isUse = HandleUse(I, Pat, InstInputs, InstImpInputs);
+ if (!isUse && Pat->getTransformFn())
+ I->error("Cannot specify a transform function for a non-input value!");
+ return;
+ } else if (Pat->getOperator()->getName() != "set") {
+ // If this is not a set, verify that the children nodes are not void typed,
+ // and recurse.
+ for (unsigned i = 0, e = Pat->getNumChildren(); i != e; ++i) {
+ if (Pat->getChild(i)->getExtTypeNum(0) == MVT::isVoid)
+ I->error("Cannot have void nodes inside of patterns!");
+ FindPatternInputsAndOutputs(I, Pat->getChild(i), InstInputs, InstResults,
+ InstImpInputs, InstImpResults);
+ }
+
+ // If this is a non-leaf node with no children, treat it basically as if
+ // it were a leaf. This handles nodes like (imm).
+ bool isUse = false;
+ if (Pat->getNumChildren() == 0)
+ isUse = HandleUse(I, Pat, InstInputs, InstImpInputs);
+
+ if (!isUse && Pat->getTransformFn())
+ I->error("Cannot specify a transform function for a non-input value!");
+ return;
+ }
+
+ // Otherwise, this is a set, validate and collect instruction results.
+ if (Pat->getNumChildren() == 0)
+ I->error("set requires operands!");
+ else if (Pat->getNumChildren() & 1)
+ I->error("set requires an even number of operands");
+
+ if (Pat->getTransformFn())
+ I->error("Cannot specify a transform function on a set node!");
+
+ // Check the set destinations.
+ unsigned NumValues = Pat->getNumChildren()/2;
+ for (unsigned i = 0; i != NumValues; ++i) {
+ TreePatternNode *Dest = Pat->getChild(i);
+ if (!Dest->isLeaf())
+ I->error("set destination should be a register!");
+
+ DefInit *Val = dynamic_cast<DefInit*>(Dest->getLeafValue());
+ if (!Val)
+ I->error("set destination should be a register!");
+
+ if (Val->getDef()->isSubClassOf("RegisterClass") ||
+ Val->getDef()->getName() == "ptr_rc") {
+ if (Dest->getName().empty())
+ I->error("set destination must have a name!");
+ if (InstResults.count(Dest->getName()))
+ I->error("cannot set '" + Dest->getName() +"' multiple times");
+ InstResults[Dest->getName()] = Dest;
+ } else if (Val->getDef()->isSubClassOf("Register")) {
+ InstImpResults.push_back(Val->getDef());
+ } else {
+ I->error("set destination should be a register!");
+ }
+
+ // Verify and collect info from the computation.
+ FindPatternInputsAndOutputs(I, Pat->getChild(i+NumValues),
+ InstInputs, InstResults,
+ InstImpInputs, InstImpResults);
+ }
+}
+
+/// ParseInstructions - Parse all of the instructions, inlining and resolving
+/// any fragments involved. This populates the Instructions list with fully
+/// resolved instructions.
+void DAGISelEmitter::ParseInstructions() {
+ std::vector<Record*> Instrs = Records.getAllDerivedDefinitions("Instruction");
+
+ for (unsigned i = 0, e = Instrs.size(); i != e; ++i) {
+ ListInit *LI = 0;
+
+ if (dynamic_cast<ListInit*>(Instrs[i]->getValueInit("Pattern")))
+ LI = Instrs[i]->getValueAsListInit("Pattern");
+
+ // If there is no pattern, only collect minimal information about the
+ // instruction for its operand list. We have to assume that there is one
+ // result, as we have no detailed info.
+ if (!LI || LI->getSize() == 0) {
+ std::vector<Record*> Results;
+ std::vector<Record*> Operands;
+
+ CodeGenInstruction &InstInfo =Target.getInstruction(Instrs[i]->getName());
+
+ if (InstInfo.OperandList.size() != 0) {
+ // FIXME: temporary hack...
+ if (InstInfo.noResults) {
+ // These produce no results
+ for (unsigned j = 0, e = InstInfo.OperandList.size(); j < e; ++j)
+ Operands.push_back(InstInfo.OperandList[j].Rec);
+ } else {
+ // Assume the first operand is the result.
+ Results.push_back(InstInfo.OperandList[0].Rec);
+
+ // The rest are inputs.
+ for (unsigned j = 1, e = InstInfo.OperandList.size(); j < e; ++j)
+ Operands.push_back(InstInfo.OperandList[j].Rec);
+ }
+ }
+
+ // Create and insert the instruction.
+ std::vector<Record*> ImpResults;
+ std::vector<Record*> ImpOperands;
+ Instructions.insert(std::make_pair(Instrs[i],
+ DAGInstruction(0, Results, Operands, ImpResults,
+ ImpOperands)));
+ continue; // no pattern.
+ }
+
+ // Parse the instruction.
+ TreePattern *I = new TreePattern(Instrs[i], LI, true, *this);
+ // Inline pattern fragments into it.
+ I->InlinePatternFragments();
+
+ // Infer as many types as possible. If we cannot infer all of them, we can
+ // never do anything with this instruction pattern: report it to the user.
+ if (!I->InferAllTypes())
+ I->error("Could not infer all types in pattern!");
+
+ // InstInputs - Keep track of all of the inputs of the instruction, along
+ // with the record they are declared as.
+ std::map<std::string, TreePatternNode*> InstInputs;
+
+ // InstResults - Keep track of all the virtual registers that are 'set'
+ // in the instruction, including what reg class they are.
+ std::map<std::string, TreePatternNode*> InstResults;
+
+ std::vector<Record*> InstImpInputs;
+ std::vector<Record*> InstImpResults;
+
+ // Verify that the top-level forms in the instruction are of void type, and
+ // fill in the InstResults map.
+ for (unsigned j = 0, e = I->getNumTrees(); j != e; ++j) {
+ TreePatternNode *Pat = I->getTree(j);
+ if (Pat->getExtTypeNum(0) != MVT::isVoid)
+ I->error("Top-level forms in instruction pattern should have"
+ " void types");
+
+ // Find inputs and outputs, and verify the structure of the uses/defs.
+ FindPatternInputsAndOutputs(I, Pat, InstInputs, InstResults,
+ InstImpInputs, InstImpResults);
+ }
+
+ // Now that we have inputs and outputs of the pattern, inspect the operands
+ // list for the instruction. This determines the order that operands are
+ // added to the machine instruction the node corresponds to.
+ unsigned NumResults = InstResults.size();
+
+ // Parse the operands list from the (ops) list, validating it.
+ assert(I->getArgList().empty() && "Args list should still be empty here!");
+ CodeGenInstruction &CGI = Target.getInstruction(Instrs[i]->getName());
+
+ // Check that all of the results occur first in the list.
+ std::vector<Record*> Results;
+ TreePatternNode *Res0Node = NULL;
+ for (unsigned i = 0; i != NumResults; ++i) {
+ if (i == CGI.OperandList.size())
+ I->error("'" + InstResults.begin()->first +
+ "' set but does not appear in operand list!");
+ const std::string &OpName = CGI.OperandList[i].Name;
+
+ // Check that it exists in InstResults.
+ TreePatternNode *RNode = InstResults[OpName];
+ if (RNode == 0)
+ I->error("Operand $" + OpName + " does not exist in operand list!");
+
+ if (i == 0)
+ Res0Node = RNode;
+ Record *R = dynamic_cast<DefInit*>(RNode->getLeafValue())->getDef();
+ if (R == 0)
+ I->error("Operand $" + OpName + " should be a set destination: all "
+ "outputs must occur before inputs in operand list!");
+
+ if (CGI.OperandList[i].Rec != R)
+ I->error("Operand $" + OpName + " class mismatch!");
+
+ // Remember the return type.
+ Results.push_back(CGI.OperandList[i].Rec);
+
+ // Okay, this one checks out.
+ InstResults.erase(OpName);
+ }
+
+ // Loop over the inputs next. Make a copy of InstInputs so we can destroy
+ // the copy while we're checking the inputs.
+ std::map<std::string, TreePatternNode*> InstInputsCheck(InstInputs);
+
+ std::vector<TreePatternNode*> ResultNodeOperands;
+ std::vector<Record*> Operands;
+ for (unsigned i = NumResults, e = CGI.OperandList.size(); i != e; ++i) {
+ CodeGenInstruction::OperandInfo &Op = CGI.OperandList[i];
+ const std::string &OpName = Op.Name;
+ if (OpName.empty())
+ I->error("Operand #" + utostr(i) + " in operands list has no name!");
+
+ if (!InstInputsCheck.count(OpName)) {
+ // If this is an predicate operand or optional def operand with an
+ // DefaultOps set filled in, we can ignore this. When we codegen it,
+ // we will do so as always executed.
+ if (Op.Rec->isSubClassOf("PredicateOperand") ||
+ Op.Rec->isSubClassOf("OptionalDefOperand")) {
+ // Does it have a non-empty DefaultOps field? If so, ignore this
+ // operand.
+ if (!getDefaultOperand(Op.Rec).DefaultOps.empty())
+ continue;
+ }
+ I->error("Operand $" + OpName +
+ " does not appear in the instruction pattern");
+ }
+ TreePatternNode *InVal = InstInputsCheck[OpName];
+ InstInputsCheck.erase(OpName); // It occurred, remove from map.
+
+ if (InVal->isLeaf() &&
+ dynamic_cast<DefInit*>(InVal->getLeafValue())) {
+ Record *InRec = static_cast<DefInit*>(InVal->getLeafValue())->getDef();
+ if (Op.Rec != InRec && !InRec->isSubClassOf("ComplexPattern"))
+ I->error("Operand $" + OpName + "'s register class disagrees"
+ " between the operand and pattern");
+ }
+ Operands.push_back(Op.Rec);
+
+ // Construct the result for the dest-pattern operand list.
+ TreePatternNode *OpNode = InVal->clone();
+
+ // No predicate is useful on the result.
+ OpNode->setPredicateFn("");
+
+ // Promote the xform function to be an explicit node if set.
+ if (Record *Xform = OpNode->getTransformFn()) {
+ OpNode->setTransformFn(0);
+ std::vector<TreePatternNode*> Children;
+ Children.push_back(OpNode);
+ OpNode = new TreePatternNode(Xform, Children);
+ }
+
+ ResultNodeOperands.push_back(OpNode);
+ }
+
+ if (!InstInputsCheck.empty())
+ I->error("Input operand $" + InstInputsCheck.begin()->first +
+ " occurs in pattern but not in operands list!");
+
+ TreePatternNode *ResultPattern =
+ new TreePatternNode(I->getRecord(), ResultNodeOperands);
+ // Copy fully inferred output node type to instruction result pattern.
+ if (NumResults > 0)
+ ResultPattern->setTypes(Res0Node->getExtTypes());
+
+ // Create and insert the instruction.
+ DAGInstruction TheInst(I, Results, Operands, InstImpResults, InstImpInputs);
+ Instructions.insert(std::make_pair(I->getRecord(), TheInst));
+
+ // Use a temporary tree pattern to infer all types and make sure that the
+ // constructed result is correct. This depends on the instruction already
+ // being inserted into the Instructions map.
+ TreePattern Temp(I->getRecord(), ResultPattern, false, *this);
+ Temp.InferAllTypes();
+
+ DAGInstruction &TheInsertedInst = Instructions.find(I->getRecord())->second;
+ TheInsertedInst.setResultPattern(Temp.getOnlyTree());
+
+ DEBUG(I->dump());
+ }
+
+ // If we can, convert the instructions to be patterns that are matched!
+ for (std::map<Record*, DAGInstruction>::iterator II = Instructions.begin(),
+ E = Instructions.end(); II != E; ++II) {
+ DAGInstruction &TheInst = II->second;
+ TreePattern *I = TheInst.getPattern();
+ if (I == 0) continue; // No pattern.
+
+ if (I->getNumTrees() != 1) {
+ cerr << "CANNOT HANDLE: " << I->getRecord()->getName() << " yet!";
+ continue;
+ }
+ TreePatternNode *Pattern = I->getTree(0);
+ TreePatternNode *SrcPattern;
+ if (Pattern->getOperator()->getName() == "set") {
+ if (Pattern->getNumChildren() != 2)
+ continue; // Not a set of a single value (not handled so far)
+
+ SrcPattern = Pattern->getChild(1)->clone();
+ } else{
+ // Not a set (store or something?)
+ SrcPattern = Pattern;
+ }
+
+ std::string Reason;
+ if (!SrcPattern->canPatternMatch(Reason, *this))
+ I->error("Instruction can never match: " + Reason);
+
+ Record *Instr = II->first;
+ TreePatternNode *DstPattern = TheInst.getResultPattern();
+ PatternsToMatch.
+ push_back(PatternToMatch(Instr->getValueAsListInit("Predicates"),
+ SrcPattern, DstPattern,
+ Instr->getValueAsInt("AddedComplexity")));
+ }
+}
+
+void DAGISelEmitter::ParsePatterns() {
+ std::vector<Record*> Patterns = Records.getAllDerivedDefinitions("Pattern");
+
+ for (unsigned i = 0, e = Patterns.size(); i != e; ++i) {
+ DagInit *Tree = Patterns[i]->getValueAsDag("PatternToMatch");
+ TreePattern *Pattern = new TreePattern(Patterns[i], Tree, true, *this);
+
+ // Inline pattern fragments into it.
+ Pattern->InlinePatternFragments();
+
+ ListInit *LI = Patterns[i]->getValueAsListInit("ResultInstrs");
+ if (LI->getSize() == 0) continue; // no pattern.
+
+ // Parse the instruction.
+ TreePattern *Result = new TreePattern(Patterns[i], LI, false, *this);
+
+ // Inline pattern fragments into it.
+ Result->InlinePatternFragments();
+
+ if (Result->getNumTrees() != 1)
+ Result->error("Cannot handle instructions producing instructions "
+ "with temporaries yet!");
+
+ bool IterateInference;
+ bool InferredAllPatternTypes, InferredAllResultTypes;
+ do {
+ // Infer as many types as possible. If we cannot infer all of them, we
+ // can never do anything with this pattern: report it to the user.
+ InferredAllPatternTypes = Pattern->InferAllTypes();
+
+ // Infer as many types as possible. If we cannot infer all of them, we
+ // can never do anything with this pattern: report it to the user.
+ InferredAllResultTypes = Result->InferAllTypes();
+
+ // Apply the type of the result to the source pattern. This helps us
+ // resolve cases where the input type is known to be a pointer type (which
+ // is considered resolved), but the result knows it needs to be 32- or
+ // 64-bits. Infer the other way for good measure.
+ IterateInference = Pattern->getOnlyTree()->
+ UpdateNodeType(Result->getOnlyTree()->getExtTypes(), *Result);
+ IterateInference |= Result->getOnlyTree()->
+ UpdateNodeType(Pattern->getOnlyTree()->getExtTypes(), *Result);
+ } while (IterateInference);
+
+ // Verify that we inferred enough types that we can do something with the
+ // pattern and result. If these fire the user has to add type casts.
+ if (!InferredAllPatternTypes)
+ Pattern->error("Could not infer all types in pattern!");
+ if (!InferredAllResultTypes)
+ Result->error("Could not infer all types in pattern result!");
+
+ // Validate that the input pattern is correct.
+ {
+ std::map<std::string, TreePatternNode*> InstInputs;
+ std::map<std::string, TreePatternNode*> InstResults;
+ std::vector<Record*> InstImpInputs;
+ std::vector<Record*> InstImpResults;
+ FindPatternInputsAndOutputs(Pattern, Pattern->getOnlyTree(),
+ InstInputs, InstResults,
+ InstImpInputs, InstImpResults);
+ }
+
+ // Promote the xform function to be an explicit node if set.
+ std::vector<TreePatternNode*> ResultNodeOperands;
+ TreePatternNode *DstPattern = Result->getOnlyTree();
+ for (unsigned ii = 0, ee = DstPattern->getNumChildren(); ii != ee; ++ii) {
+ TreePatternNode *OpNode = DstPattern->getChild(ii);
+ if (Record *Xform = OpNode->getTransformFn()) {
+ OpNode->setTransformFn(0);
+ std::vector<TreePatternNode*> Children;
+ Children.push_back(OpNode);
+ OpNode = new TreePatternNode(Xform, Children);
+ }
+ ResultNodeOperands.push_back(OpNode);
+ }
+ DstPattern = Result->getOnlyTree();
+ if (!DstPattern->isLeaf())
+ DstPattern = new TreePatternNode(DstPattern->getOperator(),
+ ResultNodeOperands);
+ DstPattern->setTypes(Result->getOnlyTree()->getExtTypes());
+ TreePattern Temp(Result->getRecord(), DstPattern, false, *this);
+ Temp.InferAllTypes();
+
+ std::string Reason;
+ if (!Pattern->getOnlyTree()->canPatternMatch(Reason, *this))
+ Pattern->error("Pattern can never match: " + Reason);
+
+ PatternsToMatch.
+ push_back(PatternToMatch(Patterns[i]->getValueAsListInit("Predicates"),
+ Pattern->getOnlyTree(),
+ Temp.getOnlyTree(),
+ Patterns[i]->getValueAsInt("AddedComplexity")));
+ }
+}
+
+/// CombineChildVariants - Given a bunch of permutations of each child of the
+/// 'operator' node, put them together in all possible ways.
+static void CombineChildVariants(TreePatternNode *Orig,
+ const std::vector<std::vector<TreePatternNode*> > &ChildVariants,
+ std::vector<TreePatternNode*> &OutVariants,
+ DAGISelEmitter &ISE) {
+ // Make sure that each operand has at least one variant to choose from.
+ for (unsigned i = 0, e = ChildVariants.size(); i != e; ++i)
+ if (ChildVariants[i].empty())
+ return;
+
+ // The end result is an all-pairs construction of the resultant pattern.
+ std::vector<unsigned> Idxs;
+ Idxs.resize(ChildVariants.size());
+ bool NotDone = true;
+ while (NotDone) {
+ // Create the variant and add it to the output list.
+ std::vector<TreePatternNode*> NewChildren;
+ for (unsigned i = 0, e = ChildVariants.size(); i != e; ++i)
+ NewChildren.push_back(ChildVariants[i][Idxs[i]]);
+ TreePatternNode *R = new TreePatternNode(Orig->getOperator(), NewChildren);
+
+ // Copy over properties.
+ R->setName(Orig->getName());
+ R->setPredicateFn(Orig->getPredicateFn());
+ R->setTransformFn(Orig->getTransformFn());
+ R->setTypes(Orig->getExtTypes());
+
+ // If this pattern cannot every match, do not include it as a variant.
+ std::string ErrString;
+ if (!R->canPatternMatch(ErrString, ISE)) {
+ delete R;
+ } else {
+ bool AlreadyExists = false;
+
+ // Scan to see if this pattern has already been emitted. We can get
+ // duplication due to things like commuting:
+ // (and GPRC:$a, GPRC:$b) -> (and GPRC:$b, GPRC:$a)
+ // which are the same pattern. Ignore the dups.
+ for (unsigned i = 0, e = OutVariants.size(); i != e; ++i)
+ if (R->isIsomorphicTo(OutVariants[i])) {
+ AlreadyExists = true;
+ break;
+ }
+
+ if (AlreadyExists)
+ delete R;
+ else
+ OutVariants.push_back(R);
+ }
+
+ // Increment indices to the next permutation.
+ NotDone = false;
+ // Look for something we can increment without causing a wrap-around.
+ for (unsigned IdxsIdx = 0; IdxsIdx != Idxs.size(); ++IdxsIdx) {
+ if (++Idxs[IdxsIdx] < ChildVariants[IdxsIdx].size()) {
+ NotDone = true; // Found something to increment.
+ break;
+ }
+ Idxs[IdxsIdx] = 0;
+ }
+ }
+}
+
+/// CombineChildVariants - A helper function for binary operators.
+///
+static void CombineChildVariants(TreePatternNode *Orig,
+ const std::vector<TreePatternNode*> &LHS,
+ const std::vector<TreePatternNode*> &RHS,
+ std::vector<TreePatternNode*> &OutVariants,
+ DAGISelEmitter &ISE) {
+ std::vector<std::vector<TreePatternNode*> > ChildVariants;
+ ChildVariants.push_back(LHS);
+ ChildVariants.push_back(RHS);
+ CombineChildVariants(Orig, ChildVariants, OutVariants, ISE);
+}
+
+
+static void GatherChildrenOfAssociativeOpcode(TreePatternNode *N,
+ std::vector<TreePatternNode *> &Children) {
+ assert(N->getNumChildren()==2 &&"Associative but doesn't have 2 children!");
+ Record *Operator = N->getOperator();
+
+ // Only permit raw nodes.
+ if (!N->getName().empty() || !N->getPredicateFn().empty() ||
+ N->getTransformFn()) {
+ Children.push_back(N);
+ return;
+ }
+
+ if (N->getChild(0)->isLeaf() || N->getChild(0)->getOperator() != Operator)
+ Children.push_back(N->getChild(0));
+ else
+ GatherChildrenOfAssociativeOpcode(N->getChild(0), Children);
+
+ if (N->getChild(1)->isLeaf() || N->getChild(1)->getOperator() != Operator)
+ Children.push_back(N->getChild(1));
+ else
+ GatherChildrenOfAssociativeOpcode(N->getChild(1), Children);
+}
+
+/// GenerateVariantsOf - Given a pattern N, generate all permutations we can of
+/// the (potentially recursive) pattern by using algebraic laws.
+///
+static void GenerateVariantsOf(TreePatternNode *N,
+ std::vector<TreePatternNode*> &OutVariants,
+ DAGISelEmitter &ISE) {
+ // We cannot permute leaves.
+ if (N->isLeaf()) {
+ OutVariants.push_back(N);
+ return;
+ }
+
+ // Look up interesting info about the node.
+ const SDNodeInfo &NodeInfo = ISE.getSDNodeInfo(N->getOperator());
+
+ // If this node is associative, reassociate.
+ if (NodeInfo.hasProperty(SDNPAssociative)) {
+ // Reassociate by pulling together all of the linked operators
+ std::vector<TreePatternNode*> MaximalChildren;
+ GatherChildrenOfAssociativeOpcode(N, MaximalChildren);
+
+ // Only handle child sizes of 3. Otherwise we'll end up trying too many
+ // permutations.
+ if (MaximalChildren.size() == 3) {
+ // Find the variants of all of our maximal children.
+ std::vector<TreePatternNode*> AVariants, BVariants, CVariants;
+ GenerateVariantsOf(MaximalChildren[0], AVariants, ISE);
+ GenerateVariantsOf(MaximalChildren[1], BVariants, ISE);
+ GenerateVariantsOf(MaximalChildren[2], CVariants, ISE);
+
+ // There are only two ways we can permute the tree:
+ // (A op B) op C and A op (B op C)
+ // Within these forms, we can also permute A/B/C.
+
+ // Generate legal pair permutations of A/B/C.
+ std::vector<TreePatternNode*> ABVariants;
+ std::vector<TreePatternNode*> BAVariants;
+ std::vector<TreePatternNode*> ACVariants;
+ std::vector<TreePatternNode*> CAVariants;
+ std::vector<TreePatternNode*> BCVariants;
+ std::vector<TreePatternNode*> CBVariants;
+ CombineChildVariants(N, AVariants, BVariants, ABVariants, ISE);
+ CombineChildVariants(N, BVariants, AVariants, BAVariants, ISE);
+ CombineChildVariants(N, AVariants, CVariants, ACVariants, ISE);
+ CombineChildVariants(N, CVariants, AVariants, CAVariants, ISE);
+ CombineChildVariants(N, BVariants, CVariants, BCVariants, ISE);
+ CombineChildVariants(N, CVariants, BVariants, CBVariants, ISE);
+
+ // Combine those into the result: (x op x) op x
+ CombineChildVariants(N, ABVariants, CVariants, OutVariants, ISE);
+ CombineChildVariants(N, BAVariants, CVariants, OutVariants, ISE);
+ CombineChildVariants(N, ACVariants, BVariants, OutVariants, ISE);
+ CombineChildVariants(N, CAVariants, BVariants, OutVariants, ISE);
+ CombineChildVariants(N, BCVariants, AVariants, OutVariants, ISE);
+ CombineChildVariants(N, CBVariants, AVariants, OutVariants, ISE);
+
+ // Combine those into the result: x op (x op x)
+ CombineChildVariants(N, CVariants, ABVariants, OutVariants, ISE);
+ CombineChildVariants(N, CVariants, BAVariants, OutVariants, ISE);
+ CombineChildVariants(N, BVariants, ACVariants, OutVariants, ISE);
+ CombineChildVariants(N, BVariants, CAVariants, OutVariants, ISE);
+ CombineChildVariants(N, AVariants, BCVariants, OutVariants, ISE);
+ CombineChildVariants(N, AVariants, CBVariants, OutVariants, ISE);
+ return;
+ }
+ }
+
+ // Compute permutations of all children.
+ std::vector<std::vector<TreePatternNode*> > ChildVariants;
+ ChildVariants.resize(N->getNumChildren());
+ for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i)
+ GenerateVariantsOf(N->getChild(i), ChildVariants[i], ISE);
+
+ // Build all permutations based on how the children were formed.
+ CombineChildVariants(N, ChildVariants, OutVariants, ISE);
+
+ // If this node is commutative, consider the commuted order.
+ if (NodeInfo.hasProperty(SDNPCommutative)) {
+ assert(N->getNumChildren()==2 &&"Commutative but doesn't have 2 children!");
+ // Don't count children which are actually register references.
+ unsigned NC = 0;
+ for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) {
+ TreePatternNode *Child = N->getChild(i);
+ if (Child->isLeaf())
+ if (DefInit *DI = dynamic_cast<DefInit*>(Child->getLeafValue())) {
+ Record *RR = DI->getDef();
+ if (RR->isSubClassOf("Register"))
+ continue;
+ }
+ NC++;
+ }
+ // Consider the commuted order.
+ if (NC == 2)
+ CombineChildVariants(N, ChildVariants[1], ChildVariants[0],
+ OutVariants, ISE);
+ }
+}
+
+
+// GenerateVariants - Generate variants. For example, commutative patterns can
+// match multiple ways. Add them to PatternsToMatch as well.
+void DAGISelEmitter::GenerateVariants() {
+
+ DOUT << "Generating instruction variants.\n";
+
+ // Loop over all of the patterns we've collected, checking to see if we can
+ // generate variants of the instruction, through the exploitation of
+ // identities. This permits the target to provide agressive matching without
+ // the .td file having to contain tons of variants of instructions.
+ //
+ // Note that this loop adds new patterns to the PatternsToMatch list, but we
+ // intentionally do not reconsider these. Any variants of added patterns have
+ // already been added.
+ //
+ for (unsigned i = 0, e = PatternsToMatch.size(); i != e; ++i) {
+ std::vector<TreePatternNode*> Variants;
+ GenerateVariantsOf(PatternsToMatch[i].getSrcPattern(), Variants, *this);
+
+ assert(!Variants.empty() && "Must create at least original variant!");
+ Variants.erase(Variants.begin()); // Remove the original pattern.
+
+ if (Variants.empty()) // No variants for this pattern.
+ continue;
+
+ DOUT << "FOUND VARIANTS OF: ";
+ DEBUG(PatternsToMatch[i].getSrcPattern()->dump());
+ DOUT << "\n";
+
+ for (unsigned v = 0, e = Variants.size(); v != e; ++v) {
+ TreePatternNode *Variant = Variants[v];
+
+ DOUT << " VAR#" << v << ": ";
+ DEBUG(Variant->dump());
+ DOUT << "\n";
+
+ // Scan to see if an instruction or explicit pattern already matches this.
+ bool AlreadyExists = false;
+ for (unsigned p = 0, e = PatternsToMatch.size(); p != e; ++p) {
+ // Check to see if this variant already exists.
+ if (Variant->isIsomorphicTo(PatternsToMatch[p].getSrcPattern())) {
+ DOUT << " *** ALREADY EXISTS, ignoring variant.\n";
+ AlreadyExists = true;
+ break;
+ }
+ }
+ // If we already have it, ignore the variant.
+ if (AlreadyExists) continue;
+
+ // Otherwise, add it to the list of patterns we have.
+ PatternsToMatch.
+ push_back(PatternToMatch(PatternsToMatch[i].getPredicates(),
+ Variant, PatternsToMatch[i].getDstPattern(),
+ PatternsToMatch[i].getAddedComplexity()));
+ }
+
+ DOUT << "\n";
+ }
+}
+
+// NodeIsComplexPattern - return true if N is a leaf node and a subclass of
+// ComplexPattern.
+static bool NodeIsComplexPattern(TreePatternNode *N)
+{
+ return (N->isLeaf() &&
+ dynamic_cast<DefInit*>(N->getLeafValue()) &&
+ static_cast<DefInit*>(N->getLeafValue())->getDef()->
+ isSubClassOf("ComplexPattern"));
+}
+
+// NodeGetComplexPattern - return the pointer to the ComplexPattern if N
+// is a leaf node and a subclass of ComplexPattern, else it returns NULL.
+static const ComplexPattern *NodeGetComplexPattern(TreePatternNode *N,
+ DAGISelEmitter &ISE)
+{
+ if (N->isLeaf() &&
+ dynamic_cast<DefInit*>(N->getLeafValue()) &&
+ static_cast<DefInit*>(N->getLeafValue())->getDef()->
+ isSubClassOf("ComplexPattern")) {
+ return &ISE.getComplexPattern(static_cast<DefInit*>(N->getLeafValue())
+ ->getDef());
+ }
+ return NULL;
+}
+
+/// getPatternSize - Return the 'size' of this pattern. We want to match large
+/// patterns before small ones. This is used to determine the size of a
+/// pattern.
+static unsigned getPatternSize(TreePatternNode *P, DAGISelEmitter &ISE) {
+ assert((isExtIntegerInVTs(P->getExtTypes()) ||
+ isExtFloatingPointInVTs(P->getExtTypes()) ||
+ P->getExtTypeNum(0) == MVT::isVoid ||
+ P->getExtTypeNum(0) == MVT::Flag ||
+ P->getExtTypeNum(0) == MVT::iPTR) &&
+ "Not a valid pattern node to size!");
+ unsigned Size = 3; // The node itself.
+ // If the root node is a ConstantSDNode, increases its size.
+ // e.g. (set R32:$dst, 0).
+ if (P->isLeaf() && dynamic_cast<IntInit*>(P->getLeafValue()))
+ Size += 2;
+
+ // FIXME: This is a hack to statically increase the priority of patterns
+ // which maps a sub-dag to a complex pattern. e.g. favors LEA over ADD.
+ // Later we can allow complexity / cost for each pattern to be (optionally)
+ // specified. To get best possible pattern match we'll need to dynamically
+ // calculate the complexity of all patterns a dag can potentially map to.
+ const ComplexPattern *AM = NodeGetComplexPattern(P, ISE);
+ if (AM)
+ Size += AM->getNumOperands() * 3;
+
+ // If this node has some predicate function that must match, it adds to the
+ // complexity of this node.
+ if (!P->getPredicateFn().empty())
+ ++Size;
+
+ // Count children in the count if they are also nodes.
+ for (unsigned i = 0, e = P->getNumChildren(); i != e; ++i) {
+ TreePatternNode *Child = P->getChild(i);
+ if (!Child->isLeaf() && Child->getExtTypeNum(0) != MVT::Other)
+ Size += getPatternSize(Child, ISE);
+ else if (Child->isLeaf()) {
+ if (dynamic_cast<IntInit*>(Child->getLeafValue()))
+ Size += 5; // Matches a ConstantSDNode (+3) and a specific value (+2).
+ else if (NodeIsComplexPattern(Child))
+ Size += getPatternSize(Child, ISE);
+ else if (!Child->getPredicateFn().empty())
+ ++Size;
+ }
+ }
+
+ return Size;
+}
+
+/// getResultPatternCost - Compute the number of instructions for this pattern.
+/// This is a temporary hack. We should really include the instruction
+/// latencies in this calculation.
+static unsigned getResultPatternCost(TreePatternNode *P, DAGISelEmitter &ISE) {
+ if (P->isLeaf()) return 0;
+
+ unsigned Cost = 0;
+ Record *Op = P->getOperator();
+ if (Op->isSubClassOf("Instruction")) {
+ Cost++;
+ CodeGenInstruction &II = ISE.getTargetInfo().getInstruction(Op->getName());
+ if (II.usesCustomDAGSchedInserter)
+ Cost += 10;
+ }
+ for (unsigned i = 0, e = P->getNumChildren(); i != e; ++i)
+ Cost += getResultPatternCost(P->getChild(i), ISE);
+ return Cost;
+}
+
+/// getResultPatternCodeSize - Compute the code size of instructions for this
+/// pattern.
+static unsigned getResultPatternSize(TreePatternNode *P, DAGISelEmitter &ISE) {
+ if (P->isLeaf()) return 0;
+
+ unsigned Cost = 0;
+ Record *Op = P->getOperator();
+ if (Op->isSubClassOf("Instruction")) {
+ Cost += Op->getValueAsInt("CodeSize");
+ }
+ for (unsigned i = 0, e = P->getNumChildren(); i != e; ++i)
+ Cost += getResultPatternSize(P->getChild(i), ISE);
+ return Cost;
+}
+
+// PatternSortingPredicate - return true if we prefer to match LHS before RHS.
+// In particular, we want to match maximal patterns first and lowest cost within
+// a particular complexity first.
+struct PatternSortingPredicate {
+ PatternSortingPredicate(DAGISelEmitter &ise) : ISE(ise) {};
+ DAGISelEmitter &ISE;
+
+ bool operator()(PatternToMatch *LHS,
+ PatternToMatch *RHS) {
+ unsigned LHSSize = getPatternSize(LHS->getSrcPattern(), ISE);
+ unsigned RHSSize = getPatternSize(RHS->getSrcPattern(), ISE);
+ LHSSize += LHS->getAddedComplexity();
+ RHSSize += RHS->getAddedComplexity();
+ if (LHSSize > RHSSize) return true; // LHS -> bigger -> less cost
+ if (LHSSize < RHSSize) return false;
+
+ // If the patterns have equal complexity, compare generated instruction cost
+ unsigned LHSCost = getResultPatternCost(LHS->getDstPattern(), ISE);
+ unsigned RHSCost = getResultPatternCost(RHS->getDstPattern(), ISE);
+ if (LHSCost < RHSCost) return true;
+ if (LHSCost > RHSCost) return false;
+
+ return getResultPatternSize(LHS->getDstPattern(), ISE) <
+ getResultPatternSize(RHS->getDstPattern(), ISE);
+ }
+};
+
+/// getRegisterValueType - Look up and return the first ValueType of specified
+/// RegisterClass record
+static MVT::ValueType getRegisterValueType(Record *R, const CodeGenTarget &T) {
+ if (const CodeGenRegisterClass *RC = T.getRegisterClassForRegister(R))
+ return RC->getValueTypeNum(0);
+ return MVT::Other;
+}
+
+
+/// RemoveAllTypes - A quick recursive walk over a pattern which removes all
+/// type information from it.
+static void RemoveAllTypes(TreePatternNode *N) {
+ N->removeTypes();
+ if (!N->isLeaf())
+ for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i)
+ RemoveAllTypes(N->getChild(i));
+}
+
+Record *DAGISelEmitter::getSDNodeNamed(const std::string &Name) const {
+ Record *N = Records.getDef(Name);
+ if (!N || !N->isSubClassOf("SDNode")) {
+ cerr << "Error getting SDNode '" << Name << "'!\n";
+ exit(1);
+ }
+ return N;
+}
+
+/// NodeHasProperty - return true if TreePatternNode has the specified
+/// property.
+static bool NodeHasProperty(TreePatternNode *N, SDNP Property,
+ DAGISelEmitter &ISE)
+{
+ if (N->isLeaf()) {
+ const ComplexPattern *CP = NodeGetComplexPattern(N, ISE);
+ if (CP)
+ return CP->hasProperty(Property);
+ return false;
+ }
+ Record *Operator = N->getOperator();
+ if (!Operator->isSubClassOf("SDNode")) return false;
+
+ const SDNodeInfo &NodeInfo = ISE.getSDNodeInfo(Operator);
+ return NodeInfo.hasProperty(Property);
+}
+
+static bool PatternHasProperty(TreePatternNode *N, SDNP Property,
+ DAGISelEmitter &ISE)
+{
+ if (NodeHasProperty(N, Property, ISE))
+ return true;
+
+ for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) {
+ TreePatternNode *Child = N->getChild(i);
+ if (PatternHasProperty(Child, Property, ISE))
+ return true;
+ }
+
+ return false;
+}
+
+class PatternCodeEmitter {
+private:
+ DAGISelEmitter &ISE;
+
+ // Predicates.
+ ListInit *Predicates;
+ // Pattern cost.
+ unsigned Cost;
+ // Instruction selector pattern.
+ TreePatternNode *Pattern;
+ // Matched instruction.
+ TreePatternNode *Instruction;
+
+ // Node to name mapping
+ std::map<std::string, std::string> VariableMap;
+ // Node to operator mapping
+ std::map<std::string, Record*> OperatorMap;
+ // Names of all the folded nodes which produce chains.
+ std::vector<std::pair<std::string, unsigned> > FoldedChains;
+ // Original input chain(s).
+ std::vector<std::pair<std::string, std::string> > OrigChains;
+ std::set<std::string> Duplicates;
+
+ /// GeneratedCode - This is the buffer that we emit code to. The first int
+ /// indicates whether this is an exit predicate (something that should be
+ /// tested, and if true, the match fails) [when 1], or normal code to emit
+ /// [when 0], or initialization code to emit [when 2].
+ std::vector<std::pair<unsigned, std::string> > &GeneratedCode;
+ /// GeneratedDecl - This is the set of all SDOperand declarations needed for
+ /// the set of patterns for each top-level opcode.
+ std::set<std::string> &GeneratedDecl;
+ /// TargetOpcodes - The target specific opcodes used by the resulting
+ /// instructions.
+ std::vector<std::string> &TargetOpcodes;
+ std::vector<std::string> &TargetVTs;
+
+ std::string ChainName;
+ unsigned TmpNo;
+ unsigned OpcNo;
+ unsigned VTNo;
+
+ void emitCheck(const std::string &S) {
+ if (!S.empty())
+ GeneratedCode.push_back(std::make_pair(1, S));
+ }
+ void emitCode(const std::string &S) {
+ if (!S.empty())
+ GeneratedCode.push_back(std::make_pair(0, S));
+ }
+ void emitInit(const std::string &S) {
+ if (!S.empty())
+ GeneratedCode.push_back(std::make_pair(2, S));
+ }
+ void emitDecl(const std::string &S) {
+ assert(!S.empty() && "Invalid declaration");
+ GeneratedDecl.insert(S);
+ }
+ void emitOpcode(const std::string &Opc) {
+ TargetOpcodes.push_back(Opc);
+ OpcNo++;
+ }
+ void emitVT(const std::string &VT) {
+ TargetVTs.push_back(VT);
+ VTNo++;
+ }
+public:
+ PatternCodeEmitter(DAGISelEmitter &ise, ListInit *preds,
+ TreePatternNode *pattern, TreePatternNode *instr,
+ std::vector<std::pair<unsigned, std::string> > &gc,
+ std::set<std::string> &gd,
+ std::vector<std::string> &to,
+ std::vector<std::string> &tv)
+ : ISE(ise), Predicates(preds), Pattern(pattern), Instruction(instr),
+ GeneratedCode(gc), GeneratedDecl(gd),
+ TargetOpcodes(to), TargetVTs(tv),
+ TmpNo(0), OpcNo(0), VTNo(0) {}
+
+ /// EmitMatchCode - Emit a matcher for N, going to the label for PatternNo
+ /// if the match fails. At this point, we already know that the opcode for N
+ /// matches, and the SDNode for the result has the RootName specified name.
+ void EmitMatchCode(TreePatternNode *N, TreePatternNode *P,
+ const std::string &RootName, const std::string &ChainSuffix,
+ bool &FoundChain) {
+ bool isRoot = (P == NULL);
+ // Emit instruction predicates. Each predicate is just a string for now.
+ if (isRoot) {
+ std::string PredicateCheck;
+ for (unsigned i = 0, e = Predicates->getSize(); i != e; ++i) {
+ if (DefInit *Pred = dynamic_cast<DefInit*>(Predicates->getElement(i))) {
+ Record *Def = Pred->getDef();
+ if (!Def->isSubClassOf("Predicate")) {
+#ifndef NDEBUG
+ Def->dump();
+#endif
+ assert(0 && "Unknown predicate type!");
+ }
+ if (!PredicateCheck.empty())
+ PredicateCheck += " && ";
+ PredicateCheck += "(" + Def->getValueAsString("CondString") + ")";
+ }
+ }
+
+ emitCheck(PredicateCheck);
+ }
+
+ if (N->isLeaf()) {
+ if (IntInit *II = dynamic_cast<IntInit*>(N->getLeafValue())) {
+ emitCheck("cast<ConstantSDNode>(" + RootName +
+ ")->getSignExtended() == " + itostr(II->getValue()));
+ return;
+ } else if (!NodeIsComplexPattern(N)) {
+ assert(0 && "Cannot match this as a leaf value!");
+ abort();
+ }
+ }
+
+ // If this node has a name associated with it, capture it in VariableMap. If
+ // we already saw this in the pattern, emit code to verify dagness.
+ if (!N->getName().empty()) {
+ std::string &VarMapEntry = VariableMap[N->getName()];
+ if (VarMapEntry.empty()) {
+ VarMapEntry = RootName;
+ } else {
+ // If we get here, this is a second reference to a specific name. Since
+ // we already have checked that the first reference is valid, we don't
+ // have to recursively match it, just check that it's the same as the
+ // previously named thing.
+ emitCheck(VarMapEntry + " == " + RootName);
+ return;
+ }
+
+ if (!N->isLeaf())
+ OperatorMap[N->getName()] = N->getOperator();
+ }
+
+
+ // Emit code to load the child nodes and match their contents recursively.
+ unsigned OpNo = 0;
+ bool NodeHasChain = NodeHasProperty (N, SDNPHasChain, ISE);
+ bool HasChain = PatternHasProperty(N, SDNPHasChain, ISE);
+ bool EmittedUseCheck = false;
+ if (HasChain) {
+ if (NodeHasChain)
+ OpNo = 1;
+ if (!isRoot) {
+ // Multiple uses of actual result?
+ emitCheck(RootName + ".hasOneUse()");
+ EmittedUseCheck = true;
+ if (NodeHasChain) {
+ // If the immediate use can somehow reach this node through another
+ // path, then can't fold it either or it will create a cycle.
+ // e.g. In the following diagram, XX can reach ld through YY. If
+ // ld is folded into XX, then YY is both a predecessor and a successor
+ // of XX.
+ //
+ // [ld]
+ // ^ ^
+ // | |
+ // / \---
+ // / [YY]
+ // | ^
+ // [XX]-------|
+ bool NeedCheck = false;
+ if (P != Pattern)
+ NeedCheck = true;
+ else {
+ const SDNodeInfo &PInfo = ISE.getSDNodeInfo(P->getOperator());
+ NeedCheck =
+ P->getOperator() == ISE.get_intrinsic_void_sdnode() ||
+ P->getOperator() == ISE.get_intrinsic_w_chain_sdnode() ||
+ P->getOperator() == ISE.get_intrinsic_wo_chain_sdnode() ||
+ PInfo.getNumOperands() > 1 ||
+ PInfo.hasProperty(SDNPHasChain) ||
+ PInfo.hasProperty(SDNPInFlag) ||
+ PInfo.hasProperty(SDNPOptInFlag);
+ }
+
+ if (NeedCheck) {
+ std::string ParentName(RootName.begin(), RootName.end()-1);
+ emitCheck("CanBeFoldedBy(" + RootName + ".Val, " + ParentName +
+ ".Val, N.Val)");
+ }
+ }
+ }
+
+ if (NodeHasChain) {
+ if (FoundChain) {
+ emitCheck("(" + ChainName + ".Val == " + RootName + ".Val || "
+ "IsChainCompatible(" + ChainName + ".Val, " +
+ RootName + ".Val))");
+ OrigChains.push_back(std::make_pair(ChainName, RootName));
+ } else
+ FoundChain = true;
+ ChainName = "Chain" + ChainSuffix;
+ emitInit("SDOperand " + ChainName + " = " + RootName +
+ ".getOperand(0);");
+ }
+ }
+
+ // Don't fold any node which reads or writes a flag and has multiple uses.
+ // FIXME: We really need to separate the concepts of flag and "glue". Those
+ // real flag results, e.g. X86CMP output, can have multiple uses.
+ // FIXME: If the optional incoming flag does not exist. Then it is ok to
+ // fold it.
+ if (!isRoot &&
+ (PatternHasProperty(N, SDNPInFlag, ISE) ||
+ PatternHasProperty(N, SDNPOptInFlag, ISE) ||
+ PatternHasProperty(N, SDNPOutFlag, ISE))) {
+ if (!EmittedUseCheck) {
+ // Multiple uses of actual result?
+ emitCheck(RootName + ".hasOneUse()");
+ }
+ }
+
+ // If there is a node predicate for this, emit the call.
+ if (!N->getPredicateFn().empty())
+ emitCheck(N->getPredicateFn() + "(" + RootName + ".Val)");
+
+
+ // If this is an 'and R, 1234' where the operation is AND/OR and the RHS is
+ // a constant without a predicate fn that has more that one bit set, handle
+ // this as a special case. This is usually for targets that have special
+ // handling of certain large constants (e.g. alpha with it's 8/16/32-bit
+ // handling stuff). Using these instructions is often far more efficient
+ // than materializing the constant. Unfortunately, both the instcombiner
+ // and the dag combiner can often infer that bits are dead, and thus drop
+ // them from the mask in the dag. For example, it might turn 'AND X, 255'
+ // into 'AND X, 254' if it knows the low bit is set. Emit code that checks
+ // to handle this.
+ if (!N->isLeaf() &&
+ (N->getOperator()->getName() == "and" ||
+ N->getOperator()->getName() == "or") &&
+ N->getChild(1)->isLeaf() &&
+ N->getChild(1)->getPredicateFn().empty()) {
+ if (IntInit *II = dynamic_cast<IntInit*>(N->getChild(1)->getLeafValue())) {
+ if (!isPowerOf2_32(II->getValue())) { // Don't bother with single bits.
+ emitInit("SDOperand " + RootName + "0" + " = " +
+ RootName + ".getOperand(" + utostr(0) + ");");
+ emitInit("SDOperand " + RootName + "1" + " = " +
+ RootName + ".getOperand(" + utostr(1) + ");");
+
+ emitCheck("isa<ConstantSDNode>(" + RootName + "1)");
+ const char *MaskPredicate = N->getOperator()->getName() == "or"
+ ? "CheckOrMask(" : "CheckAndMask(";
+ emitCheck(MaskPredicate + RootName + "0, cast<ConstantSDNode>(" +
+ RootName + "1), " + itostr(II->getValue()) + ")");
+
+ EmitChildMatchCode(N->getChild(0), N, RootName + utostr(0),
+ ChainSuffix + utostr(0), FoundChain);
+ return;
+ }
+ }
+ }
+
+ for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i, ++OpNo) {
+ emitInit("SDOperand " + RootName + utostr(OpNo) + " = " +
+ RootName + ".getOperand(" +utostr(OpNo) + ");");
+
+ EmitChildMatchCode(N->getChild(i), N, RootName + utostr(OpNo),
+ ChainSuffix + utostr(OpNo), FoundChain);
+ }
+
+ // Handle cases when root is a complex pattern.
+ const ComplexPattern *CP;
+ if (isRoot && N->isLeaf() && (CP = NodeGetComplexPattern(N, ISE))) {
+ std::string Fn = CP->getSelectFunc();
+ unsigned NumOps = CP->getNumOperands();
+ for (unsigned i = 0; i < NumOps; ++i) {
+ emitDecl("CPTmp" + utostr(i));
+ emitCode("SDOperand CPTmp" + utostr(i) + ";");
+ }
+ if (CP->hasProperty(SDNPHasChain)) {
+ emitDecl("CPInChain");
+ emitDecl("Chain" + ChainSuffix);
+ emitCode("SDOperand CPInChain;");
+ emitCode("SDOperand Chain" + ChainSuffix + ";");
+ }
+
+ std::string Code = Fn + "(" + RootName + ", " + RootName;
+ for (unsigned i = 0; i < NumOps; i++)
+ Code += ", CPTmp" + utostr(i);
+ if (CP->hasProperty(SDNPHasChain)) {
+ ChainName = "Chain" + ChainSuffix;
+ Code += ", CPInChain, Chain" + ChainSuffix;
+ }
+ emitCheck(Code + ")");
+ }
+ }
+
+ void EmitChildMatchCode(TreePatternNode *Child, TreePatternNode *Parent,
+ const std::string &RootName,
+ const std::string &ChainSuffix, bool &FoundChain) {
+ if (!Child->isLeaf()) {
+ // If it's not a leaf, recursively match.
+ const SDNodeInfo &CInfo = ISE.getSDNodeInfo(Child->getOperator());
+ emitCheck(RootName + ".getOpcode() == " +
+ CInfo.getEnumName());
+ EmitMatchCode(Child, Parent, RootName, ChainSuffix, FoundChain);
+ if (NodeHasProperty(Child, SDNPHasChain, ISE))
+ FoldedChains.push_back(std::make_pair(RootName, CInfo.getNumResults()));
+ } else {
+ // If this child has a name associated with it, capture it in VarMap. If
+ // we already saw this in the pattern, emit code to verify dagness.
+ if (!Child->getName().empty()) {
+ std::string &VarMapEntry = VariableMap[Child->getName()];
+ if (VarMapEntry.empty()) {
+ VarMapEntry = RootName;
+ } else {
+ // If we get here, this is a second reference to a specific name.
+ // Since we already have checked that the first reference is valid,
+ // we don't have to recursively match it, just check that it's the
+ // same as the previously named thing.
+ emitCheck(VarMapEntry + " == " + RootName);
+ Duplicates.insert(RootName);
+ return;
+ }
+ }
+
+ // Handle leaves of various types.
+ if (DefInit *DI = dynamic_cast<DefInit*>(Child->getLeafValue())) {
+ Record *LeafRec = DI->getDef();
+ if (LeafRec->isSubClassOf("RegisterClass") ||
+ LeafRec->getName() == "ptr_rc") {
+ // Handle register references. Nothing to do here.
+ } else if (LeafRec->isSubClassOf("Register")) {
+ // Handle register references.
+ } else if (LeafRec->isSubClassOf("ComplexPattern")) {
+ // Handle complex pattern.
+ const ComplexPattern *CP = NodeGetComplexPattern(Child, ISE);
+ std::string Fn = CP->getSelectFunc();
+ unsigned NumOps = CP->getNumOperands();
+ for (unsigned i = 0; i < NumOps; ++i) {
+ emitDecl("CPTmp" + utostr(i));
+ emitCode("SDOperand CPTmp" + utostr(i) + ";");
+ }
+ if (CP->hasProperty(SDNPHasChain)) {
+ const SDNodeInfo &PInfo = ISE.getSDNodeInfo(Parent->getOperator());
+ FoldedChains.push_back(std::make_pair("CPInChain",
+ PInfo.getNumResults()));
+ ChainName = "Chain" + ChainSuffix;
+ emitDecl("CPInChain");
+ emitDecl(ChainName);
+ emitCode("SDOperand CPInChain;");
+ emitCode("SDOperand " + ChainName + ";");
+ }
+
+ std::string Code = Fn + "(N, ";
+ if (CP->hasProperty(SDNPHasChain)) {
+ std::string ParentName(RootName.begin(), RootName.end()-1);
+ Code += ParentName + ", ";
+ }
+ Code += RootName;
+ for (unsigned i = 0; i < NumOps; i++)
+ Code += ", CPTmp" + utostr(i);
+ if (CP->hasProperty(SDNPHasChain))
+ Code += ", CPInChain, Chain" + ChainSuffix;
+ emitCheck(Code + ")");
+ } else if (LeafRec->getName() == "srcvalue") {
+ // Place holder for SRCVALUE nodes. Nothing to do here.
+ } else if (LeafRec->isSubClassOf("ValueType")) {
+ // Make sure this is the specified value type.
+ emitCheck("cast<VTSDNode>(" + RootName +
+ ")->getVT() == MVT::" + LeafRec->getName());
+ } else if (LeafRec->isSubClassOf("CondCode")) {
+ // Make sure this is the specified cond code.
+ emitCheck("cast<CondCodeSDNode>(" + RootName +
+ ")->get() == ISD::" + LeafRec->getName());
+ } else {
+#ifndef NDEBUG
+ Child->dump();
+ cerr << " ";
+#endif
+ assert(0 && "Unknown leaf type!");
+ }
+
+ // If there is a node predicate for this, emit the call.
+ if (!Child->getPredicateFn().empty())
+ emitCheck(Child->getPredicateFn() + "(" + RootName +
+ ".Val)");
+ } else if (IntInit *II =
+ dynamic_cast<IntInit*>(Child->getLeafValue())) {
+ emitCheck("isa<ConstantSDNode>(" + RootName + ")");
+ unsigned CTmp = TmpNo++;
+ emitCode("int64_t CN"+utostr(CTmp)+" = cast<ConstantSDNode>("+
+ RootName + ")->getSignExtended();");
+
+ emitCheck("CN" + utostr(CTmp) + " == " +itostr(II->getValue()));
+ } else {
+#ifndef NDEBUG
+ Child->dump();
+#endif
+ assert(0 && "Unknown leaf type!");
+ }
+ }
+ }
+
+ /// EmitResultCode - Emit the action for a pattern. Now that it has matched
+ /// we actually have to build a DAG!
+ std::vector<std::string>
+ EmitResultCode(TreePatternNode *N, bool RetSelected,
+ bool InFlagDecled, bool ResNodeDecled,
+ bool LikeLeaf = false, bool isRoot = false) {
+ // List of arguments of getTargetNode() or SelectNodeTo().
+ std::vector<std::string> NodeOps;
+ // This is something selected from the pattern we matched.
+ if (!N->getName().empty()) {
+ std::string &Val = VariableMap[N->getName()];
+ assert(!Val.empty() &&
+ "Variable referenced but not defined and not caught earlier!");
+ if (Val[0] == 'T' && Val[1] == 'm' && Val[2] == 'p') {
+ // Already selected this operand, just return the tmpval.
+ NodeOps.push_back(Val);
+ return NodeOps;
+ }
+
+ const ComplexPattern *CP;
+ unsigned ResNo = TmpNo++;
+ if (!N->isLeaf() && N->getOperator()->getName() == "imm") {
+ assert(N->getExtTypes().size() == 1 && "Multiple types not handled!");
+ std::string CastType;
+ switch (N->getTypeNum(0)) {
+ default:
+ cerr << "Cannot handle " << getEnumName(N->getTypeNum(0))
+ << " type as an immediate constant. Aborting\n";
+ abort();
+ case MVT::i1: CastType = "bool"; break;
+ case MVT::i8: CastType = "unsigned char"; break;
+ case MVT::i16: CastType = "unsigned short"; break;
+ case MVT::i32: CastType = "unsigned"; break;
+ case MVT::i64: CastType = "uint64_t"; break;
+ }
+ emitCode("SDOperand Tmp" + utostr(ResNo) +
+ " = CurDAG->getTargetConstant(((" + CastType +
+ ") cast<ConstantSDNode>(" + Val + ")->getValue()), " +
+ getEnumName(N->getTypeNum(0)) + ");");
+ NodeOps.push_back("Tmp" + utostr(ResNo));
+ // Add Tmp<ResNo> to VariableMap, so that we don't multiply select this
+ // value if used multiple times by this pattern result.
+ Val = "Tmp"+utostr(ResNo);
+ } else if (!N->isLeaf() && N->getOperator()->getName() == "texternalsym"){
+ Record *Op = OperatorMap[N->getName()];
+ // Transform ExternalSymbol to TargetExternalSymbol
+ if (Op && Op->getName() == "externalsym") {
+ emitCode("SDOperand Tmp" + utostr(ResNo) + " = CurDAG->getTarget"
+ "ExternalSymbol(cast<ExternalSymbolSDNode>(" +
+ Val + ")->getSymbol(), " +
+ getEnumName(N->getTypeNum(0)) + ");");
+ NodeOps.push_back("Tmp" + utostr(ResNo));
+ // Add Tmp<ResNo> to VariableMap, so that we don't multiply select
+ // this value if used multiple times by this pattern result.
+ Val = "Tmp"+utostr(ResNo);
+ } else {
+ NodeOps.push_back(Val);
+ }
+ } else if (!N->isLeaf() && (N->getOperator()->getName() == "tglobaladdr"
+ || N->getOperator()->getName() == "tglobaltlsaddr")) {
+ Record *Op = OperatorMap[N->getName()];
+ // Transform GlobalAddress to TargetGlobalAddress
+ if (Op && (Op->getName() == "globaladdr" ||
+ Op->getName() == "globaltlsaddr")) {
+ emitCode("SDOperand Tmp" + utostr(ResNo) + " = CurDAG->getTarget"
+ "GlobalAddress(cast<GlobalAddressSDNode>(" + Val +
+ ")->getGlobal(), " + getEnumName(N->getTypeNum(0)) +
+ ");");
+ NodeOps.push_back("Tmp" + utostr(ResNo));
+ // Add Tmp<ResNo> to VariableMap, so that we don't multiply select
+ // this value if used multiple times by this pattern result.
+ Val = "Tmp"+utostr(ResNo);
+ } else {
+ NodeOps.push_back(Val);
+ }
+ } else if (!N->isLeaf() && N->getOperator()->getName() == "texternalsym"){
+ NodeOps.push_back(Val);
+ // Add Tmp<ResNo> to VariableMap, so that we don't multiply select this
+ // value if used multiple times by this pattern result.
+ Val = "Tmp"+utostr(ResNo);
+ } else if (!N->isLeaf() && N->getOperator()->getName() == "tconstpool") {
+ NodeOps.push_back(Val);
+ // Add Tmp<ResNo> to VariableMap, so that we don't multiply select this
+ // value if used multiple times by this pattern result.
+ Val = "Tmp"+utostr(ResNo);
+ } else if (N->isLeaf() && (CP = NodeGetComplexPattern(N, ISE))) {
+ for (unsigned i = 0; i < CP->getNumOperands(); ++i) {
+ emitCode("AddToISelQueue(CPTmp" + utostr(i) + ");");
+ NodeOps.push_back("CPTmp" + utostr(i));
+ }
+ } else {
+ // This node, probably wrapped in a SDNodeXForm, behaves like a leaf
+ // node even if it isn't one. Don't select it.
+ if (!LikeLeaf) {
+ emitCode("AddToISelQueue(" + Val + ");");
+ if (isRoot && N->isLeaf()) {
+ emitCode("ReplaceUses(N, " + Val + ");");
+ emitCode("return NULL;");
+ }
+ }
+ NodeOps.push_back(Val);
+ }
+ return NodeOps;
+ }
+ if (N->isLeaf()) {
+ // If this is an explicit register reference, handle it.
+ if (DefInit *DI = dynamic_cast<DefInit*>(N->getLeafValue())) {
+ unsigned ResNo = TmpNo++;
+ if (DI->getDef()->isSubClassOf("Register")) {
+ emitCode("SDOperand Tmp" + utostr(ResNo) + " = CurDAG->getRegister(" +
+ ISE.getQualifiedName(DI->getDef()) + ", " +
+ getEnumName(N->getTypeNum(0)) + ");");
+ NodeOps.push_back("Tmp" + utostr(ResNo));
+ return NodeOps;
+ } else if (DI->getDef()->getName() == "zero_reg") {
+ emitCode("SDOperand Tmp" + utostr(ResNo) +
+ " = CurDAG->getRegister(0, " +
+ getEnumName(N->getTypeNum(0)) + ");");
+ NodeOps.push_back("Tmp" + utostr(ResNo));
+ return NodeOps;
+ }
+ } else if (IntInit *II = dynamic_cast<IntInit*>(N->getLeafValue())) {
+ unsigned ResNo = TmpNo++;
+ assert(N->getExtTypes().size() == 1 && "Multiple types not handled!");
+ emitCode("SDOperand Tmp" + utostr(ResNo) +
+ " = CurDAG->getTargetConstant(" + itostr(II->getValue()) +
+ ", " + getEnumName(N->getTypeNum(0)) + ");");
+ NodeOps.push_back("Tmp" + utostr(ResNo));
+ return NodeOps;
+ }
+
+#ifndef NDEBUG
+ N->dump();
+#endif
+ assert(0 && "Unknown leaf type!");
+ return NodeOps;
+ }
+
+ Record *Op = N->getOperator();
+ if (Op->isSubClassOf("Instruction")) {
+ const CodeGenTarget &CGT = ISE.getTargetInfo();
+ CodeGenInstruction &II = CGT.getInstruction(Op->getName());
+ const DAGInstruction &Inst = ISE.getInstruction(Op);
+ TreePattern *InstPat = Inst.getPattern();
+ TreePatternNode *InstPatNode =
+ isRoot ? (InstPat ? InstPat->getOnlyTree() : Pattern)
+ : (InstPat ? InstPat->getOnlyTree() : NULL);
+ if (InstPatNode && InstPatNode->getOperator()->getName() == "set") {
+ InstPatNode = InstPatNode->getChild(1);
+ }
+ bool HasVarOps = isRoot && II.hasVariableNumberOfOperands;
+ bool HasImpInputs = isRoot && Inst.getNumImpOperands() > 0;
+ bool HasImpResults = isRoot && Inst.getNumImpResults() > 0;
+ bool NodeHasOptInFlag = isRoot &&
+ PatternHasProperty(Pattern, SDNPOptInFlag, ISE);
+ bool NodeHasInFlag = isRoot &&
+ PatternHasProperty(Pattern, SDNPInFlag, ISE);
+ bool NodeHasOutFlag = HasImpResults || (isRoot &&
+ PatternHasProperty(Pattern, SDNPOutFlag, ISE));
+ bool NodeHasChain = InstPatNode &&
+ PatternHasProperty(InstPatNode, SDNPHasChain, ISE);
+ bool InputHasChain = isRoot &&
+ NodeHasProperty(Pattern, SDNPHasChain, ISE);
+ unsigned NumResults = Inst.getNumResults();
+
+ if (NodeHasOptInFlag) {
+ emitCode("bool HasInFlag = "
+ "(N.getOperand(N.getNumOperands()-1).getValueType() == MVT::Flag);");
+ }
+ if (HasVarOps)
+ emitCode("SmallVector<SDOperand, 8> Ops" + utostr(OpcNo) + ";");
+
+ // How many results is this pattern expected to produce?
+ unsigned PatResults = 0;
+ for (unsigned i = 0, e = Pattern->getExtTypes().size(); i != e; i++) {
+ MVT::ValueType VT = Pattern->getTypeNum(i);
+ if (VT != MVT::isVoid && VT != MVT::Flag)
+ PatResults++;
+ }
+
+ if (OrigChains.size() > 0) {
+ // The original input chain is being ignored. If it is not just
+ // pointing to the op that's being folded, we should create a
+ // TokenFactor with it and the chain of the folded op as the new chain.
+ // We could potentially be doing multiple levels of folding, in that
+ // case, the TokenFactor can have more operands.
+ emitCode("SmallVector<SDOperand, 8> InChains;");
+ for (unsigned i = 0, e = OrigChains.size(); i < e; ++i) {
+ emitCode("if (" + OrigChains[i].first + ".Val != " +
+ OrigChains[i].second + ".Val) {");
+ emitCode(" AddToISelQueue(" + OrigChains[i].first + ");");
+ emitCode(" InChains.push_back(" + OrigChains[i].first + ");");
+ emitCode("}");
+ }
+ emitCode("AddToISelQueue(" + ChainName + ");");
+ emitCode("InChains.push_back(" + ChainName + ");");
+ emitCode(ChainName + " = CurDAG->getNode(ISD::TokenFactor, MVT::Other, "
+ "&InChains[0], InChains.size());");
+ }
+
+ // Loop over all of the operands of the instruction pattern, emitting code
+ // to fill them all in. The node 'N' usually has number children equal to
+ // the number of input operands of the instruction. However, in cases
+ // where there are predicate operands for an instruction, we need to fill
+ // in the 'execute always' values. Match up the node operands to the
+ // instruction operands to do this.
+ std::vector<std::string> AllOps;
+ unsigned NumEAInputs = 0; // # of synthesized 'execute always' inputs.
+ for (unsigned ChildNo = 0, InstOpNo = NumResults;
+ InstOpNo != II.OperandList.size(); ++InstOpNo) {
+ std::vector<std::string> Ops;
+
+ // If this is a normal operand or a predicate operand without
+ // 'execute always', emit it.
+ Record *OperandNode = II.OperandList[InstOpNo].Rec;
+ if ((!OperandNode->isSubClassOf("PredicateOperand") &&
+ !OperandNode->isSubClassOf("OptionalDefOperand")) ||
+ ISE.getDefaultOperand(OperandNode).DefaultOps.empty()) {
+ Ops = EmitResultCode(N->getChild(ChildNo), RetSelected,
+ InFlagDecled, ResNodeDecled);
+ AllOps.insert(AllOps.end(), Ops.begin(), Ops.end());
+ ++ChildNo;
+ } else {
+ // Otherwise, this is a predicate or optional def operand, emit the
+ // 'default ops' operands.
+ const DAGDefaultOperand &DefaultOp =
+ ISE.getDefaultOperand(II.OperandList[InstOpNo].Rec);
+ for (unsigned i = 0, e = DefaultOp.DefaultOps.size(); i != e; ++i) {
+ Ops = EmitResultCode(DefaultOp.DefaultOps[i], RetSelected,
+ InFlagDecled, ResNodeDecled);
+ AllOps.insert(AllOps.end(), Ops.begin(), Ops.end());
+ NumEAInputs += Ops.size();
+ }
+ }
+ }
+
+ // Emit all the chain and CopyToReg stuff.
+ bool ChainEmitted = NodeHasChain;
+ if (NodeHasChain)
+ emitCode("AddToISelQueue(" + ChainName + ");");
+ if (NodeHasInFlag || HasImpInputs)
+ EmitInFlagSelectCode(Pattern, "N", ChainEmitted,
+ InFlagDecled, ResNodeDecled, true);
+ if (NodeHasOptInFlag || NodeHasInFlag || HasImpInputs) {
+ if (!InFlagDecled) {
+ emitCode("SDOperand InFlag(0, 0);");
+ InFlagDecled = true;
+ }
+ if (NodeHasOptInFlag) {
+ emitCode("if (HasInFlag) {");
+ emitCode(" InFlag = N.getOperand(N.getNumOperands()-1);");
+ emitCode(" AddToISelQueue(InFlag);");
+ emitCode("}");
+ }
+ }
+
+ unsigned ResNo = TmpNo++;
+ if (!isRoot || InputHasChain || NodeHasChain || NodeHasOutFlag ||
+ NodeHasOptInFlag) {
+ std::string Code;
+ std::string Code2;
+ std::string NodeName;
+ if (!isRoot) {
+ NodeName = "Tmp" + utostr(ResNo);
+ Code2 = "SDOperand " + NodeName + " = SDOperand(";
+ } else {
+ NodeName = "ResNode";
+ if (!ResNodeDecled) {
+ Code2 = "SDNode *" + NodeName + " = ";
+ ResNodeDecled = true;
+ } else
+ Code2 = NodeName + " = ";
+ }
+
+ Code = "CurDAG->getTargetNode(Opc" + utostr(OpcNo);
+ unsigned OpsNo = OpcNo;
+ emitOpcode(II.Namespace + "::" + II.TheDef->getName());
+
+ // Output order: results, chain, flags
+ // Result types.
+ if (NumResults > 0 && N->getTypeNum(0) != MVT::isVoid) {
+ Code += ", VT" + utostr(VTNo);
+ emitVT(getEnumName(N->getTypeNum(0)));
+ }
+ if (NodeHasChain)
+ Code += ", MVT::Other";
+ if (NodeHasOutFlag)
+ Code += ", MVT::Flag";
+
+ // Figure out how many fixed inputs the node has. This is important to
+ // know which inputs are the variable ones if present.
+ unsigned NumInputs = AllOps.size();
+ NumInputs += NodeHasChain;
+
+ // Inputs.
+ if (HasVarOps) {
+ for (unsigned i = 0, e = AllOps.size(); i != e; ++i)
+ emitCode("Ops" + utostr(OpsNo) + ".push_back(" + AllOps[i] + ");");
+ AllOps.clear();
+ }
+
+ if (HasVarOps) {
+ // Figure out whether any operands at the end of the op list are not
+ // part of the variable section.
+ std::string EndAdjust;
+ if (NodeHasInFlag || HasImpInputs)
+ EndAdjust = "-1"; // Always has one flag.
+ else if (NodeHasOptInFlag)
+ EndAdjust = "-(HasInFlag?1:0)"; // May have a flag.
+
+ emitCode("for (unsigned i = " + utostr(NumInputs - NumEAInputs) +
+ ", e = N.getNumOperands()" + EndAdjust + "; i != e; ++i) {");
+
+ emitCode(" AddToISelQueue(N.getOperand(i));");
+ emitCode(" Ops" + utostr(OpsNo) + ".push_back(N.getOperand(i));");
+ emitCode("}");
+ }
+
+ if (NodeHasChain) {
+ if (HasVarOps)
+ emitCode("Ops" + utostr(OpsNo) + ".push_back(" + ChainName + ");");
+ else
+ AllOps.push_back(ChainName);
+ }
+
+ if (HasVarOps) {
+ if (NodeHasInFlag || HasImpInputs)
+ emitCode("Ops" + utostr(OpsNo) + ".push_back(InFlag);");
+ else if (NodeHasOptInFlag) {
+ emitCode("if (HasInFlag)");
+ emitCode(" Ops" + utostr(OpsNo) + ".push_back(InFlag);");
+ }
+ Code += ", &Ops" + utostr(OpsNo) + "[0], Ops" + utostr(OpsNo) +
+ ".size()";
+ } else if (NodeHasInFlag || NodeHasOptInFlag || HasImpInputs)
+ AllOps.push_back("InFlag");
+
+ unsigned NumOps = AllOps.size();
+ if (NumOps) {
+ if (!NodeHasOptInFlag && NumOps < 4) {
+ for (unsigned i = 0; i != NumOps; ++i)
+ Code += ", " + AllOps[i];
+ } else {
+ std::string OpsCode = "SDOperand Ops" + utostr(OpsNo) + "[] = { ";
+ for (unsigned i = 0; i != NumOps; ++i) {
+ OpsCode += AllOps[i];
+ if (i != NumOps-1)
+ OpsCode += ", ";
+ }
+ emitCode(OpsCode + " };");
+ Code += ", Ops" + utostr(OpsNo) + ", ";
+ if (NodeHasOptInFlag) {
+ Code += "HasInFlag ? ";
+ Code += utostr(NumOps) + " : " + utostr(NumOps-1);
+ } else
+ Code += utostr(NumOps);
+ }
+ }
+
+ if (!isRoot)
+ Code += "), 0";
+ emitCode(Code2 + Code + ");");
+
+ if (NodeHasChain)
+ // Remember which op produces the chain.
+ if (!isRoot)
+ emitCode(ChainName + " = SDOperand(" + NodeName +
+ ".Val, " + utostr(PatResults) + ");");
+ else
+ emitCode(ChainName + " = SDOperand(" + NodeName +
+ ", " + utostr(PatResults) + ");");
+
+ if (!isRoot) {
+ NodeOps.push_back("Tmp" + utostr(ResNo));
+ return NodeOps;
+ }
+
+ bool NeedReplace = false;
+ if (NodeHasOutFlag) {
+ if (!InFlagDecled) {
+ emitCode("SDOperand InFlag = SDOperand(ResNode, " +
+ utostr(NumResults + (unsigned)NodeHasChain) + ");");
+ InFlagDecled = true;
+ } else
+ emitCode("InFlag = SDOperand(ResNode, " +
+ utostr(NumResults + (unsigned)NodeHasChain) + ");");
+ }
+
+ if (HasImpResults && EmitCopyFromRegs(N, ResNodeDecled, ChainEmitted)) {
+ emitCode("ReplaceUses(SDOperand(N.Val, 0), SDOperand(ResNode, 0));");
+ NumResults = 1;
+ }
+
+ if (FoldedChains.size() > 0) {
+ std::string Code;
+ for (unsigned j = 0, e = FoldedChains.size(); j < e; j++)
+ emitCode("ReplaceUses(SDOperand(" +
+ FoldedChains[j].first + ".Val, " +
+ utostr(FoldedChains[j].second) + "), SDOperand(ResNode, " +
+ utostr(NumResults) + "));");
+ NeedReplace = true;
+ }
+
+ if (NodeHasOutFlag) {
+ emitCode("ReplaceUses(SDOperand(N.Val, " +
+ utostr(PatResults + (unsigned)InputHasChain) +"), InFlag);");
+ NeedReplace = true;
+ }
+
+ if (NeedReplace) {
+ for (unsigned i = 0; i < NumResults; i++)
+ emitCode("ReplaceUses(SDOperand(N.Val, " +
+ utostr(i) + "), SDOperand(ResNode, " + utostr(i) + "));");
+ if (InputHasChain)
+ emitCode("ReplaceUses(SDOperand(N.Val, " +
+ utostr(PatResults) + "), SDOperand(" + ChainName + ".Val, "
+ + ChainName + ".ResNo" + "));");
+ } else
+ RetSelected = true;
+
+ // User does not expect the instruction would produce a chain!
+ if ((!InputHasChain && NodeHasChain) && NodeHasOutFlag) {
+ ;
+ } else if (InputHasChain && !NodeHasChain) {
+ // One of the inner node produces a chain.
+ if (NodeHasOutFlag)
+ emitCode("ReplaceUses(SDOperand(N.Val, " + utostr(PatResults+1) +
+ "), SDOperand(ResNode, N.ResNo-1));");
+ for (unsigned i = 0; i < PatResults; ++i)
+ emitCode("ReplaceUses(SDOperand(N.Val, " + utostr(i) +
+ "), SDOperand(ResNode, " + utostr(i) + "));");
+ emitCode("ReplaceUses(SDOperand(N.Val, " + utostr(PatResults) +
+ "), " + ChainName + ");");
+ RetSelected = false;
+ }
+
+ if (RetSelected)
+ emitCode("return ResNode;");
+ else
+ emitCode("return NULL;");
+ } else {
+ std::string Code = "return CurDAG->SelectNodeTo(N.Val, Opc" +
+ utostr(OpcNo);
+ if (N->getTypeNum(0) != MVT::isVoid)
+ Code += ", VT" + utostr(VTNo);
+ if (NodeHasOutFlag)
+ Code += ", MVT::Flag";
+
+ if (NodeHasInFlag || NodeHasOptInFlag || HasImpInputs)
+ AllOps.push_back("InFlag");
+
+ unsigned NumOps = AllOps.size();
+ if (NumOps) {
+ if (!NodeHasOptInFlag && NumOps < 4) {
+ for (unsigned i = 0; i != NumOps; ++i)
+ Code += ", " + AllOps[i];
+ } else {
+ std::string OpsCode = "SDOperand Ops" + utostr(OpcNo) + "[] = { ";
+ for (unsigned i = 0; i != NumOps; ++i) {
+ OpsCode += AllOps[i];
+ if (i != NumOps-1)
+ OpsCode += ", ";
+ }
+ emitCode(OpsCode + " };");
+ Code += ", Ops" + utostr(OpcNo) + ", ";
+ Code += utostr(NumOps);
+ }
+ }
+ emitCode(Code + ");");
+ emitOpcode(II.Namespace + "::" + II.TheDef->getName());
+ if (N->getTypeNum(0) != MVT::isVoid)
+ emitVT(getEnumName(N->getTypeNum(0)));
+ }
+
+ return NodeOps;
+ } else if (Op->isSubClassOf("SDNodeXForm")) {
+ assert(N->getNumChildren() == 1 && "node xform should have one child!");
+ // PatLeaf node - the operand may or may not be a leaf node. But it should
+ // behave like one.
+ std::vector<std::string> Ops =
+ EmitResultCode(N->getChild(0), RetSelected, InFlagDecled,
+ ResNodeDecled, true);
+ unsigned ResNo = TmpNo++;
+ emitCode("SDOperand Tmp" + utostr(ResNo) + " = Transform_" + Op->getName()
+ + "(" + Ops.back() + ".Val);");
+ NodeOps.push_back("Tmp" + utostr(ResNo));
+ if (isRoot)
+ emitCode("return Tmp" + utostr(ResNo) + ".Val;");
+ return NodeOps;
+ } else {
+ N->dump();
+ cerr << "\n";
+ throw std::string("Unknown node in result pattern!");
+ }
+ }
+
+ /// InsertOneTypeCheck - Insert a type-check for an unresolved type in 'Pat'
+ /// and add it to the tree. 'Pat' and 'Other' are isomorphic trees except that
+ /// 'Pat' may be missing types. If we find an unresolved type to add a check
+ /// for, this returns true otherwise false if Pat has all types.
+ bool InsertOneTypeCheck(TreePatternNode *Pat, TreePatternNode *Other,
+ const std::string &Prefix, bool isRoot = false) {
+ // Did we find one?
+ if (Pat->getExtTypes() != Other->getExtTypes()) {
+ // Move a type over from 'other' to 'pat'.
+ Pat->setTypes(Other->getExtTypes());
+ // The top level node type is checked outside of the select function.
+ if (!isRoot)
+ emitCheck(Prefix + ".Val->getValueType(0) == " +
+ getName(Pat->getTypeNum(0)));
+ return true;
+ }
+
+ unsigned OpNo =
+ (unsigned) NodeHasProperty(Pat, SDNPHasChain, ISE);
+ for (unsigned i = 0, e = Pat->getNumChildren(); i != e; ++i, ++OpNo)
+ if (InsertOneTypeCheck(Pat->getChild(i), Other->getChild(i),
+ Prefix + utostr(OpNo)))
+ return true;
+ return false;
+ }
+
+private:
+ /// EmitInFlagSelectCode - Emit the flag operands for the DAG that is
+ /// being built.
+ void EmitInFlagSelectCode(TreePatternNode *N, const std::string &RootName,
+ bool &ChainEmitted, bool &InFlagDecled,
+ bool &ResNodeDecled, bool isRoot = false) {
+ const CodeGenTarget &T = ISE.getTargetInfo();
+ unsigned OpNo =
+ (unsigned) NodeHasProperty(N, SDNPHasChain, ISE);
+ bool HasInFlag = NodeHasProperty(N, SDNPInFlag, ISE);
+ for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i, ++OpNo) {
+ TreePatternNode *Child = N->getChild(i);
+ if (!Child->isLeaf()) {
+ EmitInFlagSelectCode(Child, RootName + utostr(OpNo), ChainEmitted,
+ InFlagDecled, ResNodeDecled);
+ } else {
+ if (DefInit *DI = dynamic_cast<DefInit*>(Child->getLeafValue())) {
+ if (!Child->getName().empty()) {
+ std::string Name = RootName + utostr(OpNo);
+ if (Duplicates.find(Name) != Duplicates.end())
+ // A duplicate! Do not emit a copy for this node.
+ continue;
+ }
+
+ Record *RR = DI->getDef();
+ if (RR->isSubClassOf("Register")) {
+ MVT::ValueType RVT = getRegisterValueType(RR, T);
+ if (RVT == MVT::Flag) {
+ if (!InFlagDecled) {
+ emitCode("SDOperand InFlag = " + RootName + utostr(OpNo) + ";");
+ InFlagDecled = true;
+ } else
+ emitCode("InFlag = " + RootName + utostr(OpNo) + ";");
+ emitCode("AddToISelQueue(InFlag);");
+ } else {
+ if (!ChainEmitted) {
+ emitCode("SDOperand Chain = CurDAG->getEntryNode();");
+ ChainName = "Chain";
+ ChainEmitted = true;
+ }
+ emitCode("AddToISelQueue(" + RootName + utostr(OpNo) + ");");
+ if (!InFlagDecled) {
+ emitCode("SDOperand InFlag(0, 0);");
+ InFlagDecled = true;
+ }
+ std::string Decl = (!ResNodeDecled) ? "SDNode *" : "";
+ emitCode(Decl + "ResNode = CurDAG->getCopyToReg(" + ChainName +
+ ", " + ISE.getQualifiedName(RR) +
+ ", " + RootName + utostr(OpNo) + ", InFlag).Val;");
+ ResNodeDecled = true;
+ emitCode(ChainName + " = SDOperand(ResNode, 0);");
+ emitCode("InFlag = SDOperand(ResNode, 1);");
+ }
+ }
+ }
+ }
+ }
+
+ if (HasInFlag) {
+ if (!InFlagDecled) {
+ emitCode("SDOperand InFlag = " + RootName +
+ ".getOperand(" + utostr(OpNo) + ");");
+ InFlagDecled = true;
+ } else
+ emitCode("InFlag = " + RootName +
+ ".getOperand(" + utostr(OpNo) + ");");
+ emitCode("AddToISelQueue(InFlag);");
+ }
+ }
+
+ /// EmitCopyFromRegs - Emit code to copy result to physical registers
+ /// as specified by the instruction. It returns true if any copy is
+ /// emitted.
+ bool EmitCopyFromRegs(TreePatternNode *N, bool &ResNodeDecled,
+ bool &ChainEmitted) {
+ bool RetVal = false;
+ Record *Op = N->getOperator();
+ if (Op->isSubClassOf("Instruction")) {
+ const DAGInstruction &Inst = ISE.getInstruction(Op);
+ const CodeGenTarget &CGT = ISE.getTargetInfo();
+ unsigned NumImpResults = Inst.getNumImpResults();
+ for (unsigned i = 0; i < NumImpResults; i++) {
+ Record *RR = Inst.getImpResult(i);
+ if (RR->isSubClassOf("Register")) {
+ MVT::ValueType RVT = getRegisterValueType(RR, CGT);
+ if (RVT != MVT::Flag) {
+ if (!ChainEmitted) {
+ emitCode("SDOperand Chain = CurDAG->getEntryNode();");
+ ChainEmitted = true;
+ ChainName = "Chain";
+ }
+ std::string Decl = (!ResNodeDecled) ? "SDNode *" : "";
+ emitCode(Decl + "ResNode = CurDAG->getCopyFromReg(" + ChainName +
+ ", " + ISE.getQualifiedName(RR) + ", " + getEnumName(RVT) +
+ ", InFlag).Val;");
+ ResNodeDecled = true;
+ emitCode(ChainName + " = SDOperand(ResNode, 1);");
+ emitCode("InFlag = SDOperand(ResNode, 2);");
+ RetVal = true;
+ }
+ }
+ }
+ }
+ return RetVal;
+ }
+};
+
+/// EmitCodeForPattern - Given a pattern to match, emit code to the specified
+/// stream to match the pattern, and generate the code for the match if it
+/// succeeds. Returns true if the pattern is not guaranteed to match.
+void DAGISelEmitter::GenerateCodeForPattern(PatternToMatch &Pattern,
+ std::vector<std::pair<unsigned, std::string> > &GeneratedCode,
+ std::set<std::string> &GeneratedDecl,
+ std::vector<std::string> &TargetOpcodes,
+ std::vector<std::string> &TargetVTs) {
+ PatternCodeEmitter Emitter(*this, Pattern.getPredicates(),
+ Pattern.getSrcPattern(), Pattern.getDstPattern(),
+ GeneratedCode, GeneratedDecl,
+ TargetOpcodes, TargetVTs);
+
+ // Emit the matcher, capturing named arguments in VariableMap.
+ bool FoundChain = false;
+ Emitter.EmitMatchCode(Pattern.getSrcPattern(), NULL, "N", "", FoundChain);
+
+ // TP - Get *SOME* tree pattern, we don't care which.
+ TreePattern &TP = *PatternFragments.begin()->second;
+
+ // At this point, we know that we structurally match the pattern, but the
+ // types of the nodes may not match. Figure out the fewest number of type
+ // comparisons we need to emit. For example, if there is only one integer
+ // type supported by a target, there should be no type comparisons at all for
+ // integer patterns!
+ //
+ // To figure out the fewest number of type checks needed, clone the pattern,
+ // remove the types, then perform type inference on the pattern as a whole.
+ // If there are unresolved types, emit an explicit check for those types,
+ // apply the type to the tree, then rerun type inference. Iterate until all
+ // types are resolved.
+ //
+ TreePatternNode *Pat = Pattern.getSrcPattern()->clone();
+ RemoveAllTypes(Pat);
+
+ do {
+ // Resolve/propagate as many types as possible.
+ try {
+ bool MadeChange = true;
+ while (MadeChange)
+ MadeChange = Pat->ApplyTypeConstraints(TP,
+ true/*Ignore reg constraints*/);
+ } catch (...) {
+ assert(0 && "Error: could not find consistent types for something we"
+ " already decided was ok!");
+ abort();
+ }
+
+ // Insert a check for an unresolved type and add it to the tree. If we find
+ // an unresolved type to add a check for, this returns true and we iterate,
+ // otherwise we are done.
+ } while (Emitter.InsertOneTypeCheck(Pat, Pattern.getSrcPattern(), "N", true));
+
+ Emitter.EmitResultCode(Pattern.getDstPattern(),
+ false, false, false, false, true);
+ delete Pat;
+}
+
+/// EraseCodeLine - Erase one code line from all of the patterns. If removing
+/// a line causes any of them to be empty, remove them and return true when
+/// done.
+static bool EraseCodeLine(std::vector<std::pair<PatternToMatch*,
+ std::vector<std::pair<unsigned, std::string> > > >
+ &Patterns) {
+ bool ErasedPatterns = false;
+ for (unsigned i = 0, e = Patterns.size(); i != e; ++i) {
+ Patterns[i].second.pop_back();
+ if (Patterns[i].second.empty()) {
+ Patterns.erase(Patterns.begin()+i);
+ --i; --e;
+ ErasedPatterns = true;
+ }
+ }
+ return ErasedPatterns;
+}
+
+/// EmitPatterns - Emit code for at least one pattern, but try to group common
+/// code together between the patterns.
+void DAGISelEmitter::EmitPatterns(std::vector<std::pair<PatternToMatch*,
+ std::vector<std::pair<unsigned, std::string> > > >
+ &Patterns, unsigned Indent,
+ std::ostream &OS) {
+ typedef std::pair<unsigned, std::string> CodeLine;
+ typedef std::vector<CodeLine> CodeList;
+ typedef std::vector<std::pair<PatternToMatch*, CodeList> > PatternList;
+
+ if (Patterns.empty()) return;
+
+ // Figure out how many patterns share the next code line. Explicitly copy
+ // FirstCodeLine so that we don't invalidate a reference when changing
+ // Patterns.
+ const CodeLine FirstCodeLine = Patterns.back().second.back();
+ unsigned LastMatch = Patterns.size()-1;
+ while (LastMatch != 0 && Patterns[LastMatch-1].second.back() == FirstCodeLine)
+ --LastMatch;
+
+ // If not all patterns share this line, split the list into two pieces. The
+ // first chunk will use this line, the second chunk won't.
+ if (LastMatch != 0) {
+ PatternList Shared(Patterns.begin()+LastMatch, Patterns.end());
+ PatternList Other(Patterns.begin(), Patterns.begin()+LastMatch);
+
+ // FIXME: Emit braces?
+ if (Shared.size() == 1) {
+ PatternToMatch &Pattern = *Shared.back().first;
+ OS << "\n" << std::string(Indent, ' ') << "// Pattern: ";
+ Pattern.getSrcPattern()->print(OS);
+ OS << "\n" << std::string(Indent, ' ') << "// Emits: ";
+ Pattern.getDstPattern()->print(OS);
+ OS << "\n";
+ unsigned AddedComplexity = Pattern.getAddedComplexity();
+ OS << std::string(Indent, ' ') << "// Pattern complexity = "
+ << getPatternSize(Pattern.getSrcPattern(), *this) + AddedComplexity
+ << " cost = "
+ << getResultPatternCost(Pattern.getDstPattern(), *this)
+ << " size = "
+ << getResultPatternSize(Pattern.getDstPattern(), *this) << "\n";
+ }
+ if (FirstCodeLine.first != 1) {
+ OS << std::string(Indent, ' ') << "{\n";
+ Indent += 2;
+ }
+ EmitPatterns(Shared, Indent, OS);
+ if (FirstCodeLine.first != 1) {
+ Indent -= 2;
+ OS << std::string(Indent, ' ') << "}\n";
+ }
+
+ if (Other.size() == 1) {
+ PatternToMatch &Pattern = *Other.back().first;
+ OS << "\n" << std::string(Indent, ' ') << "// Pattern: ";
+ Pattern.getSrcPattern()->print(OS);
+ OS << "\n" << std::string(Indent, ' ') << "// Emits: ";
+ Pattern.getDstPattern()->print(OS);
+ OS << "\n";
+ unsigned AddedComplexity = Pattern.getAddedComplexity();
+ OS << std::string(Indent, ' ') << "// Pattern complexity = "
+ << getPatternSize(Pattern.getSrcPattern(), *this) + AddedComplexity
+ << " cost = "
+ << getResultPatternCost(Pattern.getDstPattern(), *this)
+ << " size = "
+ << getResultPatternSize(Pattern.getDstPattern(), *this) << "\n";
+ }
+ EmitPatterns(Other, Indent, OS);
+ return;
+ }
+
+ // Remove this code from all of the patterns that share it.
+ bool ErasedPatterns = EraseCodeLine(Patterns);
+
+ bool isPredicate = FirstCodeLine.first == 1;
+
+ // Otherwise, every pattern in the list has this line. Emit it.
+ if (!isPredicate) {
+ // Normal code.
+ OS << std::string(Indent, ' ') << FirstCodeLine.second << "\n";
+ } else {
+ OS << std::string(Indent, ' ') << "if (" << FirstCodeLine.second;
+
+ // If the next code line is another predicate, and if all of the pattern
+ // in this group share the same next line, emit it inline now. Do this
+ // until we run out of common predicates.
+ while (!ErasedPatterns && Patterns.back().second.back().first == 1) {
+ // Check that all of fhe patterns in Patterns end with the same predicate.
+ bool AllEndWithSamePredicate = true;
+ for (unsigned i = 0, e = Patterns.size(); i != e; ++i)
+ if (Patterns[i].second.back() != Patterns.back().second.back()) {
+ AllEndWithSamePredicate = false;
+ break;
+ }
+ // If all of the predicates aren't the same, we can't share them.
+ if (!AllEndWithSamePredicate) break;
+
+ // Otherwise we can. Emit it shared now.
+ OS << " &&\n" << std::string(Indent+4, ' ')
+ << Patterns.back().second.back().second;
+ ErasedPatterns = EraseCodeLine(Patterns);
+ }
+
+ OS << ") {\n";
+ Indent += 2;
+ }
+
+ EmitPatterns(Patterns, Indent, OS);
+
+ if (isPredicate)
+ OS << std::string(Indent-2, ' ') << "}\n";
+}
+
+static std::string getOpcodeName(Record *Op, DAGISelEmitter &ISE) {
+ const SDNodeInfo &OpcodeInfo = ISE.getSDNodeInfo(Op);
+ return OpcodeInfo.getEnumName();
+}
+
+static std::string getLegalCName(std::string OpName) {
+ std::string::size_type pos = OpName.find("::");
+ if (pos != std::string::npos)
+ OpName.replace(pos, 2, "_");
+ return OpName;
+}
+
+void DAGISelEmitter::EmitInstructionSelector(std::ostream &OS) {
+ // Get the namespace to insert instructions into. Make sure not to pick up
+ // "TargetInstrInfo" by accidentally getting the namespace off the PHI
+ // instruction or something.
+ std::string InstNS;
+ for (CodeGenTarget::inst_iterator i = Target.inst_begin(),
+ e = Target.inst_end(); i != e; ++i) {
+ InstNS = i->second.Namespace;
+ if (InstNS != "TargetInstrInfo")
+ break;
+ }
+
+ if (!InstNS.empty()) InstNS += "::";
+
+ // Group the patterns by their top-level opcodes.
+ std::map<std::string, std::vector<PatternToMatch*> > PatternsByOpcode;
+ // All unique target node emission functions.
+ std::map<std::string, unsigned> EmitFunctions;
+ for (unsigned i = 0, e = PatternsToMatch.size(); i != e; ++i) {
+ TreePatternNode *Node = PatternsToMatch[i].getSrcPattern();
+ if (!Node->isLeaf()) {
+ PatternsByOpcode[getOpcodeName(Node->getOperator(), *this)].
+ push_back(&PatternsToMatch[i]);
+ } else {
+ const ComplexPattern *CP;
+ if (dynamic_cast<IntInit*>(Node->getLeafValue())) {
+ PatternsByOpcode[getOpcodeName(getSDNodeNamed("imm"), *this)].
+ push_back(&PatternsToMatch[i]);
+ } else if ((CP = NodeGetComplexPattern(Node, *this))) {
+ std::vector<Record*> OpNodes = CP->getRootNodes();
+ for (unsigned j = 0, e = OpNodes.size(); j != e; j++) {
+ PatternsByOpcode[getOpcodeName(OpNodes[j], *this)]
+ .insert(PatternsByOpcode[getOpcodeName(OpNodes[j], *this)].begin(),
+ &PatternsToMatch[i]);
+ }
+ } else {
+ cerr << "Unrecognized opcode '";
+ Node->dump();
+ cerr << "' on tree pattern '";
+ cerr << PatternsToMatch[i].getDstPattern()->getOperator()->getName();
+ cerr << "'!\n";
+ exit(1);
+ }
+ }
+ }
+
+ // For each opcode, there might be multiple select functions, one per
+ // ValueType of the node (or its first operand if it doesn't produce a
+ // non-chain result.
+ std::map<std::string, std::vector<std::string> > OpcodeVTMap;
+
+ // Emit one Select_* method for each top-level opcode. We do this instead of
+ // emitting one giant switch statement to support compilers where this will
+ // result in the recursive functions taking less stack space.
+ for (std::map<std::string, std::vector<PatternToMatch*> >::iterator
+ PBOI = PatternsByOpcode.begin(), E = PatternsByOpcode.end();
+ PBOI != E; ++PBOI) {
+ const std::string &OpName = PBOI->first;
+ std::vector<PatternToMatch*> &PatternsOfOp = PBOI->second;
+ assert(!PatternsOfOp.empty() && "No patterns but map has entry?");
+
+ // We want to emit all of the matching code now. However, we want to emit
+ // the matches in order of minimal cost. Sort the patterns so the least
+ // cost one is at the start.
+ std::stable_sort(PatternsOfOp.begin(), PatternsOfOp.end(),
+ PatternSortingPredicate(*this));
+
+ // Split them into groups by type.
+ std::map<MVT::ValueType, std::vector<PatternToMatch*> > PatternsByType;
+ for (unsigned i = 0, e = PatternsOfOp.size(); i != e; ++i) {
+ PatternToMatch *Pat = PatternsOfOp[i];
+ TreePatternNode *SrcPat = Pat->getSrcPattern();
+ MVT::ValueType VT = SrcPat->getTypeNum(0);
+ std::map<MVT::ValueType, std::vector<PatternToMatch*> >::iterator TI =
+ PatternsByType.find(VT);
+ if (TI != PatternsByType.end())
+ TI->second.push_back(Pat);
+ else {
+ std::vector<PatternToMatch*> PVec;
+ PVec.push_back(Pat);
+ PatternsByType.insert(std::make_pair(VT, PVec));
+ }
+ }
+
+ for (std::map<MVT::ValueType, std::vector<PatternToMatch*> >::iterator
+ II = PatternsByType.begin(), EE = PatternsByType.end(); II != EE;
+ ++II) {
+ MVT::ValueType OpVT = II->first;
+ std::vector<PatternToMatch*> &Patterns = II->second;
+ typedef std::vector<std::pair<unsigned,std::string> > CodeList;
+ typedef std::vector<std::pair<unsigned,std::string> >::iterator CodeListI;
+
+ std::vector<std::pair<PatternToMatch*, CodeList> > CodeForPatterns;
+ std::vector<std::vector<std::string> > PatternOpcodes;
+ std::vector<std::vector<std::string> > PatternVTs;
+ std::vector<std::set<std::string> > PatternDecls;
+ for (unsigned i = 0, e = Patterns.size(); i != e; ++i) {
+ CodeList GeneratedCode;
+ std::set<std::string> GeneratedDecl;
+ std::vector<std::string> TargetOpcodes;
+ std::vector<std::string> TargetVTs;
+ GenerateCodeForPattern(*Patterns[i], GeneratedCode, GeneratedDecl,
+ TargetOpcodes, TargetVTs);
+ CodeForPatterns.push_back(std::make_pair(Patterns[i], GeneratedCode));
+ PatternDecls.push_back(GeneratedDecl);
+ PatternOpcodes.push_back(TargetOpcodes);
+ PatternVTs.push_back(TargetVTs);
+ }
+
+ // Scan the code to see if all of the patterns are reachable and if it is
+ // possible that the last one might not match.
+ bool mightNotMatch = true;
+ for (unsigned i = 0, e = CodeForPatterns.size(); i != e; ++i) {
+ CodeList &GeneratedCode = CodeForPatterns[i].second;
+ mightNotMatch = false;
+
+ for (unsigned j = 0, e = GeneratedCode.size(); j != e; ++j) {
+ if (GeneratedCode[j].first == 1) { // predicate.
+ mightNotMatch = true;
+ break;
+ }
+ }
+
+ // If this pattern definitely matches, and if it isn't the last one, the
+ // patterns after it CANNOT ever match. Error out.
+ if (mightNotMatch == false && i != CodeForPatterns.size()-1) {
+ cerr << "Pattern '";
+ CodeForPatterns[i].first->getSrcPattern()->print(*cerr.stream());
+ cerr << "' is impossible to select!\n";
+ exit(1);
+ }
+ }
+
+ // Factor target node emission code (emitted by EmitResultCode) into
+ // separate functions. Uniquing and share them among all instruction
+ // selection routines.
+ for (unsigned i = 0, e = CodeForPatterns.size(); i != e; ++i) {
+ CodeList &GeneratedCode = CodeForPatterns[i].second;
+ std::vector<std::string> &TargetOpcodes = PatternOpcodes[i];
+ std::vector<std::string> &TargetVTs = PatternVTs[i];
+ std::set<std::string> Decls = PatternDecls[i];
+ std::vector<std::string> AddedInits;
+ int CodeSize = (int)GeneratedCode.size();
+ int LastPred = -1;
+ for (int j = CodeSize-1; j >= 0; --j) {
+ if (LastPred == -1 && GeneratedCode[j].first == 1)
+ LastPred = j;
+ else if (LastPred != -1 && GeneratedCode[j].first == 2)
+ AddedInits.push_back(GeneratedCode[j].second);
+ }
+
+ std::string CalleeCode = "(const SDOperand &N";
+ std::string CallerCode = "(N";
+ for (unsigned j = 0, e = TargetOpcodes.size(); j != e; ++j) {
+ CalleeCode += ", unsigned Opc" + utostr(j);
+ CallerCode += ", " + TargetOpcodes[j];
+ }
+ for (unsigned j = 0, e = TargetVTs.size(); j != e; ++j) {
+ CalleeCode += ", MVT::ValueType VT" + utostr(j);
+ CallerCode += ", " + TargetVTs[j];
+ }
+ for (std::set<std::string>::iterator
+ I = Decls.begin(), E = Decls.end(); I != E; ++I) {
+ std::string Name = *I;
+ CalleeCode += ", SDOperand &" + Name;
+ CallerCode += ", " + Name;
+ }
+ CallerCode += ");";
+ CalleeCode += ") ";
+ // Prevent emission routines from being inlined to reduce selection
+ // routines stack frame sizes.
+ CalleeCode += "DISABLE_INLINE ";
+ CalleeCode += "{\n";
+
+ for (std::vector<std::string>::const_reverse_iterator
+ I = AddedInits.rbegin(), E = AddedInits.rend(); I != E; ++I)
+ CalleeCode += " " + *I + "\n";
+
+ for (int j = LastPred+1; j < CodeSize; ++j)
+ CalleeCode += " " + GeneratedCode[j].second + "\n";
+ for (int j = LastPred+1; j < CodeSize; ++j)
+ GeneratedCode.pop_back();
+ CalleeCode += "}\n";
+
+ // Uniquing the emission routines.
+ unsigned EmitFuncNum;
+ std::map<std::string, unsigned>::iterator EFI =
+ EmitFunctions.find(CalleeCode);
+ if (EFI != EmitFunctions.end()) {
+ EmitFuncNum = EFI->second;
+ } else {
+ EmitFuncNum = EmitFunctions.size();
+ EmitFunctions.insert(std::make_pair(CalleeCode, EmitFuncNum));
+ OS << "SDNode *Emit_" << utostr(EmitFuncNum) << CalleeCode;
+ }
+
+ // Replace the emission code within selection routines with calls to the
+ // emission functions.
+ CallerCode = "return Emit_" + utostr(EmitFuncNum) + CallerCode;
+ GeneratedCode.push_back(std::make_pair(false, CallerCode));
+ }
+
+ // Print function.
+ std::string OpVTStr;
+ if (OpVT == MVT::iPTR) {
+ OpVTStr = "_iPTR";
+ } else if (OpVT == MVT::isVoid) {
+ // Nodes with a void result actually have a first result type of either
+ // Other (a chain) or Flag. Since there is no one-to-one mapping from
+ // void to this case, we handle it specially here.
+ } else {
+ OpVTStr = "_" + getEnumName(OpVT).substr(5); // Skip 'MVT::'
+ }
+ std::map<std::string, std::vector<std::string> >::iterator OpVTI =
+ OpcodeVTMap.find(OpName);
+ if (OpVTI == OpcodeVTMap.end()) {
+ std::vector<std::string> VTSet;
+ VTSet.push_back(OpVTStr);
+ OpcodeVTMap.insert(std::make_pair(OpName, VTSet));
+ } else
+ OpVTI->second.push_back(OpVTStr);
+
+ OS << "SDNode *Select_" << getLegalCName(OpName)
+ << OpVTStr << "(const SDOperand &N) {\n";
+
+ // Loop through and reverse all of the CodeList vectors, as we will be
+ // accessing them from their logical front, but accessing the end of a
+ // vector is more efficient.
+ for (unsigned i = 0, e = CodeForPatterns.size(); i != e; ++i) {
+ CodeList &GeneratedCode = CodeForPatterns[i].second;
+ std::reverse(GeneratedCode.begin(), GeneratedCode.end());
+ }
+
+ // Next, reverse the list of patterns itself for the same reason.
+ std::reverse(CodeForPatterns.begin(), CodeForPatterns.end());
+
+ // Emit all of the patterns now, grouped together to share code.
+ EmitPatterns(CodeForPatterns, 2, OS);
+
+ // If the last pattern has predicates (which could fail) emit code to
+ // catch the case where nothing handles a pattern.
+ if (mightNotMatch) {
+ OS << " cerr << \"Cannot yet select: \";\n";
+ if (OpName != "ISD::INTRINSIC_W_CHAIN" &&
+ OpName != "ISD::INTRINSIC_WO_CHAIN" &&
+ OpName != "ISD::INTRINSIC_VOID") {
+ OS << " N.Val->dump(CurDAG);\n";
+ } else {
+ OS << " unsigned iid = cast<ConstantSDNode>(N.getOperand("
+ "N.getOperand(0).getValueType() == MVT::Other))->getValue();\n"
+ << " cerr << \"intrinsic %\"<< "
+ "Intrinsic::getName((Intrinsic::ID)iid);\n";
+ }
+ OS << " cerr << '\\n';\n"
+ << " abort();\n"
+ << " return NULL;\n";
+ }
+ OS << "}\n\n";
+ }
+ }
+
+ // Emit boilerplate.
+ OS << "SDNode *Select_INLINEASM(SDOperand N) {\n"
+ << " std::vector<SDOperand> Ops(N.Val->op_begin(), N.Val->op_end());\n"
+ << " SelectInlineAsmMemoryOperands(Ops, *CurDAG);\n\n"
+
+ << " // Ensure that the asm operands are themselves selected.\n"
+ << " for (unsigned j = 0, e = Ops.size(); j != e; ++j)\n"
+ << " AddToISelQueue(Ops[j]);\n\n"
+
+ << " std::vector<MVT::ValueType> VTs;\n"
+ << " VTs.push_back(MVT::Other);\n"
+ << " VTs.push_back(MVT::Flag);\n"
+ << " SDOperand New = CurDAG->getNode(ISD::INLINEASM, VTs, &Ops[0], "
+ "Ops.size());\n"
+ << " return New.Val;\n"
+ << "}\n\n";
+
+ OS << "SDNode *Select_LABEL(const SDOperand &N) {\n"
+ << " SDOperand Chain = N.getOperand(0);\n"
+ << " SDOperand N1 = N.getOperand(1);\n"
+ << " unsigned C = cast<ConstantSDNode>(N1)->getValue();\n"
+ << " SDOperand Tmp = CurDAG->getTargetConstant(C, MVT::i32);\n"
+ << " AddToISelQueue(Chain);\n"
+ << " return CurDAG->getTargetNode(TargetInstrInfo::LABEL,\n"
+ << " MVT::Other, Tmp, Chain);\n"
+ << "}\n\n";
+
+ OS << "// The main instruction selector code.\n"
+ << "SDNode *SelectCode(SDOperand N) {\n"
+ << " if (N.getOpcode() >= ISD::BUILTIN_OP_END &&\n"
+ << " N.getOpcode() < (ISD::BUILTIN_OP_END+" << InstNS
+ << "INSTRUCTION_LIST_END)) {\n"
+ << " return NULL; // Already selected.\n"
+ << " }\n\n"
+ << " MVT::ValueType NVT = N.Val->getValueType(0);\n"
+ << " switch (N.getOpcode()) {\n"
+ << " default: break;\n"
+ << " case ISD::EntryToken: // These leaves remain the same.\n"
+ << " case ISD::BasicBlock:\n"
+ << " case ISD::Register:\n"
+ << " case ISD::HANDLENODE:\n"
+ << " case ISD::TargetConstant:\n"
+ << " case ISD::TargetConstantPool:\n"
+ << " case ISD::TargetFrameIndex:\n"
+ << " case ISD::TargetExternalSymbol:\n"
+ << " case ISD::TargetJumpTable:\n"
+ << " case ISD::TargetGlobalTLSAddress:\n"
+ << " case ISD::TargetGlobalAddress: {\n"
+ << " return NULL;\n"
+ << " }\n"
+ << " case ISD::AssertSext:\n"
+ << " case ISD::AssertZext: {\n"
+ << " AddToISelQueue(N.getOperand(0));\n"
+ << " ReplaceUses(N, N.getOperand(0));\n"
+ << " return NULL;\n"
+ << " }\n"
+ << " case ISD::TokenFactor:\n"
+ << " case ISD::CopyFromReg:\n"
+ << " case ISD::CopyToReg: {\n"
+ << " for (unsigned i = 0, e = N.getNumOperands(); i != e; ++i)\n"
+ << " AddToISelQueue(N.getOperand(i));\n"
+ << " return NULL;\n"
+ << " }\n"
+ << " case ISD::INLINEASM: return Select_INLINEASM(N);\n"
+ << " case ISD::LABEL: return Select_LABEL(N);\n";
+
+
+ // Loop over all of the case statements, emiting a call to each method we
+ // emitted above.
+ for (std::map<std::string, std::vector<PatternToMatch*> >::iterator
+ PBOI = PatternsByOpcode.begin(), E = PatternsByOpcode.end();
+ PBOI != E; ++PBOI) {
+ const std::string &OpName = PBOI->first;
+ // Potentially multiple versions of select for this opcode. One for each
+ // ValueType of the node (or its first true operand if it doesn't produce a
+ // result.
+ std::map<std::string, std::vector<std::string> >::iterator OpVTI =
+ OpcodeVTMap.find(OpName);
+ std::vector<std::string> &OpVTs = OpVTI->second;
+ OS << " case " << OpName << ": {\n";
+ if (OpVTs.size() == 1) {
+ std::string &VTStr = OpVTs[0];
+ OS << " return Select_" << getLegalCName(OpName)
+ << VTStr << "(N);\n";
+ } else {
+ // Keep track of whether we see a pattern that has an iPtr result.
+ bool HasPtrPattern = false;
+ bool HasDefaultPattern = false;
+
+ OS << " switch (NVT) {\n";
+ for (unsigned i = 0, e = OpVTs.size(); i < e; ++i) {
+ std::string &VTStr = OpVTs[i];
+ if (VTStr.empty()) {
+ HasDefaultPattern = true;
+ continue;
+ }
+
+ // If this is a match on iPTR: don't emit it directly, we need special
+ // code.
+ if (VTStr == "_iPTR") {
+ HasPtrPattern = true;
+ continue;
+ }
+ OS << " case MVT::" << VTStr.substr(1) << ":\n"
+ << " return Select_" << getLegalCName(OpName)
+ << VTStr << "(N);\n";
+ }
+ OS << " default:\n";
+
+ // If there is an iPTR result version of this pattern, emit it here.
+ if (HasPtrPattern) {
+ OS << " if (NVT == TLI.getPointerTy())\n";
+ OS << " return Select_" << getLegalCName(OpName) <<"_iPTR(N);\n";
+ }
+ if (HasDefaultPattern) {
+ OS << " return Select_" << getLegalCName(OpName) << "(N);\n";
+ }
+ OS << " break;\n";
+ OS << " }\n";
+ OS << " break;\n";
+ }
+ OS << " }\n";
+ }
+
+ OS << " } // end of big switch.\n\n"
+ << " cerr << \"Cannot yet select: \";\n"
+ << " if (N.getOpcode() != ISD::INTRINSIC_W_CHAIN &&\n"
+ << " N.getOpcode() != ISD::INTRINSIC_WO_CHAIN &&\n"
+ << " N.getOpcode() != ISD::INTRINSIC_VOID) {\n"
+ << " N.Val->dump(CurDAG);\n"
+ << " } else {\n"
+ << " unsigned iid = cast<ConstantSDNode>(N.getOperand("
+ "N.getOperand(0).getValueType() == MVT::Other))->getValue();\n"
+ << " cerr << \"intrinsic %\"<< "
+ "Intrinsic::getName((Intrinsic::ID)iid);\n"
+ << " }\n"
+ << " cerr << '\\n';\n"
+ << " abort();\n"
+ << " return NULL;\n"
+ << "}\n";
+}
+
+void DAGISelEmitter::run(std::ostream &OS) {
+ EmitSourceFileHeader("DAG Instruction Selector for the " + Target.getName() +
+ " target", OS);
+
+ OS << "// *** NOTE: This file is #included into the middle of the target\n"
+ << "// *** instruction selector class. These functions are really "
+ << "methods.\n\n";
+
+ OS << "#include \"llvm/Support/Compiler.h\"\n";
+
+ OS << "// Instruction selector priority queue:\n"
+ << "std::vector<SDNode*> ISelQueue;\n";
+ OS << "/// Keep track of nodes which have already been added to queue.\n"
+ << "unsigned char *ISelQueued;\n";
+ OS << "/// Keep track of nodes which have already been selected.\n"
+ << "unsigned char *ISelSelected;\n";
+ OS << "/// Dummy parameter to ReplaceAllUsesOfValueWith().\n"
+ << "std::vector<SDNode*> ISelKilled;\n\n";
+
+ OS << "/// IsChainCompatible - Returns true if Chain is Op or Chain does\n";
+ OS << "/// not reach Op.\n";
+ OS << "static bool IsChainCompatible(SDNode *Chain, SDNode *Op) {\n";
+ OS << " if (Chain->getOpcode() == ISD::EntryToken)\n";
+ OS << " return true;\n";
+ OS << " else if (Chain->getOpcode() == ISD::TokenFactor)\n";
+ OS << " return false;\n";
+ OS << " else if (Chain->getNumOperands() > 0) {\n";
+ OS << " SDOperand C0 = Chain->getOperand(0);\n";
+ OS << " if (C0.getValueType() == MVT::Other)\n";
+ OS << " return C0.Val != Op && IsChainCompatible(C0.Val, Op);\n";
+ OS << " }\n";
+ OS << " return true;\n";
+ OS << "}\n";
+
+ OS << "/// Sorting functions for the selection queue.\n"
+ << "struct isel_sort : public std::binary_function"
+ << "<SDNode*, SDNode*, bool> {\n"
+ << " bool operator()(const SDNode* left, const SDNode* right) "
+ << "const {\n"
+ << " return (left->getNodeId() > right->getNodeId());\n"
+ << " }\n"
+ << "};\n\n";
+
+ OS << "inline void setQueued(int Id) {\n";
+ OS << " ISelQueued[Id / 8] |= 1 << (Id % 8);\n";
+ OS << "}\n";
+ OS << "inline bool isQueued(int Id) {\n";
+ OS << " return ISelQueued[Id / 8] & (1 << (Id % 8));\n";
+ OS << "}\n";
+ OS << "inline void setSelected(int Id) {\n";
+ OS << " ISelSelected[Id / 8] |= 1 << (Id % 8);\n";
+ OS << "}\n";
+ OS << "inline bool isSelected(int Id) {\n";
+ OS << " return ISelSelected[Id / 8] & (1 << (Id % 8));\n";
+ OS << "}\n\n";
+
+ OS << "void AddToISelQueue(SDOperand N) DISABLE_INLINE {\n";
+ OS << " int Id = N.Val->getNodeId();\n";
+ OS << " if (Id != -1 && !isQueued(Id)) {\n";
+ OS << " ISelQueue.push_back(N.Val);\n";
+ OS << " std::push_heap(ISelQueue.begin(), ISelQueue.end(), isel_sort());\n";
+ OS << " setQueued(Id);\n";
+ OS << " }\n";
+ OS << "}\n\n";
+
+ OS << "inline void RemoveKilled() {\n";
+OS << " unsigned NumKilled = ISelKilled.size();\n";
+ OS << " if (NumKilled) {\n";
+ OS << " for (unsigned i = 0; i != NumKilled; ++i) {\n";
+ OS << " SDNode *Temp = ISelKilled[i];\n";
+ OS << " ISelQueue.erase(std::remove(ISelQueue.begin(), ISelQueue.end(), "
+ << "Temp), ISelQueue.end());\n";
+ OS << " };\n";
+ OS << " std::make_heap(ISelQueue.begin(), ISelQueue.end(), isel_sort());\n";
+ OS << " ISelKilled.clear();\n";
+ OS << " }\n";
+ OS << "}\n\n";
+
+ OS << "void ReplaceUses(SDOperand F, SDOperand T) DISABLE_INLINE {\n";
+ OS << " CurDAG->ReplaceAllUsesOfValueWith(F, T, ISelKilled);\n";
+ OS << " setSelected(F.Val->getNodeId());\n";
+ OS << " RemoveKilled();\n";
+ OS << "}\n";
+ OS << "inline void ReplaceUses(SDNode *F, SDNode *T) {\n";
+ OS << " CurDAG->ReplaceAllUsesWith(F, T, &ISelKilled);\n";
+ OS << " setSelected(F->getNodeId());\n";
+ OS << " RemoveKilled();\n";
+ OS << "}\n\n";
+
+ OS << "// SelectRoot - Top level entry to DAG isel.\n";
+ OS << "SDOperand SelectRoot(SDOperand Root) {\n";
+ OS << " SelectRootInit();\n";
+ OS << " unsigned NumBytes = (DAGSize + 7) / 8;\n";
+ OS << " ISelQueued = new unsigned char[NumBytes];\n";
+ OS << " ISelSelected = new unsigned char[NumBytes];\n";
+ OS << " memset(ISelQueued, 0, NumBytes);\n";
+ OS << " memset(ISelSelected, 0, NumBytes);\n";
+ OS << "\n";
+ OS << " // Create a dummy node (which is not added to allnodes), that adds\n"
+ << " // a reference to the root node, preventing it from being deleted,\n"
+ << " // and tracking any changes of the root.\n"
+ << " HandleSDNode Dummy(CurDAG->getRoot());\n"
+ << " ISelQueue.push_back(CurDAG->getRoot().Val);\n";
+ OS << " while (!ISelQueue.empty()) {\n";
+ OS << " SDNode *Node = ISelQueue.front();\n";
+ OS << " std::pop_heap(ISelQueue.begin(), ISelQueue.end(), isel_sort());\n";
+ OS << " ISelQueue.pop_back();\n";
+ OS << " if (!isSelected(Node->getNodeId())) {\n";
+ OS << " SDNode *ResNode = Select(SDOperand(Node, 0));\n";
+ OS << " if (ResNode != Node) {\n";
+ OS << " if (ResNode)\n";
+ OS << " ReplaceUses(Node, ResNode);\n";
+ OS << " if (Node->use_empty()) { // Don't delete EntryToken, etc.\n";
+ OS << " CurDAG->RemoveDeadNode(Node, ISelKilled);\n";
+ OS << " RemoveKilled();\n";
+ OS << " }\n";
+ OS << " }\n";
+ OS << " }\n";
+ OS << " }\n";
+ OS << "\n";
+ OS << " delete[] ISelQueued;\n";
+ OS << " ISelQueued = NULL;\n";
+ OS << " delete[] ISelSelected;\n";
+ OS << " ISelSelected = NULL;\n";
+ OS << " return Dummy.getValue();\n";
+ OS << "}\n";
+
+ Intrinsics = LoadIntrinsics(Records);
+ ParseNodeInfo();
+ ParseNodeTransforms(OS);
+ ParseComplexPatterns();
+ ParsePatternFragments(OS);
+ ParseDefaultOperands();
+ ParseInstructions();
+ ParsePatterns();
+
+ // Generate variants. For example, commutative patterns can match
+ // multiple ways. Add them to PatternsToMatch as well.
+ GenerateVariants();
+
+ DOUT << "\n\nALL PATTERNS TO MATCH:\n\n";
+ for (unsigned i = 0, e = PatternsToMatch.size(); i != e; ++i) {
+ DOUT << "PATTERN: "; DEBUG(PatternsToMatch[i].getSrcPattern()->dump());
+ DOUT << "\nRESULT: "; DEBUG(PatternsToMatch[i].getDstPattern()->dump());
+ DOUT << "\n";
+ }
+
+ // At this point, we have full information about the 'Patterns' we need to
+ // parse, both implicitly from instructions as well as from explicit pattern
+ // definitions. Emit the resultant instruction selector.
+ EmitInstructionSelector(OS);
+
+ for (std::map<Record*, TreePattern*>::iterator I = PatternFragments.begin(),
+ E = PatternFragments.end(); I != E; ++I)
+ delete I->second;
+ PatternFragments.clear();
+
+ Instructions.clear();
+}
diff --git a/utils/TableGen/DAGISelEmitter.h b/utils/TableGen/DAGISelEmitter.h
new file mode 100644
index 0000000000..7511c4ea6a
--- /dev/null
+++ b/utils/TableGen/DAGISelEmitter.h
@@ -0,0 +1,543 @@
+//===- DAGISelEmitter.h - Generate an instruction selector ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend emits a DAG instruction selector.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef DAGISEL_EMITTER_H
+#define DAGISEL_EMITTER_H
+
+#include "TableGenBackend.h"
+#include "CodeGenTarget.h"
+#include "CodeGenIntrinsics.h"
+#include <set>
+
+namespace llvm {
+ class Record;
+ struct Init;
+ class ListInit;
+ class DagInit;
+ class SDNodeInfo;
+ class TreePattern;
+ class TreePatternNode;
+ class DAGISelEmitter;
+ class ComplexPattern;
+
+ /// MVT::DAGISelGenValueType - These are some extended forms of MVT::ValueType
+ /// that we use as lattice values during type inferrence.
+ namespace MVT {
+ enum DAGISelGenValueType {
+ isFP = MVT::LAST_VALUETYPE,
+ isInt,
+ isUnknown
+ };
+ }
+
+ /// SDTypeConstraint - This is a discriminated union of constraints,
+ /// corresponding to the SDTypeConstraint tablegen class in Target.td.
+ struct SDTypeConstraint {
+ SDTypeConstraint(Record *R);
+
+ unsigned OperandNo; // The operand # this constraint applies to.
+ enum {
+ SDTCisVT, SDTCisPtrTy, SDTCisInt, SDTCisFP, SDTCisSameAs,
+ SDTCisVTSmallerThanOp, SDTCisOpSmallerThanOp, SDTCisIntVectorOfSameSize
+ } ConstraintType;
+
+ union { // The discriminated union.
+ struct {
+ MVT::ValueType VT;
+ } SDTCisVT_Info;
+ struct {
+ unsigned OtherOperandNum;
+ } SDTCisSameAs_Info;
+ struct {
+ unsigned OtherOperandNum;
+ } SDTCisVTSmallerThanOp_Info;
+ struct {
+ unsigned BigOperandNum;
+ } SDTCisOpSmallerThanOp_Info;
+ struct {
+ unsigned OtherOperandNum;
+ } SDTCisIntVectorOfSameSize_Info;
+ } x;
+
+ /// ApplyTypeConstraint - Given a node in a pattern, apply this type
+ /// constraint to the nodes operands. This returns true if it makes a
+ /// change, false otherwise. If a type contradiction is found, throw an
+ /// exception.
+ bool ApplyTypeConstraint(TreePatternNode *N, const SDNodeInfo &NodeInfo,
+ TreePattern &TP) const;
+
+ /// getOperandNum - Return the node corresponding to operand #OpNo in tree
+ /// N, which has NumResults results.
+ TreePatternNode *getOperandNum(unsigned OpNo, TreePatternNode *N,
+ unsigned NumResults) const;
+ };
+
+ /// SDNodeInfo - One of these records is created for each SDNode instance in
+ /// the target .td file. This represents the various dag nodes we will be
+ /// processing.
+ class SDNodeInfo {
+ Record *Def;
+ std::string EnumName;
+ std::string SDClassName;
+ unsigned Properties;
+ unsigned NumResults;
+ int NumOperands;
+ std::vector<SDTypeConstraint> TypeConstraints;
+ public:
+ SDNodeInfo(Record *R); // Parse the specified record.
+
+ unsigned getNumResults() const { return NumResults; }
+ int getNumOperands() const { return NumOperands; }
+ Record *getRecord() const { return Def; }
+ const std::string &getEnumName() const { return EnumName; }
+ const std::string &getSDClassName() const { return SDClassName; }
+
+ const std::vector<SDTypeConstraint> &getTypeConstraints() const {
+ return TypeConstraints;
+ }
+
+ /// hasProperty - Return true if this node has the specified property.
+ ///
+ bool hasProperty(enum SDNP Prop) const { return Properties & (1 << Prop); }
+
+ /// ApplyTypeConstraints - Given a node in a pattern, apply the type
+ /// constraints for this node to the operands of the node. This returns
+ /// true if it makes a change, false otherwise. If a type contradiction is
+ /// found, throw an exception.
+ bool ApplyTypeConstraints(TreePatternNode *N, TreePattern &TP) const {
+ bool MadeChange = false;
+ for (unsigned i = 0, e = TypeConstraints.size(); i != e; ++i)
+ MadeChange |= TypeConstraints[i].ApplyTypeConstraint(N, *this, TP);
+ return MadeChange;
+ }
+ };
+
+ /// FIXME: TreePatternNode's can be shared in some cases (due to dag-shaped
+ /// patterns), and as such should be ref counted. We currently just leak all
+ /// TreePatternNode objects!
+ class TreePatternNode {
+ /// The inferred type for this node, or MVT::isUnknown if it hasn't
+ /// been determined yet.
+ std::vector<unsigned char> Types;
+
+ /// Operator - The Record for the operator if this is an interior node (not
+ /// a leaf).
+ Record *Operator;
+
+ /// Val - The init value (e.g. the "GPRC" record, or "7") for a leaf.
+ ///
+ Init *Val;
+
+ /// Name - The name given to this node with the :$foo notation.
+ ///
+ std::string Name;
+
+ /// PredicateFn - The predicate function to execute on this node to check
+ /// for a match. If this string is empty, no predicate is involved.
+ std::string PredicateFn;
+
+ /// TransformFn - The transformation function to execute on this node before
+ /// it can be substituted into the resulting instruction on a pattern match.
+ Record *TransformFn;
+
+ std::vector<TreePatternNode*> Children;
+ public:
+ TreePatternNode(Record *Op, const std::vector<TreePatternNode*> &Ch)
+ : Types(), Operator(Op), Val(0), TransformFn(0),
+ Children(Ch) { Types.push_back(MVT::isUnknown); }
+ TreePatternNode(Init *val) // leaf ctor
+ : Types(), Operator(0), Val(val), TransformFn(0) {
+ Types.push_back(MVT::isUnknown);
+ }
+ ~TreePatternNode();
+
+ const std::string &getName() const { return Name; }
+ void setName(const std::string &N) { Name = N; }
+
+ bool isLeaf() const { return Val != 0; }
+ bool hasTypeSet() const {
+ return (Types[0] < MVT::LAST_VALUETYPE) || (Types[0] == MVT::iPTR);
+ }
+ bool isTypeCompletelyUnknown() const {
+ return Types[0] == MVT::isUnknown;
+ }
+ bool isTypeDynamicallyResolved() const {
+ return Types[0] == MVT::iPTR;
+ }
+ MVT::ValueType getTypeNum(unsigned Num) const {
+ assert(hasTypeSet() && "Doesn't have a type yet!");
+ assert(Types.size() > Num && "Type num out of range!");
+ return (MVT::ValueType)Types[Num];
+ }
+ unsigned char getExtTypeNum(unsigned Num) const {
+ assert(Types.size() > Num && "Extended type num out of range!");
+ return Types[Num];
+ }
+ const std::vector<unsigned char> &getExtTypes() const { return Types; }
+ void setTypes(const std::vector<unsigned char> &T) { Types = T; }
+ void removeTypes() { Types = std::vector<unsigned char>(1,MVT::isUnknown); }
+
+ Init *getLeafValue() const { assert(isLeaf()); return Val; }
+ Record *getOperator() const { assert(!isLeaf()); return Operator; }
+
+ unsigned getNumChildren() const { return Children.size(); }
+ TreePatternNode *getChild(unsigned N) const { return Children[N]; }
+ void setChild(unsigned i, TreePatternNode *N) {
+ Children[i] = N;
+ }
+
+
+ const std::string &getPredicateFn() const { return PredicateFn; }
+ void setPredicateFn(const std::string &Fn) { PredicateFn = Fn; }
+
+ Record *getTransformFn() const { return TransformFn; }
+ void setTransformFn(Record *Fn) { TransformFn = Fn; }
+
+ void print(std::ostream &OS) const;
+ void dump() const;
+
+ public: // Higher level manipulation routines.
+
+ /// clone - Return a new copy of this tree.
+ ///
+ TreePatternNode *clone() const;
+
+ /// isIsomorphicTo - Return true if this node is recursively isomorphic to
+ /// the specified node. For this comparison, all of the state of the node
+ /// is considered, except for the assigned name. Nodes with differing names
+ /// that are otherwise identical are considered isomorphic.
+ bool isIsomorphicTo(const TreePatternNode *N) const;
+
+ /// SubstituteFormalArguments - Replace the formal arguments in this tree
+ /// with actual values specified by ArgMap.
+ void SubstituteFormalArguments(std::map<std::string,
+ TreePatternNode*> &ArgMap);
+
+ /// InlinePatternFragments - If this pattern refers to any pattern
+ /// fragments, inline them into place, giving us a pattern without any
+ /// PatFrag references.
+ TreePatternNode *InlinePatternFragments(TreePattern &TP);
+
+ /// ApplyTypeConstraints - Apply all of the type constraints relevent to
+ /// this node and its children in the tree. This returns true if it makes a
+ /// change, false otherwise. If a type contradiction is found, throw an
+ /// exception.
+ bool ApplyTypeConstraints(TreePattern &TP, bool NotRegisters);
+
+ /// 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(const std::vector<unsigned char> &ExtVTs,
+ TreePattern &TP);
+ bool UpdateNodeType(unsigned char ExtVT, TreePattern &TP) {
+ std::vector<unsigned char> ExtVTs(1, ExtVT);
+ return UpdateNodeType(ExtVTs, TP);
+ }
+
+ /// ContainsUnresolvedType - Return true if this tree contains any
+ /// unresolved types.
+ bool ContainsUnresolvedType() const {
+ if (!hasTypeSet() && !isTypeDynamicallyResolved()) return true;
+ for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
+ if (getChild(i)->ContainsUnresolvedType()) return true;
+ return false;
+ }
+
+ /// canPatternMatch - If it is impossible for this pattern to match on this
+ /// target, fill in Reason and return false. Otherwise, return true.
+ bool canPatternMatch(std::string &Reason, DAGISelEmitter &ISE);
+ };
+
+
+ /// TreePattern - Represent a pattern, used for instructions, pattern
+ /// fragments, etc.
+ ///
+ class TreePattern {
+ /// Trees - The list of pattern trees which corresponds to this pattern.
+ /// Note that PatFrag's only have a single tree.
+ ///
+ std::vector<TreePatternNode*> Trees;
+
+ /// TheRecord - The actual TableGen record corresponding to this pattern.
+ ///
+ Record *TheRecord;
+
+ /// Args - This is a list of all of the arguments to this pattern (for
+ /// PatFrag patterns), which are the 'node' markers in this pattern.
+ std::vector<std::string> Args;
+
+ /// ISE - the DAG isel emitter coordinating this madness.
+ ///
+ DAGISelEmitter &ISE;
+
+ /// isInputPattern - True if this is an input pattern, something to match.
+ /// False if this is an output pattern, something to emit.
+ bool isInputPattern;
+ public:
+
+ /// TreePattern constructor - Parse the specified DagInits into the
+ /// current record.
+ TreePattern(Record *TheRec, ListInit *RawPat, bool isInput,
+ DAGISelEmitter &ise);
+ TreePattern(Record *TheRec, DagInit *Pat, bool isInput,
+ DAGISelEmitter &ise);
+ TreePattern(Record *TheRec, TreePatternNode *Pat, bool isInput,
+ DAGISelEmitter &ise);
+
+ /// getTrees - Return the tree patterns which corresponds to this pattern.
+ ///
+ const std::vector<TreePatternNode*> &getTrees() const { return Trees; }
+ unsigned getNumTrees() const { return Trees.size(); }
+ TreePatternNode *getTree(unsigned i) const { return Trees[i]; }
+ TreePatternNode *getOnlyTree() const {
+ assert(Trees.size() == 1 && "Doesn't have exactly one pattern!");
+ return Trees[0];
+ }
+
+ /// getRecord - Return the actual TableGen record corresponding to this
+ /// pattern.
+ ///
+ Record *getRecord() const { return TheRecord; }
+
+ unsigned getNumArgs() const { return Args.size(); }
+ const std::string &getArgName(unsigned i) const {
+ assert(i < Args.size() && "Argument reference out of range!");
+ return Args[i];
+ }
+ std::vector<std::string> &getArgList() { return Args; }
+
+ DAGISelEmitter &getDAGISelEmitter() const { return ISE; }
+
+ /// InlinePatternFragments - If this pattern refers to any pattern
+ /// fragments, inline them into place, giving us a pattern without any
+ /// PatFrag references.
+ void InlinePatternFragments() {
+ for (unsigned i = 0, e = Trees.size(); i != e; ++i)
+ Trees[i] = Trees[i]->InlinePatternFragments(*this);
+ }
+
+ /// InferAllTypes - Infer/propagate as many types throughout the expression
+ /// patterns as possible. Return true if all types are infered, false
+ /// otherwise. Throw an exception if a type contradiction is found.
+ bool InferAllTypes();
+
+ /// error - Throw an exception, prefixing it with information about this
+ /// pattern.
+ void error(const std::string &Msg) const;
+
+ void print(std::ostream &OS) const;
+ void dump() const;
+
+ private:
+ TreePatternNode *ParseTreePattern(DagInit *DI);
+ };
+
+ /// DAGDefaultOperand - One of these is created for each PredicateOperand
+ /// or OptionalDefOperand that has a set ExecuteAlways / DefaultOps field.
+ struct DAGDefaultOperand {
+ std::vector<TreePatternNode*> DefaultOps;
+ };
+
+ class DAGInstruction {
+ TreePattern *Pattern;
+ std::vector<Record*> Results;
+ std::vector<Record*> Operands;
+ std::vector<Record*> ImpResults;
+ std::vector<Record*> ImpOperands;
+ TreePatternNode *ResultPattern;
+ public:
+ DAGInstruction(TreePattern *TP,
+ const std::vector<Record*> &results,
+ const std::vector<Record*> &operands,
+ const std::vector<Record*> &impresults,
+ const std::vector<Record*> &impoperands)
+ : Pattern(TP), Results(results), Operands(operands),
+ ImpResults(impresults), ImpOperands(impoperands),
+ ResultPattern(0) {}
+
+ TreePattern *getPattern() const { return Pattern; }
+ unsigned getNumResults() const { return Results.size(); }
+ unsigned getNumOperands() const { return Operands.size(); }
+ unsigned getNumImpResults() const { return ImpResults.size(); }
+ unsigned getNumImpOperands() const { return ImpOperands.size(); }
+
+ void setResultPattern(TreePatternNode *R) { ResultPattern = R; }
+
+ Record *getResult(unsigned RN) const {
+ assert(RN < Results.size());
+ return Results[RN];
+ }
+
+ Record *getOperand(unsigned ON) const {
+ assert(ON < Operands.size());
+ return Operands[ON];
+ }
+
+ Record *getImpResult(unsigned RN) const {
+ assert(RN < ImpResults.size());
+ return ImpResults[RN];
+ }
+
+ Record *getImpOperand(unsigned ON) const {
+ assert(ON < ImpOperands.size());
+ return ImpOperands[ON];
+ }
+
+ TreePatternNode *getResultPattern() const { return ResultPattern; }
+ };
+
+/// PatternToMatch - Used by DAGISelEmitter to keep tab of patterns processed
+/// to produce isel.
+struct PatternToMatch {
+ PatternToMatch(ListInit *preds,
+ TreePatternNode *src, TreePatternNode *dst,
+ unsigned complexity):
+ Predicates(preds), SrcPattern(src), DstPattern(dst),
+ AddedComplexity(complexity) {};
+
+ ListInit *Predicates; // Top level predicate conditions to match.
+ TreePatternNode *SrcPattern; // Source pattern to match.
+ TreePatternNode *DstPattern; // Resulting pattern.
+ unsigned AddedComplexity; // Add to matching pattern complexity.
+
+ ListInit *getPredicates() const { return Predicates; }
+ TreePatternNode *getSrcPattern() const { return SrcPattern; }
+ TreePatternNode *getDstPattern() const { return DstPattern; }
+ unsigned getAddedComplexity() const { return AddedComplexity; }
+};
+
+/// DAGISelEmitter - The top-level class which coordinates construction
+/// and emission of the instruction selector.
+///
+class DAGISelEmitter : public TableGenBackend {
+private:
+ RecordKeeper &Records;
+ CodeGenTarget Target;
+ std::vector<CodeGenIntrinsic> Intrinsics;
+
+ std::map<Record*, SDNodeInfo> SDNodes;
+ std::map<Record*, std::pair<Record*, std::string> > SDNodeXForms;
+ std::map<Record*, ComplexPattern> ComplexPatterns;
+ std::map<Record*, TreePattern*> PatternFragments;
+ std::map<Record*, DAGDefaultOperand> DefaultOperands;
+ std::map<Record*, DAGInstruction> Instructions;
+
+ // Specific SDNode definitions:
+ Record *intrinsic_void_sdnode;
+ Record *intrinsic_w_chain_sdnode, *intrinsic_wo_chain_sdnode;
+
+ /// PatternsToMatch - All of the things we are matching on the DAG. The first
+ /// value is the pattern to match, the second pattern is the result to
+ /// emit.
+ std::vector<PatternToMatch> PatternsToMatch;
+public:
+ DAGISelEmitter(RecordKeeper &R) : Records(R) {}
+
+ // run - Output the isel, returning true on failure.
+ void run(std::ostream &OS);
+
+ const CodeGenTarget &getTargetInfo() const { return Target; }
+
+ Record *getSDNodeNamed(const std::string &Name) const;
+
+ const SDNodeInfo &getSDNodeInfo(Record *R) const {
+ assert(SDNodes.count(R) && "Unknown node!");
+ return SDNodes.find(R)->second;
+ }
+
+ const std::pair<Record*, std::string> &getSDNodeTransform(Record *R) const {
+ assert(SDNodeXForms.count(R) && "Invalid transform!");
+ return SDNodeXForms.find(R)->second;
+ }
+
+ const ComplexPattern &getComplexPattern(Record *R) const {
+ assert(ComplexPatterns.count(R) && "Unknown addressing mode!");
+ return ComplexPatterns.find(R)->second;
+ }
+
+ const CodeGenIntrinsic &getIntrinsic(Record *R) const {
+ for (unsigned i = 0, e = Intrinsics.size(); i != e; ++i)
+ if (Intrinsics[i].TheDef == R) return Intrinsics[i];
+ assert(0 && "Unknown intrinsic!");
+ abort();
+ }
+
+ const CodeGenIntrinsic &getIntrinsicInfo(unsigned IID) const {
+ assert(IID-1 < Intrinsics.size() && "Bad intrinsic ID!");
+ return Intrinsics[IID-1];
+ }
+
+ unsigned getIntrinsicID(Record *R) const {
+ for (unsigned i = 0, e = Intrinsics.size(); i != e; ++i)
+ if (Intrinsics[i].TheDef == R) return i;
+ assert(0 && "Unknown intrinsic!");
+ abort();
+ }
+
+ const DAGDefaultOperand &getDefaultOperand(Record *R) {
+ assert(DefaultOperands.count(R) &&"Isn't an analyzed default operand!");
+ return DefaultOperands.find(R)->second;
+ }
+
+ TreePattern *getPatternFragment(Record *R) const {
+ assert(PatternFragments.count(R) && "Invalid pattern fragment request!");
+ return PatternFragments.find(R)->second;
+ }
+
+ const DAGInstruction &getInstruction(Record *R) const {
+ assert(Instructions.count(R) && "Unknown instruction!");
+ return Instructions.find(R)->second;
+ }
+
+ Record *get_intrinsic_void_sdnode() const {
+ return intrinsic_void_sdnode;
+ }
+ Record *get_intrinsic_w_chain_sdnode() const {
+ return intrinsic_w_chain_sdnode;
+ }
+ Record *get_intrinsic_wo_chain_sdnode() const {
+ return intrinsic_wo_chain_sdnode;
+ }
+
+
+private:
+ void ParseNodeInfo();
+ void ParseNodeTransforms(std::ostream &OS);
+ void ParseComplexPatterns();
+ void ParsePatternFragments(std::ostream &OS);
+ void ParseDefaultOperands();
+ void ParseInstructions();
+ void ParsePatterns();
+ void GenerateVariants();
+ void FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat,
+ std::map<std::string,
+ TreePatternNode*> &InstInputs,
+ std::map<std::string,
+ TreePatternNode*> &InstResults,
+ std::vector<Record*> &InstImpInputs,
+ std::vector<Record*> &InstImpResults);
+ void GenerateCodeForPattern(PatternToMatch &Pattern,
+ std::vector<std::pair<unsigned, std::string> > &GeneratedCode,
+ std::set<std::string> &GeneratedDecl,
+ std::vector<std::string> &TargetOpcodes,
+ std::vector<std::string> &TargetVTs);
+ void EmitPatterns(std::vector<std::pair<PatternToMatch*,
+ std::vector<std::pair<unsigned, std::string> > > > &Patterns,
+ unsigned Indent, std::ostream &OS);
+ void EmitInstructionSelector(std::ostream &OS);
+};
+
+} // End llvm namespace
+
+#endif
diff --git a/utils/TableGen/FileLexer.cpp.cvs b/utils/TableGen/FileLexer.cpp.cvs
new file mode 100644
index 0000000000..f36921b8bd
--- /dev/null
+++ b/utils/TableGen/FileLexer.cpp.cvs
@@ -0,0 +1,1983 @@
+#define yy_create_buffer File_create_buffer
+#define yy_delete_buffer File_delete_buffer
+#define yy_scan_buffer File_scan_buffer
+#define yy_scan_string File_scan_string
+#define yy_scan_bytes File_scan_bytes
+#define yy_flex_debug File_flex_debug
+#define yy_init_buffer File_init_buffer
+#define yy_flush_buffer File_flush_buffer
+#define yy_load_buffer_state File_load_buffer_state
+#define yy_switch_to_buffer File_switch_to_buffer
+#define yyin Filein
+#define yyleng Fileleng
+#define yylex Filelex
+#define yyout Fileout
+#define yyrestart Filerestart
+#define yytext Filetext
+#define yylineno Filelineno
+#define yywrap Filewrap
+
+#line 21 "Lexer.cpp"
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header$
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE (16384*64)
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator). This
+ * avoids problems with code like:
+ *
+ * if ( condition_holds )
+ * yyless( 5 );
+ * else
+ * do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ *yy_cp = yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+ };
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO(( FILE *input_file ));
+
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
+YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static inline void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+
+#define YY_USES_REJECT
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern int yylineno;
+int yylineno = 1;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yytext_ptr = yy_bp; \
+ yyleng = (int) (yy_cp - yy_bp); \
+ yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 35
+#define YY_END_OF_BUFFER 36
+static yyconst short int yy_acclist[146] =
+ { 0,
+ 29, 29, 36, 34, 35, 27, 34, 35, 27, 35,
+ 34, 35, 34, 35, 34, 35, 34, 35, 34, 35,
+ 26, 34, 35, 26, 34, 35, 23, 34, 35, 34,
+ 35, 23, 34, 35, 23, 34, 35, 23, 34, 35,
+ 23, 34, 35, 23, 34, 35, 23, 34, 35, 23,
+ 34, 35, 23, 34, 35, 29, 35, 30, 35, 32,
+ 35, 27, 25, 24, 26, 28, 1, 23, 23, 23,
+ 23, 23, 23, 23, 17, 23, 23, 23, 23, 23,
+ 29, 30, 30, 33, 32, 31, 32, 24, 1, 26,
+ 26, 5, 23, 23, 23, 10, 23, 12, 23, 23,
+
+ 23, 4, 23, 16, 23, 23, 23, 23, 18, 21,
+ 19, 20, 3, 6, 23, 23, 9, 23, 13, 23,
+ 23, 23, 8, 23, 23, 23, 11, 23, 15, 23,
+ 23, 23, 23, 23, 23, 7, 23, 23, 23, 23,
+ 23, 22, 2, 14, 23
+ } ;
+
+static yyconst short int yy_accept[123] =
+ { 0,
+ 1, 1, 1, 2, 3, 4, 6, 9, 11, 13,
+ 15, 17, 19, 21, 24, 27, 30, 32, 35, 38,
+ 41, 44, 47, 50, 53, 56, 58, 60, 62, 63,
+ 63, 63, 63, 64, 65, 66, 67, 68, 68, 68,
+ 69, 69, 70, 71, 72, 73, 74, 75, 77, 78,
+ 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
+ 88, 88, 88, 88, 89, 90, 91, 92, 92, 92,
+ 94, 95, 96, 98, 100, 101, 102, 104, 106, 107,
+ 108, 109, 110, 111, 112, 113, 113, 113, 114, 116,
+ 117, 119, 121, 122, 123, 125, 126, 127, 127, 129,
+
+ 131, 132, 133, 134, 134, 135, 136, 138, 138, 139,
+ 140, 140, 140, 141, 141, 141, 142, 143, 143, 144,
+ 146, 146
+ } ;
+
+static yyconst int yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 4, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 5, 6, 1, 7, 1, 1, 1, 1,
+ 1, 8, 9, 1, 9, 1, 10, 11, 12, 13,
+ 13, 13, 13, 13, 13, 13, 13, 1, 1, 1,
+ 1, 1, 1, 1, 14, 14, 14, 14, 14, 14,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 16, 1, 17, 1, 15, 1, 18, 19, 20, 21,
+
+ 22, 23, 24, 25, 26, 15, 15, 27, 28, 29,
+ 30, 15, 15, 31, 32, 33, 34, 15, 15, 35,
+ 15, 15, 36, 1, 37, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst int yy_meta[38] =
+ { 0,
+ 1, 1, 2, 1, 1, 1, 1, 3, 1, 3,
+ 4, 4, 4, 5, 6, 1, 1, 5, 5, 5,
+ 5, 5, 5, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 1, 1
+ } ;
+
+static yyconst short int yy_base[135] =
+ { 0,
+ 0, 0, 30, 31, 221, 222, 40, 43, 28, 214,
+ 0, 38, 44, 44, 53, 0, 183, 192, 31, 49,
+ 191, 187, 46, 181, 181, 0, 65, 66, 78, 183,
+ 52, 206, 222, 0, 75, 222, 0, 58, 0, 0,
+ 174, 177, 191, 187, 183, 183, 183, 58, 171, 171,
+ 175, 170, 0, 82, 85, 222, 86, 222, 89, 171,
+ 172, 35, 167, 0, 0, 89, 0, 160, 179, 163,
+ 162, 171, 0, 164, 164, 163, 0, 0, 156, 155,
+ 161, 222, 222, 222, 222, 166, 148, 222, 0, 152,
+ 0, 0, 162, 148, 0, 155, 151, 149, 0, 0,
+
+ 157, 157, 152, 146, 152, 146, 0, 128, 100, 110,
+ 89, 102, 74, 65, 83, 52, 222, 53, 222, 0,
+ 222, 108, 114, 116, 119, 125, 131, 137, 140, 146,
+ 149, 154, 160, 166
+ } ;
+
+static yyconst short int yy_def[135] =
+ { 0,
+ 121, 1, 122, 122, 121, 121, 121, 121, 121, 123,
+ 124, 121, 121, 121, 121, 125, 121, 125, 125, 125,
+ 125, 125, 125, 125, 125, 126, 127, 128, 121, 121,
+ 121, 123, 121, 129, 121, 121, 130, 121, 131, 125,
+ 132, 125, 125, 125, 125, 125, 125, 125, 125, 125,
+ 125, 125, 126, 127, 127, 121, 128, 121, 128, 121,
+ 121, 121, 121, 129, 130, 121, 131, 132, 133, 125,
+ 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
+ 125, 121, 121, 121, 121, 121, 132, 121, 125, 125,
+ 125, 125, 125, 125, 125, 125, 125, 121, 125, 125,
+
+ 125, 125, 125, 121, 125, 125, 125, 121, 125, 125,
+ 121, 121, 125, 121, 134, 125, 121, 134, 121, 125,
+ 0, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+ 121, 121, 121, 121
+ } ;
+
+static yyconst short int yy_nxt[260] =
+ { 0,
+ 6, 7, 8, 7, 9, 10, 11, 6, 12, 13,
+ 14, 15, 15, 16, 16, 17, 6, 16, 18, 19,
+ 20, 16, 21, 16, 16, 22, 23, 24, 16, 16,
+ 16, 25, 16, 16, 16, 6, 6, 27, 27, 28,
+ 28, 29, 29, 29, 29, 29, 29, 30, 35, 35,
+ 35, 36, 84, 37, 35, 35, 35, 43, 119, 31,
+ 44, 85, 38, 35, 35, 35, 45, 49, 66, 66,
+ 46, 50, 55, 58, 56, 59, 61, 76, 39, 29,
+ 29, 29, 62, 120, 63, 35, 35, 35, 119, 121,
+ 77, 121, 55, 121, 56, 121, 121, 117, 59, 66,
+
+ 66, 112, 112, 112, 112, 116, 114, 115, 26, 26,
+ 26, 26, 26, 26, 32, 32, 32, 32, 32, 32,
+ 34, 34, 40, 40, 40, 53, 53, 113, 53, 53,
+ 53, 54, 54, 54, 54, 54, 54, 57, 57, 57,
+ 57, 57, 57, 64, 64, 64, 65, 111, 65, 65,
+ 65, 65, 67, 67, 68, 68, 68, 68, 68, 68,
+ 87, 87, 87, 87, 87, 87, 118, 118, 118, 118,
+ 118, 118, 110, 109, 108, 107, 106, 105, 104, 103,
+ 102, 101, 100, 99, 69, 98, 97, 96, 95, 94,
+ 93, 92, 91, 90, 89, 88, 69, 86, 83, 82,
+
+ 81, 80, 79, 78, 75, 74, 73, 72, 71, 70,
+ 69, 33, 60, 52, 51, 48, 47, 42, 41, 33,
+ 121, 5, 121, 121, 121, 121, 121, 121, 121, 121,
+ 121, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+ 121, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+ 121, 121, 121, 121, 121, 121, 121, 121, 121
+ } ;
+
+static yyconst short int yy_chk[260] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 3, 4, 3,
+ 4, 7, 7, 7, 8, 8, 8, 9, 12, 12,
+ 12, 13, 62, 13, 14, 14, 14, 19, 118, 9,
+ 19, 62, 14, 15, 15, 15, 20, 23, 38, 38,
+ 20, 23, 27, 28, 27, 28, 31, 48, 14, 29,
+ 29, 29, 31, 116, 31, 35, 35, 35, 115, 54,
+ 48, 54, 55, 57, 55, 57, 59, 114, 59, 66,
+
+ 66, 109, 109, 112, 112, 113, 111, 112, 122, 122,
+ 122, 122, 122, 122, 123, 123, 123, 123, 123, 123,
+ 124, 124, 125, 125, 125, 126, 126, 110, 126, 126,
+ 126, 127, 127, 127, 127, 127, 127, 128, 128, 128,
+ 128, 128, 128, 129, 129, 129, 130, 108, 130, 130,
+ 130, 130, 131, 131, 132, 132, 132, 132, 132, 132,
+ 133, 133, 133, 133, 133, 133, 134, 134, 134, 134,
+ 134, 134, 106, 105, 104, 103, 102, 101, 98, 97,
+ 96, 94, 93, 90, 87, 86, 81, 80, 79, 76,
+ 75, 74, 72, 71, 70, 69, 68, 63, 61, 60,
+
+ 52, 51, 50, 49, 47, 46, 45, 44, 43, 42,
+ 41, 32, 30, 25, 24, 22, 21, 18, 17, 10,
+ 5, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+ 121, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+ 121, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+ 121, 121, 121, 121, 121, 121, 121, 121, 121
+ } ;
+
+static yy_state_type yy_state_buf[YY_BUF_SIZE + 2], *yy_state_ptr;
+static char *yy_full_match;
+static int yy_lp;
+#define REJECT \
+{ \
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ \
+yy_cp = yy_full_match; /* restore poss. backed-over text */ \
+++yy_lp; \
+goto find_rule; \
+}
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+#define INITIAL 0
+/*===-- FileLexer.l - Scanner for TableGen Files ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a simple flex scanner for TableGen files. This is pretty
+// straight-forward, except for the magic to handle file inclusion.
+//
+//===----------------------------------------------------------------------===*/
+#define YY_NEVER_INTERACTIVE 1
+#define comment 1
+
+#line 30 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+#include "llvm/Config/config.h"
+#include "llvm/Support/Streams.h"
+#include "Record.h"
+typedef std::pair<llvm::Record*, std::vector<llvm::Init*>*> SubClassRefTy;
+#include "FileParser.h"
+
+int Fileparse();
+
+namespace llvm {
+
+// Global variable recording the location of the include directory
+std::vector<std::string> IncludeDirectories;
+
+/// 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 strtoll(Str+2, 0, 2);
+ return strtoll(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()) {
+ cerr << "At end of input: ";
+ return *cerr.stream();
+ }
+
+ for (unsigned i = 0, e = IncludeStack.size()-1; i != e; ++i)
+ cerr << "Included from " << IncludeStack[i].Filename << ":"
+ << IncludeStack[i].LineNo << ":\n";
+ cerr << "Parsing " << IncludeStack.back().Filename << ":"
+ << Filelineno << ": ";
+ return *cerr.stream();
+}
+
+/// ParseFile - this function begins the parsing of the specified tablegen file.
+///
+void ParseFile(const std::string &Filename,
+ const std::vector<std::string> &IncludeDirs) {
+ FILE *F = stdin;
+ if (Filename != "-") {
+ F = fopen(Filename.c_str(), "r");
+
+ if (F == 0) {
+ 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.
+ IncludeDirectories = IncludeDirs;
+
+ 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);
+ //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.
+ //
+ std::string NextFilename;
+ for (unsigned i = 0, e = IncludeDirectories.size(); i != e; ++i) {
+ NextFilename = IncludeDirectories[i] + "/" + Filename;
+ if ((yyin = fopen(NextFilename.c_str(), "r")))
+ break;
+ }
+
+ if (yyin == 0) {
+ err() << "Could not find include file '" << Filename << "'!\n";
+ exit(1);
+ }
+ Filename = NextFilename;
+ }
+
+ // 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(void) {
+ 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;
+}
+
+} // End llvm namespace
+
+using namespace llvm;
+
+#line 670 "Lexer.cpp"
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static inline void yyunput YY_PROTO(( int c, char *buf_ptr ));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines. This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( yy_current_buffer->yy_is_interactive ) \
+ { \
+ int c = '*', n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+ && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+YY_DECL
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+#line 185 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+
+
+#line 824 "Lexer.cpp"
+
+ if ( yy_init )
+ {
+ yy_init = 0;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yy_start )
+ yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! yy_current_buffer )
+ yy_current_buffer =
+ yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_load_buffer_state();
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yy_start;
+ yy_state_ptr = yy_state_buf;
+ *yy_state_ptr++ = yy_current_state;
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 122 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ *yy_state_ptr++ = yy_current_state;
+ ++yy_cp;
+ }
+ while ( yy_current_state != 121 );
+
+yy_find_action:
+ yy_current_state = *--yy_state_ptr;
+ yy_lp = yy_accept[yy_current_state];
+find_rule: /* we branch to this label when backing up */
+ for ( ; ; ) /* until we find what rule we matched */
+ {
+ if ( yy_lp && yy_lp < yy_accept[yy_current_state + 1] )
+ {
+ yy_act = yy_acclist[yy_lp];
+ {
+ yy_full_match = yy_cp;
+ break;
+ }
+ }
+ --yy_cp;
+ yy_current_state = *--yy_state_ptr;
+ yy_lp = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+ if ( yy_act != YY_END_OF_BUFFER )
+ {
+ int yyl;
+ for ( yyl = 0; yyl < yyleng; ++yyl )
+ if ( yytext[yyl] == '\n' )
+ ++yylineno;
+ }
+
+do_action: /* This label is used only to access EOF actions. */
+
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+case 1:
+YY_RULE_SETUP
+#line 187 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ /* Ignore comments */ }
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 189 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ HandleInclude(yytext); }
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 190 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ Filelval.StrVal = new std::string(yytext+2, yytext+yyleng-2);
+ return CODEFRAGMENT; }
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 193 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ return INT; }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 194 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ return BIT; }
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 195 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ return BITS; }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 196 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ return STRING; }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 197 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ return LIST; }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 198 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ return CODE; }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 199 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ return DAG; }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 201 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ return CLASS; }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 202 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ return DEF; }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 203 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ return DEFM; }
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 204 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ return MULTICLASS; }
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 205 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ return FIELD; }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 206 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ return LET; }
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 207 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ return IN; }
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 209 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ return CONCATTOK; }
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 210 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ return SRATOK; }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 211 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ return SRLTOK; }
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 212 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ return SHLTOK; }
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 213 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ return STRCONCATTOK; }
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 216 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ Filelval.StrVal = new std::string(yytext, yytext+yyleng);
+ return ID; }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 218 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ Filelval.StrVal = new std::string(yytext+1, yytext+yyleng);
+ return VARNAME; }
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 221 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ Filelval.StrVal = new std::string(yytext+1, yytext+yyleng-1);
+ return STRVAL; }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 224 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ Filelval.IntVal = ParseInt(Filetext); return INTVAL; }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 226 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ /* Ignore whitespace */ }
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 229 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ BEGIN(comment); CommentDepth++; }
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 230 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{} /* eat anything that's not a '*' or '/' */
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 231 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{} /* eat up '*'s not followed by '/'s */
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 232 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ ++CommentDepth; }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 233 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{} /* eat up /'s not followed by *'s */
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 234 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ if (!--CommentDepth) { BEGIN(INITIAL); } }
+ YY_BREAK
+case YY_STATE_EOF(comment):
+#line 235 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ err() << "Unterminated comment!\n"; exit(1); }
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 237 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+{ return Filetext[0]; }
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 239 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+YY_FATAL_ERROR( "flex scanner jammed" );
+ YY_BREAK
+#line 1098 "Lexer.cpp"
+ case YY_STATE_EOF(INITIAL):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between yy_current_buffer and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yy_current_buffer->yy_input_file = yyin;
+ yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap() )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p =
+ yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yy_c_buf_p =
+ &yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+ {
+ register char *dest = yy_current_buffer->yy_ch_buf;
+ register char *source = yytext_ptr;
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( yy_current_buffer->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+ YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = yy_current_buffer;
+
+ int yy_c_buf_p_offset =
+ (int) (yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yy_flex_realloc( (void *) b->yy_ch_buf,
+ b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = yy_current_buffer->yy_buf_size -
+ number_to_move - 1;
+#endif
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+ yy_n_chars, num_to_read );
+
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ if ( yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ yy_current_buffer->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ yy_n_chars += number_to_move;
+ yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+ return ret_val;
+ }
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = yy_start;
+ yy_state_ptr = yy_state_buf;
+ *yy_state_ptr++ = yy_current_state;
+
+ for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 122 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ *yy_state_ptr++ = yy_current_state;
+ }
+
+ return yy_current_state;
+ }
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+ {
+ register int yy_is_jam;
+
+ register YY_CHAR yy_c = 1;
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 122 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 121);
+ if ( ! yy_is_jam )
+ *yy_state_ptr++ = yy_current_state;
+
+ return yy_is_jam ? 0 : yy_current_state;
+ }
+
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static inline void yyunput( int c, register char *yy_bp )
+#else
+static inline void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+ {
+ register char *yy_cp = yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yy_hold_char;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = yy_n_chars + 2;
+ register char *dest = &yy_current_buffer->yy_ch_buf[
+ yy_current_buffer->yy_buf_size + 2];
+ register char *source =
+ &yy_current_buffer->yy_ch_buf[number_to_move];
+
+ while ( source > yy_current_buffer->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ yy_current_buffer->yy_n_chars =
+ yy_n_chars = yy_current_buffer->yy_buf_size;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ if ( c == '\n' )
+ --yylineno;
+
+ yytext_ptr = yy_bp;
+ yy_hold_char = *yy_cp;
+ yy_c_buf_p = yy_cp;
+ }
+#endif /* ifndef YY_NO_UNPUT */
+
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+ {
+ int c;
+
+ *yy_c_buf_p = yy_hold_char;
+
+ if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ /* This was really a NUL. */
+ *yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = yy_c_buf_p - yytext_ptr;
+ ++yy_c_buf_p;
+
+ switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin );
+
+ /* fall through */
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap() )
+ return EOF;
+
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p = yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */
+ *yy_c_buf_p = '\0'; /* preserve yytext */
+ yy_hold_char = *++yy_c_buf_p;
+
+ if ( c == '\n' )
+ ++yylineno;
+
+ return c;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+ {
+ if ( ! yy_current_buffer )
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_init_buffer( yy_current_buffer, input_file );
+ yy_load_buffer_state();
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+ {
+ if ( yy_current_buffer == new_buffer )
+ return;
+
+ if ( yy_current_buffer )
+ {
+ /* Flush out information for old buffer. */
+ *yy_c_buf_p = yy_hold_char;
+ yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ yy_current_buffer = new_buffer;
+ yy_load_buffer_state();
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yy_did_buffer_switch_on_eof = 1;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+ {
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+ yyin = yy_current_buffer->yy_input_file;
+ yy_hold_char = *yy_c_buf_p;
+ }
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+ {
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file );
+
+ return b;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+ {
+ if ( ! b )
+ return;
+
+ if ( b == yy_current_buffer )
+ yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yy_flex_free( (void *) b->yy_ch_buf );
+
+ yy_flex_free( (void *) b );
+ }
+
+
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int isatty YY_PROTO(( int ));
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+ {
+ yy_flush_buffer( b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+#if YY_ALWAYS_INTERACTIVE
+ b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+ b->yy_is_interactive = 0;
+#else
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer( YY_BUFFER_STATE b )
+#else
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+
+ {
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == yy_current_buffer )
+ yy_load_buffer_state();
+ }
+
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+#else
+YY_BUFFER_STATE yy_scan_buffer( base, size )
+char *base;
+yy_size_t size;
+#endif
+ {
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer( b );
+
+ return b;
+ }
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
+#else
+YY_BUFFER_STATE yy_scan_string( yy_str )
+yyconst char *yy_str;
+#endif
+ {
+ int len;
+ for ( len = 0; yy_str[len]; ++len )
+ ;
+
+ return yy_scan_bytes( yy_str, len );
+ }
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
+#else
+YY_BUFFER_STATE yy_scan_bytes( bytes, len )
+yyconst char *bytes;
+int len;
+#endif
+ {
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = len + 2;
+ buf = (char *) yy_flex_alloc( n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < len; ++i )
+ buf[i] = bytes[i];
+
+ buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer( buf, n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+ }
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+ {
+ if ( yy_start_stack_ptr >= yy_start_stack_depth )
+ {
+ yy_size_t new_size;
+
+ yy_start_stack_depth += YY_START_STACK_INCR;
+ new_size = yy_start_stack_depth * sizeof( int );
+
+ if ( ! yy_start_stack )
+ yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+ else
+ yy_start_stack = (int *) yy_flex_realloc(
+ (void *) yy_start_stack, new_size );
+
+ if ( ! yy_start_stack )
+ YY_FATAL_ERROR(
+ "out of memory expanding start-condition stack" );
+ }
+
+ yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+ BEGIN(new_state);
+ }
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+ {
+ if ( --yy_start_stack_ptr < 0 )
+ YY_FATAL_ERROR( "start-condition stack underflow" );
+
+ BEGIN(yy_start_stack[yy_start_stack_ptr]);
+ }
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+ {
+ return yy_start_stack[yy_start_stack_ptr - 1];
+ }
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( yyconst char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+ {
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+ }
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ yytext[yyleng] = yy_hold_char; \
+ yy_c_buf_p = yytext + n; \
+ yy_hold_char = *yy_c_buf_p; \
+ *yy_c_buf_p = '\0'; \
+ yyleng = n; \
+ } \
+ while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+ {
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+ }
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+ {
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+ }
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+ {
+ return (void *) malloc( size );
+ }
+
+#ifdef YY_USE_PROTOS
+static inline void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static inline void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+ {
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+ {
+ free( ptr );
+ }
+
+#if YY_MAIN
+int main()
+ {
+ yylex();
+ return 0;
+ }
+#endif
+#line 239 "/Volumes/Wildlings/echeng/llvm/utils/TableGen/FileLexer.l"
+
+
diff --git a/utils/TableGen/FileLexer.l b/utils/TableGen/FileLexer.l
new file mode 100644
index 0000000000..59bbdad7bf
--- /dev/null
+++ b/utils/TableGen/FileLexer.l
@@ -0,0 +1,240 @@
+/*===-- FileLexer.l - Scanner for TableGen Files ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This 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 "llvm/Config/config.h"
+#include "llvm/Support/Streams.h"
+#include "Record.h"
+typedef std::pair<llvm::Record*, std::vector<llvm::Init*>*> SubClassRefTy;
+#include "FileParser.h"
+
+int Fileparse();
+
+namespace llvm {
+
+// Global variable recording the location of the include directory
+std::vector<std::string> IncludeDirectories;
+
+/// 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 strtoll(Str+2, 0, 2);
+ return strtoll(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()) {
+ cerr << "At end of input: ";
+ return *cerr.stream();
+ }
+
+ for (unsigned i = 0, e = IncludeStack.size()-1; i != e; ++i)
+ cerr << "Included from " << IncludeStack[i].Filename << ":"
+ << IncludeStack[i].LineNo << ":\n";
+ cerr << "Parsing " << IncludeStack.back().Filename << ":"
+ << Filelineno << ": ";
+ return *cerr.stream();
+}
+
+/// ParseFile - this function begins the parsing of the specified tablegen file.
+///
+void ParseFile(const std::string &Filename,
+ const std::vector<std::string> &IncludeDirs) {
+ FILE *F = stdin;
+ if (Filename != "-") {
+ F = fopen(Filename.c_str(), "r");
+
+ if (F == 0) {
+ 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.
+ IncludeDirectories = IncludeDirs;
+
+ 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);
+ //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.
+ //
+ std::string NextFilename;
+ for (unsigned i = 0, e = IncludeDirectories.size(); i != e; ++i) {
+ NextFilename = IncludeDirectories[i] + "/" + Filename;
+ if ((yyin = fopen(NextFilename.c_str(), "r")))
+ break;
+ }
+
+ if (yyin == 0) {
+ err() << "Could not find include file '" << Filename << "'!\n";
+ exit(1);
+ }
+ Filename = NextFilename;
+ }
+
+ // 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(void) {
+ 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;
+}
+
+} // End llvm namespace
+
+using namespace llvm;
+
+%}
+
+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; }
+defm { return DEFM; }
+multiclass { return MULTICLASS; }
+field { return FIELD; }
+let { return LET; }
+in { return IN; }
+
+!con { return CONCATTOK; }
+!sra { return SRATOK; }
+!srl { return SRLTOK; }
+!shl { return SHLTOK; }
+!strconcat { return STRCONCATTOK; }
+
+
+{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\r]+ { /* 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"; exit(1); }
+
+. { return Filetext[0]; }
+
+%%
+
diff --git a/utils/TableGen/FileLexer.l.cvs b/utils/TableGen/FileLexer.l.cvs
new file mode 100644
index 0000000000..59bbdad7bf
--- /dev/null
+++ b/utils/TableGen/FileLexer.l.cvs
@@ -0,0 +1,240 @@
+/*===-- FileLexer.l - Scanner for TableGen Files ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This 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 "llvm/Config/config.h"
+#include "llvm/Support/Streams.h"
+#include "Record.h"
+typedef std::pair<llvm::Record*, std::vector<llvm::Init*>*> SubClassRefTy;
+#include "FileParser.h"
+
+int Fileparse();
+
+namespace llvm {
+
+// Global variable recording the location of the include directory
+std::vector<std::string> IncludeDirectories;
+
+/// 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 strtoll(Str+2, 0, 2);
+ return strtoll(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()) {
+ cerr << "At end of input: ";
+ return *cerr.stream();
+ }
+
+ for (unsigned i = 0, e = IncludeStack.size()-1; i != e; ++i)
+ cerr << "Included from " << IncludeStack[i].Filename << ":"
+ << IncludeStack[i].LineNo << ":\n";
+ cerr << "Parsing " << IncludeStack.back().Filename << ":"
+ << Filelineno << ": ";
+ return *cerr.stream();
+}
+
+/// ParseFile - this function begins the parsing of the specified tablegen file.
+///
+void ParseFile(const std::string &Filename,
+ const std::vector<std::string> &IncludeDirs) {
+ FILE *F = stdin;
+ if (Filename != "-") {
+ F = fopen(Filename.c_str(), "r");
+
+ if (F == 0) {
+ 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.
+ IncludeDirectories = IncludeDirs;
+
+ 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);
+ //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.
+ //
+ std::string NextFilename;
+ for (unsigned i = 0, e = IncludeDirectories.size(); i != e; ++i) {
+ NextFilename = IncludeDirectories[i] + "/" + Filename;
+ if ((yyin = fopen(NextFilename.c_str(), "r")))
+ break;
+ }
+
+ if (yyin == 0) {
+ err() << "Could not find include file '" << Filename << "'!\n";
+ exit(1);
+ }
+ Filename = NextFilename;
+ }
+
+ // 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(void) {
+ 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;
+}
+
+} // End llvm namespace
+
+using namespace llvm;
+
+%}
+
+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; }
+defm { return DEFM; }
+multiclass { return MULTICLASS; }
+field { return FIELD; }
+let { return LET; }
+in { return IN; }
+
+!con { return CONCATTOK; }
+!sra { return SRATOK; }
+!srl { return SRLTOK; }
+!shl { return SHLTOK; }
+!strconcat { return STRCONCATTOK; }
+
+
+{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\r]+ { /* 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"; exit(1); }
+
+. { return Filetext[0]; }
+
+%%
+
diff --git a/utils/TableGen/FileParser.cpp.cvs b/utils/TableGen/FileParser.cpp.cvs
new file mode 100644
index 0000000000..6cfc3dde27
--- /dev/null
+++ b/utils/TableGen/FileParser.cpp.cvs
@@ -0,0 +1,2863 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+/* Substitute the variable and function names. */
+#define yyparse Fileparse
+#define yylex Filelex
+#define yyerror Fileerror
+#define yylval Filelval
+#define yychar Filechar
+#define yydebug Filedebug
+#define yynerrs Filenerrs
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ INT = 258,
+ BIT = 259,
+ STRING = 260,
+ BITS = 261,
+ LIST = 262,
+ CODE = 263,
+ DAG = 264,
+ CLASS = 265,
+ DEF = 266,
+ MULTICLASS = 267,
+ DEFM = 268,
+ FIELD = 269,
+ LET = 270,
+ IN = 271,
+ SHLTOK = 272,
+ SRATOK = 273,
+ SRLTOK = 274,
+ STRCONCATTOK = 275,
+ INTVAL = 276,
+ ID = 277,
+ VARNAME = 278,
+ STRVAL = 279,
+ CODEFRAGMENT = 280
+ };
+#endif
+/* Tokens. */
+#define INT 258
+#define BIT 259
+#define STRING 260
+#define BITS 261
+#define LIST 262
+#define CODE 263
+#define DAG 264
+#define CLASS 265
+#define DEF 266
+#define MULTICLASS 267
+#define DEFM 268
+#define FIELD 269
+#define LET 270
+#define IN 271
+#define SHLTOK 272
+#define SRATOK 273
+#define SRLTOK 274
+#define STRCONCATTOK 275
+#define INTVAL 276
+#define ID 277
+#define VARNAME 278
+#define STRVAL 279
+#define CODEFRAGMENT 280
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 14 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+
+#include "Record.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Streams.h"
+#include <algorithm>
+#include <cstdio>
+#define YYERROR_VERBOSE 1
+
+int yyerror(const char *ErrorMsg);
+int yylex();
+
+namespace llvm {
+ struct MultiClass {
+ Record Rec; // Placeholder for template args and Name.
+ std::vector<Record*> DefPrototypes;
+
+ MultiClass(const std::string &Name) : Rec(Name) {}
+ };
+
+
+static std::map<std::string, MultiClass*> MultiClasses;
+
+extern int Filelineno;
+static MultiClass *CurMultiClass = 0; // Set while parsing a multiclass.
+static std::string *CurDefmPrefix = 0; // Set while parsing defm.
+static Record *CurRec = 0;
+static bool ParsingTemplateArgs = false;
+
+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();
+
+/// getActiveRec - If inside a def/class definition, return the def/class.
+/// Otherwise, if within a multidef, return it.
+static Record *getActiveRec() {
+ return CurRec ? CurRec : &CurMultiClass->Rec;
+}
+
+static void addValue(const RecordVal &RV) {
+ Record *TheRec = getActiveRec();
+
+ if (RecordVal *ERV = TheRec->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";
+ exit(1);
+ }
+ } else {
+ TheRec->addValue(RV);
+ }
+}
+
+static void addSuperClass(Record *SC) {
+ if (CurRec->isSubClassOf(SC)) {
+ err() << "Already subclass of '" << SC->getName() << "'!\n";
+ exit(1);
+ }
+ CurRec->addSuperClass(SC);
+}
+
+static void setValue(const std::string &ValName,
+ std::vector<unsigned> *BitList, Init *V) {
+ if (!V) return;
+
+ Record *TheRec = getActiveRec();
+ RecordVal *RV = TheRec->getValue(ValName);
+ if (RV == 0) {
+ err() << "Value '" << ValName << "' unknown!\n";
+ exit(1);
+ }
+
+ // Do not allow assignments like 'X = X'. This will just cause infinite loops
+ // in the resolution machinery.
+ if (!BitList)
+ if (VarInit *VI = dynamic_cast<VarInit*>(V))
+ if (VI->getName() == ValName)
+ return;
+
+ // 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";
+ exit(1);
+ }
+
+ // 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";
+ exit(1);
+ }
+
+ // We should have a BitsInit type now...
+ assert(dynamic_cast<BitsInit*>(BI) != 0 || (cerr << *BI).stream() == 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";
+ exit(1);
+ }
+ 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";
+ exit(1);
+ }
+}
+
+// addSubClass - Add SC as a subclass to CurRec, resolving TemplateArgs as SC's
+// template arguments.
+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";
+ exit(1);
+ }
+
+ // Loop over all of the template arguments, setting them to the specified
+ // value or leaving them as the default if 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]);
+
+ // Resolve it next.
+ CurRec->resolveReferencesTo(CurRec->getValue(TArgs[i]));
+
+
+ // Now remove it.
+ CurRec->removeValue(TArgs[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";
+ exit(1);
+ }
+ }
+
+ // 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);
+}
+
+} // End llvm namespace
+
+using namespace llvm;
+
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 210 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+{
+ std::string* StrVal;
+ int IntVal;
+ llvm::RecTy* Ty;
+ llvm::Init* Initializer;
+ std::vector<llvm::Init*>* FieldList;
+ std::vector<unsigned>* BitList;
+ llvm::Record* Rec;
+ std::vector<llvm::Record*>* RecList;
+ SubClassRefTy* SubClassRef;
+ std::vector<SubClassRefTy>* SubClassList;
+ std::vector<std::pair<llvm::Init*, std::string> >* DagValueList;
+}
+/* Line 193 of yacc.c. */
+#line 364 "FileParser.tab.c"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 216 of yacc.c. */
+#line 377 "FileParser.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+ int i;
+#endif
+{
+ return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 27
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 204
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 41
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 50
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 102
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 188
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 280
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 35, 36, 2, 2, 37, 39, 34, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 38, 40,
+ 26, 28, 27, 29, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 32, 2, 33, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 30, 2, 31, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint16 yyprhs[] =
+{
+ 0, 0, 3, 5, 7, 9, 14, 16, 21, 23,
+ 25, 27, 28, 30, 31, 34, 36, 38, 40, 42,
+ 44, 46, 50, 55, 60, 64, 68, 73, 78, 85,
+ 92, 99, 106, 107, 110, 113, 118, 119, 121, 123,
+ 127, 130, 134, 140, 145, 147, 148, 152, 153, 155,
+ 157, 161, 166, 169, 176, 177, 180, 182, 186, 188,
+ 193, 195, 199, 200, 203, 205, 209, 213, 214, 216,
+ 218, 219, 221, 223, 225, 226, 230, 231, 232, 239,
+ 243, 245, 247, 250, 252, 253, 254, 263, 264, 271,
+ 273, 275, 277, 279, 284, 286, 290, 291, 296, 301,
+ 304, 306, 309
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 90, 0, -1, 22, -1, 5, -1, 4, -1, 6,
+ 26, 21, 27, -1, 3, -1, 7, 26, 43, 27,
+ -1, 8, -1, 9, -1, 42, -1, -1, 14, -1,
+ -1, 28, 47, -1, 22, -1, 46, -1, 21, -1,
+ 24, -1, 25, -1, 29, -1, 30, 54, 31, -1,
+ 22, 26, 55, 27, -1, 47, 30, 52, 31, -1,
+ 32, 54, 33, -1, 47, 34, 22, -1, 35, 46,
+ 50, 36, -1, 47, 32, 52, 33, -1, 17, 35,
+ 47, 37, 47, 36, -1, 18, 35, 47, 37, 47,
+ 36, -1, 19, 35, 47, 37, 47, 36, -1, 20,
+ 35, 47, 37, 47, 36, -1, -1, 38, 23, -1,
+ 47, 48, -1, 49, 37, 47, 48, -1, -1, 49,
+ -1, 21, -1, 21, 39, 21, -1, 21, 21, -1,
+ 51, 37, 21, -1, 51, 37, 21, 39, 21, -1,
+ 51, 37, 21, 21, -1, 51, -1, -1, 30, 52,
+ 31, -1, -1, 55, -1, 47, -1, 55, 37, 47,
+ -1, 44, 43, 22, 45, -1, 56, 40, -1, 15,
+ 22, 53, 28, 47, 40, -1, -1, 58, 57, -1,
+ 40, -1, 30, 58, 31, -1, 42, -1, 42, 26,
+ 55, 27, -1, 60, -1, 61, 37, 60, -1, -1,
+ 38, 61, -1, 56, -1, 63, 37, 56, -1, 26,
+ 63, 27, -1, -1, 64, -1, 22, -1, -1, 66,
+ -1, 67, -1, 67, -1, -1, 62, 71, 59, -1,
+ -1, -1, 10, 68, 73, 65, 74, 70, -1, 11,
+ 69, 70, -1, 75, -1, 76, -1, 77, 76, -1,
+ 22, -1, -1, -1, 12, 78, 80, 65, 81, 30,
+ 77, 31, -1, -1, 13, 22, 83, 38, 60, 40,
+ -1, 72, -1, 75, -1, 79, -1, 82, -1, 22,
+ 53, 28, 47, -1, 85, -1, 86, 37, 85, -1,
+ -1, 15, 88, 86, 16, -1, 87, 30, 89, 31,
+ -1, 87, 84, -1, 84, -1, 89, 84, -1, 89,
+ -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 246, 246, 268, 270, 272, 274, 276, 278, 280,
+ 282, 286, 286, 288, 288, 290, 313, 315, 317, 320,
+ 323, 325, 338, 366, 373, 376, 383, 386, 394, 396,
+ 398, 400, 404, 407, 411, 416, 422, 425, 428, 431,
+ 444, 458, 460, 473, 489, 491, 491, 495, 497, 501,
+ 504, 508, 525, 527, 533, 533, 534, 534, 536, 538,
+ 542, 547, 552, 555, 559, 562, 567, 568, 568, 570,
+ 570, 572, 579, 597, 622, 622, 641, 643, 641, 649,
+ 659, 673, 676, 680, 691, 693, 691, 700, 700, 774,
+ 774, 775, 775, 777, 782, 782, 785, 785, 788, 791,
+ 795, 795, 797
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "INT", "BIT", "STRING", "BITS", "LIST",
+ "CODE", "DAG", "CLASS", "DEF", "MULTICLASS", "DEFM", "FIELD", "LET",
+ "IN", "SHLTOK", "SRATOK", "SRLTOK", "STRCONCATTOK", "INTVAL", "ID",
+ "VARNAME", "STRVAL", "CODEFRAGMENT", "'<'", "'>'", "'='", "'?'", "'{'",
+ "'}'", "'['", "']'", "'.'", "'('", "')'", "','", "':'", "'-'", "';'",
+ "$accept", "ClassID", "Type", "OptPrefix", "OptValue", "IDValue",
+ "Value", "OptVarName", "DagArgListNE", "DagArgList", "RBitList",
+ "BitList", "OptBitList", "ValueList", "ValueListNE", "Declaration",
+ "BodyItem", "BodyList", "Body", "SubClassRef", "ClassListNE",
+ "ClassList", "DeclListNE", "TemplateArgList", "OptTemplateArgList",
+ "OptID", "ObjectName", "ClassName", "DefName", "ObjectBody", "@1",
+ "ClassInst", "@2", "@3", "DefInst", "MultiClassDef", "MultiClassBody",
+ "MultiClassName", "MultiClassInst", "@4", "@5", "DefMInst", "@6",
+ "Object", "LETItem", "LETList", "LETCommand", "@7", "ObjectList", "File", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 60, 62, 61, 63,
+ 123, 125, 91, 93, 46, 40, 41, 44, 58, 45,
+ 59
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 41, 42, 43, 43, 43, 43, 43, 43, 43,
+ 43, 44, 44, 45, 45, 46, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 48, 48, 49, 49, 50, 50, 51, 51,
+ 51, 51, 51, 51, 52, 53, 53, 54, 54, 55,
+ 55, 56, 57, 57, 58, 58, 59, 59, 60, 60,
+ 61, 61, 62, 62, 63, 63, 64, 65, 65, 66,
+ 66, 67, 68, 69, 71, 70, 73, 74, 72, 75,
+ 76, 77, 77, 78, 80, 81, 79, 83, 82, 84,
+ 84, 84, 84, 85, 86, 86, 88, 87, 84, 84,
+ 89, 89, 90
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 1, 1, 1, 4, 1, 4, 1, 1,
+ 1, 0, 1, 0, 2, 1, 1, 1, 1, 1,
+ 1, 3, 4, 4, 3, 3, 4, 4, 6, 6,
+ 6, 6, 0, 2, 2, 4, 0, 1, 1, 3,
+ 2, 3, 5, 4, 1, 0, 3, 0, 1, 1,
+ 3, 4, 2, 6, 0, 2, 1, 3, 1, 4,
+ 1, 3, 0, 2, 1, 3, 3, 0, 1, 1,
+ 0, 1, 1, 1, 0, 3, 0, 0, 6, 3,
+ 1, 1, 2, 1, 0, 0, 8, 0, 6, 1,
+ 1, 1, 1, 4, 1, 3, 0, 4, 4, 2,
+ 1, 2, 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 0, 70, 70, 0, 0, 96, 89, 90, 91, 92,
+ 100, 0, 102, 0, 69, 71, 72, 76, 73, 62,
+ 83, 84, 87, 0, 0, 99, 101, 1, 67, 0,
+ 74, 79, 67, 0, 45, 94, 0, 0, 11, 68,
+ 77, 2, 58, 60, 63, 0, 85, 0, 0, 0,
+ 97, 0, 98, 12, 0, 64, 0, 62, 0, 0,
+ 54, 56, 75, 0, 0, 38, 44, 0, 0, 95,
+ 6, 4, 3, 0, 0, 8, 9, 10, 0, 66,
+ 11, 78, 0, 0, 0, 0, 17, 15, 18, 19,
+ 20, 47, 47, 0, 16, 49, 0, 61, 11, 0,
+ 88, 40, 0, 0, 46, 93, 0, 0, 13, 65,
+ 0, 0, 0, 0, 0, 0, 48, 0, 15, 36,
+ 0, 0, 0, 59, 0, 0, 57, 0, 55, 80,
+ 81, 0, 39, 41, 0, 0, 0, 51, 0, 0,
+ 0, 0, 0, 21, 24, 32, 37, 0, 0, 0,
+ 25, 50, 45, 52, 86, 82, 43, 0, 5, 7,
+ 14, 0, 0, 0, 0, 22, 0, 34, 0, 26,
+ 23, 27, 0, 42, 0, 0, 0, 0, 33, 32,
+ 0, 28, 29, 30, 31, 35, 0, 53
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 42, 78, 54, 137, 94, 95, 167, 146, 147,
+ 66, 67, 49, 115, 116, 55, 128, 98, 62, 43,
+ 44, 30, 56, 39, 40, 15, 16, 17, 19, 31,
+ 45, 6, 28, 57, 7, 130, 131, 21, 8, 32,
+ 63, 9, 33, 10, 35, 36, 11, 23, 12, 13
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -97
+static const yytype_int16 yypact[] =
+{
+ 129, 3, 3, 11, 19, -97, -97, -97, -97, -97,
+ -97, 2, 129, 48, -97, -97, -97, -97, -97, 29,
+ -97, -97, -97, 31, 129, -97, -97, -97, 43, 56,
+ -97, -97, 43, 42, 53, -97, -6, -4, 71, -97,
+ -97, -97, 72, -97, 65, 9, -97, 56, 87, 78,
+ -97, 31, -97, -97, 15, -97, 13, 29, 41, 56,
+ -97, -97, -97, 84, 80, 7, 81, 106, 41, -97,
+ -97, -97, -97, 120, 122, -97, -97, -97, 127, -97,
+ 71, -97, 115, 116, 117, 118, -97, 128, -97, -97,
+ -97, 41, 41, 133, -97, 113, 27, -97, 60, 145,
+ -97, -97, 136, 137, -97, 113, 138, 15, 132, -97,
+ 41, 41, 41, 41, 41, 130, 125, 131, -97, 41,
+ 87, 87, 141, -97, 41, 143, -97, 126, -97, -97,
+ -97, 5, -97, 8, 140, 142, 41, -97, 67, 73,
+ 79, 85, 45, -97, -97, 54, 134, 139, 146, 135,
+ -97, 113, 53, -97, -97, -97, -97, 149, -97, -97,
+ 113, 41, 41, 41, 41, -97, 150, -97, 41, -97,
+ -97, -97, 144, -97, 91, 94, 99, 102, -97, 54,
+ 41, -97, -97, -97, -97, -97, 47, -97
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -97, -52, 69, -97, -97, 86, -68, -5, -97, -97,
+ -97, -31, 26, 88, -57, -46, -97, -97, -97, -21,
+ -97, -97, -97, -97, 151, -97, 179, -97, -97, 147,
+ -97, -97, -97, -97, -96, 51, -97, -97, -97, -97,
+ -97, -97, -97, -7, 148, -97, -97, -97, 160, -97
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+ 105, 96, 77, 129, 25, 26, 1, 2, 3, 4,
+ 50, 5, 1, 2, 3, 4, 2, 5, 70, 71,
+ 72, 73, 74, 75, 76, 14, 64, 52, 101, 156,
+ 26, 51, 24, 20, 109, 129, 154, 41, 97, 60,
+ 79, 22, 138, 139, 140, 141, 102, 157, 27, 61,
+ 80, 145, 127, 34, 123, 77, 151, 142, 82, 83,
+ 84, 85, 86, 87, 124, 88, 89, 29, 160, 38,
+ 90, 91, 165, 92, 53, 125, 93, 120, 41, 121,
+ 47, 122, 124, 48, 120, 53, 121, 187, 122, 148,
+ 149, 126, 166, 174, 175, 176, 177, 120, 58, 121,
+ 179, 122, 59, 120, 161, 121, 68, 122, 65, 120,
+ 162, 121, 186, 122, 99, 120, 163, 121, 103, 122,
+ 100, 120, 164, 121, 120, 122, 121, 181, 122, 120,
+ 182, 121, 120, 122, 121, 183, 122, 104, 184, 1,
+ 2, 3, 4, 120, 5, 121, 106, 122, 107, 108,
+ 110, 111, 112, 113, 114, 118, 2, 132, 133, 134,
+ 136, 143, 124, 150, 144, 152, 153, 158, 171, 159,
+ 173, 168, 180, 178, 185, 169, 135, 170, 172, 119,
+ 117, 18, 155, 46, 37, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 69,
+ 0, 0, 0, 0, 81
+};
+
+static const yytype_int16 yycheck[] =
+{
+ 68, 58, 54, 99, 11, 12, 10, 11, 12, 13,
+ 16, 15, 10, 11, 12, 13, 11, 15, 3, 4,
+ 5, 6, 7, 8, 9, 22, 47, 31, 21, 21,
+ 37, 37, 30, 22, 80, 131, 31, 22, 59, 30,
+ 27, 22, 110, 111, 112, 113, 39, 39, 0, 40,
+ 37, 119, 98, 22, 27, 107, 124, 114, 17, 18,
+ 19, 20, 21, 22, 37, 24, 25, 38, 136, 26,
+ 29, 30, 27, 32, 14, 15, 35, 30, 22, 32,
+ 38, 34, 37, 30, 30, 14, 32, 40, 34, 120,
+ 121, 31, 38, 161, 162, 163, 164, 30, 26, 32,
+ 168, 34, 37, 30, 37, 32, 28, 34, 21, 30,
+ 37, 32, 180, 34, 30, 30, 37, 32, 37, 34,
+ 40, 30, 37, 32, 30, 34, 32, 36, 34, 30,
+ 36, 32, 30, 34, 32, 36, 34, 31, 36, 10,
+ 11, 12, 13, 30, 15, 32, 26, 34, 26, 22,
+ 35, 35, 35, 35, 26, 22, 11, 21, 21, 21,
+ 28, 31, 37, 22, 33, 22, 40, 27, 33, 27,
+ 21, 37, 28, 23, 179, 36, 107, 31, 152, 93,
+ 92, 2, 131, 32, 24, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 51,
+ -1, -1, -1, -1, 57
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 10, 11, 12, 13, 15, 72, 75, 79, 82,
+ 84, 87, 89, 90, 22, 66, 67, 68, 67, 69,
+ 22, 78, 22, 88, 30, 84, 84, 0, 73, 38,
+ 62, 70, 80, 83, 22, 85, 86, 89, 26, 64,
+ 65, 22, 42, 60, 61, 71, 65, 38, 30, 53,
+ 16, 37, 31, 14, 44, 56, 63, 74, 26, 37,
+ 30, 40, 59, 81, 60, 21, 51, 52, 28, 85,
+ 3, 4, 5, 6, 7, 8, 9, 42, 43, 27,
+ 37, 70, 17, 18, 19, 20, 21, 22, 24, 25,
+ 29, 30, 32, 35, 46, 47, 55, 60, 58, 30,
+ 40, 21, 39, 37, 31, 47, 26, 26, 22, 56,
+ 35, 35, 35, 35, 26, 54, 55, 54, 22, 46,
+ 30, 32, 34, 27, 37, 15, 31, 56, 57, 75,
+ 76, 77, 21, 21, 21, 43, 28, 45, 47, 47,
+ 47, 47, 55, 31, 33, 47, 49, 50, 52, 52,
+ 22, 47, 22, 40, 31, 76, 21, 39, 27, 27,
+ 47, 37, 37, 37, 37, 27, 38, 48, 37, 36,
+ 31, 33, 53, 21, 47, 47, 47, 47, 23, 47,
+ 28, 36, 36, 36, 36, 48, 47, 40
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ yytype_int16 *bottom;
+ yytype_int16 *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ fprintf (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ fprintf (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+ int yyn = yypact[yystate];
+
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol. */
+int yychar;
+
+/* The semantic value of the look-ahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ int yystate;
+ int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss = yyssa;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ look-ahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to look-ahead token. */
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a look-ahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the look-ahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 2:
+#line 246 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ if (CurDefmPrefix) {
+ // If CurDefmPrefix is set, we're parsing a defm, which means that this is
+ // actually the name of a multiclass.
+ MultiClass *MC = MultiClasses[*(yyvsp[(1) - (1)].StrVal)];
+ if (MC == 0) {
+ err() << "Couldn't find class '" << *(yyvsp[(1) - (1)].StrVal) << "'!\n";
+ exit(1);
+ }
+ (yyval.Rec) = &MC->Rec;
+ } else {
+ (yyval.Rec) = Records.getClass(*(yyvsp[(1) - (1)].StrVal));
+ }
+ if ((yyval.Rec) == 0) {
+ err() << "Couldn't find class '" << *(yyvsp[(1) - (1)].StrVal) << "'!\n";
+ exit(1);
+ }
+ delete (yyvsp[(1) - (1)].StrVal);
+ ;}
+ break;
+
+ case 3:
+#line 268 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ { // string type
+ (yyval.Ty) = new StringRecTy();
+ ;}
+ break;
+
+ case 4:
+#line 270 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ { // bit type
+ (yyval.Ty) = new BitRecTy();
+ ;}
+ break;
+
+ case 5:
+#line 272 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ { // bits<x> type
+ (yyval.Ty) = new BitsRecTy((yyvsp[(3) - (4)].IntVal));
+ ;}
+ break;
+
+ case 6:
+#line 274 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ { // int type
+ (yyval.Ty) = new IntRecTy();
+ ;}
+ break;
+
+ case 7:
+#line 276 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ { // list<x> type
+ (yyval.Ty) = new ListRecTy((yyvsp[(3) - (4)].Ty));
+ ;}
+ break;
+
+ case 8:
+#line 278 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ { // code type
+ (yyval.Ty) = new CodeRecTy();
+ ;}
+ break;
+
+ case 9:
+#line 280 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ { // dag type
+ (yyval.Ty) = new DagRecTy();
+ ;}
+ break;
+
+ case 10:
+#line 282 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ { // Record Type
+ (yyval.Ty) = new RecordRecTy((yyvsp[(1) - (1)].Rec));
+ ;}
+ break;
+
+ case 11:
+#line 286 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ { (yyval.IntVal) = 0; ;}
+ break;
+
+ case 12:
+#line 286 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ { (yyval.IntVal) = 1; ;}
+ break;
+
+ case 13:
+#line 288 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ { (yyval.Initializer) = 0; ;}
+ break;
+
+ case 14:
+#line 288 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ { (yyval.Initializer) = (yyvsp[(2) - (2)].Initializer); ;}
+ break;
+
+ case 15:
+#line 290 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ if (const RecordVal *RV = (CurRec ? CurRec->getValue(*(yyvsp[(1) - (1)].StrVal)) : 0)) {
+ (yyval.Initializer) = new VarInit(*(yyvsp[(1) - (1)].StrVal), RV->getType());
+ } else if (CurRec && CurRec->isTemplateArg(CurRec->getName()+":"+*(yyvsp[(1) - (1)].StrVal))) {
+ const RecordVal *RV = CurRec->getValue(CurRec->getName()+":"+*(yyvsp[(1) - (1)].StrVal));
+ assert(RV && "Template arg doesn't exist??");
+ (yyval.Initializer) = new VarInit(CurRec->getName()+":"+*(yyvsp[(1) - (1)].StrVal), RV->getType());
+ } else if (CurMultiClass &&
+ CurMultiClass->Rec.isTemplateArg(CurMultiClass->Rec.getName()+"::"+*(yyvsp[(1) - (1)].StrVal))) {
+ std::string Name = CurMultiClass->Rec.getName()+"::"+*(yyvsp[(1) - (1)].StrVal);
+ const RecordVal *RV = CurMultiClass->Rec.getValue(Name);
+ assert(RV && "Template arg doesn't exist??");
+ (yyval.Initializer) = new VarInit(Name, RV->getType());
+ } else if (Record *D = Records.getDef(*(yyvsp[(1) - (1)].StrVal))) {
+ (yyval.Initializer) = new DefInit(D);
+ } else {
+ err() << "Variable not defined: '" << *(yyvsp[(1) - (1)].StrVal) << "'!\n";
+ exit(1);
+ }
+
+ delete (yyvsp[(1) - (1)].StrVal);
+;}
+ break;
+
+ case 16:
+#line 313 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.Initializer) = (yyvsp[(1) - (1)].Initializer);
+ ;}
+ break;
+
+ case 17:
+#line 315 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.Initializer) = new IntInit((yyvsp[(1) - (1)].IntVal));
+ ;}
+ break;
+
+ case 18:
+#line 317 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.Initializer) = new StringInit(*(yyvsp[(1) - (1)].StrVal));
+ delete (yyvsp[(1) - (1)].StrVal);
+ ;}
+ break;
+
+ case 19:
+#line 320 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.Initializer) = new CodeInit(*(yyvsp[(1) - (1)].StrVal));
+ delete (yyvsp[(1) - (1)].StrVal);
+ ;}
+ break;
+
+ case 20:
+#line 323 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.Initializer) = new UnsetInit();
+ ;}
+ break;
+
+ case 21:
+#line 325 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ BitsInit *Init = new BitsInit((yyvsp[(2) - (3)].FieldList)->size());
+ for (unsigned i = 0, e = (yyvsp[(2) - (3)].FieldList)->size(); i != e; ++i) {
+ struct Init *Bit = (*(yyvsp[(2) - (3)].FieldList))[i]->convertInitializerTo(new BitRecTy());
+ if (Bit == 0) {
+ err() << "Element #" << i << " (" << *(*(yyvsp[(2) - (3)].FieldList))[i]
+ << ") is not convertable to a bit!\n";
+ exit(1);
+ }
+ Init->setBit((yyvsp[(2) - (3)].FieldList)->size()-i-1, Bit);
+ }
+ (yyval.Initializer) = Init;
+ delete (yyvsp[(2) - (3)].FieldList);
+ ;}
+ break;
+
+ case 22:
+#line 338 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ // This is a CLASS<initvalslist> expression. This is supposed to synthesize
+ // a new anonymous definition, deriving from CLASS<initvalslist> with no
+ // body.
+ Record *Class = Records.getClass(*(yyvsp[(1) - (4)].StrVal));
+ if (!Class) {
+ err() << "Expected a class, got '" << *(yyvsp[(1) - (4)].StrVal) << "'!\n";
+ exit(1);
+ }
+ delete (yyvsp[(1) - (4)].StrVal);
+
+ static unsigned AnonCounter = 0;
+ Record *OldRec = CurRec; // Save CurRec.
+
+ // Create the new record, set it as CurRec temporarily.
+ CurRec = new Record("anonymous.val."+utostr(AnonCounter++));
+ addSubClass(Class, *(yyvsp[(3) - (4)].FieldList)); // Add info about the subclass to CurRec.
+ delete (yyvsp[(3) - (4)].FieldList); // Free up the template args.
+
+ CurRec->resolveReferences();
+
+ Records.addDef(CurRec);
+
+ // The result of the expression is a reference to the new record.
+ (yyval.Initializer) = new DefInit(CurRec);
+
+ // Restore the old CurRec
+ CurRec = OldRec;
+ ;}
+ break;
+
+ case 23:
+#line 366 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.Initializer) = (yyvsp[(1) - (4)].Initializer)->convertInitializerBitRange(*(yyvsp[(3) - (4)].BitList));
+ if ((yyval.Initializer) == 0) {
+ err() << "Invalid bit range for value '" << *(yyvsp[(1) - (4)].Initializer) << "'!\n";
+ exit(1);
+ }
+ delete (yyvsp[(3) - (4)].BitList);
+ ;}
+ break;
+
+ case 24:
+#line 373 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.Initializer) = new ListInit(*(yyvsp[(2) - (3)].FieldList));
+ delete (yyvsp[(2) - (3)].FieldList);
+ ;}
+ break;
+
+ case 25:
+#line 376 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ if (!(yyvsp[(1) - (3)].Initializer)->getFieldType(*(yyvsp[(3) - (3)].StrVal))) {
+ err() << "Cannot access field '" << *(yyvsp[(3) - (3)].StrVal) << "' of value '" << *(yyvsp[(1) - (3)].Initializer) << "!\n";
+ exit(1);
+ }
+ (yyval.Initializer) = new FieldInit((yyvsp[(1) - (3)].Initializer), *(yyvsp[(3) - (3)].StrVal));
+ delete (yyvsp[(3) - (3)].StrVal);
+ ;}
+ break;
+
+ case 26:
+#line 383 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.Initializer) = new DagInit((yyvsp[(2) - (4)].Initializer), *(yyvsp[(3) - (4)].DagValueList));
+ delete (yyvsp[(3) - (4)].DagValueList);
+ ;}
+ break;
+
+ case 27:
+#line 386 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ std::reverse((yyvsp[(3) - (4)].BitList)->begin(), (yyvsp[(3) - (4)].BitList)->end());
+ (yyval.Initializer) = (yyvsp[(1) - (4)].Initializer)->convertInitListSlice(*(yyvsp[(3) - (4)].BitList));
+ if ((yyval.Initializer) == 0) {
+ err() << "Invalid list slice for value '" << *(yyvsp[(1) - (4)].Initializer) << "'!\n";
+ exit(1);
+ }
+ delete (yyvsp[(3) - (4)].BitList);
+ ;}
+ break;
+
+ case 28:
+#line 394 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.Initializer) = (new BinOpInit(BinOpInit::SHL, (yyvsp[(3) - (6)].Initializer), (yyvsp[(5) - (6)].Initializer)))->Fold();
+ ;}
+ break;
+
+ case 29:
+#line 396 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.Initializer) = (new BinOpInit(BinOpInit::SRA, (yyvsp[(3) - (6)].Initializer), (yyvsp[(5) - (6)].Initializer)))->Fold();
+ ;}
+ break;
+
+ case 30:
+#line 398 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.Initializer) = (new BinOpInit(BinOpInit::SRL, (yyvsp[(3) - (6)].Initializer), (yyvsp[(5) - (6)].Initializer)))->Fold();
+ ;}
+ break;
+
+ case 31:
+#line 400 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.Initializer) = (new BinOpInit(BinOpInit::STRCONCAT, (yyvsp[(3) - (6)].Initializer), (yyvsp[(5) - (6)].Initializer)))->Fold();
+ ;}
+ break;
+
+ case 32:
+#line 404 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.StrVal) = new std::string();
+ ;}
+ break;
+
+ case 33:
+#line 407 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.StrVal) = (yyvsp[(2) - (2)].StrVal);
+ ;}
+ break;
+
+ case 34:
+#line 411 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.DagValueList) = new std::vector<std::pair<Init*, std::string> >();
+ (yyval.DagValueList)->push_back(std::make_pair((yyvsp[(1) - (2)].Initializer), *(yyvsp[(2) - (2)].StrVal)));
+ delete (yyvsp[(2) - (2)].StrVal);
+ ;}
+ break;
+
+ case 35:
+#line 416 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyvsp[(1) - (4)].DagValueList)->push_back(std::make_pair((yyvsp[(3) - (4)].Initializer), *(yyvsp[(4) - (4)].StrVal)));
+ delete (yyvsp[(4) - (4)].StrVal);
+ (yyval.DagValueList) = (yyvsp[(1) - (4)].DagValueList);
+ ;}
+ break;
+
+ case 36:
+#line 422 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.DagValueList) = new std::vector<std::pair<Init*, std::string> >();
+ ;}
+ break;
+
+ case 37:
+#line 425 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ { (yyval.DagValueList) = (yyvsp[(1) - (1)].DagValueList); ;}
+ break;
+
+ case 38:
+#line 428 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.BitList) = new std::vector<unsigned>();
+ (yyval.BitList)->push_back((yyvsp[(1) - (1)].IntVal));
+ ;}
+ break;
+
+ case 39:
+#line 431 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ if ((yyvsp[(1) - (3)].IntVal) < 0 || (yyvsp[(3) - (3)].IntVal) < 0) {
+ err() << "Invalid range: " << (yyvsp[(1) - (3)].IntVal) << "-" << (yyvsp[(3) - (3)].IntVal) << "!\n";
+ exit(1);
+ }
+ (yyval.BitList) = new std::vector<unsigned>();
+ if ((yyvsp[(1) - (3)].IntVal) < (yyvsp[(3) - (3)].IntVal)) {
+ for (int i = (yyvsp[(1) - (3)].IntVal); i <= (yyvsp[(3) - (3)].IntVal); ++i)
+ (yyval.BitList)->push_back(i);
+ } else {
+ for (int i = (yyvsp[(1) - (3)].IntVal); i >= (yyvsp[(3) - (3)].IntVal); --i)
+ (yyval.BitList)->push_back(i);
+ }
+ ;}
+ break;
+
+ case 40:
+#line 444 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyvsp[(2) - (2)].IntVal) = -(yyvsp[(2) - (2)].IntVal);
+ if ((yyvsp[(1) - (2)].IntVal) < 0 || (yyvsp[(2) - (2)].IntVal) < 0) {
+ err() << "Invalid range: " << (yyvsp[(1) - (2)].IntVal) << "-" << (yyvsp[(2) - (2)].IntVal) << "!\n";
+ exit(1);
+ }
+ (yyval.BitList) = new std::vector<unsigned>();
+ if ((yyvsp[(1) - (2)].IntVal) < (yyvsp[(2) - (2)].IntVal)) {
+ for (int i = (yyvsp[(1) - (2)].IntVal); i <= (yyvsp[(2) - (2)].IntVal); ++i)
+ (yyval.BitList)->push_back(i);
+ } else {
+ for (int i = (yyvsp[(1) - (2)].IntVal); i >= (yyvsp[(2) - (2)].IntVal); --i)
+ (yyval.BitList)->push_back(i);
+ }
+ ;}
+ break;
+
+ case 41:
+#line 458 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ ((yyval.BitList)=(yyvsp[(1) - (3)].BitList))->push_back((yyvsp[(3) - (3)].IntVal));
+ ;}
+ break;
+
+ case 42:
+#line 460 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ if ((yyvsp[(3) - (5)].IntVal) < 0 || (yyvsp[(5) - (5)].IntVal) < 0) {
+ err() << "Invalid range: " << (yyvsp[(3) - (5)].IntVal) << "-" << (yyvsp[(5) - (5)].IntVal) << "!\n";
+ exit(1);
+ }
+ (yyval.BitList) = (yyvsp[(1) - (5)].BitList);
+ if ((yyvsp[(3) - (5)].IntVal) < (yyvsp[(5) - (5)].IntVal)) {
+ for (int i = (yyvsp[(3) - (5)].IntVal); i <= (yyvsp[(5) - (5)].IntVal); ++i)
+ (yyval.BitList)->push_back(i);
+ } else {
+ for (int i = (yyvsp[(3) - (5)].IntVal); i >= (yyvsp[(5) - (5)].IntVal); --i)
+ (yyval.BitList)->push_back(i);
+ }
+ ;}
+ break;
+
+ case 43:
+#line 473 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyvsp[(4) - (4)].IntVal) = -(yyvsp[(4) - (4)].IntVal);
+ if ((yyvsp[(3) - (4)].IntVal) < 0 || (yyvsp[(4) - (4)].IntVal) < 0) {
+ err() << "Invalid range: " << (yyvsp[(3) - (4)].IntVal) << "-" << (yyvsp[(4) - (4)].IntVal) << "!\n";
+ exit(1);
+ }
+ (yyval.BitList) = (yyvsp[(1) - (4)].BitList);
+ if ((yyvsp[(3) - (4)].IntVal) < (yyvsp[(4) - (4)].IntVal)) {
+ for (int i = (yyvsp[(3) - (4)].IntVal); i <= (yyvsp[(4) - (4)].IntVal); ++i)
+ (yyval.BitList)->push_back(i);
+ } else {
+ for (int i = (yyvsp[(3) - (4)].IntVal); i >= (yyvsp[(4) - (4)].IntVal); --i)
+ (yyval.BitList)->push_back(i);
+ }
+ ;}
+ break;
+
+ case 44:
+#line 489 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ { (yyval.BitList) = (yyvsp[(1) - (1)].BitList); std::reverse((yyvsp[(1) - (1)].BitList)->begin(), (yyvsp[(1) - (1)].BitList)->end()); ;}
+ break;
+
+ case 45:
+#line 491 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ { (yyval.BitList) = 0; ;}
+ break;
+
+ case 46:
+#line 491 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ { (yyval.BitList) = (yyvsp[(2) - (3)].BitList); ;}
+ break;
+
+ case 47:
+#line 495 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.FieldList) = new std::vector<Init*>();
+ ;}
+ break;
+
+ case 48:
+#line 497 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.FieldList) = (yyvsp[(1) - (1)].FieldList);
+ ;}
+ break;
+
+ case 49:
+#line 501 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.FieldList) = new std::vector<Init*>();
+ (yyval.FieldList)->push_back((yyvsp[(1) - (1)].Initializer));
+ ;}
+ break;
+
+ case 50:
+#line 504 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ ((yyval.FieldList) = (yyvsp[(1) - (3)].FieldList))->push_back((yyvsp[(3) - (3)].Initializer));
+ ;}
+ break;
+
+ case 51:
+#line 508 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ std::string DecName = *(yyvsp[(3) - (4)].StrVal);
+ if (ParsingTemplateArgs) {
+ if (CurRec) {
+ DecName = CurRec->getName() + ":" + DecName;
+ } else {
+ assert(CurMultiClass);
+ }
+ if (CurMultiClass)
+ DecName = CurMultiClass->Rec.getName() + "::" + DecName;
+ }
+
+ addValue(RecordVal(DecName, (yyvsp[(2) - (4)].Ty), (yyvsp[(1) - (4)].IntVal)));
+ setValue(DecName, 0, (yyvsp[(4) - (4)].Initializer));
+ (yyval.StrVal) = new std::string(DecName);
+;}
+ break;
+
+ case 52:
+#line 525 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ delete (yyvsp[(1) - (2)].StrVal);
+;}
+ break;
+
+ case 53:
+#line 527 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ setValue(*(yyvsp[(2) - (6)].StrVal), (yyvsp[(3) - (6)].BitList), (yyvsp[(5) - (6)].Initializer));
+ delete (yyvsp[(2) - (6)].StrVal);
+ delete (yyvsp[(3) - (6)].BitList);
+;}
+ break;
+
+ case 58:
+#line 536 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.SubClassRef) = new SubClassRefTy((yyvsp[(1) - (1)].Rec), new std::vector<Init*>());
+ ;}
+ break;
+
+ case 59:
+#line 538 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.SubClassRef) = new SubClassRefTy((yyvsp[(1) - (4)].Rec), (yyvsp[(3) - (4)].FieldList));
+ ;}
+ break;
+
+ case 60:
+#line 542 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.SubClassList) = new std::vector<SubClassRefTy>();
+ (yyval.SubClassList)->push_back(*(yyvsp[(1) - (1)].SubClassRef));
+ delete (yyvsp[(1) - (1)].SubClassRef);
+ ;}
+ break;
+
+ case 61:
+#line 547 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ ((yyval.SubClassList)=(yyvsp[(1) - (3)].SubClassList))->push_back(*(yyvsp[(3) - (3)].SubClassRef));
+ delete (yyvsp[(3) - (3)].SubClassRef);
+ ;}
+ break;
+
+ case 62:
+#line 552 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.SubClassList) = new std::vector<SubClassRefTy>();
+ ;}
+ break;
+
+ case 63:
+#line 555 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.SubClassList) = (yyvsp[(2) - (2)].SubClassList);
+ ;}
+ break;
+
+ case 64:
+#line 559 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ getActiveRec()->addTemplateArg(*(yyvsp[(1) - (1)].StrVal));
+ delete (yyvsp[(1) - (1)].StrVal);
+;}
+ break;
+
+ case 65:
+#line 562 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ getActiveRec()->addTemplateArg(*(yyvsp[(3) - (3)].StrVal));
+ delete (yyvsp[(3) - (3)].StrVal);
+;}
+ break;
+
+ case 66:
+#line 567 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {;}
+ break;
+
+ case 69:
+#line 570 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ { (yyval.StrVal) = (yyvsp[(1) - (1)].StrVal); ;}
+ break;
+
+ case 70:
+#line 570 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ { (yyval.StrVal) = new std::string(); ;}
+ break;
+
+ case 71:
+#line 572 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ static unsigned AnonCounter = 0;
+ if ((yyvsp[(1) - (1)].StrVal)->empty())
+ *(yyvsp[(1) - (1)].StrVal) = "anonymous."+utostr(AnonCounter++);
+ (yyval.StrVal) = (yyvsp[(1) - (1)].StrVal);
+;}
+ break;
+
+ case 72:
+#line 579 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ // If a class of this name already exists, it must be a forward ref.
+ if ((CurRec = Records.getClass(*(yyvsp[(1) - (1)].StrVal)))) {
+ // If the body was previously defined, this is an error.
+ if (!CurRec->getValues().empty() ||
+ !CurRec->getSuperClasses().empty() ||
+ !CurRec->getTemplateArgs().empty()) {
+ err() << "Class '" << CurRec->getName() << "' already defined!\n";
+ exit(1);
+ }
+ } else {
+ // If this is the first reference to this class, create and add it.
+ CurRec = new Record(*(yyvsp[(1) - (1)].StrVal));
+ Records.addClass(CurRec);
+ }
+ delete (yyvsp[(1) - (1)].StrVal);
+;}
+ break;
+
+ case 73:
+#line 597 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ CurRec = new Record(*(yyvsp[(1) - (1)].StrVal));
+ delete (yyvsp[(1) - (1)].StrVal);
+
+ if (!CurMultiClass) {
+ // Top-level def definition.
+
+ // Ensure redefinition doesn't happen.
+ if (Records.getDef(CurRec->getName())) {
+ err() << "def '" << CurRec->getName() << "' already defined!\n";
+ exit(1);
+ }
+ Records.addDef(CurRec);
+ } else {
+ // Otherwise, a def inside a multiclass, add it to the multiclass.
+ for (unsigned i = 0, e = CurMultiClass->DefPrototypes.size(); i != e; ++i)
+ if (CurMultiClass->DefPrototypes[i]->getName() == CurRec->getName()) {
+ err() << "def '" << CurRec->getName()
+ << "' already defined in this multiclass!\n";
+ exit(1);
+ }
+ CurMultiClass->DefPrototypes.push_back(CurRec);
+ }
+;}
+ break;
+
+ case 74:
+#line 622 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ for (unsigned i = 0, e = (yyvsp[(1) - (1)].SubClassList)->size(); i != e; ++i) {
+ addSubClass((*(yyvsp[(1) - (1)].SubClassList))[i].first, *(*(yyvsp[(1) - (1)].SubClassList))[i].second);
+ // Delete the template arg values for the class
+ delete (*(yyvsp[(1) - (1)].SubClassList))[i].second;
+ }
+ delete (yyvsp[(1) - (1)].SubClassList); // Delete the class list.
+
+ // Process any variables on the let 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);
+ ;}
+ break;
+
+ case 75:
+#line 636 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.Rec) = CurRec;
+ CurRec = 0;
+ ;}
+ break;
+
+ case 76:
+#line 641 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ ParsingTemplateArgs = true;
+ ;}
+ break;
+
+ case 77:
+#line 643 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ ParsingTemplateArgs = false;
+ ;}
+ break;
+
+ case 78:
+#line 645 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.Rec) = (yyvsp[(6) - (6)].Rec);
+ ;}
+ break;
+
+ case 79:
+#line 649 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ if (CurMultiClass == 0) // Def's in multiclasses aren't really defs.
+ (yyvsp[(3) - (3)].Rec)->resolveReferences();
+
+ // If ObjectBody has template arguments, it's an error.
+ assert((yyvsp[(3) - (3)].Rec)->getTemplateArgs().empty() && "How'd this get template args?");
+ (yyval.Rec) = (yyvsp[(3) - (3)].Rec);
+;}
+ break;
+
+ case 80:
+#line 659 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.Rec) = (yyvsp[(1) - (1)].Rec);
+ // Copy the template arguments for the multiclass into the def.
+ const std::vector<std::string> &TArgs = CurMultiClass->Rec.getTemplateArgs();
+
+ for (unsigned i = 0, e = TArgs.size(); i != e; ++i) {
+ const RecordVal *RV = CurMultiClass->Rec.getValue(TArgs[i]);
+ assert(RV && "Template arg doesn't exist?");
+ (yyval.Rec)->addValue(*RV);
+ }
+;}
+ break;
+
+ case 81:
+#line 673 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.RecList) = new std::vector<Record*>();
+ (yyval.RecList)->push_back((yyvsp[(1) - (1)].Rec));
+;}
+ break;
+
+ case 82:
+#line 676 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ (yyval.RecList)->push_back((yyvsp[(2) - (2)].Rec));
+;}
+ break;
+
+ case 83:
+#line 680 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ MultiClass *&MCE = MultiClasses[*(yyvsp[(1) - (1)].StrVal)];
+ if (MCE) {
+ err() << "multiclass '" << *(yyvsp[(1) - (1)].StrVal) << "' already defined!\n";
+ exit(1);
+ }
+ MCE = CurMultiClass = new MultiClass(*(yyvsp[(1) - (1)].StrVal));
+ delete (yyvsp[(1) - (1)].StrVal);
+;}
+ break;
+
+ case 84:
+#line 691 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ ParsingTemplateArgs = true;
+ ;}
+ break;
+
+ case 85:
+#line 693 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ ParsingTemplateArgs = false;
+ ;}
+ break;
+
+ case 86:
+#line 695 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ CurMultiClass = 0;
+;}
+ break;
+
+ case 87:
+#line 700 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ { CurDefmPrefix = (yyvsp[(2) - (2)].StrVal); ;}
+ break;
+
+ case 88:
+#line 700 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ // To instantiate a multiclass, we need to first get the multiclass, then
+ // instantiate each def contained in the multiclass with the SubClassRef
+ // template parameters.
+ MultiClass *MC = MultiClasses[(yyvsp[(5) - (6)].SubClassRef)->first->getName()];
+ assert(MC && "Didn't lookup multiclass correctly?");
+ std::vector<Init*> &TemplateVals = *(yyvsp[(5) - (6)].SubClassRef)->second;
+ delete (yyvsp[(5) - (6)].SubClassRef);
+
+ // Verify that the correct number of template arguments were specified.
+ const std::vector<std::string> &TArgs = MC->Rec.getTemplateArgs();
+ if (TArgs.size() < TemplateVals.size()) {
+ err() << "ERROR: More template args specified than multiclass expects!\n";
+ exit(1);
+ }
+
+ // Loop over all the def's in the multiclass, instantiating each one.
+ for (unsigned i = 0, e = MC->DefPrototypes.size(); i != e; ++i) {
+ Record *DefProto = MC->DefPrototypes[i];
+
+ // Add the suffix to the defm name to get the new name.
+ assert(CurRec == 0 && "A def is current?");
+ CurRec = new Record(*(yyvsp[(2) - (6)].StrVal) + DefProto->getName());
+
+ addSubClass(DefProto, std::vector<Init*>());
+
+ // Loop over all of the template arguments, setting them to the specified
+ // value or leaving them as the default if necessary.
+ for (unsigned i = 0, e = TArgs.size(); i != e; ++i) {
+ if (i < TemplateVals.size()) { // A value is specified for this temp-arg?
+ // Set it now.
+ setValue(TArgs[i], 0, TemplateVals[i]);
+
+ // Resolve it next.
+ CurRec->resolveReferencesTo(CurRec->getValue(TArgs[i]));
+
+ // Now remove it.
+ CurRec->removeValue(TArgs[i]);
+
+ } else if (!CurRec->getValue(TArgs[i])->getValue()->isComplete()) {
+ err() << "ERROR: Value not specified for template argument #"
+ << i << " (" << TArgs[i] << ") of multiclassclass '"
+ << MC->Rec.getName() << "'!\n";
+ exit(1);
+ }
+ }
+
+ // If the mdef is inside a 'let' expression, add to each def.
+ 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);
+
+
+ // Ensure redefinition doesn't happen.
+ if (Records.getDef(CurRec->getName())) {
+ err() << "def '" << CurRec->getName() << "' already defined, "
+ << "instantiating defm '" << *(yyvsp[(2) - (6)].StrVal) << "' with subdef '"
+ << DefProto->getName() << "'!\n";
+ exit(1);
+ }
+ Records.addDef(CurRec);
+
+ CurRec->resolveReferences();
+
+ CurRec = 0;
+ }
+
+ delete &TemplateVals;
+ delete (yyvsp[(2) - (6)].StrVal);
+ CurDefmPrefix = 0;
+;}
+ break;
+
+ case 89:
+#line 774 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {;}
+ break;
+
+ case 90:
+#line 774 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {;}
+ break;
+
+ case 93:
+#line 777 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ LetStack.back().push_back(LetRecord(*(yyvsp[(1) - (4)].StrVal), (yyvsp[(2) - (4)].BitList), (yyvsp[(4) - (4)].Initializer)));
+ delete (yyvsp[(1) - (4)].StrVal); delete (yyvsp[(2) - (4)].BitList);
+;}
+ break;
+
+ case 96:
+#line 785 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ { LetStack.push_back(std::vector<LetRecord>()); ;}
+ break;
+
+ case 98:
+#line 788 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ LetStack.pop_back();
+ ;}
+ break;
+
+ case 99:
+#line 791 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {
+ LetStack.pop_back();
+ ;}
+ break;
+
+ case 100:
+#line 795 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {;}
+ break;
+
+ case 101:
+#line 795 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+ {;}
+ break;
+
+
+/* Line 1267 of yacc.c. */
+#line 2643 "FileParser.tab.c"
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse look-ahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse look-ahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+#line 799 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+
+
+int yyerror(const char *ErrorMsg) {
+ err() << "Error parsing: " << ErrorMsg << "\n";
+ exit(1);
+}
+
diff --git a/utils/TableGen/FileParser.h.cvs b/utils/TableGen/FileParser.h.cvs
new file mode 100644
index 0000000000..e753937550
--- /dev/null
+++ b/utils/TableGen/FileParser.h.cvs
@@ -0,0 +1,120 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ INT = 258,
+ BIT = 259,
+ STRING = 260,
+ BITS = 261,
+ LIST = 262,
+ CODE = 263,
+ DAG = 264,
+ CLASS = 265,
+ DEF = 266,
+ MULTICLASS = 267,
+ DEFM = 268,
+ FIELD = 269,
+ LET = 270,
+ IN = 271,
+ SHLTOK = 272,
+ SRATOK = 273,
+ SRLTOK = 274,
+ STRCONCATTOK = 275,
+ INTVAL = 276,
+ ID = 277,
+ VARNAME = 278,
+ STRVAL = 279,
+ CODEFRAGMENT = 280
+ };
+#endif
+/* Tokens. */
+#define INT 258
+#define BIT 259
+#define STRING 260
+#define BITS 261
+#define LIST 262
+#define CODE 263
+#define DAG 264
+#define CLASS 265
+#define DEF 266
+#define MULTICLASS 267
+#define DEFM 268
+#define FIELD 269
+#define LET 270
+#define IN 271
+#define SHLTOK 272
+#define SRATOK 273
+#define SRLTOK 274
+#define STRCONCATTOK 275
+#define INTVAL 276
+#define ID 277
+#define VARNAME 278
+#define STRVAL 279
+#define CODEFRAGMENT 280
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 210 "/Volumes/Gir/devel/llvm/llvm.src/utils/TableGen/FileParser.y"
+{
+ std::string* StrVal;
+ int IntVal;
+ llvm::RecTy* Ty;
+ llvm::Init* Initializer;
+ std::vector<llvm::Init*>* FieldList;
+ std::vector<unsigned>* BitList;
+ llvm::Record* Rec;
+ std::vector<llvm::Record*>* RecList;
+ SubClassRefTy* SubClassRef;
+ std::vector<SubClassRefTy>* SubClassList;
+ std::vector<std::pair<llvm::Init*, std::string> >* DagValueList;
+}
+/* Line 1529 of yacc.c. */
+#line 113 "FileParser.tab.h"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+extern YYSTYPE Filelval;
+
diff --git a/utils/TableGen/FileParser.y b/utils/TableGen/FileParser.y
new file mode 100644
index 0000000000..0612f56ca0
--- /dev/null
+++ b/utils/TableGen/FileParser.y
@@ -0,0 +1,806 @@
+//===-- FileParser.y - Parser for TableGen files ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the bison parser for Table Generator files...
+//
+//===----------------------------------------------------------------------===//
+
+%{
+#include "Record.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Streams.h"
+#include <algorithm>
+#include <cstdio>
+#define YYERROR_VERBOSE 1
+
+int yyerror(const char *ErrorMsg);
+int yylex();
+
+namespace llvm {
+ struct MultiClass {
+ Record Rec; // Placeholder for template args and Name.
+ std::vector<Record*> DefPrototypes;
+
+ MultiClass(const std::string &Name) : Rec(Name) {}
+ };
+
+
+static std::map<std::string, MultiClass*> MultiClasses;
+
+extern int Filelineno;
+static MultiClass *CurMultiClass = 0; // Set while parsing a multiclass.
+static std::string *CurDefmPrefix = 0; // Set while parsing defm.
+static Record *CurRec = 0;
+static bool ParsingTemplateArgs = false;
+
+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();
+
+/// getActiveRec - If inside a def/class definition, return the def/class.
+/// Otherwise, if within a multidef, return it.
+static Record *getActiveRec() {
+ return CurRec ? CurRec : &CurMultiClass->Rec;
+}
+
+static void addValue(const RecordVal &RV) {
+ Record *TheRec = getActiveRec();
+
+ if (RecordVal *ERV = TheRec->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";
+ exit(1);
+ }
+ } else {
+ TheRec->addValue(RV);
+ }
+}
+
+static void addSuperClass(Record *SC) {
+ if (CurRec->isSubClassOf(SC)) {
+ err() << "Already subclass of '" << SC->getName() << "'!\n";
+ exit(1);
+ }
+ CurRec->addSuperClass(SC);
+}
+
+static void setValue(const std::string &ValName,
+ std::vector<unsigned> *BitList, Init *V) {
+ if (!V) return;
+
+ Record *TheRec = getActiveRec();
+ RecordVal *RV = TheRec->getValue(ValName);
+ if (RV == 0) {
+ err() << "Value '" << ValName << "' unknown!\n";
+ exit(1);
+ }
+
+ // Do not allow assignments like 'X = X'. This will just cause infinite loops
+ // in the resolution machinery.
+ if (!BitList)
+ if (VarInit *VI = dynamic_cast<VarInit*>(V))
+ if (VI->getName() == ValName)
+ return;
+
+ // 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";
+ exit(1);
+ }
+
+ // 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";
+ exit(1);
+ }
+
+ // We should have a BitsInit type now...
+ assert(dynamic_cast<BitsInit*>(BI) != 0 || (cerr << *BI).stream() == 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";
+ exit(1);
+ }
+ 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";
+ exit(1);
+ }
+}
+
+// addSubClass - Add SC as a subclass to CurRec, resolving TemplateArgs as SC's
+// template arguments.
+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";
+ exit(1);
+ }
+
+ // Loop over all of the template arguments, setting them to the specified
+ // value or leaving them as the default if 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]);
+
+ // Resolve it next.
+ CurRec->resolveReferencesTo(CurRec->getValue(TArgs[i]));
+
+
+ // Now remove it.
+ CurRec->removeValue(TArgs[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";
+ exit(1);
+ }
+ }
+
+ // 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);
+}
+
+} // End llvm namespace
+
+using namespace llvm;
+
+%}
+
+%union {
+ std::string* StrVal;
+ int IntVal;
+ llvm::RecTy* Ty;
+ llvm::Init* Initializer;
+ std::vector<llvm::Init*>* FieldList;
+ std::vector<unsigned>* BitList;
+ llvm::Record* Rec;
+ std::vector<llvm::Record*>* RecList;
+ SubClassRefTy* SubClassRef;
+ std::vector<SubClassRefTy>* SubClassList;
+ std::vector<std::pair<llvm::Init*, std::string> >* DagValueList;
+};
+
+%token INT BIT STRING BITS LIST CODE DAG CLASS DEF MULTICLASS DEFM FIELD LET IN
+%token CONCATTOK SHLTOK SRATOK SRLTOK STRCONCATTOK
+%token <IntVal> INTVAL
+%token <StrVal> ID VARNAME STRVAL CODEFRAGMENT
+
+%type <Ty> Type
+%type <Rec> ClassInst DefInst MultiClassDef ObjectBody ClassID
+%type <RecList> MultiClassBody
+
+%type <SubClassRef> SubClassRef
+%type <SubClassList> ClassList ClassListNE
+%type <IntVal> OptPrefix
+%type <Initializer> Value OptValue IDValue
+%type <DagValueList> DagArgList DagArgListNE
+%type <FieldList> ValueList ValueListNE
+%type <BitList> BitList OptBitList RBitList
+%type <StrVal> Declaration OptID OptVarName ObjectName
+
+%start File
+
+%%
+
+ClassID : ID {
+ if (CurDefmPrefix) {
+ // If CurDefmPrefix is set, we're parsing a defm, which means that this is
+ // actually the name of a multiclass.
+ MultiClass *MC = MultiClasses[*$1];
+ if (MC == 0) {
+ err() << "Couldn't find class '" << *$1 << "'!\n";
+ exit(1);
+ }
+ $$ = &MC->Rec;
+ } else {
+ $$ = Records.getClass(*$1);
+ }
+ if ($$ == 0) {
+ err() << "Couldn't find class '" << *$1 << "'!\n";
+ exit(1);
+ }
+ 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; };
+
+IDValue : ID {
+ if (const RecordVal *RV = (CurRec ? CurRec->getValue(*$1) : 0)) {
+ $$ = new VarInit(*$1, RV->getType());
+ } else if (CurRec && CurRec->isTemplateArg(CurRec->getName()+":"+*$1)) {
+ const RecordVal *RV = CurRec->getValue(CurRec->getName()+":"+*$1);
+ assert(RV && "Template arg doesn't exist??");
+ $$ = new VarInit(CurRec->getName()+":"+*$1, RV->getType());
+ } else if (CurMultiClass &&
+ CurMultiClass->Rec.isTemplateArg(CurMultiClass->Rec.getName()+"::"+*$1)) {
+ std::string Name = CurMultiClass->Rec.getName()+"::"+*$1;
+ const RecordVal *RV = CurMultiClass->Rec.getValue(Name);
+ assert(RV && "Template arg doesn't exist??");
+ $$ = new VarInit(Name, RV->getType());
+ } else if (Record *D = Records.getDef(*$1)) {
+ $$ = new DefInit(D);
+ } else {
+ err() << "Variable not defined: '" << *$1 << "'!\n";
+ exit(1);
+ }
+
+ delete $1;
+};
+
+Value : IDValue {
+ $$ = $1;
+ } | 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";
+ exit(1);
+ }
+ Init->setBit($2->size()-i-1, Bit);
+ }
+ $$ = Init;
+ delete $2;
+ } | ID '<' ValueListNE '>' {
+ // This is a CLASS<initvalslist> expression. This is supposed to synthesize
+ // a new anonymous definition, deriving from CLASS<initvalslist> with no
+ // body.
+ Record *Class = Records.getClass(*$1);
+ if (!Class) {
+ err() << "Expected a class, got '" << *$1 << "'!\n";
+ exit(1);
+ }
+ delete $1;
+
+ static unsigned AnonCounter = 0;
+ Record *OldRec = CurRec; // Save CurRec.
+
+ // Create the new record, set it as CurRec temporarily.
+ CurRec = new Record("anonymous.val."+utostr(AnonCounter++));
+ addSubClass(Class, *$3); // Add info about the subclass to CurRec.
+ delete $3; // Free up the template args.
+
+ CurRec->resolveReferences();
+
+ Records.addDef(CurRec);
+
+ // The result of the expression is a reference to the new record.
+ $$ = new DefInit(CurRec);
+
+ // Restore the old CurRec
+ CurRec = OldRec;
+ } | Value '{' BitList '}' {
+ $$ = $1->convertInitializerBitRange(*$3);
+ if ($$ == 0) {
+ err() << "Invalid bit range for value '" << *$1 << "'!\n";
+ exit(1);
+ }
+ delete $3;
+ } | '[' ValueList ']' {
+ $$ = new ListInit(*$2);
+ delete $2;
+ } | Value '.' ID {
+ if (!$1->getFieldType(*$3)) {
+ err() << "Cannot access field '" << *$3 << "' of value '" << *$1 << "!\n";
+ exit(1);
+ }
+ $$ = new FieldInit($1, *$3);
+ delete $3;
+ } | '(' IDValue DagArgList ')' {
+ $$ = new DagInit($2, *$3);
+ delete $3;
+ } | Value '[' BitList ']' {
+ std::reverse($3->begin(), $3->end());
+ $$ = $1->convertInitListSlice(*$3);
+ if ($$ == 0) {
+ err() << "Invalid list slice for value '" << *$1 << "'!\n";
+ exit(1);
+ }
+ delete $3;
+ } | CONCATTOK '(' Value ',' Value ')' {
+ $$ = (new BinOpInit(BinOpInit::CONCAT, $3, $5))->Fold();
+ } | SHLTOK '(' Value ',' Value ')' {
+ $$ = (new BinOpInit(BinOpInit::SHL, $3, $5))->Fold();
+ } | SRATOK '(' Value ',' Value ')' {
+ $$ = (new BinOpInit(BinOpInit::SRA, $3, $5))->Fold();
+ } | SRLTOK '(' Value ',' Value ')' {
+ $$ = (new BinOpInit(BinOpInit::SRL, $3, $5))->Fold();
+ } | STRCONCATTOK '(' Value ',' Value ')' {
+ $$ = (new BinOpInit(BinOpInit::STRCONCAT, $3, $5))->Fold();
+ };
+
+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 < 0 || $3 < 0) {
+ err() << "Invalid range: " << $1 << "-" << $3 << "!\n";
+ exit(1);
+ }
+ $$ = new std::vector<unsigned>();
+ if ($1 < $3) {
+ for (int i = $1; i <= $3; ++i)
+ $$->push_back(i);
+ } else {
+ for (int i = $1; i >= $3; --i)
+ $$->push_back(i);
+ }
+ } | INTVAL INTVAL {
+ $2 = -$2;
+ if ($1 < 0 || $2 < 0) {
+ err() << "Invalid range: " << $1 << "-" << $2 << "!\n";
+ exit(1);
+ }
+ $$ = new std::vector<unsigned>();
+ if ($1 < $2) {
+ for (int i = $1; i <= $2; ++i)
+ $$->push_back(i);
+ } else {
+ for (int i = $1; i >= $2; --i)
+ $$->push_back(i);
+ }
+ } | RBitList ',' INTVAL {
+ ($$=$1)->push_back($3);
+ } | RBitList ',' INTVAL '-' INTVAL {
+ if ($3 < 0 || $5 < 0) {
+ err() << "Invalid range: " << $3 << "-" << $5 << "!\n";
+ exit(1);
+ }
+ $$ = $1;
+ if ($3 < $5) {
+ for (int i = $3; i <= $5; ++i)
+ $$->push_back(i);
+ } else {
+ for (int i = $3; i >= $5; --i)
+ $$->push_back(i);
+ }
+ } | RBitList ',' INTVAL INTVAL {
+ $4 = -$4;
+ if ($3 < 0 || $4 < 0) {
+ err() << "Invalid range: " << $3 << "-" << $4 << "!\n";
+ exit(1);
+ }
+ $$ = $1;
+ if ($3 < $4) {
+ for (int i = $3; i <= $4; ++i)
+ $$->push_back(i);
+ } else {
+ 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 {
+ std::string DecName = *$3;
+ if (ParsingTemplateArgs) {
+ if (CurRec) {
+ DecName = CurRec->getName() + ":" + DecName;
+ } else {
+ assert(CurMultiClass);
+ }
+ if (CurMultiClass)
+ DecName = CurMultiClass->Rec.getName() + "::" + DecName;
+ }
+
+ addValue(RecordVal(DecName, $2, $1));
+ setValue(DecName, 0, $4);
+ $$ = new std::string(DecName);
+};
+
+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 {
+ getActiveRec()->addTemplateArg(*$1);
+ delete $1;
+} | DeclListNE ',' Declaration {
+ getActiveRec()->addTemplateArg(*$3);
+ delete $3;
+};
+
+TemplateArgList : '<' DeclListNE '>' {};
+OptTemplateArgList : /*empty*/ | TemplateArgList;
+
+OptID : ID { $$ = $1; } | /*empty*/ { $$ = new std::string(); };
+
+ObjectName : OptID {
+ static unsigned AnonCounter = 0;
+ if ($1->empty())
+ *$1 = "anonymous."+utostr(AnonCounter++);
+ $$ = $1;
+};
+
+ClassName : ObjectName {
+ // If a class of this name already exists, it must be a forward ref.
+ if ((CurRec = Records.getClass(*$1))) {
+ // If the body was previously defined, this is an error.
+ if (!CurRec->getValues().empty() ||
+ !CurRec->getSuperClasses().empty() ||
+ !CurRec->getTemplateArgs().empty()) {
+ err() << "Class '" << CurRec->getName() << "' already defined!\n";
+ exit(1);
+ }
+ } else {
+ // If this is the first reference to this class, create and add it.
+ CurRec = new Record(*$1);
+ Records.addClass(CurRec);
+ }
+ delete $1;
+};
+
+DefName : ObjectName {
+ CurRec = new Record(*$1);
+ delete $1;
+
+ if (!CurMultiClass) {
+ // Top-level def definition.
+
+ // Ensure redefinition doesn't happen.
+ if (Records.getDef(CurRec->getName())) {
+ err() << "def '" << CurRec->getName() << "' already defined!\n";
+ exit(1);
+ }
+ Records.addDef(CurRec);
+ } else {
+ // Otherwise, a def inside a multiclass, add it to the multiclass.
+ for (unsigned i = 0, e = CurMultiClass->DefPrototypes.size(); i != e; ++i)
+ if (CurMultiClass->DefPrototypes[i]->getName() == CurRec->getName()) {
+ err() << "def '" << CurRec->getName()
+ << "' already defined in this multiclass!\n";
+ exit(1);
+ }
+ CurMultiClass->DefPrototypes.push_back(CurRec);
+ }
+};
+
+ObjectBody : ClassList {
+ for (unsigned i = 0, e = $1->size(); i != e; ++i) {
+ addSubClass((*$1)[i].first, *(*$1)[i].second);
+ // Delete the template arg values for the class
+ delete (*$1)[i].second;
+ }
+ delete $1; // Delete the class list.
+
+ // Process any variables on the let 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;
+ CurRec = 0;
+ };
+
+ClassInst : CLASS ClassName {
+ ParsingTemplateArgs = true;
+ } OptTemplateArgList {
+ ParsingTemplateArgs = false;
+ } ObjectBody {
+ $$ = $6;
+ };
+
+DefInst : DEF DefName ObjectBody {
+ if (CurMultiClass == 0) // Def's in multiclasses aren't really defs.
+ $3->resolveReferences();
+
+ // If ObjectBody has template arguments, it's an error.
+ assert($3->getTemplateArgs().empty() && "How'd this get template args?");
+ $$ = $3;
+};
+
+// MultiClassDef - A def instance specified inside a multiclass.
+MultiClassDef : DefInst {
+ $$ = $1;
+ // Copy the template arguments for the multiclass into the def.
+ const std::vector<std::string> &TArgs = CurMultiClass->Rec.getTemplateArgs();
+
+ for (unsigned i = 0, e = TArgs.size(); i != e; ++i) {
+ const RecordVal *RV = CurMultiClass->Rec.getValue(TArgs[i]);
+ assert(RV && "Template arg doesn't exist?");
+ $$->addValue(*RV);
+ }
+};
+
+// MultiClassBody - Sequence of def's that are instantiated when a multiclass is
+// used.
+MultiClassBody : MultiClassDef {
+ $$ = new std::vector<Record*>();
+ $$->push_back($1);
+} | MultiClassBody MultiClassDef {
+ $$->push_back($2);
+};
+
+MultiClassName : ID {
+ MultiClass *&MCE = MultiClasses[*$1];
+ if (MCE) {
+ err() << "multiclass '" << *$1 << "' already defined!\n";
+ exit(1);
+ }
+ MCE = CurMultiClass = new MultiClass(*$1);
+ delete $1;
+};
+
+// MultiClass - Multiple definitions.
+MultiClassInst : MULTICLASS MultiClassName {
+ ParsingTemplateArgs = true;
+ } OptTemplateArgList {
+ ParsingTemplateArgs = false;
+ }'{' MultiClassBody '}' {
+ CurMultiClass = 0;
+};
+
+// DefMInst - Instantiate a multiclass.
+DefMInst : DEFM ID { CurDefmPrefix = $2; } ':' SubClassRef ';' {
+ // To instantiate a multiclass, we need to first get the multiclass, then
+ // instantiate each def contained in the multiclass with the SubClassRef
+ // template parameters.
+ MultiClass *MC = MultiClasses[$5->first->getName()];
+ assert(MC && "Didn't lookup multiclass correctly?");
+ std::vector<Init*> &TemplateVals = *$5->second;
+ delete $5;
+
+ // Verify that the correct number of template arguments were specified.
+ const std::vector<std::string> &TArgs = MC->Rec.getTemplateArgs();
+ if (TArgs.size() < TemplateVals.size()) {
+ err() << "ERROR: More template args specified than multiclass expects!\n";
+ exit(1);
+ }
+
+ // Loop over all the def's in the multiclass, instantiating each one.
+ for (unsigned i = 0, e = MC->DefPrototypes.size(); i != e; ++i) {
+ Record *DefProto = MC->DefPrototypes[i];
+
+ // Add the suffix to the defm name to get the new name.
+ assert(CurRec == 0 && "A def is current?");
+ CurRec = new Record(*$2 + DefProto->getName());
+
+ addSubClass(DefProto, std::vector<Init*>());
+
+ // Loop over all of the template arguments, setting them to the specified
+ // value or leaving them as the default if necessary.
+ for (unsigned i = 0, e = TArgs.size(); i != e; ++i) {
+ if (i < TemplateVals.size()) { // A value is specified for this temp-arg?
+ // Set it now.
+ setValue(TArgs[i], 0, TemplateVals[i]);
+
+ // Resolve it next.
+ CurRec->resolveReferencesTo(CurRec->getValue(TArgs[i]));
+
+ // Now remove it.
+ CurRec->removeValue(TArgs[i]);
+
+ } else if (!CurRec->getValue(TArgs[i])->getValue()->isComplete()) {
+ err() << "ERROR: Value not specified for template argument #"
+ << i << " (" << TArgs[i] << ") of multiclassclass '"
+ << MC->Rec.getName() << "'!\n";
+ exit(1);
+ }
+ }
+
+ // If the mdef is inside a 'let' expression, add to each def.
+ 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);
+
+
+ // Ensure redefinition doesn't happen.
+ if (Records.getDef(CurRec->getName())) {
+ err() << "def '" << CurRec->getName() << "' already defined, "
+ << "instantiating defm '" << *$2 << "' with subdef '"
+ << DefProto->getName() << "'!\n";
+ exit(1);
+ }
+ Records.addDef(CurRec);
+
+ CurRec->resolveReferences();
+
+ CurRec = 0;
+ }
+
+ delete &TemplateVals;
+ delete $2;
+ CurDefmPrefix = 0;
+};
+
+Object : ClassInst {} | DefInst {};
+Object : MultiClassInst | DefMInst;
+
+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";
+ exit(1);
+}
diff --git a/utils/TableGen/FileParser.y.cvs b/utils/TableGen/FileParser.y.cvs
new file mode 100644
index 0000000000..0612f56ca0
--- /dev/null
+++ b/utils/TableGen/FileParser.y.cvs
@@ -0,0 +1,806 @@
+//===-- FileParser.y - Parser for TableGen files ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the bison parser for Table Generator files...
+//
+//===----------------------------------------------------------------------===//
+
+%{
+#include "Record.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Streams.h"
+#include <algorithm>
+#include <cstdio>
+#define YYERROR_VERBOSE 1
+
+int yyerror(const char *ErrorMsg);
+int yylex();
+
+namespace llvm {
+ struct MultiClass {
+ Record Rec; // Placeholder for template args and Name.
+ std::vector<Record*> DefPrototypes;
+
+ MultiClass(const std::string &Name) : Rec(Name) {}
+ };
+
+
+static std::map<std::string, MultiClass*> MultiClasses;
+
+extern int Filelineno;
+static MultiClass *CurMultiClass = 0; // Set while parsing a multiclass.
+static std::string *CurDefmPrefix = 0; // Set while parsing defm.
+static Record *CurRec = 0;
+static bool ParsingTemplateArgs = false;
+
+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();
+
+/// getActiveRec - If inside a def/class definition, return the def/class.
+/// Otherwise, if within a multidef, return it.
+static Record *getActiveRec() {
+ return CurRec ? CurRec : &CurMultiClass->Rec;
+}
+
+static void addValue(const RecordVal &RV) {
+ Record *TheRec = getActiveRec();
+
+ if (RecordVal *ERV = TheRec->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";
+ exit(1);
+ }
+ } else {
+ TheRec->addValue(RV);
+ }
+}
+
+static void addSuperClass(Record *SC) {
+ if (CurRec->isSubClassOf(SC)) {
+ err() << "Already subclass of '" << SC->getName() << "'!\n";
+ exit(1);
+ }
+ CurRec->addSuperClass(SC);
+}
+
+static void setValue(const std::string &ValName,
+ std::vector<unsigned> *BitList, Init *V) {
+ if (!V) return;
+
+ Record *TheRec = getActiveRec();
+ RecordVal *RV = TheRec->getValue(ValName);
+ if (RV == 0) {
+ err() << "Value '" << ValName << "' unknown!\n";
+ exit(1);
+ }
+
+ // Do not allow assignments like 'X = X'. This will just cause infinite loops
+ // in the resolution machinery.
+ if (!BitList)
+ if (VarInit *VI = dynamic_cast<VarInit*>(V))
+ if (VI->getName() == ValName)
+ return;
+
+ // 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";
+ exit(1);
+ }
+
+ // 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";
+ exit(1);
+ }
+
+ // We should have a BitsInit type now...
+ assert(dynamic_cast<BitsInit*>(BI) != 0 || (cerr << *BI).stream() == 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";
+ exit(1);
+ }
+ 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";
+ exit(1);
+ }
+}
+
+// addSubClass - Add SC as a subclass to CurRec, resolving TemplateArgs as SC's
+// template arguments.
+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";
+ exit(1);
+ }
+
+ // Loop over all of the template arguments, setting them to the specified
+ // value or leaving them as the default if 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]);
+
+ // Resolve it next.
+ CurRec->resolveReferencesTo(CurRec->getValue(TArgs[i]));
+
+
+ // Now remove it.
+ CurRec->removeValue(TArgs[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";
+ exit(1);
+ }
+ }
+
+ // 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);
+}
+
+} // End llvm namespace
+
+using namespace llvm;
+
+%}
+
+%union {
+ std::string* StrVal;
+ int IntVal;
+ llvm::RecTy* Ty;
+ llvm::Init* Initializer;
+ std::vector<llvm::Init*>* FieldList;
+ std::vector<unsigned>* BitList;
+ llvm::Record* Rec;
+ std::vector<llvm::Record*>* RecList;
+ SubClassRefTy* SubClassRef;
+ std::vector<SubClassRefTy>* SubClassList;
+ std::vector<std::pair<llvm::Init*, std::string> >* DagValueList;
+};
+
+%token INT BIT STRING BITS LIST CODE DAG CLASS DEF MULTICLASS DEFM FIELD LET IN
+%token CONCATTOK SHLTOK SRATOK SRLTOK STRCONCATTOK
+%token <IntVal> INTVAL
+%token <StrVal> ID VARNAME STRVAL CODEFRAGMENT
+
+%type <Ty> Type
+%type <Rec> ClassInst DefInst MultiClassDef ObjectBody ClassID
+%type <RecList> MultiClassBody
+
+%type <SubClassRef> SubClassRef
+%type <SubClassList> ClassList ClassListNE
+%type <IntVal> OptPrefix
+%type <Initializer> Value OptValue IDValue
+%type <DagValueList> DagArgList DagArgListNE
+%type <FieldList> ValueList ValueListNE
+%type <BitList> BitList OptBitList RBitList
+%type <StrVal> Declaration OptID OptVarName ObjectName
+
+%start File
+
+%%
+
+ClassID : ID {
+ if (CurDefmPrefix) {
+ // If CurDefmPrefix is set, we're parsing a defm, which means that this is
+ // actually the name of a multiclass.
+ MultiClass *MC = MultiClasses[*$1];
+ if (MC == 0) {
+ err() << "Couldn't find class '" << *$1 << "'!\n";
+ exit(1);
+ }
+ $$ = &MC->Rec;
+ } else {
+ $$ = Records.getClass(*$1);
+ }
+ if ($$ == 0) {
+ err() << "Couldn't find class '" << *$1 << "'!\n";
+ exit(1);
+ }
+ 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; };
+
+IDValue : ID {
+ if (const RecordVal *RV = (CurRec ? CurRec->getValue(*$1) : 0)) {
+ $$ = new VarInit(*$1, RV->getType());
+ } else if (CurRec && CurRec->isTemplateArg(CurRec->getName()+":"+*$1)) {
+ const RecordVal *RV = CurRec->getValue(CurRec->getName()+":"+*$1);
+ assert(RV && "Template arg doesn't exist??");
+ $$ = new VarInit(CurRec->getName()+":"+*$1, RV->getType());
+ } else if (CurMultiClass &&
+ CurMultiClass->Rec.isTemplateArg(CurMultiClass->Rec.getName()+"::"+*$1)) {
+ std::string Name = CurMultiClass->Rec.getName()+"::"+*$1;
+ const RecordVal *RV = CurMultiClass->Rec.getValue(Name);
+ assert(RV && "Template arg doesn't exist??");
+ $$ = new VarInit(Name, RV->getType());
+ } else if (Record *D = Records.getDef(*$1)) {
+ $$ = new DefInit(D);
+ } else {
+ err() << "Variable not defined: '" << *$1 << "'!\n";
+ exit(1);
+ }
+
+ delete $1;
+};
+
+Value : IDValue {
+ $$ = $1;
+ } | 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";
+ exit(1);
+ }
+ Init->setBit($2->size()-i-1, Bit);
+ }
+ $$ = Init;
+ delete $2;
+ } | ID '<' ValueListNE '>' {
+ // This is a CLASS<initvalslist> expression. This is supposed to synthesize
+ // a new anonymous definition, deriving from CLASS<initvalslist> with no
+ // body.
+ Record *Class = Records.getClass(*$1);
+ if (!Class) {
+ err() << "Expected a class, got '" << *$1 << "'!\n";
+ exit(1);
+ }
+ delete $1;
+
+ static unsigned AnonCounter = 0;
+ Record *OldRec = CurRec; // Save CurRec.
+
+ // Create the new record, set it as CurRec temporarily.
+ CurRec = new Record("anonymous.val."+utostr(AnonCounter++));
+ addSubClass(Class, *$3); // Add info about the subclass to CurRec.
+ delete $3; // Free up the template args.
+
+ CurRec->resolveReferences();
+
+ Records.addDef(CurRec);
+
+ // The result of the expression is a reference to the new record.
+ $$ = new DefInit(CurRec);
+
+ // Restore the old CurRec
+ CurRec = OldRec;
+ } | Value '{' BitList '}' {
+ $$ = $1->convertInitializerBitRange(*$3);
+ if ($$ == 0) {
+ err() << "Invalid bit range for value '" << *$1 << "'!\n";
+ exit(1);
+ }
+ delete $3;
+ } | '[' ValueList ']' {
+ $$ = new ListInit(*$2);
+ delete $2;
+ } | Value '.' ID {
+ if (!$1->getFieldType(*$3)) {
+ err() << "Cannot access field '" << *$3 << "' of value '" << *$1 << "!\n";
+ exit(1);
+ }
+ $$ = new FieldInit($1, *$3);
+ delete $3;
+ } | '(' IDValue DagArgList ')' {
+ $$ = new DagInit($2, *$3);
+ delete $3;
+ } | Value '[' BitList ']' {
+ std::reverse($3->begin(), $3->end());
+ $$ = $1->convertInitListSlice(*$3);
+ if ($$ == 0) {
+ err() << "Invalid list slice for value '" << *$1 << "'!\n";
+ exit(1);
+ }
+ delete $3;
+ } | CONCATTOK '(' Value ',' Value ')' {
+ $$ = (new BinOpInit(BinOpInit::CONCAT, $3, $5))->Fold();
+ } | SHLTOK '(' Value ',' Value ')' {
+ $$ = (new BinOpInit(BinOpInit::SHL, $3, $5))->Fold();
+ } | SRATOK '(' Value ',' Value ')' {
+ $$ = (new BinOpInit(BinOpInit::SRA, $3, $5))->Fold();
+ } | SRLTOK '(' Value ',' Value ')' {
+ $$ = (new BinOpInit(BinOpInit::SRL, $3, $5))->Fold();
+ } | STRCONCATTOK '(' Value ',' Value ')' {
+ $$ = (new BinOpInit(BinOpInit::STRCONCAT, $3, $5))->Fold();
+ };
+
+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 < 0 || $3 < 0) {
+ err() << "Invalid range: " << $1 << "-" << $3 << "!\n";
+ exit(1);
+ }
+ $$ = new std::vector<unsigned>();
+ if ($1 < $3) {
+ for (int i = $1; i <= $3; ++i)
+ $$->push_back(i);
+ } else {
+ for (int i = $1; i >= $3; --i)
+ $$->push_back(i);
+ }
+ } | INTVAL INTVAL {
+ $2 = -$2;
+ if ($1 < 0 || $2 < 0) {
+ err() << "Invalid range: " << $1 << "-" << $2 << "!\n";
+ exit(1);
+ }
+ $$ = new std::vector<unsigned>();
+ if ($1 < $2) {
+ for (int i = $1; i <= $2; ++i)
+ $$->push_back(i);
+ } else {
+ for (int i = $1; i >= $2; --i)
+ $$->push_back(i);
+ }
+ } | RBitList ',' INTVAL {
+ ($$=$1)->push_back($3);
+ } | RBitList ',' INTVAL '-' INTVAL {
+ if ($3 < 0 || $5 < 0) {
+ err() << "Invalid range: " << $3 << "-" << $5 << "!\n";
+ exit(1);
+ }
+ $$ = $1;
+ if ($3 < $5) {
+ for (int i = $3; i <= $5; ++i)
+ $$->push_back(i);
+ } else {
+ for (int i = $3; i >= $5; --i)
+ $$->push_back(i);
+ }
+ } | RBitList ',' INTVAL INTVAL {
+ $4 = -$4;
+ if ($3 < 0 || $4 < 0) {
+ err() << "Invalid range: " << $3 << "-" << $4 << "!\n";
+ exit(1);
+ }
+ $$ = $1;
+ if ($3 < $4) {
+ for (int i = $3; i <= $4; ++i)
+ $$->push_back(i);
+ } else {
+ 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 {
+ std::string DecName = *$3;
+ if (ParsingTemplateArgs) {
+ if (CurRec) {
+ DecName = CurRec->getName() + ":" + DecName;
+ } else {
+ assert(CurMultiClass);
+ }
+ if (CurMultiClass)
+ DecName = CurMultiClass->Rec.getName() + "::" + DecName;
+ }
+
+ addValue(RecordVal(DecName, $2, $1));
+ setValue(DecName, 0, $4);
+ $$ = new std::string(DecName);
+};
+
+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 {
+ getActiveRec()->addTemplateArg(*$1);
+ delete $1;
+} | DeclListNE ',' Declaration {
+ getActiveRec()->addTemplateArg(*$3);
+ delete $3;
+};
+
+TemplateArgList : '<' DeclListNE '>' {};
+OptTemplateArgList : /*empty*/ | TemplateArgList;
+
+OptID : ID { $$ = $1; } | /*empty*/ { $$ = new std::string(); };
+
+ObjectName : OptID {
+ static unsigned AnonCounter = 0;
+ if ($1->empty())
+ *$1 = "anonymous."+utostr(AnonCounter++);
+ $$ = $1;
+};
+
+ClassName : ObjectName {
+ // If a class of this name already exists, it must be a forward ref.
+ if ((CurRec = Records.getClass(*$1))) {
+ // If the body was previously defined, this is an error.
+ if (!CurRec->getValues().empty() ||
+ !CurRec->getSuperClasses().empty() ||
+ !CurRec->getTemplateArgs().empty()) {
+ err() << "Class '" << CurRec->getName() << "' already defined!\n";
+ exit(1);
+ }
+ } else {
+ // If this is the first reference to this class, create and add it.
+ CurRec = new Record(*$1);
+ Records.addClass(CurRec);
+ }
+ delete $1;
+};
+
+DefName : ObjectName {
+ CurRec = new Record(*$1);
+ delete $1;
+
+ if (!CurMultiClass) {
+ // Top-level def definition.
+
+ // Ensure redefinition doesn't happen.
+ if (Records.getDef(CurRec->getName())) {
+ err() << "def '" << CurRec->getName() << "' already defined!\n";
+ exit(1);
+ }
+ Records.addDef(CurRec);
+ } else {
+ // Otherwise, a def inside a multiclass, add it to the multiclass.
+ for (unsigned i = 0, e = CurMultiClass->DefPrototypes.size(); i != e; ++i)
+ if (CurMultiClass->DefPrototypes[i]->getName() == CurRec->getName()) {
+ err() << "def '" << CurRec->getName()
+ << "' already defined in this multiclass!\n";
+ exit(1);
+ }
+ CurMultiClass->DefPrototypes.push_back(CurRec);
+ }
+};
+
+ObjectBody : ClassList {
+ for (unsigned i = 0, e = $1->size(); i != e; ++i) {
+ addSubClass((*$1)[i].first, *(*$1)[i].second);
+ // Delete the template arg values for the class
+ delete (*$1)[i].second;
+ }
+ delete $1; // Delete the class list.
+
+ // Process any variables on the let 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;
+ CurRec = 0;
+ };
+
+ClassInst : CLASS ClassName {
+ ParsingTemplateArgs = true;
+ } OptTemplateArgList {
+ ParsingTemplateArgs = false;
+ } ObjectBody {
+ $$ = $6;
+ };
+
+DefInst : DEF DefName ObjectBody {
+ if (CurMultiClass == 0) // Def's in multiclasses aren't really defs.
+ $3->resolveReferences();
+
+ // If ObjectBody has template arguments, it's an error.
+ assert($3->getTemplateArgs().empty() && "How'd this get template args?");
+ $$ = $3;
+};
+
+// MultiClassDef - A def instance specified inside a multiclass.
+MultiClassDef : DefInst {
+ $$ = $1;
+ // Copy the template arguments for the multiclass into the def.
+ const std::vector<std::string> &TArgs = CurMultiClass->Rec.getTemplateArgs();
+
+ for (unsigned i = 0, e = TArgs.size(); i != e; ++i) {
+ const RecordVal *RV = CurMultiClass->Rec.getValue(TArgs[i]);
+ assert(RV && "Template arg doesn't exist?");
+ $$->addValue(*RV);
+ }
+};
+
+// MultiClassBody - Sequence of def's that are instantiated when a multiclass is
+// used.
+MultiClassBody : MultiClassDef {
+ $$ = new std::vector<Record*>();
+ $$->push_back($1);
+} | MultiClassBody MultiClassDef {
+ $$->push_back($2);
+};
+
+MultiClassName : ID {
+ MultiClass *&MCE = MultiClasses[*$1];
+ if (MCE) {
+ err() << "multiclass '" << *$1 << "' already defined!\n";
+ exit(1);
+ }
+ MCE = CurMultiClass = new MultiClass(*$1);
+ delete $1;
+};
+
+// MultiClass - Multiple definitions.
+MultiClassInst : MULTICLASS MultiClassName {
+ ParsingTemplateArgs = true;
+ } OptTemplateArgList {
+ ParsingTemplateArgs = false;
+ }'{' MultiClassBody '}' {
+ CurMultiClass = 0;
+};
+
+// DefMInst - Instantiate a multiclass.
+DefMInst : DEFM ID { CurDefmPrefix = $2; } ':' SubClassRef ';' {
+ // To instantiate a multiclass, we need to first get the multiclass, then
+ // instantiate each def contained in the multiclass with the SubClassRef
+ // template parameters.
+ MultiClass *MC = MultiClasses[$5->first->getName()];
+ assert(MC && "Didn't lookup multiclass correctly?");
+ std::vector<Init*> &TemplateVals = *$5->second;
+ delete $5;
+
+ // Verify that the correct number of template arguments were specified.
+ const std::vector<std::string> &TArgs = MC->Rec.getTemplateArgs();
+ if (TArgs.size() < TemplateVals.size()) {
+ err() << "ERROR: More template args specified than multiclass expects!\n";
+ exit(1);
+ }
+
+ // Loop over all the def's in the multiclass, instantiating each one.
+ for (unsigned i = 0, e = MC->DefPrototypes.size(); i != e; ++i) {
+ Record *DefProto = MC->DefPrototypes[i];
+
+ // Add the suffix to the defm name to get the new name.
+ assert(CurRec == 0 && "A def is current?");
+ CurRec = new Record(*$2 + DefProto->getName());
+
+ addSubClass(DefProto, std::vector<Init*>());
+
+ // Loop over all of the template arguments, setting them to the specified
+ // value or leaving them as the default if necessary.
+ for (unsigned i = 0, e = TArgs.size(); i != e; ++i) {
+ if (i < TemplateVals.size()) { // A value is specified for this temp-arg?
+ // Set it now.
+ setValue(TArgs[i], 0, TemplateVals[i]);
+
+ // Resolve it next.
+ CurRec->resolveReferencesTo(CurRec->getValue(TArgs[i]));
+
+ // Now remove it.
+ CurRec->removeValue(TArgs[i]);
+
+ } else if (!CurRec->getValue(TArgs[i])->getValue()->isComplete()) {
+ err() << "ERROR: Value not specified for template argument #"
+ << i << " (" << TArgs[i] << ") of multiclassclass '"
+ << MC->Rec.getName() << "'!\n";
+ exit(1);
+ }
+ }
+
+ // If the mdef is inside a 'let' expression, add to each def.
+ 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);
+
+
+ // Ensure redefinition doesn't happen.
+ if (Records.getDef(CurRec->getName())) {
+ err() << "def '" << CurRec->getName() << "' already defined, "
+ << "instantiating defm '" << *$2 << "' with subdef '"
+ << DefProto->getName() << "'!\n";
+ exit(1);
+ }
+ Records.addDef(CurRec);
+
+ CurRec->resolveReferences();
+
+ CurRec = 0;
+ }
+
+ delete &TemplateVals;
+ delete $2;
+ CurDefmPrefix = 0;
+};
+
+Object : ClassInst {} | DefInst {};
+Object : MultiClassInst | DefMInst;
+
+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";
+ exit(1);
+}
diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp
new file mode 100644
index 0000000000..da2308e9e4
--- /dev/null
+++ b/utils/TableGen/InstrInfoEmitter.cpp
@@ -0,0 +1,365 @@
+//===- InstrInfoEmitter.cpp - Generate a Instruction Set Desc. ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend is responsible for emitting a description of the target
+// instruction set for the code generator.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InstrInfoEmitter.h"
+#include "CodeGenTarget.h"
+#include "llvm/Target/TargetInstrInfo.h"
+#include "Record.h"
+#include <algorithm>
+using namespace llvm;
+
+// runEnums - Print out enum values for all of the instructions.
+void InstrInfoEmitter::runEnums(std::ostream &OS) {
+ EmitSourceFileHeader("Target Instruction Enum Values", OS);
+ OS << "namespace llvm {\n\n";
+
+ CodeGenTarget Target;
+
+ // We must emit the PHI opcode first...
+ std::string Namespace;
+ for (CodeGenTarget::inst_iterator II = Target.inst_begin(),
+ E = Target.inst_end(); II != E; ++II) {
+ if (II->second.Namespace != "TargetInstrInfo") {
+ Namespace = II->second.Namespace;
+ break;
+ }
+ }
+
+ if (Namespace.empty()) {
+ cerr << "No instructions defined!\n";
+ exit(1);
+ }
+
+ std::vector<const CodeGenInstruction*> NumberedInstructions;
+ Target.getInstructionsByEnumValue(NumberedInstructions);
+
+ OS << "namespace " << Namespace << " {\n";
+ OS << " enum {\n";
+ for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
+ OS << " " << NumberedInstructions[i]->TheDef->getName()
+ << "\t= " << i << ",\n";
+ }
+ OS << " INSTRUCTION_LIST_END = " << NumberedInstructions.size() << "\n";
+ OS << " };\n}\n";
+ OS << "} // End llvm namespace \n";
+}
+
+void InstrInfoEmitter::printDefList(const std::vector<Record*> &Uses,
+ unsigned Num, std::ostream &OS) const {
+ OS << "static const unsigned ImplicitList" << Num << "[] = { ";
+ for (unsigned i = 0, e = Uses.size(); i != e; ++i)
+ OS << getQualifiedName(Uses[i]) << ", ";
+ OS << "0 };\n";
+}
+
+std::vector<std::string>
+InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
+ std::vector<std::string> Result;
+
+ for (unsigned i = 0, e = Inst.OperandList.size(); i != e; ++i) {
+ // Handle aggregate operands and normal operands the same way by expanding
+ // either case into a list of operands for this op.
+ std::vector<CodeGenInstruction::OperandInfo> OperandList;
+
+ // This might be a multiple operand thing. Targets like X86 have
+ // registers in their multi-operand operands. It may also be an anonymous
+ // operand, which has a single operand, but no declared class for the
+ // operand.
+ DagInit *MIOI = Inst.OperandList[i].MIOperandInfo;
+
+ if (!MIOI || MIOI->getNumArgs() == 0) {
+ // Single, anonymous, operand.
+ OperandList.push_back(Inst.OperandList[i]);
+ } else {
+ for (unsigned j = 0, e = Inst.OperandList[i].MINumOperands; j != e; ++j) {
+ OperandList.push_back(Inst.OperandList[i]);
+
+ Record *OpR = dynamic_cast<DefInit*>(MIOI->getArg(j))->getDef();
+ OperandList.back().Rec = OpR;
+ }
+ }
+
+ for (unsigned j = 0, e = OperandList.size(); j != e; ++j) {
+ Record *OpR = OperandList[j].Rec;
+ std::string Res;
+
+ if (OpR->isSubClassOf("RegisterClass"))
+ Res += getQualifiedName(OpR) + "RegClassID, ";
+ else
+ Res += "0, ";
+ // Fill in applicable flags.
+ Res += "0";
+
+ // Ptr value whose register class is resolved via callback.
+ if (OpR->getName() == "ptr_rc")
+ Res += "|M_LOOK_UP_PTR_REG_CLASS";
+
+ // Predicate operands. Check to see if the original unexpanded operand
+ // was of type PredicateOperand.
+ if (Inst.OperandList[i].Rec->isSubClassOf("PredicateOperand"))
+ Res += "|M_PREDICATE_OPERAND";
+
+ // Optional def operands. Check to see if the original unexpanded operand
+ // was of type OptionalDefOperand.
+ if (Inst.OperandList[i].Rec->isSubClassOf("OptionalDefOperand"))
+ Res += "|M_OPTIONAL_DEF_OPERAND";
+
+ // Fill in constraint info.
+ Res += ", " + Inst.OperandList[i].Constraints[j];
+ Result.push_back(Res);
+ }
+ }
+
+ return Result;
+}
+
+
+// run - Emit the main instruction description records for the target...
+void InstrInfoEmitter::run(std::ostream &OS) {
+ GatherItinClasses();
+
+ EmitSourceFileHeader("Target Instruction Descriptors", OS);
+ OS << "namespace llvm {\n\n";
+
+ CodeGenTarget Target;
+ const std::string &TargetName = Target.getName();
+ Record *InstrInfo = Target.getInstructionSet();
+
+ // Keep track of all of the def lists we have emitted already.
+ std::map<std::vector<Record*>, unsigned> EmittedLists;
+ unsigned ListNumber = 0;
+
+ // Emit all of the instruction's implicit uses and defs.
+ for (CodeGenTarget::inst_iterator II = Target.inst_begin(),
+ E = Target.inst_end(); II != E; ++II) {
+ Record *Inst = II->second.TheDef;
+ std::vector<Record*> Uses = Inst->getValueAsListOfDefs("Uses");
+ if (!Uses.empty()) {
+ unsigned &IL = EmittedLists[Uses];
+ if (!IL) printDefList(Uses, IL = ++ListNumber, OS);
+ }
+ std::vector<Record*> Defs = Inst->getValueAsListOfDefs("Defs");
+ if (!Defs.empty()) {
+ unsigned &IL = EmittedLists[Defs];
+ if (!IL) printDefList(Defs, IL = ++ListNumber, OS);
+ }
+ }
+
+ std::map<std::vector<std::string>, unsigned> OperandInfosEmitted;
+ unsigned OperandListNum = 0;
+ OperandInfosEmitted[std::vector<std::string>()] = ++OperandListNum;
+
+ // Emit all of the operand info records.
+ OS << "\n";
+ for (CodeGenTarget::inst_iterator II = Target.inst_begin(),
+ E = Target.inst_end(); II != E; ++II) {
+ std::vector<std::string> OperandInfo = GetOperandInfo(II->second);
+ unsigned &N = OperandInfosEmitted[OperandInfo];
+ if (N == 0) {
+ N = ++OperandListNum;
+ OS << "static const TargetOperandInfo OperandInfo" << N << "[] = { ";
+ for (unsigned i = 0, e = OperandInfo.size(); i != e; ++i)
+ OS << "{ " << OperandInfo[i] << " }, ";
+ OS << "};\n";
+ }
+ }
+
+ // Emit all of the TargetInstrDescriptor records in their ENUM ordering.
+ //
+ OS << "\nstatic const TargetInstrDescriptor " << TargetName
+ << "Insts[] = {\n";
+ std::vector<const CodeGenInstruction*> NumberedInstructions;
+ Target.getInstructionsByEnumValue(NumberedInstructions);
+
+ for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i)
+ emitRecord(*NumberedInstructions[i], i, InstrInfo, EmittedLists,
+ OperandInfosEmitted, OS);
+ OS << "};\n";
+ OS << "} // End llvm namespace \n";
+}
+
+void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
+ Record *InstrInfo,
+ std::map<std::vector<Record*>, unsigned> &EmittedLists,
+ std::map<std::vector<std::string>, unsigned> &OpInfo,
+ std::ostream &OS) {
+ int MinOperands;
+ if (!Inst.OperandList.empty())
+ // Each logical operand can be multiple MI operands.
+ MinOperands = Inst.OperandList.back().MIOperandNo +
+ Inst.OperandList.back().MINumOperands;
+ else
+ MinOperands = 0;
+
+ OS << " { ";
+ OS << Num << ",\t" << MinOperands << ",\t\"";
+
+ if (Inst.Name.empty())
+ OS << Inst.TheDef->getName();
+ else
+ OS << Inst.Name;
+
+ unsigned ItinClass = !IsItineraries ? 0 :
+ ItinClassNumber(Inst.TheDef->getValueAsDef("Itinerary")->getName());
+
+ OS << "\",\t" << ItinClass << ", 0";
+
+ // Try to determine (from the pattern), if the instruction is a store.
+ bool isStore = false;
+ if (dynamic_cast<ListInit*>(Inst.TheDef->getValueInit("Pattern"))) {
+ ListInit *LI = Inst.TheDef->getValueAsListInit("Pattern");
+ if (LI && LI->getSize() > 0) {
+ DagInit *Dag = (DagInit *)LI->getElement(0);
+ DefInit *OpDef = dynamic_cast<DefInit*>(Dag->getOperator());
+ if (OpDef) {
+ Record *Operator = OpDef->getDef();
+ if (Operator->isSubClassOf("SDNode")) {
+ const std::string Opcode = Operator->getValueAsString("Opcode");
+ if (Opcode == "ISD::STORE" || Opcode == "ISD::TRUNCSTORE")
+ isStore = true;
+ }
+ }
+ }
+ }
+
+ // Emit all of the target indepedent flags...
+ if (Inst.isReturn) OS << "|M_RET_FLAG";
+ if (Inst.isBranch) OS << "|M_BRANCH_FLAG";
+ if (Inst.isBarrier) OS << "|M_BARRIER_FLAG";
+ if (Inst.hasDelaySlot) OS << "|M_DELAY_SLOT_FLAG";
+ if (Inst.isCall) OS << "|M_CALL_FLAG";
+ if (Inst.isLoad) OS << "|M_LOAD_FLAG";
+ if (Inst.isStore || isStore) OS << "|M_STORE_FLAG";
+ if (Inst.isPredicable) OS << "|M_PREDICABLE";
+ if (Inst.isConvertibleToThreeAddress) OS << "|M_CONVERTIBLE_TO_3_ADDR";
+ if (Inst.isCommutable) OS << "|M_COMMUTABLE";
+ if (Inst.isTerminator) OS << "|M_TERMINATOR_FLAG";
+ if (Inst.isReMaterializable) OS << "|M_REMATERIALIZIBLE";
+ if (Inst.isNotDuplicable) OS << "|M_NOT_DUPLICABLE";
+ if (Inst.hasOptionalDef) OS << "|M_HAS_OPTIONAL_DEF";
+ if (Inst.usesCustomDAGSchedInserter)
+ OS << "|M_USES_CUSTOM_DAG_SCHED_INSERTION";
+ if (Inst.hasVariableNumberOfOperands)
+ OS << "|M_VARIABLE_OPS";
+ 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(Inst.TheDef, dynamic_cast<StringInit*>(LI->getElement(i)),
+ dynamic_cast<IntInit*>(Shift->getElement(i)), OS);
+
+ OS << ", ";
+
+ // Emit the implicit uses and defs lists...
+ std::vector<Record*> UseList = Inst.TheDef->getValueAsListOfDefs("Uses");
+ if (UseList.empty())
+ OS << "NULL, ";
+ else
+ OS << "ImplicitList" << EmittedLists[UseList] << ", ";
+
+ std::vector<Record*> DefList = Inst.TheDef->getValueAsListOfDefs("Defs");
+ if (DefList.empty())
+ OS << "NULL, ";
+ else
+ OS << "ImplicitList" << EmittedLists[DefList] << ", ";
+
+ // Emit the operand info.
+ std::vector<std::string> OperandInfo = GetOperandInfo(Inst);
+ if (OperandInfo.empty())
+ OS << "0";
+ else
+ OS << "OperandInfo" << OpInfo[OperandInfo];
+
+ OS << " }, // Inst #" << Num << " = " << Inst.TheDef->getName() << "\n";
+}
+
+struct LessRecord {
+ bool operator()(const Record *Rec1, const Record *Rec2) const {
+ return Rec1->getName() < Rec2->getName();
+ }
+};
+void InstrInfoEmitter::GatherItinClasses() {
+ std::vector<Record*> DefList =
+ Records.getAllDerivedDefinitions("InstrItinClass");
+ IsItineraries = !DefList.empty();
+
+ if (!IsItineraries) return;
+
+ std::sort(DefList.begin(), DefList.end(), LessRecord());
+
+ for (unsigned i = 0, N = DefList.size(); i < N; i++) {
+ Record *Def = DefList[i];
+ ItinClassMap[Def->getName()] = i;
+ }
+}
+
+unsigned InstrInfoEmitter::ItinClassNumber(std::string ItinName) {
+ return ItinClassMap[ItinName];
+}
+
+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) {
+ // This isn't an error if this is a builtin instruction.
+ if (R->getName() != "PHI" &&
+ R->getName() != "INLINEASM" &&
+ R->getName() != "LABEL")
+ throw R->getName() + " doesn't have a field named '" +
+ Val->getValue() + "'!";
+ return;
+ }
+
+ 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()) {
+ if (Shift)
+ OS << "|(" << II->getValue() << "<<" << Shift << ")";
+ else
+ OS << "|" << II->getValue();
+ }
+ return;
+ }
+
+ } else if (IntInit *II = dynamic_cast<IntInit*>(Value)) {
+ if (II->getValue()) {
+ if (Shift)
+ OS << "|(" << II->getValue() << "<<" << Shift << ")";
+ else
+ OS << II->getValue();
+ }
+ return;
+ }
+
+ cerr << "Unhandled initializer: " << *Val << "\n";
+ throw "In record '" + R->getName() + "' for TSFlag emission.";
+}
+
diff --git a/utils/TableGen/InstrInfoEmitter.h b/utils/TableGen/InstrInfoEmitter.h
new file mode 100644
index 0000000000..adc871129e
--- /dev/null
+++ b/utils/TableGen/InstrInfoEmitter.h
@@ -0,0 +1,59 @@
+//===- InstrInfoEmitter.h - Generate a Instruction Set Desc. ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This 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"
+#include <vector>
+#include <map>
+
+namespace llvm {
+
+class StringInit;
+class IntInit;
+class ListInit;
+class CodeGenInstruction;
+
+class InstrInfoEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+ bool IsItineraries;
+ std::map<std::string, unsigned> ItinClassMap;
+
+public:
+ InstrInfoEmitter(RecordKeeper &R) : Records(R), IsItineraries(false) {}
+
+ // 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(const std::vector<Record*> &Uses, unsigned Num,
+ std::ostream &OS) const;
+ void emitRecord(const CodeGenInstruction &Inst, unsigned Num,
+ Record *InstrInfo,
+ std::map<std::vector<Record*>, unsigned> &EL,
+ std::map<std::vector<std::string>, unsigned> &OpInfo,
+ std::ostream &OS);
+ void GatherItinClasses();
+ unsigned ItinClassNumber(std::string ItinName);
+ void emitShiftedValue(Record *R, StringInit *Val, IntInit *Shift,
+ std::ostream &OS);
+ std::vector<std::string> GetOperandInfo(const CodeGenInstruction &Inst);
+};
+
+} // End llvm namespace
+
+#endif
diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp
new file mode 100644
index 0000000000..89e9621c17
--- /dev/null
+++ b/utils/TableGen/IntrinsicEmitter.cpp
@@ -0,0 +1,389 @@
+//===- IntrinsicEmitter.cpp - Generate intrinsic information --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend emits information about intrinsic functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IntrinsicEmitter.h"
+#include "Record.h"
+#include "llvm/ADT/StringExtras.h"
+#include <algorithm>
+using namespace llvm;
+
+//===----------------------------------------------------------------------===//
+// IntrinsicEmitter Implementation
+//===----------------------------------------------------------------------===//
+
+void IntrinsicEmitter::run(std::ostream &OS) {
+ EmitSourceFileHeader("Intrinsic Function Source Fragment", OS);
+
+ std::vector<CodeGenIntrinsic> Ints = LoadIntrinsics(Records);
+
+ // Emit the enum information.
+ EmitEnumInfo(Ints, OS);
+
+ // Emit the intrinsic ID -> name table.
+ EmitIntrinsicToNameTable(Ints, OS);
+
+ // Emit the function name recognizer.
+ EmitFnNameRecognizer(Ints, OS);
+
+ // Emit the intrinsic verifier.
+ EmitVerifier(Ints, OS);
+
+ // Emit the intrinsic declaration generator.
+ EmitGenerator(Ints, OS);
+
+ // Emit mod/ref info for each function.
+ EmitModRefInfo(Ints, OS);
+
+ // Emit table of non-memory accessing intrinsics.
+ EmitNoMemoryInfo(Ints, OS);
+
+ // Emit side effect info for each intrinsic.
+ EmitSideEffectInfo(Ints, OS);
+
+ // Emit a list of intrinsics with corresponding GCC builtins.
+ EmitGCCBuiltinList(Ints, OS);
+
+ // Emit code to translate GCC builtins into LLVM intrinsics.
+ EmitIntrinsicToGCCBuiltinMap(Ints, OS);
+}
+
+void IntrinsicEmitter::EmitEnumInfo(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS) {
+ OS << "// Enum values for Intrinsics.h\n";
+ OS << "#ifdef GET_INTRINSIC_ENUM_VALUES\n";
+ for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
+ OS << " " << Ints[i].EnumName;
+ OS << ((i != e-1) ? ", " : " ");
+ OS << std::string(40-Ints[i].EnumName.size(), ' ')
+ << "// " << Ints[i].Name << "\n";
+ }
+ OS << "#endif\n\n";
+}
+
+void IntrinsicEmitter::
+EmitFnNameRecognizer(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS) {
+ // Build a function name -> intrinsic name mapping.
+ std::map<std::string, unsigned> IntMapping;
+ for (unsigned i = 0, e = Ints.size(); i != e; ++i)
+ IntMapping[Ints[i].Name] = i;
+
+ OS << "// Function name -> enum value recognizer code.\n";
+ OS << "#ifdef GET_FUNCTION_RECOGNIZER\n";
+ OS << " switch (Name[5]) {\n";
+ OS << " default:\n";
+ // Emit the intrinsics in sorted order.
+ char LastChar = 0;
+ for (std::map<std::string, unsigned>::iterator I = IntMapping.begin(),
+ E = IntMapping.end(); I != E; ++I) {
+ if (I->first[5] != LastChar) {
+ LastChar = I->first[5];
+ OS << " break;\n";
+ OS << " case '" << LastChar << "':\n";
+ }
+
+ // For overloaded intrinsics, only the prefix needs to match
+ if (Ints[I->second].isOverloaded)
+ OS << " if (Len >= " << I->first.size()
+ << " && !memcmp(Name, \"" << I->first << "\", " << I->first.size()
+ << ")) return Intrinsic::" << Ints[I->second].EnumName << ";\n";
+ else
+ OS << " if (Len == " << I->first.size()
+ << " && !memcmp(Name, \"" << I->first << "\", Len)) return Intrinsic::"
+ << Ints[I->second].EnumName << ";\n";
+ }
+ OS << " }\n";
+ OS << "#endif\n\n";
+}
+
+void IntrinsicEmitter::
+EmitIntrinsicToNameTable(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS) {
+ OS << "// Intrinsic ID to name table\n";
+ OS << "#ifdef GET_INTRINSIC_NAME_TABLE\n";
+ OS << " // Note that entry #0 is the invalid intrinsic!\n";
+ for (unsigned i = 0, e = Ints.size(); i != e; ++i)
+ OS << " \"" << Ints[i].Name << "\",\n";
+ OS << "#endif\n\n";
+}
+
+static bool EmitTypeVerify(std::ostream &OS, Record *ArgType) {
+ if (ArgType->getValueAsString("TypeVal") == "...") return true;
+
+ OS << "(int)" << ArgType->getValueAsString("TypeVal") << ", ";
+ // If this is an integer type, check the width is correct.
+ if (ArgType->isSubClassOf("LLVMIntegerType"))
+ OS << ArgType->getValueAsInt("Width") << ", ";
+
+ // If this is a vector type, check that the subtype and size are correct.
+ else if (ArgType->isSubClassOf("LLVMVectorType")) {
+ EmitTypeVerify(OS, ArgType->getValueAsDef("ElTy"));
+ OS << ArgType->getValueAsInt("NumElts") << ", ";
+ }
+
+ return false;
+}
+
+static void EmitTypeGenerate(std::ostream &OS, Record *ArgType,
+ unsigned &ArgNo) {
+ if (ArgType->isSubClassOf("LLVMIntegerType")) {
+ unsigned BitWidth = ArgType->getValueAsInt("Width");
+ // NOTE: The ArgNo variable here is not the absolute argument number, it is
+ // the index of the "arbitrary" type in the Tys array passed to the
+ // Intrinsic::getDeclaration function. Consequently, we only want to
+ // increment it when we actually hit an arbitrary integer type which is
+ // identified by BitWidth == 0. Getting this wrong leads to very subtle
+ // bugs!
+ if (BitWidth == 0)
+ OS << "Tys[" << ArgNo++ << "]";
+ else
+ OS << "IntegerType::get(" << BitWidth << ")";
+ } else if (ArgType->isSubClassOf("LLVMVectorType")) {
+ OS << "VectorType::get(";
+ EmitTypeGenerate(OS, ArgType->getValueAsDef("ElTy"), ArgNo);
+ OS << ", " << ArgType->getValueAsInt("NumElts") << ")";
+ } else if (ArgType->isSubClassOf("LLVMPointerType")) {
+ OS << "PointerType::get(";
+ EmitTypeGenerate(OS, ArgType->getValueAsDef("ElTy"), ArgNo);
+ OS << ")";
+ } else if (ArgType->isSubClassOf("LLVMEmptyStructType")) {
+ OS << "StructType::get(std::vector<const Type *>())";
+ } else {
+ OS << "Type::getPrimitiveType(";
+ OS << ArgType->getValueAsString("TypeVal") << ")";
+ }
+}
+
+/// RecordListComparator - Provide a determinstic comparator for lists of
+/// records.
+namespace {
+ struct RecordListComparator {
+ bool operator()(const std::vector<Record*> &LHS,
+ const std::vector<Record*> &RHS) const {
+ unsigned i = 0;
+ do {
+ if (i == RHS.size()) return false; // RHS is shorter than LHS.
+ if (LHS[i] != RHS[i])
+ return LHS[i]->getName() < RHS[i]->getName();
+ } while (++i != LHS.size());
+
+ return i != RHS.size();
+ }
+ };
+}
+
+void IntrinsicEmitter::EmitVerifier(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS) {
+ OS << "// Verifier::visitIntrinsicFunctionCall code.\n";
+ OS << "#ifdef GET_INTRINSIC_VERIFIER\n";
+ OS << " switch (ID) {\n";
+ OS << " default: assert(0 && \"Invalid intrinsic!\");\n";
+
+ // This checking can emit a lot of very common code. To reduce the amount of
+ // code that we emit, batch up cases that have identical types. This avoids
+ // problems where GCC can run out of memory compiling Verifier.cpp.
+ typedef std::map<std::vector<Record*>, std::vector<unsigned>,
+ RecordListComparator> MapTy;
+ MapTy UniqueArgInfos;
+
+ // Compute the unique argument type info.
+ for (unsigned i = 0, e = Ints.size(); i != e; ++i)
+ UniqueArgInfos[Ints[i].ArgTypeDefs].push_back(i);
+
+ // Loop through the array, emitting one comparison for each batch.
+ for (MapTy::iterator I = UniqueArgInfos.begin(),
+ E = UniqueArgInfos.end(); I != E; ++I) {
+ for (unsigned i = 0, e = I->second.size(); i != e; ++i) {
+ OS << " case Intrinsic::" << Ints[I->second[i]].EnumName << ":\t\t// "
+ << Ints[I->second[i]].Name << "\n";
+ }
+
+ const std::vector<Record*> &ArgTypes = I->first;
+ OS << " VerifyIntrinsicPrototype(ID, IF, ";
+ bool VarArg = false;
+ for (unsigned j = 0; j != ArgTypes.size(); ++j) {
+ VarArg = EmitTypeVerify(OS, ArgTypes[j]);
+ if (VarArg) {
+ if ((j+1) != ArgTypes.size())
+ throw "Var arg type not last argument";
+ break;
+ }
+ }
+
+ OS << (VarArg ? "-2);\n" : "-1);\n");
+ OS << " break;\n";
+ }
+ OS << " }\n";
+ OS << "#endif\n\n";
+}
+
+void IntrinsicEmitter::EmitGenerator(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS) {
+ OS << "// Code for generating Intrinsic function declarations.\n";
+ OS << "#ifdef GET_INTRINSIC_GENERATOR\n";
+ OS << " switch (id) {\n";
+ OS << " default: assert(0 && \"Invalid intrinsic!\");\n";
+
+ // Similar to GET_INTRINSIC_VERIFIER, batch up cases that have identical
+ // types.
+ typedef std::map<std::vector<Record*>, std::vector<unsigned>,
+ RecordListComparator> MapTy;
+ MapTy UniqueArgInfos;
+
+ // Compute the unique argument type info.
+ for (unsigned i = 0, e = Ints.size(); i != e; ++i)
+ UniqueArgInfos[Ints[i].ArgTypeDefs].push_back(i);
+
+ // Loop through the array, emitting one generator for each batch.
+ for (MapTy::iterator I = UniqueArgInfos.begin(),
+ E = UniqueArgInfos.end(); I != E; ++I) {
+ for (unsigned i = 0, e = I->second.size(); i != e; ++i) {
+ OS << " case Intrinsic::" << Ints[I->second[i]].EnumName << ":\t\t// "
+ << Ints[I->second[i]].Name << "\n";
+ }
+
+ const std::vector<Record*> &ArgTypes = I->first;
+ unsigned N = ArgTypes.size();
+
+ if (ArgTypes[N-1]->getValueAsString("TypeVal") == "...") {
+ OS << " IsVarArg = true;\n";
+ --N;
+ }
+
+ unsigned ArgNo = 0;
+ OS << " ResultTy = ";
+ EmitTypeGenerate(OS, ArgTypes[0], ArgNo);
+ OS << ";\n";
+
+ for (unsigned j = 1; j != N; ++j) {
+ OS << " ArgTys.push_back(";
+ EmitTypeGenerate(OS, ArgTypes[j], ArgNo);
+ OS << ");\n";
+ }
+ OS << " break;\n";
+ }
+ OS << " }\n";
+ OS << "#endif\n\n";
+}
+
+void IntrinsicEmitter::EmitModRefInfo(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS) {
+ OS << "// BasicAliasAnalysis code.\n";
+ OS << "#ifdef GET_MODREF_BEHAVIOR\n";
+ for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
+ switch (Ints[i].ModRef) {
+ default: break;
+ case CodeGenIntrinsic::NoMem:
+ OS << " NoMemoryTable->push_back(\"" << Ints[i].Name << "\");\n";
+ break;
+ case CodeGenIntrinsic::ReadArgMem:
+ case CodeGenIntrinsic::ReadMem:
+ OS << " OnlyReadsMemoryTable->push_back(\"" << Ints[i].Name << "\");\n";
+ break;
+ }
+ }
+ OS << "#endif\n\n";
+}
+
+void IntrinsicEmitter::
+EmitNoMemoryInfo(const std::vector<CodeGenIntrinsic> &Ints, std::ostream &OS) {
+ OS << "// SelectionDAGIsel code.\n";
+ OS << "#ifdef GET_NO_MEMORY_INTRINSICS\n";
+ OS << " switch (IntrinsicID) {\n";
+ OS << " default: break;\n";
+ for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
+ switch (Ints[i].ModRef) {
+ default: break;
+ case CodeGenIntrinsic::NoMem:
+ OS << " case Intrinsic::" << Ints[i].EnumName << ":\n";
+ break;
+ }
+ }
+ OS << " return true; // These intrinsics have no side effects.\n";
+ OS << " }\n";
+ OS << "#endif\n\n";
+}
+
+void IntrinsicEmitter::
+EmitSideEffectInfo(const std::vector<CodeGenIntrinsic> &Ints, std::ostream &OS){
+ OS << "// Return true if doesn't access or only reads memory.\n";
+ OS << "#ifdef GET_SIDE_EFFECT_INFO\n";
+ OS << " switch (IntrinsicID) {\n";
+ OS << " default: break;\n";
+ for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
+ switch (Ints[i].ModRef) {
+ default: break;
+ case CodeGenIntrinsic::NoMem:
+ case CodeGenIntrinsic::ReadArgMem:
+ case CodeGenIntrinsic::ReadMem:
+ OS << " case Intrinsic::" << Ints[i].EnumName << ":\n";
+ break;
+ }
+ }
+ OS << " return true; // These intrinsics have no side effects.\n";
+ OS << " }\n";
+ OS << "#endif\n\n";
+}
+
+void IntrinsicEmitter::
+EmitGCCBuiltinList(const std::vector<CodeGenIntrinsic> &Ints, std::ostream &OS){
+ OS << "// Get the GCC builtin that corresponds to an LLVM intrinsic.\n";
+ OS << "#ifdef GET_GCC_BUILTIN_NAME\n";
+ OS << " switch (F->getIntrinsicID()) {\n";
+ OS << " default: BuiltinName = \"\"; break;\n";
+ for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
+ if (!Ints[i].GCCBuiltinName.empty()) {
+ OS << " case Intrinsic::" << Ints[i].EnumName << ": BuiltinName = \""
+ << Ints[i].GCCBuiltinName << "\"; break;\n";
+ }
+ }
+ OS << " }\n";
+ OS << "#endif\n\n";
+}
+
+void IntrinsicEmitter::
+EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS) {
+ typedef std::map<std::pair<std::string, std::string>, std::string> BIMTy;
+ BIMTy BuiltinMap;
+ for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
+ if (!Ints[i].GCCBuiltinName.empty()) {
+ std::pair<std::string, std::string> Key(Ints[i].GCCBuiltinName,
+ Ints[i].TargetPrefix);
+ if (!BuiltinMap.insert(std::make_pair(Key, Ints[i].EnumName)).second)
+ throw "Intrinsic '" + Ints[i].TheDef->getName() +
+ "': duplicate GCC builtin name!";
+ }
+ }
+
+ OS << "// Get the LLVM intrinsic that corresponds to a GCC builtin.\n";
+ OS << "// This is used by the C front-end. The GCC builtin name is passed\n";
+ OS << "// in as BuiltinName, and a target prefix (e.g. 'ppc') is passed\n";
+ OS << "// in as TargetPrefix. The result is assigned to 'IntrinsicID'.\n";
+ OS << "#ifdef GET_LLVM_INTRINSIC_FOR_GCC_BUILTIN\n";
+ OS << " if (0);\n";
+ // Note: this could emit significantly better code if we cared.
+ for (BIMTy::iterator I = BuiltinMap.begin(), E = BuiltinMap.end();I != E;++I){
+ OS << " else if (";
+ if (!I->first.second.empty()) {
+ // Emit this as a strcmp, so it can be constant folded by the FE.
+ OS << "!strcmp(TargetPrefix, \"" << I->first.second << "\") &&\n"
+ << " ";
+ }
+ OS << "!strcmp(BuiltinName, \"" << I->first.first << "\"))\n";
+ OS << " IntrinsicID = Intrinsic::" << I->second << ";\n";
+ }
+ OS << " else\n";
+ OS << " IntrinsicID = Intrinsic::not_intrinsic;\n";
+ OS << "#endif\n\n";
+}
diff --git a/utils/TableGen/IntrinsicEmitter.h b/utils/TableGen/IntrinsicEmitter.h
new file mode 100644
index 0000000000..fa483ce674
--- /dev/null
+++ b/utils/TableGen/IntrinsicEmitter.h
@@ -0,0 +1,57 @@
+//===- IntrinsicEmitter.h - Generate intrinsic information ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend emits information about intrinsic functions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef INTRINSIC_EMITTER_H
+#define INTRINSIC_EMITTER_H
+
+#include "CodeGenIntrinsics.h"
+#include "TableGenBackend.h"
+
+namespace llvm {
+ class IntrinsicEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+
+ public:
+ IntrinsicEmitter(RecordKeeper &R) : Records(R) {}
+
+ void run(std::ostream &OS);
+
+ void EmitEnumInfo(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS);
+
+ void EmitFnNameRecognizer(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS);
+ void EmitIntrinsicToNameTable(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS);
+ void EmitVerifier(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS);
+ void EmitGenerator(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS);
+ void EmitModRefInfo(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS);
+ void EmitNoMemoryInfo(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS);
+ void EmitSideEffectInfo(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS);
+ void EmitGCCBuiltinList(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS);
+ void EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS);
+ };
+
+} // End llvm namespace
+
+#endif
+
+
+
diff --git a/utils/TableGen/Makefile b/utils/TableGen/Makefile
new file mode 100644
index 0000000000..5b93bf2e54
--- /dev/null
+++ b/utils/TableGen/Makefile
@@ -0,0 +1,29 @@
+##===- utils/TableGen/Makefile -----------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file was developed by the LLVM research group and is distributed under
+# the University of Illinois Open Source License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../..
+TOOLNAME = tblgen
+NO_INSTALL = 1;
+USEDLIBS = LLVMSupport.a LLVMSystem.a
+EXTRA_DIST = FileLexer.cpp.cvs FileLexer.l.cvs \
+ FileParser.cpp.cvs FileParser.h.cvs FileParser.y.cvs
+REQUIRES_EH := 1
+
+include $(LEVEL)/Makefile.common
+
+# Disable -pedantic for tblgen
+CompileCommonOpts := $(filter-out -pedantic,$(CompileCommonOpts))
+CompileCommonOpts := $(filter-out -Wno-long-long,$(CompileCommonOpts))
+
+#
+# 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.
+#
+$(ObjDir)/FileLexer.o : $(PROJ_SRC_DIR)/FileParser.h
diff --git a/utils/TableGen/Record.cpp b/utils/TableGen/Record.cpp
new file mode 100644
index 0000000000..e81a361eae
--- /dev/null
+++ b/utils/TableGen/Record.cpp
@@ -0,0 +1,955 @@
+//===- Record.cpp - Record implementation ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implement the tablegen record classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Record.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Streams.h"
+#include <ios>
+
+using namespace llvm;
+
+//===----------------------------------------------------------------------===//
+// Type implementations
+//===----------------------------------------------------------------------===//
+
+void RecTy::dump() const { print(*cerr.stream()); }
+
+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) {
+ int64_t Value = II->getValue();
+ // Make sure this bitfield is large enough to hold the integer value...
+ if (Value >= 0) {
+ if (Value & ~((1LL << Size)-1))
+ return 0;
+ } else {
+ if ((Value >> Size) != -1 || ((Value & (1LL << (Size-1))) == 0))
+ return 0;
+ }
+
+ BitsInit *Ret = new BitsInit(Size);
+ for (unsigned i = 0; i != Size; ++i)
+ Ret->setBit(i, new BitInit(Value & (1LL << 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(BinOpInit *BO) {
+ if (BO->getOpcode() == BinOpInit::STRCONCAT) {
+ Init *L = BO->getLHS()->convertInitializerTo(this);
+ Init *R = BO->getRHS()->convertInitializerTo(this);
+ if (L == 0 || R == 0) return 0;
+ if (L != BO->getLHS() || R != BO->getRHS())
+ return new BinOpInit(BinOpInit::STRCONCAT, L, R);
+ return BO;
+ }
+ 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;
+}
+
+Init *DagRecTy::convertValue(BinOpInit *BO) {
+ if (BO->getOpcode() == BinOpInit::CONCAT) {
+ Init *L = BO->getLHS()->convertInitializerTo(this);
+ Init *R = BO->getRHS()->convertInitializerTo(this);
+ if (L == 0 || R == 0) return 0;
+ if (L != BO->getLHS() || R != BO->getRHS())
+ return new BinOpInit(BinOpInit::CONCAT, L, R);
+ return BO;
+ }
+ 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(*cerr.stream()); }
+
+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, const RecordVal *RV) {
+ 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, RV);
+ 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;
+}
+
+Init *ListInit::convertInitListSlice(const std::vector<unsigned> &Elements) {
+ std::vector<Init*> Vals;
+ for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
+ if (Elements[i] >= getSize())
+ return 0;
+ Vals.push_back(getElement(Elements[i]));
+ }
+ return new ListInit(Vals);
+}
+
+Record *ListInit::getElementAsRecord(unsigned i) const {
+ assert(i < Values.size() && "List element index out of range!");
+ DefInit *DI = dynamic_cast<DefInit*>(Values[i]);
+ if (DI == 0) throw "Expected record in list!";
+ return DI->getDef();
+}
+
+Init *ListInit::resolveReferences(Record &R, const RecordVal *RV) {
+ std::vector<Init*> Resolved;
+ Resolved.reserve(getSize());
+ bool Changed = false;
+
+ for (unsigned i = 0, e = getSize(); i != e; ++i) {
+ Init *E;
+ Init *CurElt = getElement(i);
+
+ do {
+ E = CurElt;
+ CurElt = CurElt->resolveReferences(R, RV);
+ Changed |= E != CurElt;
+ } while (E != CurElt);
+ Resolved.push_back(E);
+ }
+
+ if (Changed)
+ return new ListInit(Resolved);
+ return this;
+}
+
+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 *BinOpInit::Fold() {
+ switch (getOpcode()) {
+ default: assert(0 && "Unknown binop");
+ case CONCAT: {
+ DagInit *LHSs = dynamic_cast<DagInit*>(LHS);
+ DagInit *RHSs = dynamic_cast<DagInit*>(RHS);
+ if (LHSs && RHSs) {
+ DefInit *LOp = dynamic_cast<DefInit*>(LHSs->getOperator());
+ DefInit *ROp = dynamic_cast<DefInit*>(RHSs->getOperator());
+ if (LOp->getDef() != ROp->getDef())
+ throw "Concated Dag operators do not match!";
+ std::vector<Init*> Args;
+ std::vector<std::string> ArgNames;
+ for (unsigned i = 0, e = LHSs->getNumArgs(); i != e; ++i) {
+ Args.push_back(LHSs->getArg(i));
+ ArgNames.push_back(LHSs->getArgName(i));
+ }
+ for (unsigned i = 0, e = RHSs->getNumArgs(); i != e; ++i) {
+ Args.push_back(RHSs->getArg(i));
+ ArgNames.push_back(RHSs->getArgName(i));
+ }
+ return new DagInit(LHSs->getOperator(), Args, ArgNames);
+ }
+ break;
+ }
+ case STRCONCAT: {
+ StringInit *LHSs = dynamic_cast<StringInit*>(LHS);
+ StringInit *RHSs = dynamic_cast<StringInit*>(RHS);
+ if (LHSs && RHSs)
+ return new StringInit(LHSs->getValue() + RHSs->getValue());
+ break;
+ }
+ case SHL:
+ case SRA:
+ case SRL: {
+ IntInit *LHSi = dynamic_cast<IntInit*>(LHS);
+ IntInit *RHSi = dynamic_cast<IntInit*>(RHS);
+ if (LHSi && RHSi) {
+ int LHSv = LHSi->getValue(), RHSv = RHSi->getValue();
+ int Result;
+ switch (getOpcode()) {
+ default: assert(0 && "Bad opcode!");
+ case SHL: Result = LHSv << RHSv; break;
+ case SRA: Result = LHSv >> RHSv; break;
+ case SRL: Result = (unsigned)LHSv >> (unsigned)RHSv; break;
+ }
+ return new IntInit(Result);
+ }
+ break;
+ }
+ }
+ return this;
+}
+
+Init *BinOpInit::resolveReferences(Record &R, const RecordVal *RV) {
+ Init *lhs = LHS->resolveReferences(R, RV);
+ Init *rhs = RHS->resolveReferences(R, RV);
+
+ if (LHS != lhs || RHS != rhs)
+ return (new BinOpInit(getOpcode(), lhs, rhs))->Fold();
+ return Fold();
+}
+
+void BinOpInit::print(std::ostream &OS) const {
+ switch (Opc) {
+ case CONCAT: OS << "!con"; break;
+ case SHL: OS << "!shl"; break;
+ case SRA: OS << "!sra"; break;
+ case SRL: OS << "!srl"; break;
+ case STRCONCAT: OS << "!strconcat"; break;
+ }
+ OS << "(";
+ LHS->print(OS);
+ OS << ", ";
+ RHS->print(OS);
+ OS << ")";
+}
+
+Init *TypedInit::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 *TypedInit::convertInitListSlice(const std::vector<unsigned> &Elements) {
+ ListRecTy *T = dynamic_cast<ListRecTy*>(getType());
+ if (T == 0) return 0; // Cannot subscript a non-list variable...
+
+ if (Elements.size() == 1)
+ return new VarListElementInit(this, Elements[0]);
+
+ std::vector<Init*> ListInits;
+ ListInits.reserve(Elements.size());
+ for (unsigned i = 0, e = Elements.size(); i != e; ++i)
+ ListInits.push_back(new VarListElementInit(this, Elements[i]));
+ return new ListInit(ListInits);
+}
+
+
+Init *VarInit::resolveBitReference(Record &R, const RecordVal *IRV,
+ unsigned Bit) {
+ if (R.isTemplateArg(getName())) return 0;
+ if (IRV && IRV->getName() != getName()) return 0;
+
+ 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 0;
+}
+
+Init *VarInit::resolveListElementReference(Record &R, const RecordVal *IRV,
+ unsigned Elt) {
+ if (R.isTemplateArg(getName())) return 0;
+ if (IRV && IRV->getName() != getName()) return 0;
+
+ RecordVal *RV = R.getValue(getName());
+ assert(RV && "Reference to a non-existant variable?");
+ ListInit *LI = dynamic_cast<ListInit*>(RV->getValue());
+ assert(LI && "Invalid list element!");
+
+ if (Elt >= LI->getSize())
+ return 0; // Out of range reference.
+ Init *E = LI->getElement(Elt);
+ if (!dynamic_cast<UnsetInit*>(E)) // If the element is set
+ return E; // Replace the VarListElementInit with it.
+ return 0;
+}
+
+
+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 (dynamic_cast<RecordRecTy*>(getType()))
+ if (const RecordVal *RV = R.getValue(VarName)) {
+ Init *TheInit = RV->getValue();
+ assert(TheInit != this && "Infinite loop detected!");
+ if (Init *I = TheInit->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, const RecordVal *RV) {
+ if (RecordVal *Val = R.getValue(VarName))
+ if (RV == Val || (RV == 0 && !dynamic_cast<UnsetInit*>(Val->getValue())))
+ return Val->getValue();
+ return this;
+}
+
+
+Init *VarBitInit::resolveReferences(Record &R, const RecordVal *RV) {
+ if (Init *I = getVariable()->resolveBitReference(R, RV, getBitNum()))
+ return I;
+ return this;
+}
+
+Init *VarListElementInit::resolveReferences(Record &R, const RecordVal *RV) {
+ if (Init *I = getVariable()->resolveListElementReference(R, RV,
+ getElementNum()))
+ return I;
+ return this;
+}
+
+Init *VarListElementInit::resolveBitReference(Record &R, const RecordVal *RV,
+ unsigned Bit) {
+ // FIXME: This should be implemented, to support references like:
+ // bit B = AA[0]{1};
+ return 0;
+}
+
+Init *VarListElementInit::
+resolveListElementReference(Record &R, const RecordVal *RV, unsigned Elt) {
+ // FIXME: This should be implemented, to support references like:
+ // int B = AA[0][1];
+ return 0;
+}
+
+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::resolveBitReference(Record &R, const RecordVal *RV,
+ unsigned Bit) {
+ if (Init *BitsVal = Rec->getFieldInit(R, FieldName))
+ 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 0;
+}
+
+Init *FieldInit::resolveListElementReference(Record &R, const RecordVal *RV,
+ unsigned Elt) {
+ if (Init *ListVal = Rec->getFieldInit(R, FieldName))
+ if (ListInit *LI = dynamic_cast<ListInit*>(ListVal)) {
+ if (Elt >= LI->getSize()) return 0;
+ Init *E = LI->getElement(Elt);
+
+ if (!dynamic_cast<UnsetInit*>(E)) // If the bit is set...
+ return E; // Replace the VarListElementInit with it.
+ }
+ return 0;
+}
+
+Init *FieldInit::resolveReferences(Record &R, const RecordVal *RV) {
+ Init *NewRec = RV ? Rec->resolveReferences(R, RV) : Rec;
+
+ Init *BitsVal = NewRec->getFieldInit(R, FieldName);
+ if (BitsVal) {
+ Init *BVR = BitsVal->resolveReferences(R, RV);
+ return BVR->isComplete() ? BVR : this;
+ }
+
+ if (NewRec != Rec) {
+ dump();
+ NewRec->dump(); cerr << "\n";
+ return new FieldInit(NewRec, FieldName);
+ }
+ return this;
+}
+
+Init *DagInit::resolveReferences(Record &R, const RecordVal *RV) {
+ std::vector<Init*> NewArgs;
+ for (unsigned i = 0, e = Args.size(); i != e; ++i)
+ NewArgs.push_back(Args[i]->resolveReferences(R, RV));
+
+ Init *Op = Val->resolveReferences(R, RV);
+
+ if (Args != NewArgs || Op != Val)
+ return new DagInit(Op, NewArgs, ArgNames);
+
+ return this;
+}
+
+
+void DagInit::print(std::ostream &OS) const {
+ OS << "(" << *Val;
+ 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 { 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";
+}
+
+void Record::setName(const std::string &Name) {
+ if (Records.getDef(getName()) == this) {
+ Records.removeDef(getName());
+ this->Name = Name;
+ Records.addDef(this);
+ } else {
+ Records.removeClass(getName());
+ this->Name = Name;
+ Records.addClass(this);
+ }
+}
+
+/// resolveReferencesTo - If anything in this record refers to RV, replace the
+/// reference to RV with the RHS of RV. If RV is null, we resolve all possible
+/// references.
+void Record::resolveReferencesTo(const RecordVal *RV) {
+ for (unsigned i = 0, e = Values.size(); i != e; ++i) {
+ if (Init *V = Values[i].getValue())
+ Values[i].setValue(V->resolveReferences(*this, RV));
+ }
+}
+
+
+void Record::dump() const { cerr << *this; }
+
+std::ostream &llvm::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!";
+}
+
+/// getValueAsListOfDefs - This method looks up the specified field and returns
+/// its value as a vector of records, throwing an exception if the field does
+/// not exist or if the value is not the right type.
+///
+std::vector<Record*>
+Record::getValueAsListOfDefs(const std::string &FieldName) const {
+ ListInit *List = getValueAsListInit(FieldName);
+ std::vector<Record*> Defs;
+ for (unsigned i = 0; i < List->getSize(); i++) {
+ if (DefInit *DI = dynamic_cast<DefInit*>(List->getElement(i))) {
+ Defs.push_back(DI->getDef());
+ } else {
+ throw "Record `" + getName() + "', field `" + FieldName +
+ "' list is not entirely DefInit!";
+ }
+ }
+ return Defs;
+}
+
+/// 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 an int 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 def 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!";
+}
+
+std::string Record::getValueAsCode(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 CodeInit *CI = dynamic_cast<const CodeInit*>(R->getValue()))
+ return CI->getValue();
+ throw "Record `" + getName() + "', field `" + FieldName +
+ "' does not have a code initializer!";
+}
+
+
+void RecordKeeper::dump() const { cerr << *this; }
+
+std::ostream &llvm::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;
+}
+
diff --git a/utils/TableGen/Record.h b/utils/TableGen/Record.h
new file mode 100644
index 0000000000..d419f0b629
--- /dev/null
+++ b/utils/TableGen/Record.h
@@ -0,0 +1,1147 @@
+//===- Record.h - Classes to represent Table Records ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This 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 <ostream>
+#include <cassert>
+
+namespace llvm {
+
+// RecTy subclasses.
+class BitRecTy;
+class BitsRecTy;
+class IntRecTy;
+class StringRecTy;
+class ListRecTy;
+class CodeRecTy;
+class DagRecTy;
+class RecordRecTy;
+
+// Init subclasses.
+struct Init;
+class UnsetInit;
+class BitInit;
+class BitsInit;
+class IntInit;
+class StringInit;
+class CodeInit;
+class ListInit;
+class BinOpInit;
+class DefInit;
+class DagInit;
+class TypedInit;
+class VarInit;
+class FieldInit;
+class VarBitInit;
+class VarListElementInit;
+
+// Other classes.
+class Record;
+class RecordVal;
+
+//===----------------------------------------------------------------------===//
+// 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( BinOpInit *UI) { 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
+///
+class BitRecTy : public RecTy {
+public:
+ virtual Init *convertValue( UnsetInit *UI) { return (Init*)UI; }
+ virtual Init *convertValue( BitInit *BI) { return (Init*)BI; }
+ virtual Init *convertValue( BitsInit *BI);
+ virtual Init *convertValue( IntInit *II);
+ 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 (Init*)VB; }
+ virtual Init *convertValue( DefInit *DI) { return 0; }
+ virtual Init *convertValue( DagInit *DI) { return 0; }
+ virtual Init *convertValue( BinOpInit *UI) { return 0; }
+ virtual Init *convertValue( TypedInit *TI);
+ virtual Init *convertValue( VarInit *VI) { return RecTy::convertValue(VI);}
+ virtual Init *convertValue( FieldInit *FI) { return RecTy::convertValue(FI);}
+
+ 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; }
+ 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; }
+
+};
+
+
+// BitsRecTy - 'bits<n>' - Represent a fixed number of bits
+/// BitsRecTy - 'bits&lt;n&gt;' - Represent a fixed number of bits
+///
+class BitsRecTy : public RecTy {
+ unsigned Size;
+public:
+ BitsRecTy(unsigned Sz) : Size(Sz) {}
+
+ unsigned getNumBits() const { return Size; }
+
+ virtual Init *convertValue( UnsetInit *UI);
+ virtual Init *convertValue( BitInit *UI);
+ virtual Init *convertValue( BitsInit *BI);
+ virtual Init *convertValue( IntInit *II);
+ 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( BinOpInit *UI) { return 0; }
+ virtual Init *convertValue( TypedInit *TI);
+ virtual Init *convertValue( VarInit *VI) { return RecTy::convertValue(VI);}
+ virtual Init *convertValue( FieldInit *FI) { return RecTy::convertValue(FI);}
+
+
+ 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 BitsRecTy *RHS) const {
+ return RHS->Size == Size;
+ }
+ virtual bool baseClassOf(const IntRecTy *RHS) const { return true; }
+ 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; }
+
+};
+
+
+/// IntRecTy - 'int' - Represent an integer value of no particular size
+///
+class IntRecTy : public RecTy {
+public:
+ virtual Init *convertValue( UnsetInit *UI) { return (Init*)UI; }
+ virtual Init *convertValue( BitInit *BI);
+ virtual Init *convertValue( BitsInit *BI);
+ virtual Init *convertValue( IntInit *II) { return (Init*)II; }
+ 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( BinOpInit *UI) { return 0; }
+ virtual Init *convertValue( TypedInit *TI);
+ virtual Init *convertValue( VarInit *VI) { return RecTy::convertValue(VI);}
+ virtual Init *convertValue( FieldInit *FI) { return RecTy::convertValue(FI);}
+
+
+ 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 BitsRecTy *RHS) const { return true; }
+ virtual bool baseClassOf(const IntRecTy *RHS) const { return true; }
+ 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; }
+
+};
+
+/// StringRecTy - 'string' - Represent an string value
+///
+class StringRecTy : public RecTy {
+public:
+ virtual Init *convertValue( UnsetInit *UI) { return (Init*)UI; }
+ 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 (Init*)SI; }
+ virtual Init *convertValue( ListInit *LI) { return 0; }
+ virtual Init *convertValue( BinOpInit *BO);
+ 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);
+ virtual Init *convertValue( VarInit *VI) { return RecTy::convertValue(VI);}
+ virtual Init *convertValue( FieldInit *FI) { return RecTy::convertValue(FI);}
+
+ void print(std::ostream &OS) const { OS << "string"; }
+
+ bool typeIsConvertibleTo(const RecTy *RHS) const {
+ return RHS->baseClassOf(this);
+ }
+
+ 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 true; }
+ 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; }
+};
+
+// ListRecTy - 'list<Ty>' - Represent a list of values, all of which must be of
+// the specified type.
+/// ListRecTy - 'list&lt;Ty&gt;' - 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; }
+
+ virtual Init *convertValue( UnsetInit *UI) { return (Init*)UI; }
+ 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);
+ 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( BinOpInit *UI) { return 0; }
+ virtual Init *convertValue( TypedInit *TI);
+ virtual Init *convertValue( VarInit *VI) { return RecTy::convertValue(VI);}
+ virtual Init *convertValue( FieldInit *FI) { return RecTy::convertValue(FI);}
+
+ void print(std::ostream &OS) const;
+
+ bool typeIsConvertibleTo(const RecTy *RHS) const {
+ return RHS->baseClassOf(this);
+ }
+
+ 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 RHS->getElementType()->typeIsConvertibleTo(Ty);
+ }
+ 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; }
+};
+
+/// CodeRecTy - 'code' - Represent an code fragment, function or method.
+///
+class CodeRecTy : public RecTy {
+public:
+ virtual Init *convertValue( UnsetInit *UI) { return (Init*)UI; }
+ 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 (Init*)CI; }
+ virtual Init *convertValue(VarBitInit *VB) { return 0; }
+ virtual Init *convertValue( DefInit *DI) { return 0; }
+ virtual Init *convertValue( DagInit *DI) { return 0; }
+ virtual Init *convertValue( BinOpInit *UI) { return 0; }
+ virtual Init *convertValue( TypedInit *TI);
+ virtual Init *convertValue( VarInit *VI) { return RecTy::convertValue(VI);}
+ virtual Init *convertValue( FieldInit *FI) { return RecTy::convertValue(FI);}
+
+
+ void print(std::ostream &OS) const { OS << "code"; }
+
+ bool typeIsConvertibleTo(const RecTy *RHS) const {
+ return RHS->baseClassOf(this);
+ }
+ 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 true; }
+ virtual bool baseClassOf(const DagRecTy *RHS) const { return false; }
+ virtual bool baseClassOf(const RecordRecTy *RHS) const { return false; }
+};
+
+/// DagRecTy - 'dag' - Represent a dag fragment
+///
+class DagRecTy : public RecTy {
+public:
+ virtual Init *convertValue( UnsetInit *UI) { return (Init*)UI; }
+ 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( BinOpInit *BO);
+ virtual Init *convertValue( DagInit *CI) { return (Init*)CI; }
+ virtual Init *convertValue( TypedInit *TI);
+ virtual Init *convertValue( VarInit *VI) { return RecTy::convertValue(VI);}
+ virtual Init *convertValue( FieldInit *FI) { return RecTy::convertValue(FI);}
+
+ void print(std::ostream &OS) const { OS << "dag"; }
+
+ bool typeIsConvertibleTo(const RecTy *RHS) const {
+ return RHS->baseClassOf(this);
+ }
+
+ 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 true; }
+ virtual bool baseClassOf(const RecordRecTy *RHS) const { return false; }
+};
+
+
+/// 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; }
+
+ virtual Init *convertValue( UnsetInit *UI) { return (Init*)UI; }
+ 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( BinOpInit *UI) { return 0; }
+ virtual Init *convertValue( DefInit *DI);
+ virtual Init *convertValue( DagInit *DI) { return 0; }
+ virtual Init *convertValue( TypedInit *VI);
+ virtual Init *convertValue( VarInit *VI) { return RecTy::convertValue(VI);}
+ virtual Init *convertValue( FieldInit *FI) { return RecTy::convertValue(FI);}
+
+ void print(std::ostream &OS) const;
+
+ bool typeIsConvertibleTo(const RecTy *RHS) const {
+ return RHS->baseClassOf(this);
+ }
+ 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;
+};
+
+
+
+//===----------------------------------------------------------------------===//
+// 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;
+ }
+
+ /// convertInitListSlice - This method is used to implement the list slice
+ /// selection operator. Given an initializer, it selects the specified list
+ /// elements, returning them as a new init of list type. If it is not legal
+ /// to take a slice of this, return null.
+ ///
+ virtual Init *convertInitListSlice(const std::vector<unsigned> &Elements) {
+ 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, const RecordVal *RV) {
+ return this;
+ }
+};
+
+inline std::ostream &operator<<(std::ostream &OS, const Init &I) {
+ I.print(OS); return OS;
+}
+
+
+/// UnsetInit - ? - Represents an uninitialized value
+///
+class UnsetInit : public Init {
+public:
+ 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, const RecordVal *RV);
+
+ // 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];
+ }
+
+ Record *getElementAsRecord(unsigned i) const;
+
+ Init *convertInitListSlice(const std::vector<unsigned> &Elements);
+
+ virtual Init *convertInitializerTo(RecTy *Ty) {
+ return Ty->convertValue(this);
+ }
+
+ /// 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, const RecordVal *RV);
+
+ virtual void print(std::ostream &OS) const;
+};
+
+/// BinOpInit - !op (X, Y) - Combine two inits.
+///
+class BinOpInit : public Init {
+public:
+ enum BinaryOp { SHL, SRA, SRL, STRCONCAT, CONCAT };
+private:
+ BinaryOp Opc;
+ Init *LHS, *RHS;
+public:
+ BinOpInit(BinaryOp opc, Init *lhs, Init *rhs) : Opc(opc), LHS(lhs), RHS(rhs) {
+ }
+
+ BinaryOp getOpcode() const { return Opc; }
+ Init *getLHS() const { return LHS; }
+ Init *getRHS() const { return RHS; }
+
+ // Fold - If possible, fold this to a simpler init. Return this if not
+ // possible to fold.
+ Init *Fold();
+
+ virtual Init *convertInitializerTo(RecTy *Ty) {
+ return Ty->convertValue(this);
+ }
+
+ virtual Init *resolveReferences(Record &R, const RecordVal *RV);
+
+ 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; }
+
+ virtual Init *convertInitializerBitRange(const std::vector<unsigned> &Bits);
+ virtual Init *convertInitListSlice(const std::vector<unsigned> &Elements);
+
+ /// 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 null.
+ ///
+ virtual Init *resolveBitReference(Record &R, const RecordVal *RV,
+ unsigned Bit) = 0;
+
+ /// resolveListElementReference - This method is used to implement
+ /// VarListElementInit::resolveReferences. If the list element is resolvable
+ /// now, we return the resolved value, otherwise we return null.
+ virtual Init *resolveListElementReference(Record &R, const RecordVal *RV,
+ unsigned Elt) = 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 *resolveBitReference(Record &R, const RecordVal *RV,
+ unsigned Bit);
+ virtual Init *resolveListElementReference(Record &R, const RecordVal *RV,
+ unsigned Elt);
+
+ 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, const RecordVal *RV);
+
+ 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, const RecordVal *RV);
+};
+
+/// VarListElementInit - List[4] - Represent access to one element of a var or
+/// field.
+class VarListElementInit : public TypedInit {
+ TypedInit *TI;
+ unsigned Element;
+public:
+ VarListElementInit(TypedInit *T, unsigned E)
+ : TypedInit(dynamic_cast<ListRecTy*>(T->getType())->getElementType()),
+ TI(T), Element(E) {
+ assert(T->getType() && dynamic_cast<ListRecTy*>(T->getType()) &&
+ "Illegal VarBitInit expression!");
+ }
+
+ virtual Init *convertInitializerTo(RecTy *Ty) {
+ return Ty->convertValue(this);
+ }
+
+ TypedInit *getVariable() const { return TI; }
+ unsigned getElementNum() const { return Element; }
+
+ virtual Init *resolveBitReference(Record &R, const RecordVal *RV,
+ unsigned Bit);
+
+ /// resolveListElementReference - This method is used to implement
+ /// VarListElementInit::resolveReferences. If the list element is resolvable
+ /// now, we return the resolved value, otherwise we return null.
+ virtual Init *resolveListElementReference(Record &R, const RecordVal *RV,
+ unsigned Elt);
+
+ virtual void print(std::ostream &OS) const {
+ TI->print(OS); OS << "[" << Element << "]";
+ }
+ virtual Init *resolveReferences(Record &R, const RecordVal *RV);
+};
+
+/// 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 *resolveBitReference(Record &R, const RecordVal *RV,
+ unsigned Bit);
+ virtual Init *resolveListElementReference(Record &R, const RecordVal *RV,
+ unsigned Elt);
+
+ virtual Init *resolveReferences(Record &R, const RecordVal *RV);
+
+ virtual void print(std::ostream &OS) const {
+ Rec->print(OS); OS << "." << FieldName;
+ }
+};
+
+/// DagInit - (v a, b) - Represent a DAG tree value. DAG inits are required
+/// to have at least one value then a (possibly empty) list of arguments. Each
+/// argument can have a name associated with it.
+///
+class DagInit : public Init {
+ Init *Val;
+ std::vector<Init*> Args;
+ std::vector<std::string> ArgNames;
+public:
+ DagInit(Init *V, const std::vector<std::pair<Init*, std::string> > &args)
+ : Val(V) {
+ 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);
+ }
+ }
+ DagInit(Init *V, const std::vector<Init*> &args,
+ const std::vector<std::string> &argNames)
+ : Val(V), Args(args), ArgNames(argNames) {
+ }
+
+ virtual Init *convertInitializerTo(RecTy *Ty) {
+ return Ty->convertValue(this);
+ }
+
+ Init *getOperator() const { return Val; }
+
+ 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 Init *resolveReferences(Record &R, const RecordVal *RV);
+
+ 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;
+}
+
+class Record {
+ 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; }
+ void setName(const std::string &Name); // Also updates RecordKeeper.
+ 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() { resolveReferencesTo(0); }
+
+ /// resolveReferencesTo - If anything in this record refers to RV, replace the
+ /// reference to RV with the RHS of RV. If RV is null, we resolve all
+ /// possible references.
+ void resolveReferencesTo(const RecordVal *RV);
+
+ 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;
+
+ /// getValueAsListOfDefs - This method looks up the specified field and
+ /// returnsits value as a vector of records, throwing an exception if the
+ /// field does not exist or if the value is not the right type.
+ ///
+ std::vector<Record*> getValueAsListOfDefs(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;
+
+ /// getValueAsCode - This method looks up the specified field and returns
+ /// its value as the string data in a CodeInit, throwing an exception if the
+ /// field does not exist or if the value is not a code object.
+ ///
+ std::string getValueAsCode(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));
+ }
+
+ /// removeClass - Remove, but do not delete, the specified record.
+ ///
+ void removeClass(const std::string &Name) {
+ assert(Classes.count(Name) && "Class does not exist!");
+ Classes.erase(Name);
+ }
+ /// removeDef - Remove, but do not delete, the specified record.
+ ///
+ void removeDef(const std::string &Name) {
+ assert(Defs.count(Name) && "Def does not exist!");
+ Defs.erase(Name);
+ }
+
+ //===--------------------------------------------------------------------===//
+ // 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;
+
+} // End llvm namespace
+
+#endif
diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp
new file mode 100644
index 0000000000..378671d0fc
--- /dev/null
+++ b/utils/TableGen/RegisterInfoEmitter.cpp
@@ -0,0 +1,568 @@
+//===- RegisterInfoEmitter.cpp - Generate a Register File Desc. -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This 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 "CodeGenTarget.h"
+#include "CodeGenRegisters.h"
+#include "Record.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Streams.h"
+#include <set>
+using namespace llvm;
+
+// runEnums - Print out enum values for all of the registers.
+void RegisterInfoEmitter::runEnums(std::ostream &OS) {
+ CodeGenTarget Target;
+ const std::vector<CodeGenRegister> &Registers = Target.getRegisters();
+
+ std::string Namespace = Registers[0].TheDef->getValueAsString("Namespace");
+
+ EmitSourceFileHeader("Target Register Enum Values", OS);
+ OS << "namespace llvm {\n\n";
+
+ 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 << " NUM_TARGET_REGS \t// " << Registers.size()+1 << "\n";
+ OS << " };\n";
+ if (!Namespace.empty())
+ OS << "}\n";
+ OS << "} // End llvm namespace \n";
+}
+
+void RegisterInfoEmitter::runHeader(std::ostream &OS) {
+ EmitSourceFileHeader("Register Information Header Fragment", OS);
+ CodeGenTarget Target;
+ const std::string &TargetName = Target.getName();
+ std::string ClassName = TargetName + "GenRegisterInfo";
+
+ OS << "#include \"llvm/Target/MRegisterInfo.h\"\n";
+ OS << "#include <string>\n\n";
+
+ OS << "namespace llvm {\n\n";
+
+ OS << "struct " << ClassName << " : public MRegisterInfo {\n"
+ << " " << ClassName
+ << "(int CallFrameSetupOpcode = -1, int CallFrameDestroyOpcode = -1);\n"
+ << " int getDwarfRegNum(unsigned RegNum) const;\n"
+ << " unsigned getSubReg(unsigned RegNo, unsigned Index) const;\n"
+ << "};\n\n";
+
+ const std::vector<CodeGenRegisterClass> &RegisterClasses =
+ Target.getRegisterClasses();
+
+ if (!RegisterClasses.empty()) {
+ OS << "namespace " << RegisterClasses[0].Namespace
+ << " { // Register classes\n";
+
+ OS << " enum {\n";
+ for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i) {
+ if (i) OS << ",\n";
+ OS << " " << RegisterClasses[i].getName() << "RegClassID";
+ if (!i) OS << " = 1";
+ }
+ OS << "\n };\n\n";
+
+ for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i) {
+ const std::string &Name = RegisterClasses[i].getName();
+
+ // Output the register class definition.
+ OS << " struct " << Name << "Class : public TargetRegisterClass {\n"
+ << " " << Name << "Class();\n"
+ << RegisterClasses[i].MethodProtos << " };\n";
+
+ // Output the extern for the instance.
+ OS << " extern " << Name << "Class\t" << Name << "RegClass;\n";
+ // Output the extern for the pointer to the instance (should remove).
+ OS << " static TargetRegisterClass * const "<< Name <<"RegisterClass = &"
+ << Name << "RegClass;\n";
+ }
+ OS << "} // end of namespace " << TargetName << "\n\n";
+ }
+ OS << "} // End llvm namespace \n";
+}
+
+bool isSubRegisterClass(const CodeGenRegisterClass &RC,
+ std::set<Record*> &RegSet) {
+ for (unsigned i = 0, e = RC.Elements.size(); i != e; ++i) {
+ Record *Reg = RC.Elements[i];
+ if (!RegSet.count(Reg))
+ return false;
+ }
+ return true;
+}
+
+static void addSuperReg(Record *R, Record *S,
+ std::map<Record*, std::set<Record*> > &SubRegs,
+ std::map<Record*, std::set<Record*> > &SuperRegs,
+ std::map<Record*, std::set<Record*> > &Aliases,
+ RegisterInfoEmitter &RIE) {
+ if (R == S) {
+ cerr << "Error: recursive sub-register relationship between"
+ << " register " << RIE.getQualifiedName(R)
+ << " and its sub-registers?\n";
+ abort();
+ }
+ if (!SuperRegs[R].insert(S).second)
+ return;
+ SubRegs[S].insert(R);
+ Aliases[R].insert(S);
+ Aliases[S].insert(R);
+ if (SuperRegs.count(S))
+ for (std::set<Record*>::iterator I = SuperRegs[S].begin(),
+ E = SuperRegs[S].end(); I != E; ++I)
+ addSuperReg(R, *I, SubRegs, SuperRegs, Aliases, RIE);
+}
+
+static void addSubSuperReg(Record *R, Record *S,
+ std::map<Record*, std::set<Record*> > &SubRegs,
+ std::map<Record*, std::set<Record*> > &SuperRegs,
+ std::map<Record*, std::set<Record*> > &Aliases,
+ RegisterInfoEmitter &RIE) {
+ if (R == S) {
+ cerr << "Error: recursive sub-register relationship between"
+ << " register " << RIE.getQualifiedName(R)
+ << " and its sub-registers?\n";
+ abort();
+ }
+
+ if (!SubRegs[R].insert(S).second)
+ return;
+ addSuperReg(S, R, SubRegs, SuperRegs, Aliases, RIE);
+ Aliases[R].insert(S);
+ Aliases[S].insert(R);
+ if (SubRegs.count(S))
+ for (std::set<Record*>::iterator I = SubRegs[S].begin(),
+ E = SubRegs[S].end(); I != E; ++I)
+ addSubSuperReg(R, *I, SubRegs, SuperRegs, Aliases, RIE);
+}
+
+// RegisterInfoEmitter::run - Main register file description emitter.
+//
+void RegisterInfoEmitter::run(std::ostream &OS) {
+ CodeGenTarget Target;
+ EmitSourceFileHeader("Register Information Source Fragment", OS);
+
+ OS << "namespace llvm {\n\n";
+
+ // 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.
+ //
+ const std::vector<CodeGenRegisterClass> &RegisterClasses =
+ Target.getRegisterClasses();
+
+ // Loop over all of the register classes... emitting each one.
+ OS << "namespace { // Register classes...\n";
+
+ // RegClassesBelongedTo - Keep track of which register classes each reg
+ // belongs to.
+ std::multimap<Record*, const CodeGenRegisterClass*> RegClassesBelongedTo;
+
+ // Emit the register enum value arrays for each RegisterClass
+ for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) {
+ const CodeGenRegisterClass &RC = RegisterClasses[rc];
+
+ // Give the register class a legal C name if it's anonymous.
+ std::string Name = RC.TheDef->getName();
+
+ // Emit the register list now.
+ OS << " // " << Name << " Register Class...\n"
+ << " static const unsigned " << Name
+ << "[] = {\n ";
+ for (unsigned i = 0, e = RC.Elements.size(); i != e; ++i) {
+ Record *Reg = RC.Elements[i];
+ OS << getQualifiedName(Reg) << ", ";
+
+ // Keep track of which regclasses this register is in.
+ RegClassesBelongedTo.insert(std::make_pair(Reg, &RC));
+ }
+ OS << "\n };\n\n";
+ }
+
+ // Emit the ValueType arrays for each RegisterClass
+ for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) {
+ const CodeGenRegisterClass &RC = RegisterClasses[rc];
+
+ // Give the register class a legal C name if it's anonymous.
+ std::string Name = RC.TheDef->getName() + "VTs";
+
+ // Emit the register list now.
+ OS << " // " << Name
+ << " Register Class Value Types...\n"
+ << " static const MVT::ValueType " << Name
+ << "[] = {\n ";
+ for (unsigned i = 0, e = RC.VTs.size(); i != e; ++i)
+ OS << getName(RC.VTs[i]) << ", ";
+ OS << "MVT::Other\n };\n\n";
+ }
+ OS << "} // end anonymous namespace\n\n";
+
+ // Now that all of the structs have been emitted, emit the instances.
+ if (!RegisterClasses.empty()) {
+ OS << "namespace " << RegisterClasses[0].Namespace
+ << " { // Register class instances\n";
+ for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i)
+ OS << " " << RegisterClasses[i].getName() << "Class\t"
+ << RegisterClasses[i].getName() << "RegClass;\n";
+
+ std::map<unsigned, std::set<unsigned> > SuperClassMap;
+ OS << "\n";
+
+
+ // Emit the sub-register classes for each RegisterClass
+ for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) {
+ const CodeGenRegisterClass &RC = RegisterClasses[rc];
+
+ // Give the register class a legal C name if it's anonymous.
+ std::string Name = RC.TheDef->getName();
+
+ OS << " // " << Name
+ << " Sub-register Classess...\n"
+ << " static const TargetRegisterClass* const "
+ << Name << "SubRegClasses [] = {\n ";
+
+ bool Empty = true;
+
+ for (unsigned subrc = 0, e2 = RC.SubRegClasses.size();
+ subrc != e2; ++subrc) {
+ unsigned rc2 = 0, e2 = RegisterClasses.size();
+ for (; rc2 != e2; ++rc2) {
+ const CodeGenRegisterClass &RC2 = RegisterClasses[rc2];
+ if (RC.SubRegClasses[subrc]->getName() == RC2.getName()) {
+ if (!Empty) OS << ", ";
+ OS << "&" << getQualifiedName(RC2.TheDef) << "RegClass";
+ Empty = false;
+ break;
+ }
+ }
+ if (rc2 == e2)
+ throw "Register Class member '" +
+ RC.SubRegClasses[subrc]->getName() +
+ "' is not a valid RegisterClass!";
+ }
+
+ OS << (!Empty ? ", " : "") << "NULL";
+ OS << "\n };\n\n";
+ }
+
+ // Emit the sub-classes array for each RegisterClass
+ for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) {
+ const CodeGenRegisterClass &RC = RegisterClasses[rc];
+
+ // Give the register class a legal C name if it's anonymous.
+ std::string Name = RC.TheDef->getName();
+
+ std::set<Record*> RegSet;
+ for (unsigned i = 0, e = RC.Elements.size(); i != e; ++i) {
+ Record *Reg = RC.Elements[i];
+ RegSet.insert(Reg);
+ }
+
+ OS << " // " << Name
+ << " Register Class sub-classes...\n"
+ << " static const TargetRegisterClass* const "
+ << Name << "Subclasses [] = {\n ";
+
+ bool Empty = true;
+ for (unsigned rc2 = 0, e2 = RegisterClasses.size(); rc2 != e2; ++rc2) {
+ const CodeGenRegisterClass &RC2 = RegisterClasses[rc2];
+ if (rc == rc2 || RC2.Elements.size() > RC.Elements.size() ||
+ RC.SpillSize != RC2.SpillSize || !isSubRegisterClass(RC2, RegSet))
+ continue;
+
+ if (!Empty) OS << ", ";
+ OS << "&" << getQualifiedName(RC2.TheDef) << "RegClass";
+ Empty = false;
+
+ std::map<unsigned, std::set<unsigned> >::iterator SCMI =
+ SuperClassMap.find(rc2);
+ if (SCMI == SuperClassMap.end()) {
+ SuperClassMap.insert(std::make_pair(rc2, std::set<unsigned>()));
+ SCMI = SuperClassMap.find(rc2);
+ }
+ SCMI->second.insert(rc);
+ }
+
+ OS << (!Empty ? ", " : "") << "NULL";
+ OS << "\n };\n\n";
+ }
+
+ for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) {
+ const CodeGenRegisterClass &RC = RegisterClasses[rc];
+
+ // Give the register class a legal C name if it's anonymous.
+ std::string Name = RC.TheDef->getName();
+
+ OS << " // " << Name
+ << " Register Class super-classes...\n"
+ << " static const TargetRegisterClass* const "
+ << Name << "Superclasses [] = {\n ";
+
+ bool Empty = true;
+ std::map<unsigned, std::set<unsigned> >::iterator I =
+ SuperClassMap.find(rc);
+ if (I != SuperClassMap.end()) {
+ for (std::set<unsigned>::iterator II = I->second.begin(),
+ EE = I->second.end(); II != EE; ++II) {
+ const CodeGenRegisterClass &RC2 = RegisterClasses[*II];
+ if (!Empty) OS << ", ";
+ OS << "&" << getQualifiedName(RC2.TheDef) << "RegClass";
+ Empty = false;
+ }
+ }
+
+ OS << (!Empty ? ", " : "") << "NULL";
+ OS << "\n };\n\n";
+ }
+
+
+ for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i) {
+ const CodeGenRegisterClass &RC = RegisterClasses[i];
+ OS << RC.MethodBodies << "\n";
+ OS << RC.getName() << "Class::" << RC.getName()
+ << "Class() : TargetRegisterClass("
+ << RC.getName() + "RegClassID" << ", "
+ << RC.getName() + "VTs" << ", "
+ << RC.getName() + "Subclasses" << ", "
+ << RC.getName() + "Superclasses" << ", "
+ << RC.getName() + "SubRegClasses" << ", "
+ << RC.SpillSize/8 << ", "
+ << RC.SpillAlignment/8 << ", " << RC.getName() << ", "
+ << RC.getName() << " + " << RC.Elements.size() << ") {}\n";
+ }
+
+ OS << "}\n";
+ }
+
+ OS << "\nnamespace {\n";
+ OS << " const TargetRegisterClass* const RegisterClasses[] = {\n";
+ for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i)
+ OS << " &" << getQualifiedName(RegisterClasses[i].TheDef)
+ << "RegClass,\n";
+ OS << " };\n";
+
+ // Emit register sub-registers / super-registers, aliases...
+ std::map<Record*, std::set<Record*> > RegisterImmSubRegs;
+ std::map<Record*, std::set<Record*> > RegisterSubRegs;
+ std::map<Record*, std::set<Record*> > RegisterSuperRegs;
+ std::map<Record*, std::set<Record*> > RegisterAliases;
+ std::map<Record*, std::vector<std::pair<int, Record*> > > SubRegVectors;
+ const std::vector<CodeGenRegister> &Regs = Target.getRegisters();
+
+ for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
+ Record *R = Regs[i].TheDef;
+ std::vector<Record*> LI = Regs[i].TheDef->getValueAsListOfDefs("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.size(); j != e; ++j) {
+ Record *Reg = LI[j];
+ if (RegisterAliases[R].count(Reg))
+ cerr << "Warning: register alias between " << getQualifiedName(R)
+ << " and " << getQualifiedName(Reg)
+ << " specified multiple times!\n";
+ RegisterAliases[R].insert(Reg);
+
+ if (RegisterAliases[Reg].count(R))
+ cerr << "Warning: register alias between " << getQualifiedName(R)
+ << " and " << getQualifiedName(Reg)
+ << " specified multiple times!\n";
+ RegisterAliases[Reg].insert(R);
+ }
+ }
+
+ // Process sub-register sets.
+ for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
+ Record *R = Regs[i].TheDef;
+ std::vector<Record*> LI = Regs[i].TheDef->getValueAsListOfDefs("SubRegs");
+ // Process sub-register set and add aliases information.
+ for (unsigned j = 0, e = LI.size(); j != e; ++j) {
+ Record *SubReg = LI[j];
+ if (RegisterSubRegs[R].count(SubReg))
+ cerr << "Warning: register " << getQualifiedName(SubReg)
+ << " specified as a sub-register of " << getQualifiedName(R)
+ << " multiple times!\n";
+ RegisterImmSubRegs[R].insert(SubReg);
+ addSubSuperReg(R, SubReg, RegisterSubRegs, RegisterSuperRegs,
+ RegisterAliases, *this);
+ }
+ }
+
+ if (!RegisterAliases.empty())
+ OS << "\n\n // Register Alias Sets...\n";
+
+ // Emit the empty alias list
+ OS << " const unsigned Empty_AliasSet[] = { 0 };\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";
+ }
+
+ if (!RegisterSubRegs.empty())
+ OS << "\n\n // Register Sub-registers Sets...\n";
+
+ // Emit the empty sub-registers list
+ OS << " const unsigned Empty_SubRegsSet[] = { 0 };\n";
+ // Loop over all of the registers which have sub-registers, emitting the
+ // sub-registers list to memory.
+ for (std::map<Record*, std::set<Record*> >::iterator
+ I = RegisterSubRegs.begin(), E = RegisterSubRegs.end(); I != E; ++I) {
+ OS << " const unsigned " << I->first->getName() << "_SubRegsSet[] = { ";
+ for (std::set<Record*>::iterator ASI = I->second.begin(),
+ E = I->second.end(); ASI != E; ++ASI)
+ OS << getQualifiedName(*ASI) << ", ";
+ OS << "0 };\n";
+ }
+
+ if (!RegisterImmSubRegs.empty())
+ OS << "\n\n // Register Immediate Sub-registers Sets...\n";
+
+ // Loop over all of the registers which have sub-registers, emitting the
+ // sub-registers list to memory.
+ for (std::map<Record*, std::set<Record*> >::iterator
+ I = RegisterImmSubRegs.begin(), E = RegisterImmSubRegs.end();
+ I != E; ++I) {
+ OS << " const unsigned " << I->first->getName() << "_ImmSubRegsSet[] = { ";
+ for (std::set<Record*>::iterator ASI = I->second.begin(),
+ E = I->second.end(); ASI != E; ++ASI)
+ OS << getQualifiedName(*ASI) << ", ";
+ OS << "0 };\n";
+ }
+
+ if (!RegisterSuperRegs.empty())
+ OS << "\n\n // Register Super-registers Sets...\n";
+
+ // Emit the empty super-registers list
+ OS << " const unsigned Empty_SuperRegsSet[] = { 0 };\n";
+ // Loop over all of the registers which have super-registers, emitting the
+ // super-registers list to memory.
+ for (std::map<Record*, std::set<Record*> >::iterator
+ I = RegisterSuperRegs.begin(), E = RegisterSuperRegs.end(); I != E; ++I) {
+ OS << " const unsigned " << I->first->getName() << "_SuperRegsSet[] = { ";
+ 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 TargetRegisterDesc RegisterDescriptors[] = { // Descriptors\n";
+ OS << " { \"NOREG\",\t0,\t0,\t0,\t0 },\n";
+
+ // Now that register alias and sub-registers sets have been emitted, emit the
+ // register descriptors now.
+ const std::vector<CodeGenRegister> &Registers = Target.getRegisters();
+ for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
+ const CodeGenRegister &Reg = Registers[i];
+ OS << " { \"";
+ if (!Reg.TheDef->getValueAsString("Name").empty())
+ OS << Reg.TheDef->getValueAsString("Name");
+ else
+ OS << Reg.getName();
+ OS << "\",\t";
+ if (RegisterAliases.count(Reg.TheDef))
+ OS << Reg.getName() << "_AliasSet,\t";
+ else
+ OS << "Empty_AliasSet,\t";
+ if (RegisterSubRegs.count(Reg.TheDef))
+ OS << Reg.getName() << "_SubRegsSet,\t";
+ else
+ OS << "Empty_SubRegsSet,\t";
+ if (RegisterImmSubRegs.count(Reg.TheDef))
+ OS << Reg.getName() << "_ImmSubRegsSet,\t";
+ else
+ OS << "Empty_SubRegsSet,\t";
+ if (RegisterSuperRegs.count(Reg.TheDef))
+ OS << Reg.getName() << "_SuperRegsSet },\n";
+ else
+ OS << "Empty_SuperRegsSet },\n";
+ }
+ OS << " };\n"; // End of register descriptors...
+ OS << "}\n\n"; // End of anonymous namespace...
+
+ std::string ClassName = Target.getName() + "GenRegisterInfo";
+
+ // Calculate the mapping of subregister+index pairs to physical registers.
+ std::vector<Record*> SubRegs = Records.getAllDerivedDefinitions("SubRegSet");
+ for (unsigned i = 0, e = SubRegs.size(); i != e; ++i) {
+ int subRegIndex = SubRegs[i]->getValueAsInt("index");
+ std::vector<Record*> From = SubRegs[i]->getValueAsListOfDefs("From");
+ std::vector<Record*> To = SubRegs[i]->getValueAsListOfDefs("To");
+
+ if (From.size() != To.size()) {
+ cerr << "Error: register list and sub-register list not of equal length"
+ << " in SubRegSet\n";
+ exit(1);
+ }
+
+ // For each entry in from/to vectors, insert the to register at index
+ for (unsigned ii = 0, ee = From.size(); ii != ee; ++ii)
+ SubRegVectors[From[ii]].push_back(std::make_pair(subRegIndex, To[ii]));
+ }
+
+ // Emit the subregister + index mapping function based on the information
+ // calculated above.
+ OS << "unsigned " << ClassName
+ << "::getSubReg(unsigned RegNo, unsigned Index) const {\n"
+ << " switch (RegNo) {\n"
+ << " default: abort(); break;\n";
+ for (std::map<Record*, std::vector<std::pair<int, Record*> > >::iterator
+ I = SubRegVectors.begin(), E = SubRegVectors.end(); I != E; ++I) {
+ OS << " case " << getQualifiedName(I->first) << ":\n";
+ OS << " switch (Index) {\n";
+ OS << " default: abort(); break;\n";
+ for (unsigned i = 0, e = I->second.size(); i != e; ++i)
+ OS << " case " << (I->second)[i].first << ": return "
+ << getQualifiedName((I->second)[i].second) << ";\n";
+ OS << " }; break;\n";
+ }
+ OS << " };\n";
+ OS << " return 0;\n";
+ OS << "}\n\n";
+
+ // Emit the constructor of the class...
+ OS << ClassName << "::" << ClassName
+ << "(int CallFrameSetupOpcode, int CallFrameDestroyOpcode)\n"
+ << " : MRegisterInfo(RegisterDescriptors, " << Registers.size()+1
+ << ", RegisterClasses, RegisterClasses+" << RegisterClasses.size() <<",\n "
+ << " CallFrameSetupOpcode, CallFrameDestroyOpcode) {}\n\n";
+
+ // Emit information about the dwarf register numbers.
+ OS << "int " << ClassName << "::getDwarfRegNum(unsigned RegNum) const {\n";
+ OS << " static const int DwarfRegNums[] = { -1, // NoRegister";
+ for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
+ if (!(i % 16)) OS << "\n ";
+ const CodeGenRegister &Reg = Registers[i];
+ int DwarfRegNum = Reg.TheDef->getValueAsInt("DwarfNumber");
+ OS << DwarfRegNum;
+ if ((i + 1) != e) OS << ", ";
+ }
+ OS << "\n };\n";
+ OS << " assert(RegNum < (sizeof(DwarfRegNums)/sizeof(int)) &&\n";
+ OS << " \"RegNum exceeds number of registers\");\n";
+ OS << " return DwarfRegNums[RegNum];\n";
+ OS << "}\n\n";
+
+ OS << "} // End llvm namespace \n";
+}
diff --git a/utils/TableGen/RegisterInfoEmitter.h b/utils/TableGen/RegisterInfoEmitter.h
new file mode 100644
index 0000000000..06e2e5cf5a
--- /dev/null
+++ b/utils/TableGen/RegisterInfoEmitter.h
@@ -0,0 +1,40 @@
+//===- RegisterInfoEmitter.h - Generate a Register File Desc. ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This 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"
+
+namespace llvm {
+
+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);
+};
+
+} // End llvm namespace
+
+#endif
diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp
new file mode 100644
index 0000000000..fc913e69e1
--- /dev/null
+++ b/utils/TableGen/SubtargetEmitter.cpp
@@ -0,0 +1,523 @@
+//===- SubtargetEmitter.cpp - Generate subtarget enumerations -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by James M. Laskey and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend emits subtarget enumerations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SubtargetEmitter.h"
+#include "CodeGenTarget.h"
+#include "Record.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Debug.h"
+#include <algorithm>
+using namespace llvm;
+
+//
+// Record sort by name function.
+//
+struct LessRecord {
+ bool operator()(const Record *Rec1, const Record *Rec2) const {
+ return Rec1->getName() < Rec2->getName();
+ }
+};
+
+//
+// Record sort by field "Name" function.
+//
+struct LessRecordFieldName {
+ bool operator()(const Record *Rec1, const Record *Rec2) const {
+ return Rec1->getValueAsString("Name") < Rec2->getValueAsString("Name");
+ }
+};
+
+//
+// Enumeration - Emit the specified class as an enumeration.
+//
+void SubtargetEmitter::Enumeration(std::ostream &OS,
+ const char *ClassName,
+ bool isBits) {
+ // Get all records of class and sort
+ std::vector<Record*> DefList = Records.getAllDerivedDefinitions(ClassName);
+ std::sort(DefList.begin(), DefList.end(), LessRecord());
+
+ // Open enumeration
+ OS << "enum {\n";
+
+ // For each record
+ for (unsigned i = 0, N = DefList.size(); i < N;) {
+ // Next record
+ Record *Def = DefList[i];
+
+ // Get and emit name
+ OS << " " << Def->getName();
+
+ // If bit flags then emit expression (1 << i)
+ if (isBits) OS << " = " << " 1 << " << i;
+
+ // Depending on 'if more in the list' emit comma
+ if (++i < N) OS << ",";
+
+ OS << "\n";
+ }
+
+ // Close enumeration
+ OS << "};\n";
+}
+
+//
+// FeatureKeyValues - Emit data of all the subtarget features. Used by the
+// command line.
+//
+void SubtargetEmitter::FeatureKeyValues(std::ostream &OS) {
+ // Gather and sort all the features
+ std::vector<Record*> FeatureList =
+ Records.getAllDerivedDefinitions("SubtargetFeature");
+ std::sort(FeatureList.begin(), FeatureList.end(), LessRecord());
+
+ // Begin feature table
+ OS << "// Sorted (by key) array of values for CPU features.\n"
+ << "static llvm::SubtargetFeatureKV FeatureKV[] = {\n";
+
+ // For each feature
+ for (unsigned i = 0, N = FeatureList.size(); i < N; ++i) {
+ // Next feature
+ Record *Feature = FeatureList[i];
+
+ const std::string &Name = Feature->getName();
+ const std::string &CommandLineName = Feature->getValueAsString("Name");
+ const std::string &Desc = Feature->getValueAsString("Desc");
+
+ if (CommandLineName.empty()) continue;
+
+ // Emit as { "feature", "decription", feactureEnum, i1 | i2 | ... | in }
+ OS << " { "
+ << "\"" << CommandLineName << "\", "
+ << "\"" << Desc << "\", "
+ << Name << ", ";
+
+ const std::vector<Record*> &ImpliesList =
+ Feature->getValueAsListOfDefs("Implies");
+
+ if (ImpliesList.empty()) {
+ OS << "0";
+ } else {
+ for (unsigned j = 0, M = ImpliesList.size(); j < M;) {
+ OS << ImpliesList[j]->getName();
+ if (++j < M) OS << " | ";
+ }
+ }
+
+ OS << " }";
+
+ // Depending on 'if more in the list' emit comma
+ if ((i + 1) < N) OS << ",";
+
+ OS << "\n";
+ }
+
+ // End feature table
+ OS << "};\n";
+
+ // Emit size of table
+ OS<<"\nenum {\n";
+ OS<<" FeatureKVSize = sizeof(FeatureKV)/sizeof(llvm::SubtargetFeatureKV)\n";
+ OS<<"};\n";
+}
+
+//
+// CPUKeyValues - Emit data of all the subtarget processors. Used by command
+// line.
+//
+void SubtargetEmitter::CPUKeyValues(std::ostream &OS) {
+ // Gather and sort processor information
+ std::vector<Record*> ProcessorList =
+ Records.getAllDerivedDefinitions("Processor");
+ std::sort(ProcessorList.begin(), ProcessorList.end(), LessRecordFieldName());
+
+ // Begin processor table
+ OS << "// Sorted (by key) array of values for CPU subtype.\n"
+ << "static const llvm::SubtargetFeatureKV SubTypeKV[] = {\n";
+
+ // For each processor
+ for (unsigned i = 0, N = ProcessorList.size(); i < N;) {
+ // Next processor
+ Record *Processor = ProcessorList[i];
+
+ const std::string &Name = Processor->getValueAsString("Name");
+ const std::vector<Record*> &FeatureList =
+ Processor->getValueAsListOfDefs("Features");
+
+ // Emit as { "cpu", "description", f1 | f2 | ... fn },
+ OS << " { "
+ << "\"" << Name << "\", "
+ << "\"Select the " << Name << " processor\", ";
+
+ if (FeatureList.empty()) {
+ OS << "0";
+ } else {
+ for (unsigned j = 0, M = FeatureList.size(); j < M;) {
+ OS << FeatureList[j]->getName();
+ if (++j < M) OS << " | ";
+ }
+ }
+
+ // The "0" is for the "implies" section of this data structure.
+ OS << ", 0 }";
+
+ // Depending on 'if more in the list' emit comma
+ if (++i < N) OS << ",";
+
+ OS << "\n";
+ }
+
+ // End processor table
+ OS << "};\n";
+
+ // Emit size of table
+ OS<<"\nenum {\n";
+ OS<<" SubTypeKVSize = sizeof(SubTypeKV)/sizeof(llvm::SubtargetFeatureKV)\n";
+ OS<<"};\n";
+}
+
+//
+// CollectAllItinClasses - Gathers and enumerates all the itinerary classes.
+// Returns itinerary class count.
+//
+unsigned SubtargetEmitter::CollectAllItinClasses(std::ostream &OS,
+ std::map<std::string, unsigned> &ItinClassesMap) {
+ // Gather and sort all itinerary classes
+ std::vector<Record*> ItinClassList =
+ Records.getAllDerivedDefinitions("InstrItinClass");
+ std::sort(ItinClassList.begin(), ItinClassList.end(), LessRecord());
+
+ // For each itinerary class
+ unsigned N = ItinClassList.size();
+ for (unsigned i = 0; i < N; i++) {
+ // Next itinerary class
+ const Record *ItinClass = ItinClassList[i];
+ // Get name of itinerary class
+ // Assign itinerary class a unique number
+ ItinClassesMap[ItinClass->getName()] = i;
+ }
+
+ // Emit size of table
+ OS<<"\nenum {\n";
+ OS<<" ItinClassesSize = " << N << "\n";
+ OS<<"};\n";
+
+ // Return itinerary class count
+ return N;
+}
+
+//
+// FormItineraryString - Compose a string containing the data initialization
+// for the specified itinerary. N is the number of stages.
+//
+void SubtargetEmitter::FormItineraryString(Record *ItinData,
+ std::string &ItinString,
+ unsigned &NStages) {
+ // Get states list
+ const std::vector<Record*> &StageList =
+ ItinData->getValueAsListOfDefs("Stages");
+
+ // For each stage
+ unsigned N = NStages = StageList.size();
+ for (unsigned i = 0; i < N;) {
+ // Next stage
+ const Record *Stage = StageList[i];
+
+ // Form string as ,{ cycles, u1 | u2 | ... | un }
+ int Cycles = Stage->getValueAsInt("Cycles");
+ ItinString += " { " + itostr(Cycles) + ", ";
+
+ // Get unit list
+ const std::vector<Record*> &UnitList = Stage->getValueAsListOfDefs("Units");
+
+ // For each unit
+ for (unsigned j = 0, M = UnitList.size(); j < M;) {
+ // Add name and bitwise or
+ ItinString += UnitList[j]->getName();
+ if (++j < M) ItinString += " | ";
+ }
+
+ // Close off stage
+ ItinString += " }";
+ if (++i < N) ItinString += ", ";
+ }
+}
+
+//
+// EmitStageData - Generate unique itinerary stages. Record itineraries for
+// processors.
+//
+void SubtargetEmitter::EmitStageData(std::ostream &OS,
+ unsigned NItinClasses,
+ std::map<std::string, unsigned> &ItinClassesMap,
+ std::vector<std::vector<InstrItinerary> > &ProcList) {
+ // Gather processor iteraries
+ std::vector<Record*> ProcItinList =
+ Records.getAllDerivedDefinitions("ProcessorItineraries");
+
+ // If just no itinerary then don't bother
+ if (ProcItinList.size() < 2) return;
+
+ // Begin stages table
+ OS << "static llvm::InstrStage Stages[] = {\n"
+ " { 0, 0 }, // No itinerary\n";
+
+ unsigned ItinEnum = 1;
+ std::map<std::string, unsigned> ItinMap;
+ for (unsigned i = 0, N = ProcItinList.size(); i < N; i++) {
+ // Next record
+ Record *Proc = ProcItinList[i];
+
+ // Get processor itinerary name
+ const std::string &Name = Proc->getName();
+
+ // Skip default
+ if (Name == "NoItineraries") continue;
+
+ // Create and expand processor itinerary to cover all itinerary classes
+ std::vector<InstrItinerary> ItinList;
+ ItinList.resize(NItinClasses);
+
+ // Get itinerary data list
+ std::vector<Record*> ItinDataList = Proc->getValueAsListOfDefs("IID");
+
+ // For each itinerary data
+ for (unsigned j = 0, M = ItinDataList.size(); j < M; j++) {
+ // Next itinerary data
+ Record *ItinData = ItinDataList[j];
+
+ // Get string and stage count
+ std::string ItinString;
+ unsigned NStages;
+ FormItineraryString(ItinData, ItinString, NStages);
+
+ // Check to see if it already exists
+ unsigned Find = ItinMap[ItinString];
+
+ // If new itinerary
+ if (Find == 0) {
+ // Emit as { cycles, u1 | u2 | ... | un }, // index
+ OS << ItinString << ", // " << ItinEnum << "\n";
+ // Record Itin class number
+ ItinMap[ItinString] = Find = ItinEnum++;
+ }
+
+ // Set up itinerary as location and location + stage count
+ InstrItinerary Intinerary = { Find, Find + NStages };
+
+ // Locate where to inject into processor itinerary table
+ const std::string &Name = ItinData->getValueAsDef("TheClass")->getName();
+ Find = ItinClassesMap[Name];
+
+ // Inject - empty slots will be 0, 0
+ ItinList[Find] = Intinerary;
+ }
+
+ // Add process itinerary to list
+ ProcList.push_back(ItinList);
+ }
+
+ // Closing stage
+ OS << " { 0, 0 } // End itinerary\n";
+ // End stages table
+ OS << "};\n";
+
+ // Emit size of table
+ OS<<"\nenum {\n";
+ OS<<" StagesSize = sizeof(Stages)/sizeof(llvm::InstrStage)\n";
+ OS<<"};\n";
+}
+
+//
+// EmitProcessorData - Generate data for processor itineraries.
+//
+void SubtargetEmitter::EmitProcessorData(std::ostream &OS,
+ std::vector<std::vector<InstrItinerary> > &ProcList) {
+ // Get an iterator for processor itinerary stages
+ std::vector<std::vector<InstrItinerary> >::iterator
+ ProcListIter = ProcList.begin();
+
+ // For each processor itinerary
+ std::vector<Record*> Itins =
+ Records.getAllDerivedDefinitions("ProcessorItineraries");
+ for (unsigned i = 0, N = Itins.size(); i < N; i++) {
+ // Next record
+ Record *Itin = Itins[i];
+
+ // Get processor itinerary name
+ const std::string &Name = Itin->getName();
+
+ // Skip default
+ if (Name == "NoItineraries") continue;
+
+ // Begin processor itinerary table
+ OS << "\n";
+ OS << "static llvm::InstrItinerary " << Name << "[] = {\n";
+
+ // For each itinerary class
+ std::vector<InstrItinerary> &ItinList = *ProcListIter++;
+ for (unsigned j = 0, M = ItinList.size(); j < M;) {
+ InstrItinerary &Intinerary = ItinList[j];
+
+ // Emit in the form of { first, last } // index
+ if (Intinerary.First == 0) {
+ OS << " { 0, 0 }";
+ } else {
+ OS << " { " << Intinerary.First << ", " << Intinerary.Last << " }";
+ }
+
+ // If more in list add comma
+ if (++j < M) OS << ",";
+
+ OS << " // " << (j - 1) << "\n";
+ }
+
+ // End processor itinerary table
+ OS << "};\n";
+ }
+}
+
+//
+// EmitProcessorLookup - generate cpu name to itinerary lookup table.
+//
+void SubtargetEmitter::EmitProcessorLookup(std::ostream &OS) {
+ // Gather and sort processor information
+ std::vector<Record*> ProcessorList =
+ Records.getAllDerivedDefinitions("Processor");
+ std::sort(ProcessorList.begin(), ProcessorList.end(), LessRecordFieldName());
+
+ // Begin processor table
+ OS << "\n";
+ OS << "// Sorted (by key) array of itineraries for CPU subtype.\n"
+ << "static const llvm::SubtargetInfoKV ProcItinKV[] = {\n";
+
+ // For each processor
+ for (unsigned i = 0, N = ProcessorList.size(); i < N;) {
+ // Next processor
+ Record *Processor = ProcessorList[i];
+
+ const std::string &Name = Processor->getValueAsString("Name");
+ const std::string &ProcItin =
+ Processor->getValueAsDef("ProcItin")->getName();
+
+ // Emit as { "cpu", procinit },
+ OS << " { "
+ << "\"" << Name << "\", "
+ << "(void *)&" << ProcItin;
+
+ OS << " }";
+
+ // Depending on ''if more in the list'' emit comma
+ if (++i < N) OS << ",";
+
+ OS << "\n";
+ }
+
+ // End processor table
+ OS << "};\n";
+
+ // Emit size of table
+ OS<<"\nenum {\n";
+ OS<<" ProcItinKVSize = sizeof(ProcItinKV)/"
+ "sizeof(llvm::SubtargetInfoKV)\n";
+ OS<<"};\n";
+}
+
+//
+// EmitData - Emits all stages and itineries, folding common patterns.
+//
+void SubtargetEmitter::EmitData(std::ostream &OS) {
+ std::map<std::string, unsigned> ItinClassesMap;
+ std::vector<std::vector<InstrItinerary> > ProcList;
+
+ // Enumerate all the itinerary classes
+ unsigned NItinClasses = CollectAllItinClasses(OS, ItinClassesMap);
+ // Make sure the rest is worth the effort
+ HasItineraries = NItinClasses != 1; // Ignore NoItinerary.
+
+ if (HasItineraries) {
+ // Emit the stage data
+ EmitStageData(OS, NItinClasses, ItinClassesMap, ProcList);
+ // Emit the processor itinerary data
+ EmitProcessorData(OS, ProcList);
+ // Emit the processor lookup data
+ EmitProcessorLookup(OS);
+ }
+}
+
+//
+// ParseFeaturesFunction - Produces a subtarget specific function for parsing
+// the subtarget features string.
+//
+void SubtargetEmitter::ParseFeaturesFunction(std::ostream &OS) {
+ std::vector<Record*> Features =
+ Records.getAllDerivedDefinitions("SubtargetFeature");
+ std::sort(Features.begin(), Features.end(), LessRecord());
+
+ OS << "// ParseSubtargetFeatures - Parses features string setting specified\n"
+ << "// subtarget options.\n"
+ << "void llvm::";
+ OS << Target;
+ OS << "Subtarget::ParseSubtargetFeatures(const std::string &FS,\n"
+ << " const std::string &CPU) {\n"
+ << " SubtargetFeatures Features(FS);\n"
+ << " Features.setCPUIfNone(CPU);\n"
+ << " uint32_t Bits = Features.getBits(SubTypeKV, SubTypeKVSize,\n"
+ << " FeatureKV, FeatureKVSize);\n";
+
+ for (unsigned i = 0; i < Features.size(); i++) {
+ // Next record
+ Record *R = Features[i];
+ const std::string &Instance = R->getName();
+ const std::string &Value = R->getValueAsString("Value");
+ const std::string &Attribute = R->getValueAsString("Attribute");
+
+ OS << " if ((Bits & " << Instance << ") != 0) "
+ << Attribute << " = " << Value << ";\n";
+ }
+
+ if (HasItineraries) {
+ OS << "\n"
+ << " InstrItinerary *Itinerary = (InstrItinerary *)"
+ << "Features.getInfo(ProcItinKV, ProcItinKVSize);\n"
+ << " InstrItins = InstrItineraryData(Stages, Itinerary);\n";
+ }
+
+ OS << "}\n";
+}
+
+//
+// SubtargetEmitter::run - Main subtarget enumeration emitter.
+//
+void SubtargetEmitter::run(std::ostream &OS) {
+ Target = CodeGenTarget().getName();
+
+ EmitSourceFileHeader("Subtarget Enumeration Source Fragment", OS);
+
+ OS << "#include \"llvm/Target/SubtargetFeature.h\"\n";
+ OS << "#include \"llvm/Target/TargetInstrItineraries.h\"\n\n";
+
+ Enumeration(OS, "FuncUnit", true);
+ OS<<"\n";
+// Enumeration(OS, "InstrItinClass", false);
+// OS<<"\n";
+ Enumeration(OS, "SubtargetFeature", true);
+ OS<<"\n";
+ FeatureKeyValues(OS);
+ OS<<"\n";
+ CPUKeyValues(OS);
+ OS<<"\n";
+ EmitData(OS);
+ OS<<"\n";
+ ParseFeaturesFunction(OS);
+}
diff --git a/utils/TableGen/SubtargetEmitter.h b/utils/TableGen/SubtargetEmitter.h
new file mode 100644
index 0000000000..69feeb2d0f
--- /dev/null
+++ b/utils/TableGen/SubtargetEmitter.h
@@ -0,0 +1,62 @@
+//===- SubtargetEmitter.h - Generate subtarget enumerations -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by James M. Laskey and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend emits subtarget enumerations.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SUBTARGET_EMITTER_H
+#define SUBTARGET_EMITTER_H
+
+#include "TableGenBackend.h"
+#include "llvm/Target/TargetInstrItineraries.h"
+#include <vector>
+#include <map>
+#include <string>
+
+
+namespace llvm {
+
+class SubtargetEmitter : public TableGenBackend {
+
+ RecordKeeper &Records;
+ std::string Target;
+ bool HasItineraries;
+
+ void Enumeration(std::ostream &OS, const char *ClassName, bool isBits);
+ void FeatureKeyValues(std::ostream &OS);
+ void CPUKeyValues(std::ostream &OS);
+ unsigned CollectAllItinClasses(std::ostream &OS,
+ std::map<std::string, unsigned> &ItinClassesMap);
+ void FormItineraryString(Record *ItinData, std::string &ItinString,
+ unsigned &NStages);
+ void EmitStageData(std::ostream &OS, unsigned NItinClasses,
+ std::map<std::string, unsigned> &ItinClassesMap,
+ std::vector<std::vector<InstrItinerary> > &ProcList);
+ void EmitProcessorData(std::ostream &OS,
+ std::vector<std::vector<InstrItinerary> > &ProcList);
+ void EmitProcessorLookup(std::ostream &OS);
+ void EmitData(std::ostream &OS);
+ void ParseFeaturesFunction(std::ostream &OS);
+
+public:
+ SubtargetEmitter(RecordKeeper &R) : Records(R), HasItineraries(false) {}
+
+ // run - Output the subtarget enumerations, returning true on failure.
+ void run(std::ostream &o);
+
+};
+
+
+} // End llvm namespace
+
+#endif
+
+
+
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
new file mode 100644
index 0000000000..d3d241e6c7
--- /dev/null
+++ b/utils/TableGen/TableGen.cpp
@@ -0,0 +1,193 @@
+//===- TableGen.cpp - Top-Level TableGen implementation -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// TableGen is a tool which can be used to build up a description of something,
+// then invoke one or more "tablegen backends" to emit information about the
+// 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 "llvm/Support/CommandLine.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/System/Signals.h"
+#include "llvm/Support/FileUtilities.h"
+#include "CallingConvEmitter.h"
+#include "CodeEmitterGen.h"
+#include "RegisterInfoEmitter.h"
+#include "InstrInfoEmitter.h"
+#include "AsmWriterEmitter.h"
+#include "DAGISelEmitter.h"
+#include "SubtargetEmitter.h"
+#include "IntrinsicEmitter.h"
+#include <algorithm>
+#include <cstdio>
+#include <fstream>
+#include <ios>
+using namespace llvm;
+
+enum ActionType {
+ PrintRecords,
+ GenEmitter,
+ GenRegisterEnums, GenRegister, GenRegisterHeader,
+ GenInstrEnums, GenInstrs, GenAsmWriter,
+ GenCallingConv,
+ GenDAGISel,
+ GenSubtarget,
+ GenIntrinsic,
+ PrintEnums
+};
+
+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(GenCallingConv, "gen-callingconv",
+ "Generate calling convention descriptions"),
+ clEnumValN(GenAsmWriter, "gen-asm-writer",
+ "Generate assembly writer"),
+ clEnumValN(GenDAGISel, "gen-dag-isel",
+ "Generate a DAG instruction selector"),
+ clEnumValN(GenSubtarget, "gen-subtarget",
+ "Generate subtarget enumerations"),
+ clEnumValN(GenIntrinsic, "gen-intrinsic",
+ "Generate intrinsic information"),
+ clEnumValN(PrintEnums, "print-enums",
+ "Print enum values for a class"),
+ clEnumValEnd));
+
+ 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::list<std::string>
+ IncludeDirs("I", cl::desc("Directory of include files"),
+ cl::value_desc("directory"), cl::Prefix);
+}
+
+namespace llvm {
+ void ParseFile(const std::string &Filename,
+ const std::vector<std::string> &IncludeDirs);
+}
+
+RecordKeeper llvm::Records;
+
+int main(int argc, char **argv) {
+ cl::ParseCommandLineOptions(argc, argv);
+ ParseFile(InputFilename, IncludeDirs);
+
+ std::ostream *Out = cout.stream();
+ if (OutputFilename != "-") {
+ Out = new std::ofstream(OutputFilename.c_str());
+
+ if (!Out->good()) {
+ cerr << argv[0] << ": error opening " << OutputFilename << "!\n";
+ return 1;
+ }
+
+ // Make sure the file gets removed if *gasp* tablegen crashes...
+ sys::RemoveFileOnSignal(sys::Path(OutputFilename));
+ }
+
+ try {
+ switch (Action) {
+ case PrintRecords:
+ *Out << Records; // No argument, dump all contents
+ 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 GenCallingConv:
+ CallingConvEmitter(Records).run(*Out);
+ break;
+ case GenAsmWriter:
+ AsmWriterEmitter(Records).run(*Out);
+ break;
+
+ case GenDAGISel:
+ DAGISelEmitter(Records).run(*Out);
+ break;
+ case GenSubtarget:
+ SubtargetEmitter(Records).run(*Out);
+ break;
+ case GenIntrinsic:
+ IntrinsicEmitter(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]->getName() << ", ";
+ *Out << "\n";
+ break;
+ }
+ default:
+ assert(1 && "Invalid Action");
+ return 1;
+ }
+ } catch (const std::string &Error) {
+ cerr << argv[0] << ": " << Error << "\n";
+ if (Out != cout.stream()) {
+ delete Out; // Close the file
+ std::remove(OutputFilename.c_str()); // Remove the file, it's broken
+ }
+ return 1;
+ } catch (...) {
+ cerr << argv[0] << ": Unknown unexpected exception occurred.\n";
+ if (Out != cout.stream()) {
+ delete Out; // Close the file
+ std::remove(OutputFilename.c_str()); // Remove the file, it's broken
+ }
+ return 2;
+ }
+
+ if (Out != cout.stream()) {
+ delete Out; // Close the file
+ }
+ return 0;
+}
diff --git a/utils/TableGen/TableGenBackend.cpp b/utils/TableGen/TableGenBackend.cpp
new file mode 100644
index 0000000000..d62ba4704f
--- /dev/null
+++ b/utils/TableGen/TableGenBackend.cpp
@@ -0,0 +1,34 @@
+//===- TableGenBackend.cpp - Base class for TableGen Backends ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides useful services for TableGen backends...
+//
+//===----------------------------------------------------------------------===//
+
+#include "TableGenBackend.h"
+#include "Record.h"
+using namespace llvm;
+
+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();
+}
+
diff --git a/utils/TableGen/TableGenBackend.h b/utils/TableGen/TableGenBackend.h
new file mode 100644
index 0000000000..9e9089e22f
--- /dev/null
+++ b/utils/TableGen/TableGenBackend.h
@@ -0,0 +1,46 @@
+//===- TableGenBackend.h - Base class for TableGen Backends -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// 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>
+
+namespace llvm {
+
+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;
+};
+
+} // End llvm namespace
+
+#endif
diff --git a/utils/cgiplotNLT.pl b/utils/cgiplotNLT.pl
new file mode 100755
index 0000000000..0360e4120d
--- /dev/null
+++ b/utils/cgiplotNLT.pl
@@ -0,0 +1,68 @@
+#!/usr/bin/perl
+#takes a test and a program from a dp and produces a gnuplot script
+#use like perl plotNLT.pl password Programs/MultiSource/Benchmarks/ASCI_Purple/SMG2000/smg2000 llc
+
+use CGI;
+use DBI;
+my $q = new CGI;
+
+# database information
+$db="llvmalpha";
+$host="localhost";
+$userid="llvmdbuser";
+$passwd=$q->param('pwd');
+$connectionInfo="dbi:mysql:$db;$host";
+
+# make connection to database
+$dbh = DBI->connect($connectionInfo,$userid,$passwd) or die DBI->errstr;
+
+
+$count = 0;
+while ($q->param('n' . $count))
+ {
+ $count++;
+ }
+
+$| = 1;
+print "Content-type: image/png", "\n\n";
+
+open CMDSTREAM, "|gnuplot";
+#open CMDSTREAM, "|echo";
+
+print CMDSTREAM "set terminal png\n";
+print CMDSTREAM "set output\n";
+print CMDSTREAM "set xdata time\n";
+print CMDSTREAM 'set timefmt "%Y-%m-%d"';
+print CMDSTREAM "\nplot";
+for ($iter = 0; $iter < $count; $iter++) {
+ if ($iter)
+ { print CMDSTREAM ","; }
+ print CMDSTREAM " '-' using 1:2 title \"" . $q->param('t' . $iter) . "," . $q->param('n' . $iter) . "\"with lines";
+}
+
+print CMDSTREAM "\n";
+
+for ($iter = 0; $iter < $count; $iter++) {
+
+ $prog = $q->param('n' . $iter);
+ $test = $q->param('t' . $iter);
+
+ $query = "Select RUN, VALUE from Tests where TEST = '$test' AND NAME = '$prog' ORDER BY RUN";
+ #print "\n$query\n";
+
+ my $sth = $dbh->prepare( $query) || die "Can't prepare statement: $DBI::errstr";;
+
+ my $rc = $sth->execute or die DBI->errstr;
+
+ while(($da,$v) = $sth->fetchrow_array)
+ {
+ print CMDSTREAM "$da $v\n";
+ }
+
+ print CMDSTREAM "e\n";
+}
+print CMDSTREAM "exit\n";
+close CMDSTREAM;
+
+# disconnect from database
+$dbh->disconnect;
diff --git a/utils/check-each-file b/utils/check-each-file
new file mode 100755
index 0000000000..bd7633301d
--- /dev/null
+++ b/utils/check-each-file
@@ -0,0 +1,150 @@
+#!/bin/sh
+# check-each-file
+# Used to narrow down a miscompilation to one .o file from a list. Please read
+# the usage procedure, below, for command-line syntax (or run it with --help).
+# This script depends on the llvm-native-gcc script.
+
+if [ x$1 = x--make-linker-script ]
+then
+ program=$2
+ linker=./link-$program
+ echo "Building $program with llvm-native-gcc"
+ rm -f $program
+ gmake -e $program CC=llvm-native-gcc CXX=llvm-native-gxx
+ echo "Erasing $program and re-linking it"
+ rm -f $program
+ echo "rm -f $program" > $linker
+ gmake -n $program >> $linker
+ chmod 755 $linker
+ echo "Linker script created in $linker; testing it out"
+ output=`./$linker 2>&1`
+ case "$output" in
+ *undefined*reference*__main*)
+ echo "$program appears to need a dummy __main function; adding one"
+ echo "void __main () { }" > __main.c
+ gcc -c __main.c
+ echo "Done; rebuilding $linker"
+ echo "rm -f $program" > $linker
+ gmake -n $program 2>&1 | sed '/gcc/s/$/__main.o/' >> $linker
+ ./$linker > /dev/null 2>&1
+ if [ ! -x $program ]
+ then
+ echo "WARNING: linker script didn't work"
+ fi
+ ;;
+ *)
+ if [ ! -x $program ]
+ then
+ echo "WARNING: linker script didn't work"
+ fi
+ ;;
+ esac
+ echo "Linker script created in $linker; please check it manually"
+ exit 0
+fi
+
+checkfiles="$1"
+program="$2"
+linker="$3"
+checker="$4"
+
+usage () {
+ myname=`basename $0`
+ echo "$myname --make-linker-script PROGRAM"
+ echo "$myname OBJECTS-FILE PROGRAM LINKER CHECKER"
+ echo ""
+ echo "OBJECTS-FILE is a text file containing the names of all the .o files"
+ echo "PROGRAM is the name of the executable under test"
+ echo "(there must also exist a Makefile in the current directory which"
+ echo "has PROGRAM as a target)"
+ echo "LINKER is the script that builds PROGRAM; try --make-linker-script"
+ echo "to automatically generate it"
+ echo "CHECKER is the script that exits 0 if PROGRAM is ok, 1 if it is not OK"
+ echo "(LINKER and CHECKER must be in your PATH, or you should specify ./)"
+ echo ""
+ echo "Bugs to <gaeke@uiuc.edu>."
+ exit 1
+}
+
+if [ x$1 = x--help ]
+then
+ usage
+fi
+
+if [ -z "$checkfiles" ]
+then
+ echo "ERROR: Must specify name of file w/ list of objects as 1st arg."
+ echo "(got \"$checkfiles\")"
+ usage
+fi
+if [ ! -f "$checkfiles" ]
+then
+ echo "ERROR: $checkfiles not found"
+ usage
+fi
+if [ -z "$program" ]
+then
+ echo "ERROR: Must specify name of program as 2nd arg."
+ usage
+fi
+if [ -z "$linker" ]
+then
+ echo "ERROR: Must specify name of link script as 3rd arg."
+ usage
+fi
+if [ ! -x "$linker" ]
+then
+ echo "ERROR: $linker not found or not executable"
+ echo "You may wish to try: $0 --make-linker-script $program"
+ usage
+fi
+if [ -z "$checker" ]
+then
+ echo "ERROR: Must specify name of $program check script as 3rd arg."
+ usage
+fi
+if [ ! -x "$checker" ]
+then
+ echo "ERROR: $checker not found or not executable"
+ usage
+fi
+
+files=`cat $checkfiles`
+echo "Recompiling everything with llvm-native-gcc"
+for f in $files
+do
+ rm -f $f
+ gmake $f CC=llvm-native-gcc CXX=llvm-native-gxx
+done
+rm -f $program
+$linker
+if $checker
+then
+ echo "Sorry, I can't help you, $program is OK when compiled with llvm-native-gcc"
+ exit 1
+fi
+for f in $files
+do
+ echo Trying to compile $f with native gcc and rebuild $program
+ mv ${f} ${f}__OLD__
+ gmake ${f} CC=gcc > /dev/null 2>&1
+ $linker
+ echo Checking validity of new $program
+ if $checker
+ then
+ echo Program is OK
+ okfiles="$okfiles $f"
+ else
+ echo Program is not OK
+ notokfiles="$notokfiles $f"
+ fi
+ mv ${f}__OLD__ ${f}
+done
+echo ""
+echo "Program is OK when these files are recompiled with native gcc: "
+echo "$okfiles"
+echo ""
+echo "Program is not OK when these files are recompiled with native gcc: "
+echo "$notokfiles"
+echo ""
+exit 0
diff --git a/utils/codegen-diff b/utils/codegen-diff
new file mode 100755
index 0000000000..2c3ac4c6df
--- /dev/null
+++ b/utils/codegen-diff
@@ -0,0 +1,135 @@
+#!/usr/bin/perl
+
+use Getopt::Std;
+$DEBUG = 0;
+
+sub parse_objdump_file {
+ my ($filename) = @_;
+ my @result;
+ open (INPUT, $filename) or die "$filename: $!\n";
+ print "opened objdump output file $filename\n" if $DEBUG;
+ while (<INPUT>) {
+ if (/\s*([0-9a-f]*):\t(([0-9a-f]{2} )+) *\t(.*)$/) {
+ my ($addr, $bytes, $instr) = ($1, $2, $4);
+ $addr = "0x" . $addr;
+ $bytes =~ s/\s*(.*\S)\s*/$1/; # trim any remaining whitespace
+ $instr =~ s/\s*(.*\S)\s*/$1/;
+ push (@result, {'addr' => $addr, 'bytes' => $bytes, 'instr' => $instr});
+ print "addr=$addr bytes='$bytes' instr='$instr'\n" if $DEBUG;
+ }
+ }
+ close INPUT;
+ return @result;
+}
+
+sub parse_gdb_file {
+ my ($filename) = @_;
+ my @result;
+ my $got_addr;
+ open (INPUT, $filename) or die "$filename: $!\n";
+ print "opened gdb output file $filename\n" if $DEBUG;
+ while (<INPUT>) {
+ if (/^(0x[0-9a-f]*):\t([^\t]*)\t[^:]*:\t((0x[0-9a-f]{2}\s*)+)\s*$/) {
+ my ($addr, $bytes, $instr) = ($1, $3, $2);
+ $bytes =~ s/0x//g;
+ $bytes =~ s/\s+/ /g; # regularize whitespace
+ $bytes =~ s/\s*(.*\S)\s*/$1/; # trim any remaining whitespace
+ $instr =~ s/\s*(.*\S)\s*/$1/;
+ push (@result, {'addr' => $addr, 'bytes' => $bytes, 'instr' => $instr});
+ print "addr=$addr bytes='$bytes' instr='$instr'\n" if $DEBUG;
+ } elsif (/^(0x[0-9a-f]*):\t$/) { # deal with gdb's line breaker
+ $got_addr = $1;
+ } elsif ($got_addr && /^ ([^\t]*)\t[^:]*:\t((0x[0-9a-f]{2}\s*)+)\s*$/) {
+ my ($addr, $bytes, $instr) = ($got_addr, $2, $1);
+ $bytes =~ s/0x//g;
+ $bytes =~ s/\s+/ /g; # regularize whitespace
+ $bytes =~ s/\s*(.*\S)\s*/$1/; # trim any remaining whitespace
+ $instr =~ s/\s*(.*\S)\s*/$1/;
+ push (@result, {'addr' => $addr, 'bytes' => $bytes, 'instr' => $instr});
+ print "addr=$addr bytes='$bytes' instr='$instr'\n" if $DEBUG;
+ undef $got_addr;
+ }
+ }
+ close INPUT;
+ return @result;
+}
+
+sub binary_diffs {
+ my ($objdump_file, $gdb_file) = @_;
+ my @file1 = parse_objdump_file ($objdump_file);
+ my @file2 = parse_gdb_file ($gdb_file);
+ my $lastrecord = ($#file1 >= $#file2) ? ($#file1) : ($#file2);
+ for (my $i = 0; $i <= $lastrecord; ++$i) {
+ my $d1 = $file1[$i];
+ my $d2 = $file2[$i];
+ if ($d1->{'bytes'} ne $d2->{'bytes'}) {
+ next if (($d1->{'instr'} eq $d2->{'instr'}) && $opt_d);
+ printf "0x%08x:\t%30s \t%s\n", 0+$d1->{'addr'}, $d1->{'bytes'}, $d1->{'instr'};
+ printf "0x%08x:\t%30s \t%s\n\n", 0+$d2->{'addr'}, $d2->{'bytes'}, $d2->{'instr'};
+ }
+ }
+}
+
+&getopts('d');
+$objdump_file = $ARGV[0];
+$gdb_file = $ARGV[1];
+binary_diffs ($objdump_file, $gdb_file);
+exit (0);
+__END__
+=pod
+
+=head1 NAME
+
+codegen-diff
+
+=head1 SYNOPSIS
+
+codegen-diff [-d] I<OBJDUMP-OUTPUT-FILE> I<GDB-DISASSEMBLY-FILE>
+
+=head1 DESCRIPTION
+
+B<codegen-diff> is a program that tries to show you the differences
+between the code that B<llc> generated and the code that B<lli> generated.
+
+The way you use it is as follows: first, you create I<OBJDUMP-OUTPUT-FILE>
+by running B<objdump> on the B<llc> compiled and linked binary. You need to
+trim down the result so it contains only the function of interest.
+
+Second, you create I<GDB-DISASSEMBLY-FILE> by running B<gdb>, with my patch
+to print out hex bytes in the B<disassemble> command output, on
+B<lli>. Set a breakpoint in C<Emitter::finishFunction()> and wait until
+the function you want is compiled. Then use the B<disassemble> command
+to print out the assembly dump of the function B<lli> just compiled.
+(Use C<lli -debug> to find out where the function starts and ends in memory.)
+It's easiest to save this output by using B<script>.
+
+Finally, you run B<codegen-diff>, as indicated in the Synopsis section of
+this manpage. It will print out a two-line stanza for each mismatched
+instruction, with the B<llc> version first, and the B<lli> version second.
+
+=head1 OPTIONS
+
+=over 4
+
+=item -d
+
+Don't show instructions where the bytes are different but they
+disassemble to the same thing. This puts a lot of trust in the
+disassembler, but it might help you highlight the more egregious cases
+of misassembly.
+
+=back
+
+=head1 AUTHOR
+
+B<codegen-diff> was written by Brian Gaeke.
+
+=head1 SEE ALSO
+
+L<gdb(1)>, L<objdump(1)>, L<script(1)>.
+
+You will need my B<gdb> patch:
+
+ http://llvm.cs.uiuc.edu/~gaeke/gdb-disassembly-print-bytes.patch
+
+=cut
diff --git a/utils/countloc.sh b/utils/countloc.sh
new file mode 100755
index 0000000000..988e80360a
--- /dev/null
+++ b/utils/countloc.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+##===- utils/countloc.sh - Counts Lines Of Code --------------*- Script -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file was developed by Reid Spencer and is distributed under the
+# University of Illinois Open Source License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This script finds all the source code files in the source code directories
+# (excluding certain things), runs "wc -l" on them to get the number of lines in
+# each file and then sums up and prints the total with awk.
+#
+# The script takes one optional option, -topdir, which specifies the top llvm
+# source directory. If it is not specified then the llvm-config tool is
+# consulted to find top source dir.
+#
+# Note that the implementation is based on llvmdo. See that script for more
+# details.
+##===----------------------------------------------------------------------===##
+
+if test $# -gt 1 ; then
+ if test "$1" = "-topdir" ; then
+ TOPDIR="$2"
+ shift; shift;
+ else
+ TOPDIR=`llvm-config --src-root`
+ fi
+fi
+
+if test -d "$TOPDIR" ; then
+ cd $TOPDIR
+ ./utils/llvmdo -topdir "$TOPDIR" -dirs "include lib tools test utils examples" -code-only wc -l | awk '\
+ BEGIN { loc=0; } \
+ { loc += $1; } \
+ END { print loc; }'
+else
+ echo "Can't find LLVM top directory"
+fi
diff --git a/utils/emacs/README b/utils/emacs/README
new file mode 100644
index 0000000000..e83eeae4b0
--- /dev/null
+++ b/utils/emacs/README
@@ -0,0 +1,27 @@
+-*- llvm/utils/emacs/README -*-
+
+These are syntax highlighting files for the Emacs and XEmacs editors. Included
+are:
+
+* llvm-mode.el
+
+ Syntax highlighting mode for LLVM assembly files. To use, add this code to
+ your ~/.emacs :
+
+ (setq load-path
+ (cons (expand-file-name "path-to-llvm/utils/emacs") load-path))
+ (require 'llvm-mode)
+
+* tablegen-mode.el
+
+ Syntax highlighting mode for TableGen description files. To use, add this code
+ to your ~/.emacs:
+
+ (setq load-path
+ (cons (expand-file-name "path-to-llvm/utils/emacs") load-path))
+ (require 'tablegen-mode)
+
+
+Note: If you notice missing or incorrect syntax highlighting, please contact
+<llvmbugs [at] cs.uiuc.edu>; if you wish to provide a patch to improve the
+functionality, it will be most appreciated. Thank you.
diff --git a/utils/emacs/emacs.el b/utils/emacs/emacs.el
new file mode 100644
index 0000000000..43e17a7be6
--- /dev/null
+++ b/utils/emacs/emacs.el
@@ -0,0 +1,12 @@
+;; LLVM coding style guidelines in emacs
+;; Maintainer: LLVM Team, http://llvm.org/
+;; Modified: 2005-04-24
+
+;; Max 80 cols per line, indent by two spaces, no tabs.
+;; Apparently, this does not affect tabs in Makefiles.
+(custom-set-variables
+ '(fill-column 80)
+ '(c++-indent-level 2)
+ '(c-basic-offset 2)
+ '(indent-tabs-mode nil))
+
diff --git a/utils/emacs/llvm-mode.el b/utils/emacs/llvm-mode.el
new file mode 100644
index 0000000000..271ff0c972
--- /dev/null
+++ b/utils/emacs/llvm-mode.el
@@ -0,0 +1,127 @@
+;; Maintainer: The LLVM team, http://llvm.org/
+;; Description: Major mode for the LLVM assembler language.
+;; Updated: 2003-06-02
+
+;; Create mode-specific tables.
+(defvar llvm-mode-syntax-table nil
+ "Syntax table used while in LLVM mode.")
+
+(defvar llvm-font-lock-keywords
+ (list
+ ;; Comments
+ '(";.*" . font-lock-comment-face)
+ ;; Variables
+ '("%[-a-zA-Z$\._][-a-zA-Z$\._0-9]*" . font-lock-variable-name-face)
+ ;; Labels
+ '("[-a-zA-Z$\._0-9]+:" . font-lock-variable-name-face)
+ ;; Strings
+ '("\"[^\"]+\"" . font-lock-string-face)
+ ;; Unnamed variable slots
+ '("%[-]?[0-9]+" . font-lock-variable-name-face)
+ ;; Integer literals
+ '("[-]?[0-9]+" . font-lock-preprocessor-face)
+ ;; Floating point constants
+ '("[-+]?[0-9]+\.[0-9]*\([eE][-+]?[0-9]+\)?" . font-lock-preprocessor-face)
+ ;; Hex constants
+ '("0x[0-9A-Fa-f]+" . font-lock-preprocessor-face)
+ ;; Keywords
+ '("begin\\|end\\|true\\|false\\|zeroinitializer\\|declare\\|global\\|constant\\|const\\|internal\\|linkonce\\|weak\\|appending\\|uninitialized\\|implementation\\|\\.\\.\\.\\|null\\|undef\\|to\\|except\\|not\\|target\\|endian\\|little\\|big\\|pointersize\\|deplibs\\|volatile\\|fastcc\\|coldcc\\|cc" . font-lock-keyword-face)
+ ;; Types
+ '("void\\|bool\\|sbyte\\|ubyte\\|u?short\\|u?int\\|u?long\\|float\\|double\\|type\\|label\\|opaque" . font-lock-type-face)
+ ;; Arithmetic and Logical Operators
+ '("add\\|sub\\|mul\\|div\\|rem\\|and\\|or\\|xor\\|set\\(ne\\|eq\\|lt\\|gt\\|le\\|ge\\)" . font-lock-keyword-face)
+ ;; Special instructions
+ '("phi\\|tail\\|call\\|cast\\|select\\|to\\|shl\\|shr\\|vaarg\\|vanext" . font-lock-keyword-face)
+ ;; Control instructions
+ '("ret\\|br\\|switch\\|invoke\\|unwind\\|unreachable" . font-lock-keyword-face)
+ ;; Memory operators
+ '("malloc\\|alloca\\|free\\|load\\|store\\|getelementptr" . font-lock-keyword-face)
+ )
+ "Syntax highlighting for LLVM"
+ )
+
+;; ---------------------- Syntax table ---------------------------
+;; Shamelessly ripped from jasmin.el
+;; URL: http://www.neilvandyke.org/jasmin-emacs/jasmin.el.html
+
+(if (not llvm-mode-syntax-table)
+ (progn
+ (setq llvm-mode-syntax-table (make-syntax-table))
+ (mapcar (function (lambda (n)
+ (modify-syntax-entry (aref n 0)
+ (aref n 1)
+ llvm-mode-syntax-table)))
+ '(
+ ;; whitespace (` ')
+ [?\^m " "]
+ [?\f " "]
+ [?\n " "]
+ [?\t " "]
+ [?\ " "]
+ ;; word constituents (`w')
+ ;;[?< "w"]
+ ;;[?> "w"]
+ [?\% "w"]
+ ;;[?_ "w "]
+ ;; comments
+ [?\; "< "]
+ [?\n "> "]
+ ;;[?\r "> "]
+ ;;[?\^m "> "]
+ ;; symbol constituents (`_')
+ ;; punctuation (`.')
+ ;; open paren (`(')
+ [?\( "("]
+ [?\[ "("]
+ [?\{ "("]
+ ;; close paren (`)')
+ [?\) ")"]
+ [?\] ")"]
+ [?\} ")"]
+ ;; string quote ('"')
+ [?\" "\""]
+ ))))
+
+;; --------------------- Abbrev table -----------------------------
+
+(defvar llvm-mode-abbrev-table nil
+ "Abbrev table used while in LLVM mode.")
+(define-abbrev-table 'llvm-mode-abbrev-table ())
+
+(defvar llvm-mode-hook nil)
+(defvar llvm-mode-map nil) ; Create a mode-specific keymap.
+
+(if (not llvm-mode-map)
+ () ; Do not change the keymap if it is already set up.
+ (setq llvm-mode-map (make-sparse-keymap))
+ (define-key llvm-mode-map "\t" 'tab-to-tab-stop)
+ (define-key llvm-mode-map "\es" 'center-line)
+ (define-key llvm-mode-map "\eS" 'center-paragraph))
+
+
+(defun llvm-mode ()
+ "Major mode for editing LLVM source files.
+ \\{llvm-mode-map}
+ Runs llvm-mode-hook on startup."
+ (interactive)
+ (kill-all-local-variables)
+ (use-local-map llvm-mode-map) ; Provides the local keymap.
+ (setq major-mode 'llvm-mode)
+
+ (make-local-variable 'font-lock-defaults)
+ (setq major-mode 'llvm-mode ; This is how describe-mode
+ ; finds the doc string to print.
+ mode-name "LLVM" ; This name goes into the modeline.
+ font-lock-defaults `(llvm-font-lock-keywords))
+
+ (setq local-abbrev-table llvm-mode-abbrev-table)
+ (set-syntax-table llvm-mode-syntax-table)
+ (run-hooks 'llvm-mode-hook)) ; Finally, this permits the user to
+ ; customize the mode with a hook.
+
+;; Associate .ll files with llvm-mode
+(setq auto-mode-alist
+ (append '(("\\.ll$" . llvm-mode) ("\\.llx$" . llvm-mode)) auto-mode-alist))
+
+(provide 'llvm-mode)
+;; end of llvm-mode.el
diff --git a/utils/emacs/tablegen-mode.el b/utils/emacs/tablegen-mode.el
new file mode 100644
index 0000000000..af33cbd37f
--- /dev/null
+++ b/utils/emacs/tablegen-mode.el
@@ -0,0 +1,133 @@
+;; Maintainer: The LLVM team, http://llvm.org/
+;; Description: Major mode for TableGen description files (part of LLVM project)
+;; Updated: 2007-03-26
+
+(require 'comint)
+(require 'custom)
+(require 'ansi-color)
+
+;; Create mode-specific tables.
+(defvar tablegen-mode-syntax-table nil
+ "Syntax table used while in TableGen mode.")
+
+(defvar td-decorators-face 'td-decorators-face
+ "Face method decorators.")
+(make-face 'td-decorators-face)
+
+(defvar tablegen-font-lock-keywords
+ (let ((kw (mapconcat 'identity
+ '("class" "def" "defm" "field" "in" "include"
+ "let" "multiclass")
+ "\\|"))
+ (type-kw (mapconcat 'identity
+ '("bit" "bits" "code" "dag" "int" "list" "string")
+ "\\|"))
+ )
+ (list
+ ;; Comments
+ '("\/\/" . font-lock-comment-face)
+ ;; Strings
+ '("\"[^\"]+\"" . font-lock-string-face)
+ ;; Hex constants
+ '("0x[0-9A-Fa-f]+" . font-lock-preprocessor-face)
+ ;; Binary constants
+ '("0b[01]+" . font-lock-preprocessor-face)
+ ;; Integer literals
+ '("[-]?[0-9]+" . font-lock-preprocessor-face)
+ ;; Floating point constants
+ '("[-+]?[0-9]+\.[0-9]*\([eE][-+]?[0-9]+\)?" . font-lock-preprocessor-face)
+
+ '("^[ \t]*\\(@.+\\)" 1 'td-decorators-face)
+ ;; Keywords
+ (cons (concat "\\<\\(" kw "\\)\\>[ \n\t(]") 1)
+
+ ;; Type keywords
+ (cons (concat "\\<\\(" type-kw "\\)[ \n\t(]") 1)
+ ))
+ "Additional expressions to highlight in TableGen mode.")
+(put 'tablegen-mode 'font-lock-defaults '(tablegen-font-lock-keywords))
+
+;; ---------------------- Syntax table ---------------------------
+;; Shamelessly ripped from jasmin.el
+;; URL: http://www.neilvandyke.org/jasmin-emacs/jasmin.el.html
+
+(if (not tablegen-mode-syntax-table)
+ (progn
+ (setq tablegen-mode-syntax-table (make-syntax-table))
+ (mapcar (function (lambda (n)
+ (modify-syntax-entry (aref n 0)
+ (aref n 1)
+ tablegen-mode-syntax-table)))
+ '(
+ ;; whitespace (` ')
+ [?\^m " "]
+ [?\f " "]
+ [?\n " "]
+ [?\t " "]
+ [?\ " "]
+ ;; word constituents (`w')
+ ;;[?< "w"]
+ ;;[?> "w"]
+ [?\% "w"]
+ ;;[?_ "w "]
+ ;; comments
+ [?\; "< "]
+ [?\n "> "]
+ ;;[?\r "> "]
+ ;;[?\^m "> "]
+ ;; symbol constituents (`_')
+ ;; punctuation (`.')
+ ;; open paren (`(')
+ [?\( "("]
+ [?\[ "("]
+ [?\{ "("]
+ ;; close paren (`)')
+ [?\) ")"]
+ [?\] ")"]
+ [?\} ")"]
+ ;; string quote ('"')
+ [?\" "\""]
+ ))))
+
+;; --------------------- Abbrev table -----------------------------
+
+(defvar tablegen-mode-abbrev-table nil
+ "Abbrev table used while in TableGen mode.")
+(define-abbrev-table 'tablegen-mode-abbrev-table ())
+
+(defvar tablegen-mode-hook nil)
+(defvar tablegen-mode-map nil) ; Create a mode-specific keymap.
+
+(if (not tablegen-mode-map)
+ () ; Do not change the keymap if it is already set up.
+ (setq tablegen-mode-map (make-sparse-keymap))
+ (define-key tablegen-mode-map "\t" 'tab-to-tab-stop)
+ (define-key tablegen-mode-map "\es" 'center-line)
+ (define-key tablegen-mode-map "\eS" 'center-paragraph))
+
+
+(defun tablegen-mode ()
+ "Major mode for editing TableGen description files.
+ \\{tablegen-mode-map}
+ Runs tablegen-mode-hook on startup."
+ (interactive)
+ (kill-all-local-variables)
+ (use-local-map tablegen-mode-map) ; Provides the local keymap.
+ (setq major-mode 'tablegen-mode)
+
+ (make-local-variable 'font-lock-defaults)
+ (setq major-mode 'tablegen-mode ; This is how describe-mode
+ ; finds the doc string to print.
+ mode-name "TableGen" ; This name goes into the modeline.
+ font-lock-defaults `(tablegen-font-lock-keywords))
+
+ (setq local-abbrev-table tablegen-mode-abbrev-table)
+ (set-syntax-table tablegen-mode-syntax-table)
+ (run-hooks 'tablegen-mode-hook)) ; Finally, this permits the user to
+ ; customize the mode with a hook.
+
+;; Associate .td files with tablegen-mode
+(setq auto-mode-alist (append '(("\\.td$" . tablegen-mode)) auto-mode-alist))
+
+(provide 'tablegen-mode)
+;; end of tablegen-mode.el
diff --git a/utils/findmisopt b/utils/findmisopt
new file mode 100755
index 0000000000..2c1dc0812a
--- /dev/null
+++ b/utils/findmisopt
@@ -0,0 +1,178 @@
+#!/bin/bash
+#
+# findmisopt
+#
+# This is a quick and dirty hack to potentially find a misoptimization
+# problem. Mostly its to work around problems in bugpoint that prevent
+# it from finding a problem unless the set of failing optimizations are
+# known and given to it on the command line.
+#
+# Given a bytecode file that produces correct output (or return code),
+# this script will run through all the optimizations passes that gccas
+# uses (in the same order) and will narrow down which optimizations
+# cause the program either generate different output or return a
+# different result code. When the passes have been narrowed down,
+# bugpoint is invoked to further refine the problem to its origin. If a
+# release version of bugpoint is available it will be used, otherwise
+# debug.
+#
+# Usage:
+# findmisopt bcfile outdir progargs [match]
+#
+# Where:
+# bcfile
+# is the bytecode file input (the unoptimized working case)
+# outdir
+# is a directory into which intermediate results are placed
+# progargs
+# is a single argument containing all the arguments the program needs
+# proginput
+# is a file name from which stdin should be directed
+# match
+# if specified to any value causes the result code of the program to
+# be used to determine success/fail. If not specified success/fail is
+# determined by diffing the program's output with the non-optimized
+# output.
+#
+if [ "$#" -lt 3 ] ; then
+ echo "usage: findmisopt bcfile outdir progargs [match]"
+ exit 1
+fi
+
+dir="${0%%/utils/findmisopt}"
+if [ -x "$dir/Release/bin/bugpoint" ] ; then
+ bugpoint="$dir/Release/bin/bugpoint"
+elif [ -x "$dir/Debug/bin/bugpoint" ] ; then
+ bugpoint="$dir/Debug/bin/bugpoint"
+else
+ echo "findmisopt: bugpoint not found"
+ exit 1
+fi
+
+bcfile="$1"
+outdir="$2"
+args="$3"
+input="$4"
+if [ ! -f "$input" ] ; then
+ input="/dev/null"
+fi
+match="$5"
+name=`basename $bcfile .bc`
+ll="$outdir/${name}.ll"
+s="$outdir/${name}.s"
+prog="$outdir/${name}"
+out="$outdir/${name}.out"
+optbc="$outdir/${name}.opt.bc"
+optll="$outdir/${name}.opt.ll"
+opts="$outdir/${name}.opt.s"
+optprog="$outdir/${name}.opt"
+optout="$outdir/${name}.opt.out"
+ldflags="-lstdc++ -lm -ldl -lc"
+
+echo "Test Name: $name"
+echo "Unoptimized program: $prog"
+echo " Optimized program: $optprog"
+
+# Create output directory if it doesn't exist
+if [ -f "$outdir" ] ; then
+ echo "$outdir is not a directory"
+ exit 1
+fi
+
+if [ ! -d "$outdir" ] ; then
+ mkdir "$outdir" || exit 1
+fi
+
+# Generate the disassembly
+llvm-dis "$bcfile" -o "$ll" -f || exit 1
+
+# Generate the non-optimized program and its output
+llc "$bcfile" -o "$s" -f || exit 1
+gcc "$s" -o "$prog" $ldflags || exit 1
+"$prog" $args > "$out" 2>&1 <$input
+ex1=$?
+
+# Define the list of optimizations to run. This comprises the same set of
+# optimizations that opt -std-compile-opts and gccld run, in the same order.
+opt_switches=`llvm-as < /dev/null -o - | opt -std-compile-opts -disable-output -debug-pass=Arguments 2>&1 | sed 's/Pass Arguments: //'`
+gccld_switches="-internalize -ipsccp -globalopt -constmerge -deadargelim -inline -prune-eh -globalopt -globaldce -argpromotion -instcombine -predsimplify -scalarrepl -globalsmodref-aa -licm -load-vn -gcse -dse -instcombine -simplifycfg -verify"
+all_switches="$opt_switches $gccld_switches"
+echo "Passes : $all_switches"
+
+# Current set of switches is empty
+function tryit {
+ switches_to_use="$1"
+ opt $switches_to_use "$bcfile" -o "$optbc" -f || exit
+ llvm-dis "$optbc" -o "$optll" -f || exit
+ llc "$optbc" -o "$opts" -f || exit
+ gcc "$opts" -o "$optprog" $ldflags || exit
+ "$optprog" $args > "$optout" 2>&1 <"$input"
+ ex2=$?
+
+ if [ -n "$match" ] ; then
+ if [ "$ex1" -ne "$ex2" ] ; then
+ echo "Return code not the same with these switches:"
+ echo $switches
+ echo "Unoptimized returned: $ex1"
+ echo "Optimized returned: $ex2"
+ return 0
+ fi
+ else
+ diff "$out" "$optout" > /dev/null
+ if [ $? -ne 0 ] ; then
+ echo "Diff fails with these switches:"
+ echo $switches
+ echo "Differences:"
+ diff "$out" "$optout" | head
+ return 0;
+ fi
+ fi
+ return 1
+}
+
+echo "Trying to find optimization that breaks program:"
+for sw in $all_switches ; do
+ echo -n " $sw"
+ switches="$switches $sw"
+ if tryit "$switches" ; then
+ break;
+ fi
+done
+
+# Terminate the previous output with a newline
+echo ""
+
+# Determine if we're done because none of the optimizations broke the program
+if [ "$switches" == " $all_switches" ] ; then
+ echo "The program did not miscompile"
+ exit 0
+fi
+
+final=""
+while [ ! -z "$switches" ] ; do
+ trimmed=`echo "$switches" | sed -e 's/^ *\(-[^ ]*\).*/\1/'`
+ switches=`echo "$switches" | sed -e 's/^ *-[^ ]* *//'`
+ echo "Trimmed $trimmed from left"
+ tryit "$final $switches"
+ if [ "$?" -eq "0" ] ; then
+ echo "Still Failing .. continuing ..."
+ continue
+ else
+ echo "Found required early pass: $trimmed"
+ final="$final $trimmed"
+ continue
+ fi
+ echo "Next Loop"
+done
+
+if [ "$final" == " $all_switches" ] ; then
+ echo "findmisopt: All optimizations pass. Perhaps this isn't a misopt?"
+ exit 0
+fi
+echo "Smallest Optimization list=$final"
+
+bpcmd="$bugpoint -run-llc -disable-loop-extraction --output "$out" --input /dev/null $bcfile $final --args $args"
+
+echo "Running: $bpcmd"
+$bpcmd
+echo "findmisopt finished."
diff --git a/utils/findoptdiff b/utils/findoptdiff
new file mode 100755
index 0000000000..36620d932c
--- /dev/null
+++ b/utils/findoptdiff
@@ -0,0 +1,101 @@
+#!/bin/bash
+#
+# findoptdiff
+#
+# This script helps find the optimization difference between two llvm
+# builds. It is useful when you have a build that is known to work and
+# one that exhibits an optimization problem. Identifying the difference
+# between the two builds can lead to discovery of the source of a
+# mis-optimization.
+#
+# The script takes two llvm build paths as arguments. These specify the
+# the two llvm builds to compare. It is generally expected that they
+# are "close cousins". That is, they are the same except that the
+# second build contains some experimental optimization features that
+# are suspected of producing a misoptimization.
+#
+# The script takes two bytecode files, one from each build. They are
+# presumed to be a compilation of the same program or program fragment
+# with the only difference being the builds.
+#
+# The script operates by iteratively applying the optimizations that gccas
+# and gccld run until there is a difference in the assembly resulting
+# from the optimization. The difference is then reported with the set of
+# optimization passes that produce the difference. The processing
+# continues until all optimization passes have been tried. The differences
+# for each pass, if they do differ, are placed in a diffs.# file.
+#
+# To work around differences in the assembly language format, the script
+# can also take two filter arguments that post-process the assembly
+# so they can be differenced without making false positives for known
+# differences in the two builds. These filters are optional.
+#
+# Usage:
+# findoptdiff llvm1 llvm2 bc1 bc2 filter1 filter2
+#
+# Where:
+# llvm1
+# is the path to the first llvm build dir
+# llvm2
+# is the path to the second llvm build dir
+# bc1
+# is the bytecode file for the first llvm environment
+# bc2
+# is the bytecode file for the second llvm environment
+# filter1
+# is an optional filter for filtering the llvm1 generated assembly
+# filter2
+# is an optional filter for filtering the llvm2 generated assembly
+#
+llvm1=$1
+llvm2=$2
+bc1=$3
+bc2=$4
+filt1=$5
+filt2=$6
+if [ -z "$filt1" ] ; then
+ filt1="cat"
+fi
+if [ -z "$filt2" ] ; then
+ filt2="cat"
+fi
+opt1="${bc1}.opt"
+opt2="${bc2}.opt"
+ll1="${bc1}.ll"
+ll2="${bc2}.ll"
+opt1ll="${bc1}.opt.ll"
+opt2ll="${bc2}.opt.ll"
+dis1="$llvm1/Debug/bin/llvm-dis"
+dis2="$llvm2/Debug/bin/llvm-dis"
+opt1="$llvm1/Debug/bin/opt"
+opt2="$llvm2/Debug/bin/opt"
+
+all_switches="-verify -lowersetjmp -raiseallocs -simplifycfg -mem2reg -globalopt -globaldce -ipconstprop -deadargelim -instcombine -simplifycfg -prune-eh -inline -simplify-libcalls -argpromotion -tailduplicate -simplifycfg -scalarrepl -instcombine -predsimplify -condprop -tailcallelim -simplifycfg -reassociate -licm -loop-unswitch -instcombine -indvars -loop-unroll -instcombine -load-vn -gcse -sccp -instcombine -condprop -dse -dce -simplifycfg -deadtypeelim -constmerge -internalize -ipsccp -globalopt -constmerge -deadargelim -inline -prune-eh -globalopt -globaldce -argpromotion -instcombine -predsimplify -scalarrepl -globalsmodref-aa -licm -load-vn -gcse -dse -instcombine -simplifycfg -verify"
+
+#counter=0
+function tryit {
+ switches_to_use="$1"
+ $opt1 $switches_to_use "$bc1" -o - | $dis1 | $filt1 > "$opt1ll"
+ $opt2 $switches_to_use "$bc2" -o - | $dis2 | $filt2 > "$opt2ll"
+ diffs="diffs."$((counter++))
+ diff "$opt1ll" "$opt2ll" > $diffs
+ if [ $? -ne 0 ] ; then
+ echo
+ echo "Diff fails with these switches:"
+ echo $switches
+ echo "Differences:"
+ head $diffs
+ echo 'Switches:' $switches_to_use >> $diffs
+ else
+ rm $diffs
+ fi
+ return 1
+}
+
+for sw in $all_switches ; do
+ echo -n " $sw"
+ switches="$switches $sw"
+ if tryit "$switches" ; then
+ break;
+ fi
+done
diff --git a/utils/findsym.pl b/utils/findsym.pl
new file mode 100755
index 0000000000..92346572fe
--- /dev/null
+++ b/utils/findsym.pl
@@ -0,0 +1,33 @@
+#!/usr/bin/perl -w
+#
+# Program: findsym.pl
+#
+# Synopsis: Generate a list of the libraries in which a symbol is defined or
+# referenced.
+#
+# Syntax: findsym.pl <directory_with_libraries_in_it> <symbol>
+#
+
+# Give first option a name.
+my $Directory = $ARGV[0];
+my $Symbol = $ARGV[1];
+
+# Open the directory and read its contents, sorting by name and differentiating
+# by whether its a library (.a) or an object file (.o)
+opendir DIR,$Directory;
+my @files = readdir DIR;
+closedir DIR;
+@objects = grep(/l?i?b?LLVM.*\.[oa]$/,sort(@files));
+
+# Gather definitions from the libraries
+foreach $lib (@objects) {
+ my $head = 0;
+ open SYMS,
+ "nm $Directory/$lib | grep '$Symbol' | sort --key=3 | uniq |";
+ while (<SYMS>) {
+ if (!$head) { print "$lib:\n"; $head = 1; }
+ chomp($_);
+ print " $_\n";
+ }
+ close SYMS;
+}
diff --git a/utils/fpcmp/Makefile b/utils/fpcmp/Makefile
new file mode 100644
index 0000000000..234af089cf
--- /dev/null
+++ b/utils/fpcmp/Makefile
@@ -0,0 +1,16 @@
+##===- utils/fpcmp/Makefile --------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file was developed by the LLVM research group and is distributed under
+# the University of Illinois Open Source License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../..
+TOOLNAME = fpcmp
+USEDLIBS = LLVMSupport.a LLVMSystem.a
+NO_INSTALL = 1
+
+include $(LEVEL)/Makefile.common
+
diff --git a/utils/fpcmp/fpcmp.cpp b/utils/fpcmp/fpcmp.cpp
new file mode 100644
index 0000000000..18b9611334
--- /dev/null
+++ b/utils/fpcmp/fpcmp.cpp
@@ -0,0 +1,43 @@
+//===- fpcmp.cpp - A fuzzy "cmp" that permits floating point noise --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// fpcmp is a tool that basically works like the 'cmp' tool, except that it can
+// tolerate errors due to floating point noise, with the -r and -a options.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileUtilities.h"
+#include <iostream>
+using namespace llvm;
+
+namespace {
+ cl::opt<std::string>
+ File1(cl::Positional, cl::desc("<input file #1>"), cl::Required);
+ cl::opt<std::string>
+ File2(cl::Positional, cl::desc("<input file #2>"), cl::Required);
+
+ cl::opt<double>
+ RelTolerance("r", cl::desc("Relative error tolerated"), cl::init(0));
+ cl::opt<double>
+ AbsTolerance("a", cl::desc("Absolute error tolerated"), cl::init(0));
+}
+
+int main(int argc, char **argv) {
+ cl::ParseCommandLineOptions(argc, argv);
+
+ std::string ErrorMsg;
+ int DF = DiffFilesWithTolerance(sys::PathWithStatus(File1),
+ sys::PathWithStatus(File2),
+ AbsTolerance, RelTolerance, &ErrorMsg);
+ if (!ErrorMsg.empty())
+ std::cerr << argv[0] << ": " << ErrorMsg << "\n";
+ return DF;
+}
+
diff --git a/utils/getsrcs.sh b/utils/getsrcs.sh
new file mode 100755
index 0000000000..2432edfa75
--- /dev/null
+++ b/utils/getsrcs.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+##===- utils/getsrcs.sh - Counts Lines Of Code ---------------*- Script -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file was developed by Chris Lattner and Reid Spencer and is distributed
+# under the # University of Illinois Open Source License. See LICENSE.TXT for
+# details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This script just prints out the path names for all the source files in LLVM.
+# The optional -topdir option can be used to specify the top LLVM source
+# directory. Without it, the llvm-config command is consulted to find the
+# top source directory.
+#
+# Note that the implementation is based on llvmdo. See that script for more
+# details.
+##===----------------------------------------------------------------------===##
+
+if test "$1" = "-topdir" ; then
+ TOPDIR="$2"
+ shift; shift;
+else
+ TOPDIR=`llvm-config --src-root`
+fi
+
+if test -d "$TOPDIR" ; then
+ cd $TOPDIR
+ ./utils/llvmdo -topdir "$TOPDIR" \
+ -dirs "include lib tools utils examples projects" echo
+else
+ echo "Can't find LLVM top directory"
+fi
diff --git a/utils/importNLT.pl b/utils/importNLT.pl
new file mode 100644
index 0000000000..c1b950dc34
--- /dev/null
+++ b/utils/importNLT.pl
@@ -0,0 +1,86 @@
+#!/usr/bin/perl
+#take the output of parseNLT.pl and load it into a database
+# use like: cat file |perl parseNLT.pl |perl importNLT.pl password
+
+use DBI;
+
+# database information
+$db="llvmalpha";
+$host="localhost";
+$userid="llvmdbuser";
+$passwd=shift @ARGV;
+$connectionInfo="dbi:mysql:$db;$host";
+
+# make connection to database
+$dbh = DBI->connect($connectionInfo,$userid,$passwd) or die DBI->errstr;
+my $sth = $dbh->prepare( q{
+ INSERT INTO Tests (NAME, RUN, TEST, VALUE) VALUES (?, STR_TO_DATE(?, '\%d \%M \%Y'), ?, ?)
+ }) || die "Can't prepare statement: $DBI::errstr";;
+
+while($d = <>)
+{
+ chomp $d;
+ if (18 == scalar split " ", $d)
+ {
+ ($day, $mon, $year, $prog, $gccas, $bc, $llccompile, $llcbetacompile, $jitcompile,
+ $mc, $gcc, $cbe, $llc, $llcbeta, $jit, $foo1, $foo2, $foo3) = split " ", $d;
+ if ($gccas =~ /\d+/)
+ {
+ $dbh->do("INSERT INTO Tests (NAME, RUN, TEST, VALUE) VALUES
+ ('$prog', STR_TO_DATE('$day $mon $year', '\%d \%M \%Y'), 'gccas', $gccas)") || die DBI->errstr;
+ }
+ if ($bc =~ /\d/)
+ {
+ $dbh->do("INSERT INTO Tests (NAME, RUN, TEST, VALUE) VALUES
+ ('$prog', STR_TO_DATE('$day $mon $year', '\%d \%M \%Y'), 'bytecode', $bc)") || die DBI->errstr;
+ }
+ if ($llccompile =~ /\d/)
+ {
+ $dbh->do("INSERT INTO Tests (NAME, RUN, TEST, VALUE) VALUES
+ ('$prog', STR_TO_DATE('$day $mon $year', '\%d \%M \%Y'), 'llc-compile', $llccompile)") || die DBI->errstr;
+ }
+ if ($llcbetacompile =~ /\d/)
+ {
+ $dbh->do("INSERT INTO Tests (NAME, RUN, TEST, VALUE) VALUES
+ ('$prog', STR_TO_DATE('$day $mon $year', '\%d \%M \%Y'), 'llc-beta-compile', $llcbetacompile)") || die DBI->errstr;
+ }
+ if ($jitcompile =~ /\d/)
+ {
+ $dbh->do("INSERT INTO Tests (NAME, RUN, TEST, VALUE) VALUES
+ ('$prog', STR_TO_DATE('$day $mon $year', '\%d \%M \%Y'), 'jit-compile', $jitcompile)") || die DBI->errstr;
+ }
+ if ($mc =~ /\d/)
+ {
+ $dbh->do("INSERT INTO Tests (NAME, RUN, TEST, VALUE) VALUES
+ ('$prog', STR_TO_DATE('$day $mon $year', '\%d \%M \%Y'), 'machine-code', $mc)") || die DBI->errstr;
+ }
+ if ($gcc =~ /\d/)
+ {
+ $dbh->do("INSERT INTO Tests (NAME, RUN, TEST, VALUE) VALUES
+ ('$prog', STR_TO_DATE('$day $mon $year', '\%d \%M \%Y'), 'gcc', $gcc)") || die DBI->errstr;
+ }
+ if ($llc =~ /\d/)
+ {
+ $dbh->do("INSERT INTO Tests (NAME, RUN, TEST, VALUE) VALUES
+ ('$prog', STR_TO_DATE('$day $mon $year', '\%d \%M \%Y'), 'llc', $llc)") || die DBI->errstr;
+ }
+ if ($llcbeta =~ /\d/)
+ {
+ $dbh->do("INSERT INTO Tests (NAME, RUN, TEST, VALUE) VALUES
+ ('$prog', STR_TO_DATE('$day $mon $year', '\%d \%M \%Y'), 'llc-beta', $llcbeta)") || die DBI->errstr;
+ }
+ if ($jit =~ /\d/)
+ {
+ $dbh->do("INSERT INTO Tests (NAME, RUN, TEST, VALUE) VALUES
+ ('$prog', STR_TO_DATE('$day $mon $year', '\%d \%M \%Y'), 'jit', $jit)") || die DBI->errstr;
+ }
+ print ".";
+ }
+ else
+ {
+ print "\nNO: $d\n";
+ }
+}
+print "\n";
+# disconnect from database
+$dbh->disconnect;
diff --git a/utils/llvm-native-gcc b/utils/llvm-native-gcc
new file mode 100755
index 0000000000..b3cecb1411
--- /dev/null
+++ b/utils/llvm-native-gcc
@@ -0,0 +1,249 @@
+#!/usr/bin/perl
+# Wrapper around LLVM tools to generate a native .o from llvm-gcc using an
+# LLVM back-end (CBE by default).
+
+# set up defaults.
+$Verbose = 0;
+$SaveTemps = 1;
+$PreprocessOnly = 0;
+$CompileDontLink = 0;
+$Backend = 'cbe';
+chomp ($ProgramName = `basename $0`);
+
+sub boldprint {
+ print "", @_, "";
+}
+
+# process command-line options.
+# most of these are passed on to llvm-gcc.
+$GCCOptions = "";
+for ($i = 0; $i <= $#ARGV; ++$i) {
+ if ($ARGV[$i] =~ /-mllvm-backend=([a-z0-9]*)/) {
+ $Backend = $1;
+ if ($ProgramName =~ /llvm-native-gcc/) {
+ splice (@ARGV, $i, 1);
+ --$i;
+ }
+ } elsif ($ARGV[$i] eq "-E") {
+ $PreprocessOnly = 1;
+ } elsif ($ARGV[$i] eq "-c") {
+ $GCCOptions .= " " . $ARGV[$i];
+ $CompileDontLink = 1;
+ } elsif ($ARGV[$i] eq "-v") {
+ $GCCOptions .= " " . $ARGV[$i];
+ $Verbose = 1;
+ } elsif ($ARGV[$i] eq "-o") {
+ $OutputFile = $ARGV[$i + 1];
+ } elsif ($ARGV[$i] eq "-save-temps") {
+ $GCCOptions .= " " . $ARGV[$i];
+ $SaveTemps = 1;
+ } elsif ($ARGV[$i] =~ /\.bc$/) {
+ push (@BytecodeFiles, $ARGV[$i]);
+ } elsif ($ARGV[$i] =~ /^-L/) {
+ $GCCOptions .= " " . $ARGV[$i];
+ push (@LibDirs, $ARGV[$i]);
+ } elsif ($ARGV[$i] =~ /^-l/) {
+ $GCCOptions .= " " . $ARGV[$i];
+ push (@Libs, $ARGV[$i]);
+ } elsif ($ARGV[$i] =~ /\.(c|cpp|cc|i|ii|C)$/) {
+ $LastCFile = $ARGV[$i];
+ }
+}
+
+sub GetDefaultOutputFileName {
+ my $DefaultOutputFileBase;
+
+ if ($ProgramName =~ /llvm-native-gcc/) {
+ $DefaultOutputFileBase = $LastCFile;
+ } elsif ($ProgramName =~ /native-build/) {
+ $DefaultOutputFileBase = $BytecodeFiles[0];
+ }
+
+ my $def = $DefaultOutputFileBase;
+
+ die "Can't figure out name of output file.\n"
+ unless $DefaultOutputFileBase
+ && (($ProgramName !~ /native-build/)
+ || $#BytecodeFiles == 0);
+
+ print "Warning: defaulting output file name ",
+ "based on '$DefaultOutputFileBase'\n" if $Verbose;
+
+ if ($ProgramName =~ /llvm-native-gcc/) {
+ $def =~ s/\.(c|cpp|cc|i|ii|C)$/.o/;
+ } elsif ($ProgramName =~ /native-build/) {
+ $def =~ s/\.bc$/.$Backend/;
+ if ($CompileDontLink) {
+ $def .= ".o";
+ }
+ }
+
+ return $def;
+}
+
+# run a command, optionally echoing, and quitting if it fails:
+sub run {
+ my $command = join(" ", @_);
+ print "$command\n" if $Verbose;
+ $command =~ s/\"/\\\"/g;
+ system $command and die "$0: $command failed";
+}
+
+sub LinkBytecodeFilesIntoTemporary {
+ my $FinalOutputFileName = shift @_;
+ my @BytecodeFiles = @_;
+
+ my $BCFiles = join (" ", @BytecodeFiles);
+ my $LinkedBCFile;
+ if ($SaveTemps) {
+ $LinkedBCFile = "${FinalOutputFileName}.llvm.bc";
+ } else {
+ $LinkedBCFile = "/tmp/nativebuild-$$.llvm.bc";
+ }
+ run "llvm-link -o $LinkedBCFile $BCFiles";
+ return $LinkedBCFile;
+}
+
+sub CompileBytecodeToNative {
+ my ($BCFile, $Backend, $OutputFile) = @_;
+
+ my $GeneratedCode;
+ if ($Backend eq 'cbe') {
+ if ($SaveTemps) {
+ $GeneratedCode = "${OutputFile}.c";
+ } else {
+ $GeneratedCode = "/tmp/nativebuild-$$.c";
+ }
+ run "llc -enable-correct-eh-support -march=c -f -o $GeneratedCode $BCFile";
+ } elsif ($Backend eq 'llc') {
+ if ($SaveTemps) {
+ $GeneratedCode = "${OutputFile}.s";
+ } else {
+ $GeneratedCode = "/tmp/nativebuild-$$.s";
+ }
+ run "llc -enable-correct-eh-support -f -o $GeneratedCode $BCFile";
+ }
+ my $LibDirs = join (" ", @LibDirs);
+ my $Libs = join (" ", @Libs);
+ run "gcc $GCCOptions $GeneratedCode -o $OutputFile $LibDirs $Libs";
+ run "rm $BCFile $GeneratedCode"
+ unless $SaveTemps;
+}
+
+sub CompileCToNative {
+ my ($LLVMGCCCommand, $Backend, $OutputFile) = @_;
+ run $LLVMGCCCommand;
+ if ($PreprocessOnly) {
+ return;
+ }
+ my $BCFile = "${OutputFile}.llvm.bc";
+ if ($CompileDontLink) {
+ run "mv ${OutputFile} $BCFile";
+ } else { # gccld messes with the output file name
+ run "mv ${OutputFile}.bc $BCFile";
+ }
+ my $GeneratedCode;
+ if ($Backend eq 'cbe') {
+ $GeneratedCode = "${OutputFile}.cbe.c";
+ run "llc -enable-correct-eh-support -march=c -f -o $GeneratedCode $BCFile";
+ } elsif ($Backend eq 'llc') {
+ $GeneratedCode = "${OutputFile}.llc.s";
+ run "llc -enable-correct-eh-support -f -o $GeneratedCode $BCFile";
+ }
+ my $NativeGCCOptions = "";
+ if ($CompileDontLink) {
+ $NativeGCCOptions = "-c";
+ }
+ run "gcc $NativeGCCOptions $GeneratedCode -o $OutputFile";
+ run "rm ${OutputFile}.llvm.bc $GeneratedCode"
+ unless $SaveTemps;
+}
+
+# guess the name of the output file, if -o was not specified.
+$OutputFile = GetDefaultOutputFileName () unless $OutputFile;
+print "Output file is $OutputFile\n" if $Verbose;
+# do all the dirty work:
+if ($ProgramName eq /native-build/) {
+ my $LinkedBCFile = LinkBytecodeFilesIntoTemporary (@BytecodeFiles);
+ CompileBytecodeToNative ($LinkedBCFile, $Backend, $OutputFile);
+} elsif ($ProgramName =~ /llvm-native-gcc/) {
+ # build the llvm-gcc command line.
+ $LLVMGCCCommand = join (" ", ("llvm-gcc", @ARGV));
+ CompileCToNative ($LLVMGCCCommand, $Backend, $OutputFile);
+}
+
+# we're done.
+exit 0;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+llvm-native-gcc
+
+=head1 SYNOPSIS
+
+llvm-native-gcc [OPTIONS...] FILE
+
+native-build [OPTIONS...] FILE
+
+=head1 DESCRIPTION
+
+llvm-native-gcc is a wrapper around the LLVM command-line tools which generates
+a native object (.o) file by compiling FILE with llvm-gcc, and then running
+an LLVM back-end (CBE by default) over the resulting bytecode, and then
+compiling the resulting code to a native object file.
+
+If called as "native-build", it compiles bytecode to native code, and takes
+different options.
+
+=head1 OPTIONS
+
+llvm-native-gcc takes the same options as llvm-gcc. All options
+except -mllvm-backend=... are passed on to llvm-gcc.
+
+=over 4
+
+=item -mllvm-backend=BACKEND
+
+Use BACKEND for native code generation.
+
+=item -v
+
+Print command lines that llvm-native-gcc runs.
+
+=item -o FILE
+
+llvm-native-gcc tries to guess the name of the llvm-gcc output file by looking
+for this option in the command line. If it can't find it, it finds the last C
+or C++ source file named on the command line, and turns its suffix into .o. See
+BUGS.
+
+=item -save-temps
+
+Save temporary files used by llvm-native-gcc (and llvm-gcc, and gcc).
+
+=back
+
+=head1 BUGS
+
+llvm-native-gcc only handles the case where llvm-gcc compiles a single
+file per invocation. llvm-native-gcc has weak command-line argument
+parsing and is a poor substitute for making gcc/gcc.c do this stuff.
+
+This manual page does not adequately document native-build mode.
+
+llvm-native-gcc is pretty gross because it represents the blind merging of two
+other scripts that predated it. It could use some code clean-up.
+
+=head1 SEE ALSO
+
+gcc(1)
+
+=head1 AUTHOR
+
+Brian R. Gaeke
+
+=cut
diff --git a/utils/llvm-native-gxx b/utils/llvm-native-gxx
new file mode 100755
index 0000000000..75164af237
--- /dev/null
+++ b/utils/llvm-native-gxx
@@ -0,0 +1,249 @@
+#!/usr/bin/perl
+# Wrapper around LLVM tools to generate a native .o from llvm-gxx using an
+# LLVM back-end (CBE by default).
+
+# set up defaults.
+$Verbose = 0;
+$SaveTemps = 1;
+$PreprocessOnly = 0;
+$CompileDontLink = 0;
+$Backend = 'cbe';
+chomp ($ProgramName = `basename $0`);
+
+sub boldprint {
+ print "", @_, "";
+}
+
+# process command-line options.
+# most of these are passed on to llvm-gxx.
+$GCCOptions = "";
+for ($i = 0; $i <= $#ARGV; ++$i) {
+ if ($ARGV[$i] =~ /-mllvm-backend=([a-z0-9]*)/) {
+ $Backend = $1;
+ if ($ProgramName =~ /llvm-native-gxx/) {
+ splice (@ARGV, $i, 1);
+ --$i;
+ }
+ } elsif ($ARGV[$i] eq "-E") {
+ $PreprocessOnly = 1;
+ } elsif ($ARGV[$i] eq "-c") {
+ $GCCOptions .= " " . $ARGV[$i];
+ $CompileDontLink = 1;
+ } elsif ($ARGV[$i] eq "-v") {
+ $GCCOptions .= " " . $ARGV[$i];
+ $Verbose = 1;
+ } elsif ($ARGV[$i] eq "-o") {
+ $OutputFile = $ARGV[$i + 1];
+ } elsif ($ARGV[$i] eq "-save-temps") {
+ $GCCOptions .= " " . $ARGV[$i];
+ $SaveTemps = 1;
+ } elsif ($ARGV[$i] =~ /\.bc$/) {
+ push (@BytecodeFiles, $ARGV[$i]);
+ } elsif ($ARGV[$i] =~ /^-L/) {
+ $GCCOptions .= " " . $ARGV[$i];
+ push (@LibDirs, $ARGV[$i]);
+ } elsif ($ARGV[$i] =~ /^-l/) {
+ $GCCOptions .= " " . $ARGV[$i];
+ push (@Libs, $ARGV[$i]);
+ } elsif ($ARGV[$i] =~ /\.(c|cpp|cc|i|ii|C)$/) {
+ $LastCFile = $ARGV[$i];
+ }
+}
+
+sub GetDefaultOutputFileName {
+ my $DefaultOutputFileBase;
+
+ if ($ProgramName =~ /llvm-native-gxx/) {
+ $DefaultOutputFileBase = $LastCFile;
+ } elsif ($ProgramName =~ /native-build/) {
+ $DefaultOutputFileBase = $BytecodeFiles[0];
+ }
+
+ my $def = $DefaultOutputFileBase;
+
+ die "Can't figure out name of output file.\n"
+ unless $DefaultOutputFileBase
+ && (($ProgramName !~ /native-build/)
+ || $#BytecodeFiles == 0);
+
+ print "Warning: defaulting output file name ",
+ "based on '$DefaultOutputFileBase'\n" if $Verbose;
+
+ if ($ProgramName =~ /llvm-native-gxx/) {
+ $def =~ s/\.(c|cpp|cc|i|ii|C)$/.o/;
+ } elsif ($ProgramName =~ /native-build/) {
+ $def =~ s/\.bc$/.$Backend/;
+ if ($CompileDontLink) {
+ $def .= ".o";
+ }
+ }
+
+ return $def;
+}
+
+# run a command, optionally echoing, and quitting if it fails:
+sub run {
+ my $command = join(" ", @_);
+ print "$command\n" if $Verbose;
+ $command =~ s/\"/\\\"/g;
+ system $command and die "$0: $command failed";
+}
+
+sub LinkBytecodeFilesIntoTemporary {
+ my $FinalOutputFileName = shift @_;
+ my @BytecodeFiles = @_;
+
+ my $BCFiles = join (" ", @BytecodeFiles);
+ my $LinkedBCFile;
+ if ($SaveTemps) {
+ $LinkedBCFile = "${FinalOutputFileName}.llvm.bc";
+ } else {
+ $LinkedBCFile = "/tmp/nativebuild-$$.llvm.bc";
+ }
+ run "llvm-link -o $LinkedBCFile $BCFiles";
+ return $LinkedBCFile;
+}
+
+sub CompileBytecodeToNative {
+ my ($BCFile, $Backend, $OutputFile) = @_;
+
+ my $GeneratedCode;
+ if ($Backend eq 'cbe') {
+ if ($SaveTemps) {
+ $GeneratedCode = "${OutputFile}.c";
+ } else {
+ $GeneratedCode = "/tmp/nativebuild-$$.c";
+ }
+ run "llc -march=c -f -o $GeneratedCode $BCFile";
+ } elsif ($Backend eq 'llc') {
+ if ($SaveTemps) {
+ $GeneratedCode = "${OutputFile}.s";
+ } else {
+ $GeneratedCode = "/tmp/nativebuild-$$.s";
+ }
+ run "llc -f -o $GeneratedCode $BCFile";
+ }
+ my $LibDirs = join (" ", @LibDirs);
+ my $Libs = join (" ", @Libs);
+ run "gcc $GCCOptions $GeneratedCode -o $OutputFile $LibDirs $Libs";
+ run "rm $BCFile $GeneratedCode"
+ unless $SaveTemps;
+}
+
+sub CompileCToNative {
+ my ($LLVMGCCCommand, $Backend, $OutputFile) = @_;
+ run $LLVMGCCCommand;
+ if ($PreprocessOnly) {
+ return;
+ }
+ my $BCFile = "${OutputFile}.llvm.bc";
+ if ($CompileDontLink) {
+ run "mv ${OutputFile} $BCFile";
+ } else { # gccld messes with the output file name
+ run "mv ${OutputFile}.bc $BCFile";
+ }
+ my $GeneratedCode;
+ if ($Backend eq 'cbe') {
+ $GeneratedCode = "${OutputFile}.cbe.c";
+ run "llc -march=c -f -o $GeneratedCode $BCFile";
+ } elsif ($Backend eq 'llc') {
+ $GeneratedCode = "${OutputFile}.llc.s";
+ run "llc -f -o $GeneratedCode $BCFile";
+ }
+ my $NativeGCCOptions = "";
+ if ($CompileDontLink) {
+ $NativeGCCOptions = "-c";
+ }
+ run "gcc $NativeGCCOptions $GeneratedCode -o $OutputFile";
+ run "rm ${OutputFile}.llvm.bc $GeneratedCode"
+ unless $SaveTemps;
+}
+
+# guess the name of the output file, if -o was not specified.
+$OutputFile = GetDefaultOutputFileName () unless $OutputFile;
+print "Output file is $OutputFile\n" if $Verbose;
+# do all the dirty work:
+if ($ProgramName eq /native-build/) {
+ my $LinkedBCFile = LinkBytecodeFilesIntoTemporary (@BytecodeFiles);
+ CompileBytecodeToNative ($LinkedBCFile, $Backend, $OutputFile);
+} elsif ($ProgramName =~ /llvm-native-gxx/) {
+ # build the llvm-gxx command line.
+ $LLVMGCCCommand = join (" ", ("llvm-g++", @ARGV));
+ CompileCToNative ($LLVMGCCCommand, $Backend, $OutputFile);
+}
+
+# we're done.
+exit 0;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+llvm-native-gxx
+
+=head1 SYNOPSIS
+
+llvm-native-g++ [OPTIONS...] FILE
+
+native-build [OPTIONS...] FILE
+
+=head1 DESCRIPTION
+
+llvm-native-g++ is a wrapper around the LLVM command-line tools which generates
+a native object (.o) file by compiling FILE with llvm-g++, and then running
+an LLVM back-end (CBE by default) over the resulting bytecode, and then
+compiling the resulting code to a native object file.
+
+If called as "native-build", it compiles bytecode to native code, and takes
+different options.
+
+=head1 OPTIONS
+
+llvm-native-g++ takes the same options as llvm-gcc. All options
+except -mllvm-backend=... are passed on to llvm-g++.
+
+=over 4
+
+=item -mllvm-backend=BACKEND
+
+Use BACKEND for native code generation.
+
+=item -v
+
+Print command lines that llvm-native-g++ runs.
+
+=item -o FILE
+
+llvm-native-g++ tries to guess the name of the llvm-g++ output file by looking
+for this option in the command line. If it can't find it, it finds the last C
+or C++ source file named on the command line, and turns its suffix into .o. See
+BUGS.
+
+=item -save-temps
+
+Save temporary files used by llvm-native-g++ (and llvm-g++, and g++).
+
+=back
+
+=head1 BUGS
+
+llvm-native-g++ only handles the case where llvm-g++ compiles a single
+file per invocation. llvm-native-g++ has weak command-line argument
+parsing and is a poor substitute for making g++/g++.c do this stuff.
+
+This manual page does not adequately document native-build mode.
+
+llvm-native-g++ is pretty gross because it represents the blind merging of two
+other scripts that predated it. It could use some code clean-up.
+
+=head1 SEE ALSO
+
+g++(1)
+
+=head1 AUTHOR
+
+Brian R. Gaeke
+
+=cut
diff --git a/utils/llvmdo b/utils/llvmdo
new file mode 100755
index 0000000000..5c09005a38
--- /dev/null
+++ b/utils/llvmdo
@@ -0,0 +1,198 @@
+#!/bin/sh
+##===- utils/llvmdo - Counts Lines Of Code -------------------*- Script -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file was developed by Reid Spencer and is distributed under the
+# University of Illinois Open Source License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This script is a general purpose "apply" function for the source files in LLVM
+# It uses "find" to locate all the source files and then applies the user's
+# command to them. As such, this command is often not used by itself much but
+# the other find related tools (countloc.sh,llvmgrep,getsrcs.sh,userloc.sh) are
+# all based on this script. This script defines "what is a source file" in
+# LLVM and so should be maintained if new directories, new file extensions,
+# etc. are used in LLVM as it progresses.
+#
+# Usage:
+# llvmdo [-topdir DIR] [-dirs "DIRNAMES..."] [-code-only] PROGRAM ARGS...
+#
+# The -topdir option allows you to specify the llvm source root directly. If it
+# is not specified then it will be obtained with llvm-config which must be built
+# and in your path.
+#
+# The -dirs argument allows you to specify the set of directories that are
+# searched. The default list of directories searched is:
+# include lib tools utils runtime autoconf docs test examples projects
+# Note that you must use quotes around the list of directory names.
+#
+# The -code-only option specifies that only those files that are considered
+# "code" should be visited. HTML documentation is considered code, but things
+# like README files, etc. are not.
+#
+# Finally, you simply specify whatever program you want to run against each
+# file and the arguments to give it. The PROGRAM will be given the file name
+# as its last argument.
+##===----------------------------------------------------------------------===##
+
+if test $# -lt 1 ; then
+ echo "Usage: llvmdo [-topdir DIR] [-dirs "DIRNAMES..."] [-code-only] PROGRAM ARGS..."
+ exit 1
+fi
+
+if test "$1" = "-topdir" ; then
+ TOPDIR="$2"
+ shift; shift;
+else
+ TOPDIR=`llvm-config --src-root`
+fi
+
+if test "$1" = "-dirs" ; then
+ LLVMDO_DIRS="$2"
+ shift ; shift
+elif test -z "$LLVMDO_DIRS" ; then
+ LLVMDO_DIRS="include lib tools utils runtime autoconf docs test examples projects"
+fi
+
+if test "$1" = "-code-only" ; then
+ CODE_ONLY="set"
+ shift
+else
+ CODE_ONLY=""
+fi
+
+if test "$1" = "" ; then
+ echo "Missing program name to run"
+ exit 1
+fi
+
+PROGRAM=`which $1`
+if test ! -x "$PROGRAM" ; then
+ echo "Can't execute $1"
+ exit 1
+fi
+shift;
+
+paths_to_ignore="\
+ -path */CVS -o \
+ -path */CVS/* -o \
+ -path */.svn/ -o \
+ -path */.svn/* -o \
+ -path docs/doxygen/* -o \
+ -path docs/CommandGuide/html/* -o \
+ -path docs/CommandGuide/man/* -o \
+ -path docs/CommandGuide/ps/* -o \
+ -path docs/CommandGuide/man/* -o \
+ -path docs/HistoricalNotes/* -o \
+ -path docs/img/* -o \
+ -path */.libs/* -o \
+ -path lib/Support/bzip2/* -o \
+ -path projects/llvm-test/* \
+"
+files_to_match="\
+ -name *.ac \
+ -o -name *.b \
+ -o -name *.c \
+ -o -name *.cc \
+ -o -name *.cfg \
+ -o -name *.cpp \
+ -o -name *.css \
+ -o -name *.def \
+ -o -name *.el \
+ -o -name *.exp \
+ -o -name *.footer \
+ -o -name *.gnuplot' \
+ -o -name *.h \
+ -o -name *.header \
+ -o -name *.html \
+ -o -name *.in \
+ -o -name *.inc \
+ -o -name *.intro \
+ -o -name *.l \
+ -o -name *.ll \
+ -o -name *.llx \
+ -o -name *.lst \
+ -o -name *.m4 \
+ -o -name *.pod \
+ -o -name *.pl \
+ -o -name *.py \
+ -o -name *.sh \
+ -o -name *.schema \
+ -o -name *.st \
+ -o -name *.tcl \
+ -o -name *.td \
+ -o -name *.tr \
+ -o -name *.y \
+ -o -name Make* \
+ -o -name llvmdo \
+ -o -name llvmgrep \
+ -o -name check-each-file \
+ -o -name codgen-diff \
+ -o -name cvsupdate \
+ -o -name llvm-native-gcc \
+ -o -name llvm-native-gxx \
+ -o -name makellvm \
+ -o -path include/llvm/ADT/ilist \
+ -o -path test/\*.ll \
+ -o -path test/Scripts/not \
+ -o -path runtime/\*.ll \
+"
+if test -z "$CODE_ONLY" ; then
+ files_to_match="$files_to_match \
+ -o -name *.txt \
+ -o -name *.TXT \
+ -o -name *.vim \
+ -o -name vimrc \
+ -o -name README \
+ -o -name COPYING.LIB \
+ -o -name LICENSE* "
+fi
+files_to_ignore="\
+ -name \.* \
+ -o -name *~ \
+ -o -name #* \
+ -o -name *.cvs \
+ -o -name configure \
+ -o -name slow.ll \
+ -o -name *libtool* \
+ -o -name ltdl* \
+ -o -name ltdl.m4 \
+ -o -name ltmain.m4 \
+ -o -name ltmain.sh \
+ -o -name aclocal.m4 \
+ -o -name acinclude.m4 \
+ -o -name *VerifierIsReallySlow.llx \
+ -o -name *LoopSimplifyCrash.ll \
+ -o -name *AST-Remove.ll \
+ -o -name llvmAsmParser.cpp \
+ -o -name llvmAsmParser.h \
+ -o -name Lexer.cpp \
+ -o -name FileLexer.cpp \
+ -o -name FileParser.cpp \
+ -o -name FileParser.h \
+ -o -name StackerParser.h \
+ -o -name StackerParser.cpp \
+ -o -name ConfigLexer.cpp \
+ -o -name PPCPerfectShuffle.h \
+"
+
+if test -d "$TOPDIR" ; then
+ cd $TOPDIR
+ # Have to use the right "find" on a per-platform basis. Most platforms have
+ # Gnu find as "find", but Solaris does not.
+ case `uname -s` in
+ SunOS) find_prog=gfind ;;
+ *) find_prog=find ;;
+ esac
+ # Turn off file name generation (globbing) so that substitution of the
+ # variables doesn't cause the shell to create lists of file names
+ set -f
+ $find_prog $LLVMDO_DIRS -type f \
+ \( $paths_to_ignore \) -prune \
+ -o \( \( $files_to_match \) \! \( $files_to_ignore \) \
+ -exec $PROGRAM "$@" {} \; \)
+else
+ echo "Can't find LLVM top directory in $TOPDIR"
+fi
diff --git a/utils/llvmgrep b/utils/llvmgrep
new file mode 100755
index 0000000000..c24dc6f3ab
--- /dev/null
+++ b/utils/llvmgrep
@@ -0,0 +1,39 @@
+#!/bin/sh
+##===- utils/llvmgrep - Counts Lines Of Code -----------------*- Script -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file was developed by Reid Spencer and is distributed under the
+# University of Illinois Open Source License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This script searches your srcdir for an egrep style pattern. This can quickly
+# help you build a list of the places you need to modify when changing a header
+# or other "global" name. The only argument is the pattern you want to search
+# for. It should be quoted to escape shell interpretation of the pattern's
+# special characters.
+#
+# Note that the implementation is based on llvmdo. See that script for more
+# details.
+##===----------------------------------------------------------------------===##
+
+if test "$1" = "-topdir" ; then
+ TOPDIR="$2"
+ shift; shift;
+else
+ TOPDIR=`llvm-config --src-root`
+fi
+
+if test -d "$TOPDIR" ; then
+ cd $TOPDIR
+ case `uname -s` in
+ SunOS) grep_cmd="ggrep -H -n" ;;
+ Linux) grep_cmd="egrep -H -n" ;;
+ *) grep_cmd="egrep -l -n" ;;
+ esac
+ ./utils/llvmdo -topdir "$TOPDIR" \
+ -dirs "include lib tools utils docs examples test projects" $grep_cmd "$*"
+else
+ echo "Can't find LLVM top directory"
+fi
diff --git a/utils/makellvm b/utils/makellvm
new file mode 100755
index 0000000000..9c479efc96
--- /dev/null
+++ b/utils/makellvm
@@ -0,0 +1,144 @@
+#!/bin/csh -f
+
+set pstatus = 0
+onintr cleanup
+alias usage 'echo "USAGE: $0:t [-h] [-n] [-obj obj-root] [gmake-flags] [VAR=...] [toolname (default: opt)]"; set pstatus = 1; goto cleanup'
+
+set EXEC = opt
+set GMAKE_OPTS = ""
+set DEBUG = 0
+
+## Search path for automatically finding the obj-root to use.
+## Note: The src root directory ${LLVMDIR} will be prepended to this path later.
+##
+set OBJROOTDIRLIST = ( )
+
+set doit = 1
+unset options_done
+while ( !( $?options_done ) && ($#argv > 0))
+ switch ($argv[1])
+ case -h :
+ usage
+ case -f :
+ if ($#argv < 2) usage
+ shift argv; set MFILE = $argv[1]; shift argv; breaksw
+ case -n :
+ set doit = 0; shift argv; breaksw
+ case -obj :
+ set OBJROOT = $argv[2]; shift argv; shift argv
+ if (! -d "$OBJROOT") then
+ echo "FATAL: Illegal obj-root directory ${OBJROOT}"
+ exit 1
+ endif
+ breaksw
+ case -d :
+ set doit = 0; set DEBUG = 1; shift argv; breaksw
+ case -* :
+ set GMAKE_OPTS = ( $GMAKE_OPTS $argv[1] ); shift argv; breaksw
+ default :
+ set optarg = `echo -n $argv[1] | sed 's/^[^=]*$//'`
+ if ($#optarg) then
+ set GMAKE_OPTS = ( $GMAKE_OPTS $optarg )
+ shift argv
+ else
+ set options_done
+ endif
+ breaksw
+ endsw
+end
+
+if ($#argv > 1) then
+ echo 'ERROR: More than one tool is not supported by "makellvm"'
+ usage
+endif
+if ($#argv > 0) then
+ set EXEC = $argv[1]
+endif
+if ($DEBUG) then
+ echo "DEBUG: EXEC = $EXEC"
+endif
+
+## Compute LLVMDIR: the root of the current LLVM tree.
+## It is recorded in the variable LEVEL in Makefile, to compute it
+##
+if (! $?MFILE) then
+ if (-f GNUmakefile) then
+ set MFILE = GNUmakefile
+ else if (-f makefile) then
+ set MFILE = makefile
+ else
+ set MFILE = Makefile
+ endif
+endif
+if ($DEBUG) then
+ echo "DEBUG: MFILE = $MFILE"
+endif
+if (! -f $MFILE) then
+ echo "Missing or invalid makefile: $MFILE"
+ exit 1
+endif
+
+set LLVMDIR = `awk '/LEVEL[ ]*=/ {print $NF}' $MFILE`
+if ($DEBUG) then
+ echo "DEBUG: LLVMDIR = $LLVMDIR"
+endif
+
+if ($#LLVMDIR == 0 || ! -d "$LLVMDIR") then
+ echo "Unable to find LLVM src-root directory or directory is invalid."
+ echo "Are you within a valid LLVM directory for running gmake?"
+ exit 1
+endif
+
+## Try to determine the obj-root directory automatically if not specified
+##
+set OBJROOTDIRLIST = ( ${LLVMDIR} $OBJROOTDIRLIST ) ## add src dir
+if ($?OBJROOT == 0) then
+ ## Try to determine object root directory by looking for Makefile.config
+ foreach objdir ( $OBJROOTDIRLIST )
+ if (-f "${objdir}/Makefile.config") then
+ set OBJROOT = ${objdir}
+ break
+ endif
+ end
+ if ($?OBJROOT == 0) then
+ echo "FATAL: Could not choose an obj-root directory from these choices:"
+ echo " ${OBJROOTDIRLIST}."
+ echo " You can specify it explicitly using '-obj obj-root'."
+ exit 1
+ endif
+ echo "Using OBJ-ROOT = ${OBJROOT} (specify '-obj obj-root' to override)."
+endif
+if (${OBJROOT} == ${LLVMDIR}) then
+ # run make in the source directory itself
+ set BUILDROOT = .
+else
+ # run make in the in the obj-root tree, in the directory for $cwd
+ set SRCROOT = `sh -c "cd $LLVMDIR; pwd | sed 's/\//\\\//g'"`
+ set CURSRCDIR = `echo $cwd | sed -e "s/${SRCROOT}//"`
+ set BUILDROOT = ${OBJROOT}/${CURSRCDIR}
+ unset SRCROOT CURSRCDIR
+endif
+if ($DEBUG) then
+ echo "DEBUG: BUILDROOT = $BUILDROOT"
+endif
+if (! -d $BUILDROOT) then
+ echo "FATAL: Invalid build directory: ${BUILDROOT}"
+ exit 1
+endif
+cd $BUILDROOT
+
+set CMD = "make $GMAKE_OPTS && (cd $LLVMDIR/tools/$EXEC && make $GMAKE_OPTS)"
+
+if ($doit == 1) then
+ csh -f -c "$CMD"
+else
+ echo '(NOT EXECUTING) COMMAND:'
+ echo " $CMD"
+endif
+
+
+#=========================================================
+# CODE TO BE EXECUTED IF INTERRUPT IS RECEIVED
+#=========================================================
+cleanup:
+ exit($pstatus)
diff --git a/utils/mkpatch b/utils/mkpatch
new file mode 100755
index 0000000000..afdd5fe28c
--- /dev/null
+++ b/utils/mkpatch
@@ -0,0 +1,37 @@
+#!/bin/bash
+#
+# This script makes a patch for LLVM ensuring the correct diff options and
+# putting the files in a standard review order.
+
+
+function error {
+ retcode="$?"
+ echo "mkpatch: error: $1 ($retcode)"
+ exit 1
+}
+
+if [ ! -e llvm.spec.in ] ; then
+ error "Please change directory to the LLVM top source directory"
+fi
+if [ "$#" -ne 1 ] ; then
+ error "usage: utils/mkpatch [PATCH_NAME]"
+fi
+NAME="$1"
+echo "mkpatch: Generating differences on top level files"
+svn diff -N -x -u -N * > "$NAME".patch.raw 2>&1
+echo "mkpatch: Generating differences on all directories"
+svn diff -x -u >> "$NAME".patch.raw 2>&1 \
+ autoconf docs utils include lib/System lib/Support lib/VMCore lib/AsmParser \
+ lib/Bytecode lib/Analysis lib/Transforms lib/CodeGen lib/Target \
+ lib/ExecutionEngine lib/Debugger lib/Linker \
+ tools test runtime projects examples win32 Xcode
+
+echo "mkpatch: Removing cruft from the patch file"
+sed -e '/^[?] .*/d' -e '/^cvs diff: Diffing/d' "$NAME".patch.raw | awk '\
+BEGIN { deleting = 0; } \
+/^Index: .*[.]cvs$/ { deleting = 1; fname=substr($0,7); \
+ print "Skipping: ", fname > "/dev/stderr"; } \
+/^Index:.*/ && !/^Index: .*[.]cvs$/ { deleting = 0; } \
+{ if (! deleting) { print; } } ' > "$NAME".patch || \
+ error "sed/awk cleanup failed"
+
diff --git a/utils/parseNLT.pl b/utils/parseNLT.pl
new file mode 100644
index 0000000000..95afca73a1
--- /dev/null
+++ b/utils/parseNLT.pl
@@ -0,0 +1,34 @@
+#!/usr/bin/perl
+# a first attempt to parse the nightly tester pages into something
+# one can reason about, namely import into a database
+# USE: perl parseNLT.pl <2005-03-31.html
+# for example
+
+while(<>)
+ {
+ if (/LLVM Test Results for (\w+) (\d+), (\d+)</)
+ {
+ $mon = $1;
+ $day = $2;
+ $year = $3;
+ }
+ if (/<td>([^<]+)<\/td>/)
+ {
+ if ($prefix)
+ { $output .= "$1 "; $count++; }
+ }
+ if (/<tr/)
+ {
+ if ($output and $count > 3)
+ { print "\n$day $mon $year $prefix/$output"; }
+ $output = "";
+ $count = 0;
+ }
+ if (/<h2>(Programs.+)<\/h2>/)
+ {
+ $prefix = $1;
+ }
+ }
+
+if ($output)
+ { print "\n$day $mon $year $prefix/$output"; $output = ""; }
diff --git a/utils/plotNLT.pl b/utils/plotNLT.pl
new file mode 100644
index 0000000000..55d503d689
--- /dev/null
+++ b/utils/plotNLT.pl
@@ -0,0 +1,53 @@
+#!/usr/bin/perl
+#takes a test and a program from a dp and produces a gnuplot script
+#use like perl plotNLT.pl password Programs/MultiSource/Benchmarks/ASCI_Purple/SMG2000/smg2000 llc
+
+use DBI;
+
+# database information
+$db="llvmalpha";
+$host="localhost";
+$userid="llvmdbuser";
+$passwd=shift @ARGV;
+$connectionInfo="dbi:mysql:$db;$host";
+
+# make connection to database
+$dbh = DBI->connect($connectionInfo,$userid,$passwd) or die DBI->errstr;
+
+
+$count = @ARGV / 2;
+
+print "set xdata time\n";
+print 'set timefmt "%Y-%m-%d"';
+print "\nplot";
+for ($iter = 0; $iter < $count; $iter++) {
+ if ($iter)
+ { print ","; }
+ print " '-' using 1:2 with lines";
+}
+
+print "\n";
+
+for ($iter = 0; $iter < $count; $iter++) {
+
+ $prog = shift @ARGV;
+ $test = shift @ARGV;
+
+ $query = "Select RUN, VALUE from Tests where TEST = '$test' AND NAME = '$prog' ORDER BY RUN";
+ #print "\n$query\n";
+
+ my $sth = $dbh->prepare( $query) || die "Can't prepare statement: $DBI::errstr";;
+
+ my $rc = $sth->execute or die DBI->errstr;
+
+ while(($da,$v) = $sth->fetchrow_array)
+ {
+ print "$da $v\n";
+ }
+
+ print "e\n";
+}
+
+
+# disconnect from database
+$dbh->disconnect;
diff --git a/utils/profile.pl b/utils/profile.pl
new file mode 100755
index 0000000000..ad0be073c8
--- /dev/null
+++ b/utils/profile.pl
@@ -0,0 +1,75 @@
+#!/usr/bin/perl -w
+#
+# Program: profile.pl
+#
+# Synopsis: Insert instrumentation code into a program, run it with the JIT,
+# then print out a profile report.
+#
+# Syntax: profile.pl [OPTIONS] bytecodefile <arguments>
+#
+# OPTIONS may include one or more of the following:
+# -block - Enable basicblock profiling
+# -edge - Enable edge profiling
+# -function - Enable function profiling
+# -o <filename> - Emit profiling information to the specified file, instead
+# of llvmprof.out
+#
+# Any unrecognized options are passed into the invocation of llvm-prof
+#
+
+my $ProfilePass = "-insert-edge-profiling";
+
+my $LLVMProfOpts = "";
+my $ProgramOpts = "";
+my $ProfileFile = "";
+
+# Parse arguments...
+while (scalar(@ARGV) and ($_ = $ARGV[0], /^[-+]/)) {
+ shift;
+ last if /^--$/; # Stop processing arguments on --
+
+ # List command line options here...
+ if (/^-?-block$/) { $ProfilePass = "-insert-block-profiling"; next; }
+ if (/^-?-edge$/) { $ProfilePass = "-insert-edge-profiling"; next; }
+ if (/^-?-function$/) { $ProfilePass = "-insert-function-profiling"; next; }
+ if (/^-?-o$/) { # Read -o filename...
+ die "-o option requires a filename argument!" if (!scalar(@ARGV));
+ $ProgramOpts .= " -llvmprof-output $ARGV[0]";
+ $ProfileFile = $ARGV[0];
+ shift;
+ next;
+ }
+ if (/^-?-help$/) {
+ print "OVERVIEW: profile.pl - Instrumentation and profile printer.\n\n";
+ print "USAGE: profile.pl [options] program.bc <program args>\n\n";
+ print "OPTIONS:\n";
+ print " -block - Enable basicblock profiling\n";
+ print " -edge - Enable edge profiling\n";
+ print " -function - Enable function profiling\n";
+ print " -o <file> - Specify an output file other than llvm-prof.out.\n";
+ print " -help - Print this usage information\n";
+ print "\nAll other options are passed into llvm-prof.\n";
+ exit 1;
+ }
+
+ # Otherwise, pass the option on to llvm-prof
+ $LLVMProfOpts .= " " . $_;
+}
+
+die "Must specify LLVM bytecode file as first argument!" if (@ARGV == 0);
+
+my $BytecodeFile = $ARGV[0];
+
+shift @ARGV;
+
+my $LLIPath = `which lli`;
+$LLIPath = `dirname $LLIPath`;
+chomp $LLIPath;
+
+my $LibProfPath = $LLIPath . "/../../Debug/lib/profile_rt.so";
+
+system "opt -q -f $ProfilePass $BytecodeFile -o $BytecodeFile.inst";
+system "lli -fake-argv0 '$BytecodeFile' -load $LibProfPath " .
+ "$BytecodeFile.inst $ProgramOpts " . (join ' ', @ARGV);
+system "rm $BytecodeFile.inst";
+system "llvm-prof $LLVMProfOpts $BytecodeFile $ProfileFile";
diff --git a/utils/userloc.pl b/utils/userloc.pl
new file mode 100755
index 0000000000..4da2f40292
--- /dev/null
+++ b/utils/userloc.pl
@@ -0,0 +1,216 @@
+#!/usr/bin/perl -w
+#
+# Program: userloc.pl
+#
+# Synopsis: This program uses "cvs annotate" to get a summary of how many lines
+# of code the various developres are responsible for. It takes one
+# argument, the directory to process. If the argument is not specified
+# then the cwd is used. The directory must be an LLVM tree checked out
+# from cvs.
+#
+# Syntax: userloc.pl [-tag=tag|-html... <directory>...
+#
+# Options:
+# -tag=tag
+# Use "tag" to select the revision (as per cvs -r option)
+# -filedetails
+# Report details about lines of code in each file for each user
+# -html
+# Generate HTML output instead of text output
+# -topdir
+# Specify where the top llvm source directory is. Otherwise the
+# llvm-config tool is used to find it.
+# Directories:
+# The directories passed after the options should be relative paths to
+# directories of interest from the top of the llvm source tree, e.g. "lib"
+# or "include", etc.
+
+die "Usage userloc.pl [-tag=tag|-html] <directories>..."
+ if ($#ARGV < 0);
+
+my $tag = "";
+my $html = 0;
+my $debug = 0;
+my $filedetails = "";
+my $srcroot = "";
+while ( defined($ARGV[0]) && substr($ARGV[0],0,1) eq '-' )
+{
+ if ($ARGV[0] =~ /-tag=.*/) {
+ $tag = $ARGV[0];
+ $tag =~ s#-tag=(.*)#$1#;
+ } elsif ($ARGV[0] =~ /-filedetails/) {
+ $filedetails = 1;
+ } elsif ($ARGV[0] eq "-html") {
+ $html = 1;
+ } elsif ($ARGV[0] eq "-debug") {
+ $debug = 1;
+ } elsif ($ARGV[0] eq "-topdir") {
+ shift; $srcroot = $ARGV[0]; shift;
+ } else {
+ die "Invalid option: $ARGV[0]";
+ }
+ shift;
+}
+
+if (length($srcroot) == 0) {
+ chomp($srcroot = `llvm-config --src-root`);
+}
+if (! -d "$srcroot") {
+ die "Invalid source root: $srcroot\n";
+}
+chdir($srcroot);
+my $llvmdo = "$srcroot/utils/llvmdo -topdir '$srcroot'";
+my %Stats;
+my %FileStats;
+
+my $annotate = "cvs -z6 annotate -lf ";
+if (length($tag) > 0)
+{
+ $annotate = $annotate . " -r" . $tag;
+}
+
+sub GetCVSFiles
+{
+ my $d = $_[0];
+ my $files ="";
+ open FILELIST,
+ "$llvmdo -dirs \"$d\" -code-only echo |" || die "Can't get list of files with llvmdo";
+ while ( defined($line = <FILELIST>) ) {
+ chomp($file = $line);
+ print "File: $file\n" if ($debug);
+ $files = "$files $file";
+ }
+ return $files;
+}
+
+sub ScanDir
+{
+ my $Dir = $_[0];
+ my $files = GetCVSFiles($Dir);
+
+ open (DATA,"$annotate $files 2>&1 |")
+ || die "Can't read cvs annotation data";
+
+ my $curfile = "";
+ while ( defined($line = <DATA>) )
+ {
+ chomp($line);
+ if ($line =~ '^Annotations for.*') {
+ $curfile = $line;
+ $curfile =~ s#^Annotations for ([[:print:]]*)#$1#;
+ print "Scanning: $curfile\n" if ($debug);
+ } elsif ($line =~ /^[0-9.]*[ \t]*\([^)]*\):/) {
+ $uname = $line;
+ $uname =~ s#^[0-9.]*[ \t]*\(([a-zA-Z0-9_.-]*) [^)]*\):.*#$1#;
+ $Stats{$uname}++;
+ if ($filedetails) {
+ $FileStats{$uname} = {} unless exists $FileStats{$uname};
+ ${$FileStats{$uname}}{$curfile}++;
+ }
+ }
+ }
+ close DATA;
+}
+
+sub printStats
+{
+ my $dir = $_[0];
+ my $hash = $_[1];
+ my $user;
+ my $total = 0;
+
+ foreach $user (keys %Stats) { $total += $Stats{$user}; }
+
+ if ($html) {
+ print "<p>Total Source Lines: $total<br/></p>\n";
+ print "<table>";
+ print " <tr><th style=\"text-align:right\">LOC</th>\n";
+ print " <th style=\"text-align:right\">\%LOC</th>\n";
+ print " <th style=\"text-align:left\">User</th>\n";
+ print "</tr>\n";
+ }
+
+ foreach $user ( sort keys %Stats )
+ {
+ my $v = $Stats{$user};
+ if (defined($v))
+ {
+ if ($html) {
+ printf "<tr><td style=\"text-align:right\">%d</td><td style=\"text-align:right\">(%4.1f%%)</td><td style=\"text-align:left\">", $v, (100.0/$total)*$v;
+ if ($filedetails) {
+ print "<a href=\"#$user\">$user</a></td></tr>";
+ } else {
+ print $user,"</td></tr>";
+ }
+ } else {
+ printf "%8d (%4.1f%%) %s\n", $v, (100.0/$total)*$v, $user;
+ }
+ }
+ }
+ print "</table>\n" if ($html);
+
+ if ($filedetails) {
+ foreach $user (sort keys %FileStats) {
+ my $total = 0;
+ foreach $file (sort keys %{$FileStats{$user}}) {
+ $total += ${$FileStats{$user}}{$file}
+ }
+ if ($html) {
+ print "<table><tr><th style=\"text-align:left\" colspan=\"3\"><a name=\"$user\">$user</a></th></tr>\n";
+ } else {
+ print $user,":\n";
+ }
+ foreach $file (sort keys %{$FileStats{$user}}) {
+ my $v = ${$FileStats{$user}}{$file};
+ if ($html) {
+ printf "<tr><td style=\"text-align:right\">&nbsp;&nbsp;%d</td><td
+ style=\"text-align:right\">&nbsp;%4.1f%%</td><td
+ style=\"text-align:left\">%s</td></tr>",$v, (100.0/$total)*$v,$file;
+ } else {
+ printf "%8d (%4.1f%%) %s\n", $v, (100.0/$total)*$v, $file;
+ }
+ }
+ if ($html) { print "</table>\n"; }
+ }
+ }
+}
+
+
+if ($html)
+{
+print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n";
+print "<html>\n<head>\n";
+print " <title>LLVM LOC Based On CVS Annotation</title>\n";
+print " <link rel=\"stylesheet\" href=\"llvm.css\" type=\"text/css\"/>\n";
+print "</head>\n";
+print "<body><div class=\"doc_title\">LLVM LOC Based On CVS Annotation</div>\n";
+print "<p>This document shows the total lines of code per user in each\n";
+print "LLVM directory. Lines of code are attributed by the user that last\n";
+print "committed the line. This does not necessarily reflect authorship.</p>\n";
+}
+
+my @DIRS;
+if ($#ARGV > 0) {
+ @DIRS = @ARGV;
+} else {
+ push @DIRS, 'include';
+ push @DIRS, 'lib';
+ push @DIRS, 'tools';
+ push @DIRS, 'runtime';
+ push @DIRS, 'docs';
+ push @DIRS, 'test';
+ push @DIRS, 'utils';
+ push @DIRS, 'examples';
+ push @DIRS, 'projects/Stacker';
+ push @DIRS, 'projects/sample';
+ push @DIRS, 'autoconf';
+}
+
+for $Index ( 0 .. $#DIRS) {
+ print "Scanning Dir: $DIRS[$Index]\n" if ($debug);
+ ScanDir($DIRS[$Index]);
+}
+
+printStats;
+
+print "</body></html>\n" if ($html) ;
diff --git a/utils/vim/README b/utils/vim/README
new file mode 100644
index 0000000000..466de4f686
--- /dev/null
+++ b/utils/vim/README
@@ -0,0 +1,43 @@
+-*- llvm/utils/vim/README -*-
+
+These are syntax highlighting files for the VIM editor. Included are:
+
+* llvm.vim
+
+ Syntax highlighting mode for LLVM assembly files. To use, COPY `llvm.vim' to
+ ~/.vim/syntax and add this code to your ~/.vimrc :
+
+ augroup filetype
+ au! BufRead,BufNewFile *.ll set filetype=llvm
+ au! BufRead,BufNewFile *.llx set filetype=llvm
+ augroup END
+
+* tablegen.vim
+
+ Syntax highlighting mode for TableGen description files. To use, COPY
+ `tablegen.vim' to ~/.vim/syntax and add this code to your ~/.vimrc :
+
+ augroup filetype
+ au! BufRead,BufNewFile *.td set filetype=tablegen
+ augroup END
+
+
+IMPORTANT: Making symlinks from ~/.vim/syntax/... to the syntax files in your
+LLVM source tree does not work, you DO need to copy the files directly.
+
+However, if you do not already have a ~/.vim/syntax/ directory, simply
+symlinking it to llvm/utils/vim will do the trick nicely, and you can stay
+up-to-date with CVS.
+
+Note: If you notice missing or incorrect syntax highlighting, please contact
+<llvmbugs [at] cs.uiuc.edu>; if you wish to provide a patch to improve the
+functionality, it will be most appreciated. Thank you.
+
+If you find yourself working with LLVM Makefiles often, but you don't get syntax
+highlighting (because the files have names such as Makefile.rules or
+TEST.nightly.Makefile), add the following to your ~/.vimrc:
+
+ " LLVM Makefile highlighting mode
+ augroup filetype
+ au! BufRead,BufNewFile *Makefile* set filetype=make
+ augroup END
diff --git a/utils/vim/llvm.vim b/utils/vim/llvm.vim
new file mode 100644
index 0000000000..712a9a59a7
--- /dev/null
+++ b/utils/vim/llvm.vim
@@ -0,0 +1,61 @@
+" Vim syntax file
+" Language: llvm
+" Maintainer: The LLVM team, http://llvm.org/
+" Updated: 2003-06-02
+
+if version < 600
+ syntax clear
+elseif exists("b:current_syntax")
+ finish
+endif
+
+syn case match
+
+syn keyword llvmType void bool sbyte ubyte
+syn keyword llvmType short ushort int uint
+syn keyword llvmType long ulong float double
+syn keyword llvmType type label opaque
+
+syn keyword llvmStatement add sub mul div rem
+syn keyword llvmStatement and or xor
+syn keyword llvmStatement setne seteq setlt setgt setle setge
+
+syn keyword llvmStatement phi tail call cast to select shl shr vaarg vanext
+syn keyword llvmStatement ret br switch invoke unwind unreachable
+syn keyword llvmStatement malloc alloca free load store getelementptr
+
+syn keyword llvmStatement begin end true false zeroinitializer
+syn keyword llvmStatement declare global constant const
+syn keyword llvmStatement internal uninitialized external implementation
+syn keyword llvmStatement linkonce weak appending
+syn keyword llvmStatement undef null to except target endian pointersize deplibs
+syn keyword llvmStatement big little volatile fastcc coldcc cc
+
+"syn match llvmFunction /%[a-zA-Z\$._\-][a-zA-Z\$._\-0-9]*/
+syn match llvmNumber /\<\d\+\>/
+syn match llvmNumber /\<\d\+\.\d*\>/
+
+syn match llvmComment /;.*$/
+syn region llvmString start=/"/ skip=/\\"/ end=/"/
+syn match llvmLabel /[\-a-zA-Z\$._0-9]*:/
+
+
+if version >= 508 || !exists("did_c_syn_inits")
+ if version < 508
+ let did_c_syn_inits = 1
+ command -nargs=+ HiLink hi link <args>
+ else
+ command -nargs=+ HiLink hi def link <args>
+ endif
+
+ HiLink llvmType Type
+ HiLink llvmStatement Statement
+ HiLink llvmNumber Number
+ HiLink llvmComment Comment
+ HiLink llvmString String
+ HiLink llvmLabel Label
+
+ delcommand HiLink
+endif
+
+let b:current_syntax = "llvm"
diff --git a/utils/vim/tablegen.vim b/utils/vim/tablegen.vim
new file mode 100644
index 0000000000..1514e2e0e8
--- /dev/null
+++ b/utils/vim/tablegen.vim
@@ -0,0 +1,41 @@
+" Vim syntax file
+" Language: TableGen
+" Maintainer: The LLVM team, http://llvm.org/
+" Updated: 2003-08-11
+
+if version < 600
+ syntax clear
+elseif exists("b:current_syntax")
+ finish
+endif
+
+syn case match
+
+syn keyword tgKeyword def let in code dag field include
+syn keyword tgType class int string list bit bits
+" FIXME: this does not handle hex (0x...) or binary (0b...) constants
+syn match tgNumber /\<\d\+\>/
+syn match tgNumber /\<\d\+\.\d*\>/
+syn match tgComment /\/\/.*$/
+" FIXME: this does not capture multi-line C-style comments
+syn match tgComment /\/\*.*\*\//
+syn region tgString start=/"/ skip=/\\"/ end=/"/
+
+if version >= 508 || !exists("did_c_syn_inits")
+ if version < 508
+ let did_c_syn_inits = 1
+ command -nargs=+ HiLink hi link <args>
+ else
+ command -nargs=+ HiLink hi def link <args>
+ endif
+
+ HiLink tgKeyword Statement
+ HiLink tgType Type
+ HiLink tgNumber Number
+ HiLink tgComment Comment
+ HiLink tgString String
+
+ delcommand HiLink
+endif
+
+let b:current_syntax = "tablegen"
diff --git a/utils/vim/vimrc b/utils/vim/vimrc
new file mode 100644
index 0000000000..3c872d9862
--- /dev/null
+++ b/utils/vim/vimrc
@@ -0,0 +1,40 @@
+" LLVM coding guidelines conformance for VIM
+" Maintainer: LLVM Team, http://llvm.cs.uiuc.edu
+" Updated: 2005-04-24
+" WARNING: Read before you source in all these commands and macros! Some
+" of them may change VIM behavior that you depend on.
+
+" Wrap text at 80 cols
+set textwidth=80
+
+" A tab produces a 2-space indentation
+set tabstop=2
+set shiftwidth=2
+set expandtab
+
+" Optional
+" C/C++ programming helpers
+set autoindent
+set smartindent
+" Add and delete spaces in increments of `shiftwidth' for tabs
+set smarttab
+
+" Enable filetype detection
+filetype on
+
+" LLVM Makefiles can have names such as Makefile.rules or TEST.nightly.Makefile,
+" so it's important to categorize them as such.
+augroup filetype
+ au! BufRead,BufNewFile *Makefile* set filetype=make
+augroup END
+
+" In Makefiles, don't expand tabs to spaces, since we need the actual tabs
+autocmd FileType make set noexpandtab
+
+" Useful macros for cleaning up code to conform to LLVM coding guidelines
+
+" Delete trailing whitespace and tabs at the end of each line
+map :dtws :%s/[\ \t]\+$//
+
+" Convert all tab characters to two spaces
+map :untab :%s/\t/ /g
diff --git a/utils/webNLT.pl b/utils/webNLT.pl
new file mode 100755
index 0000000000..fb29fd292e
--- /dev/null
+++ b/utils/webNLT.pl
@@ -0,0 +1,83 @@
+#!/usr/bin/perl
+
+use DBI;
+use CGI;
+
+$q = new CGI;
+print $q->header();
+print $q->start_html(-title=>"Nightly Tester DB");
+
+unless($q->param('pwd'))
+ {
+ print $q->startform();
+ print $q->password_field(-name=>"pwd", -size=>20, -maxlength=>20);
+ print $q->submit();
+ print $q->endform();
+ }
+else
+ {
+ # database information
+ $db="llvmalpha";
+ $host="localhost";
+ $userid="llvmdbuser";
+ $passwd=$q->param('pwd');
+ $connectionInfo="dbi:mysql:$db;$host";
+
+ # make connection to database
+ $dbh = DBI->connect($connectionInfo,$userid,$passwd) or die DBI->errstr;
+ $query = "Select DISTINCT(NAME) from Tests";
+ my $sth = $dbh->prepare($query) || die "Can't prepare statement: $DBI::errstr";
+ my $rc = $sth->execute or die DBI->errstr;
+ while (($n) = $sth->fetchrow_array)
+ {
+ push @names, ($n);
+# print "$n<P>";
+ }
+ $query = "Select DISTINCT(TEST) from Tests";
+ my $sth = $dbh->prepare($query) || die "Can't prepare statement: $DBI::errstr";
+ my $rc = $sth->execute or die DBI->errstr;
+ while (($n) = $sth->fetchrow_array)
+ {
+ push @tests, ($n);
+# print "$n\n";
+ }
+
+# print join "<BR>", @names;
+
+ print $q->startform();
+ print $q->scrolling_list(-name=>"test", -values=>\@tests, -multiple=>'true');
+ print "<P>";
+ print $q->scrolling_list(-name=>"name", -values=>\@names, -multiple=>'true');
+ print "<P>";
+ print $q->submit();
+ print $q->hidden("pwd", $q->param('pwd'));
+ print $q->endform();
+
+ # disconnect from database
+ $dbh->disconnect;
+
+ #now generate the urls to the chart
+ if ($q->param('test') && $q->param('name'))
+ {
+ my @names = $q->param('name');
+ my @tests = $q->param('test');
+ print "<P>";
+ print join "<BR>", @names;
+ print "<P>";
+ print join "<BR>", @tests;
+ print "<P>";
+ $str = "pwd=" . $q->param('pwd');
+ $count = 0;
+ foreach $n (@names)
+ {
+ foreach $t (@tests)
+ {
+ $str = "$str&t$count=$t&n$count=$n";
+ $count++;
+ }
+ }
+ print "<img src=\"cgiplotNLT.pl?$str\">";
+ }
+ }
+
+print $q->end_html();