diff options
author | Dan Gohman <djg@cray.com> | 2007-07-18 16:29:46 +0000 |
---|---|---|
committer | Dan Gohman <djg@cray.com> | 2007-07-18 16:29:46 +0000 |
commit | f17a25c88b892d30c2b41ba7ecdfbdfb2b4be9cc (patch) | |
tree | ebb79ea1ee5e3bc1fdf38541a811a8b804f0679a /utils | |
download | external_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')
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 Results</a><br> +<a href="http://llvm.org/">LLVM 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<n>' - 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<Ty>' - Represent a list of values, all of which must +/// be of the specified type. +/// +class ListRecTy : public RecTy { + RecTy *Ty; +public: + ListRecTy(RecTy *T) : Ty(T) {} + + RecTy *getElementType() const { return Ty; } + + 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 "[1m", @_, "[0m"; +} + +# 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 "[1m", @_, "[0m"; +} + +# 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\"> %d</td><td + style=\"text-align:right\"> %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(); |